From 78357b8852626b510527f3b8d770a7dd8956fcc7 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Fri, 16 Jul 2021 08:38:43 -0700 Subject: . --- html/101screen.subx.html | 20 +- html/102keyboard.subx.html | 18 +- html/103grapheme.subx.html | 22 +- html/104test.subx.html | 18 +- html/105string-equal.subx.html | 20 +- html/106stream.subx.html | 18 +- html/108write.subx.html | 20 +- html/109stream-equal.subx.html | 20 +- html/112read-byte.subx.html | 35 +- html/113write-stream.subx.html | 109 +- html/115write-byte.subx.html | 20 +- html/117write-int-hex.subx.html | 20 +- html/118parse-hex-int.subx.html | 20 +- html/120allocate.subx.html | 20 +- html/121new-stream.subx.html | 20 +- html/123slice.subx.html | 22 +- html/124next-token.subx.html | 20 +- html/126write-int-decimal.subx.html | 367 +- html/127next-word.subx.html | 20 +- html/301array-equal.subx.html | 20 +- html/302stack_allocate.subx.html | 18 +- html/308allocate-array.subx.html | 16 +- html/309stream.subx.html | 18 +- html/310copy-bytes.subx.html | 128 +- html/311decimal-int.subx.html | 22 +- html/312copy.subx.html | 20 +- html/313index-bounds-check.subx.html | 16 +- html/314divide.subx.html | 18 +- html/315stack-debug.subx.html | 20 +- html/316colors.subx.html | 18 +- html/317abort.subx.html | 26 +- html/318debug-counter.subx.html | 92 + html/319timer.subx.html | 74 + html/400.mu.html | 224 +- html/403unicode.mu.html | 22 +- html/408float.mu.html | 20 +- html/411string.mu.html | 22 +- html/412render-float-decimal.mu.html | 24 +- html/500fake-screen.mu.html | 24 +- html/501draw-text.mu.html | 24 +- html/502test.mu.html | 18 +- html/503manhattan-line.mu.html | 16 +- html/504test-screen.mu.html | 24 +- html/505colors.mu.html | 618 +-- html/506math.mu.html | 18 +- html/507line.mu.html | 24 +- html/508circle.mu.html | 20 +- html/509bezier.mu.html | 22 +- html/apps/*.subx.html | 57 + html/apps/colors.mu.html | 309 ++ html/apps/ex1.mu.html | 74 + html/apps/ex10.mu.html | 105 + html/apps/ex11.mu.html | 328 ++ html/apps/ex12.mu.html | 92 + html/apps/ex2.mu.html | 92 + html/apps/ex3.mu.html | 95 + html/apps/ex4.mu.html | 75 + html/apps/ex5.mu.html | 78 + html/apps/ex6.mu.html | 95 + html/apps/ex7.mu.html | 108 + html/apps/ex8.mu.html | 74 + html/apps/ex9.mu.html | 115 + html/apps/hest-life.mu.html | 1097 ++++++ html/apps/img.mu.html | 1217 ++++++ html/apps/life.mu.html | 320 ++ html/apps/mandelbrot-fixed.mu.html | 330 ++ html/apps/mandelbrot-silhouette.mu.html | 216 ++ html/apps/mandelbrot.mu.html | 246 ++ html/apps/rpn.mu.html | 217 ++ html/boot.subx.html | 1266 +++---- html/colors.mu.html | 302 -- html/ex1.mu.html | 62 - html/ex10.mu.html | 105 - html/ex11.mu.html | 328 -- html/ex2.mu.html | 92 - html/ex3.mu.html | 95 - html/ex4.mu.html | 75 - html/ex5.mu.html | 78 - html/ex6.mu.html | 95 - html/ex7.mu.html | 108 - html/ex8.mu.html | 74 - html/ex9.mu.html | 115 - html/hest-life.mu.html | 1097 ------ html/img.mu.html | 1217 ------ html/life.mu.html | 24 +- html/linux/000init.subx.html | 14 +- html/linux/101_write.subx.html | 16 +- html/linux/102test.subx.html | 18 +- html/linux/103kernel-string-equal.subx.html | 24 +- html/linux/104new-segment.subx.html | 18 +- html/linux/105string-equal.subx.html | 24 +- html/linux/106stream.subx.html | 18 +- html/linux/107trace.subx.html | 28 +- html/linux/108write.subx.html | 20 +- html/linux/109stream-equal.subx.html | 20 +- html/linux/110stop.subx.html | 22 +- html/linux/111read.subx.html | 22 +- html/linux/112read-byte.subx.html | 24 +- html/linux/113write-stream.subx.html | 22 +- html/linux/114error.subx.html | 20 +- html/linux/115write-byte.subx.html | 24 +- html/linux/116write-buffered.subx.html | 22 +- html/linux/117write-int-hex.subx.html | 22 +- html/linux/118parse-hex-int.subx.html | 22 +- html/linux/119error-byte.subx.html | 22 +- html/linux/120allocate.subx.html | 20 +- html/linux/121new-stream.subx.html | 20 +- html/linux/122read-line.subx.html | 20 +- html/linux/123slice.subx.html | 22 +- html/linux/124next-token.subx.html | 20 +- html/linux/125write-stream-data.subx.html | 20 +- html/linux/126write-int-decimal.subx.html | 24 +- html/linux/127next-word.subx.html | 20 +- html/linux/128subx-words.subx.html | 20 +- html/linux/129emit-hex.subx.html | 20 +- html/linux/130emit.subx.html | 22 +- html/linux/131table.subx.html | 22 +- html/linux/132slurp.subx.html | 20 +- html/linux/133subx-widths.subx.html | 20 +- html/linux/134emit-hex-array.subx.html | 22 +- html/linux/135next-word-or-string.subx.html | 20 +- html/linux/201register-names.subx.html | 14 +- html/linux/202write-int.subx.html | 20 +- html/linux/203stack.subx.html | 22 +- html/linux/301array-equal.subx.html | 20 +- html/linux/302stack_allocate.subx.html | 18 +- html/linux/303kernel-string.subx.html | 16 +- html/linux/304screen.subx.html | 20 +- html/linux/305keyboard.subx.html | 20 +- html/linux/306files.subx.html | 18 +- html/linux/307size.subx.html | 16 +- html/linux/308allocate-array.subx.html | 16 +- html/linux/309stream.subx.html | 18 +- html/linux/310copy-bytes.subx.html | 18 +- html/linux/311decimal-int.subx.html | 20 +- html/linux/312copy.subx.html | 20 +- html/linux/313index-bounds-check.subx.html | 18 +- html/linux/314divide.subx.html | 18 +- html/linux/315slice.subx.html | 14 +- html/linux/400.mu.html | 16 +- html/linux/401test.mu.html | 18 +- html/linux/402time.mu.html | 20 +- html/linux/403unicode.mu.html | 24 +- html/linux/404stream.mu.html | 22 +- html/linux/405screen.mu.html | 20 +- html/linux/406int32.mu.html | 18 +- html/linux/407right-justify.mu.html | 20 +- html/linux/408float.mu.html | 20 +- html/linux/409print-float-hex.mu.html | 26 +- html/linux/410file.mu.html | 20 +- html/linux/411string.mu.html | 22 +- html/linux/412print-float-decimal.mu.html | 24 +- html/linux/apps/advent2017/1a.mu.html | 131 + html/linux/apps/advent2020/1a.mu.html | 165 + html/linux/apps/advent2020/1b.mu.html | 181 + html/linux/apps/advent2020/2a.mu.html | 159 + html/linux/apps/advent2020/2b.mu.html | 190 + html/linux/apps/advent2020/3a.mu.html | 175 + html/linux/apps/advent2020/3b.mu.html | 205 + html/linux/apps/advent2020/4a.mu.html | 142 + html/linux/apps/advent2020/4b.mu.html | 381 ++ html/linux/apps/advent2020/5a.mu.html | 146 + html/linux/apps/advent2020/5b.mu.html | 148 + html/linux/apps/arith.mu.html | 326 ++ html/linux/apps/crenshaw2-1.subx.html | 621 ++++ html/linux/apps/crenshaw2-1b.subx.html | 815 ++++ html/linux/apps/ex1.mu.html | 77 + html/linux/apps/ex1.subx.html | 79 + html/linux/apps/ex10.subx.html | 132 + html/linux/apps/ex11.subx.html | 421 +++ html/linux/apps/ex12.subx.html | 104 + html/linux/apps/ex13.subx.html | 87 + html/linux/apps/ex14.subx.html | 88 + html/linux/apps/ex2.mu.html | 83 + html/linux/apps/ex2.subx.html | 79 + html/linux/apps/ex3.2.mu.html | 98 + html/linux/apps/ex3.mu.html | 84 + html/linux/apps/ex3.subx.html | 98 + html/linux/apps/ex4.subx.html | 99 + html/linux/apps/ex5.subx.html | 101 + html/linux/apps/ex6.subx.html | 96 + html/linux/apps/ex7.subx.html | 159 + html/linux/apps/ex8.subx.html | 123 + html/linux/apps/ex9.subx.html | 114 + html/linux/apps/factorial.mu.html | 125 + html/linux/apps/factorial.subx.html | 217 ++ html/linux/apps/factorial2.subx.html | 185 + html/linux/apps/factorial3.subx.html | 142 + html/linux/apps/factorial4.subx.html | 150 + html/linux/apps/hello.mu.html | 72 + html/linux/apps/parse-int.mu.html | 114 + html/linux/apps/print-file.mu.html | 104 + html/linux/apps/raytracing/1.mu.html | 95 + html/linux/apps/raytracing/2.mu.html | 153 + html/linux/apps/raytracing/3.mu.html | 554 +++ html/linux/apps/raytracing/color.mu.html | 100 + html/linux/apps/raytracing/ray.mu.html | 86 + html/linux/apps/raytracing/vec.mu.html | 201 + html/linux/apps/rpn.mu.html | 215 ++ html/linux/apps/texture.mu.html | 126 + html/linux/apps/tui.mu.html | 98 + html/linux/arith.mu.html | 326 -- html/linux/assort.subx.html | 54 +- html/linux/braces.subx.html | 24 +- html/linux/calls.subx.html | 22 +- html/linux/dquotes.subx.html | 36 +- html/linux/ex1.mu.html | 75 - html/linux/ex2.mu.html | 83 - html/linux/ex3.2.mu.html | 98 - html/linux/ex3.mu.html | 84 - html/linux/factorial.mu.html | 125 - html/linux/hello.mu.html | 72 - html/linux/hex.subx.html | 20 +- html/linux/labels_baremetal.subx.html | 48 +- html/linux/mu-init-test.subx.html | 18 +- html/linux/mu-init.subx.html | 14 +- html/linux/mu.subx.html | 704 ++-- html/linux/pack.subx.html | 110 +- html/linux/parse-int.mu.html | 114 - html/linux/print-file.mu.html | 104 - html/linux/random.subx.html | 16 +- html/linux/rpn.mu.html | 215 -- html/linux/sigils.subx.html | 58 +- html/linux/stack_array.subx.html | 20 +- html/linux/subx-params.subx.html | 14 +- html/linux/survey_baremetal.subx.html | 32 +- html/linux/survey_elf.subx.html | 72 +- html/linux/tests.subx.html | 18 +- html/linux/texture.mu.html | 126 - html/linux/tile/box.mu.html | 20 +- html/linux/tile/data.mu.html | 24 +- html/linux/tile/environment.mu.html | 22 +- html/linux/tile/float-stack.mu.html | 20 +- html/linux/tile/gap-buffer.mu.html | 22 +- html/linux/tile/grapheme-stack.mu.html | 22 +- html/linux/tile/main.mu.html | 24 +- html/linux/tile/rpn.mu.html | 22 +- html/linux/tile/surface.mu.html | 22 +- html/linux/tile/table.mu.html | 24 +- html/linux/tile/value-stack.mu.html | 26 +- html/linux/tile/value.mu.html | 26 +- html/linux/tile/word.mu.html | 24 +- html/linux/tui.mu.html | 98 - html/mandelbrot-fixed.mu.html | 330 -- html/mandelbrot-silhouette.mu.html | 216 -- html/mandelbrot.mu.html | 246 -- html/mu-init.subx.html | 18 +- html/rpn.mu.html | 217 -- html/shell/cell.mu.html | 20 +- html/shell/environment.mu.html | 50 +- html/shell/evaluate.mu.html | 1517 ++++---- html/shell/gap-buffer.mu.html | 24 +- html/shell/global.mu.html | 32 +- html/shell/grapheme-stack.mu.html | 26 +- html/shell/infix.mu.html | 46 +- html/shell/int-stack.mu.html | 20 +- html/shell/macroexpand.mu.html | 68 +- html/shell/main.mu.html | 20 +- html/shell/parenthesize.mu.html | 20 +- html/shell/parse.mu.html | 24 +- html/shell/primitives.mu.html | 5357 +++++++++++++++++---------- html/shell/print.mu.html | 858 ++--- html/shell/read.mu.html | 20 +- html/shell/sandbox.mu.html | 1094 +++--- html/shell/tokenize.mu.html | 30 +- html/shell/trace.mu.html | 22 +- tools/update_html | 37 +- 267 files changed, 22826 insertions(+), 13506 deletions(-) create mode 100644 html/318debug-counter.subx.html create mode 100644 html/319timer.subx.html create mode 100644 html/apps/*.subx.html create mode 100644 html/apps/colors.mu.html create mode 100644 html/apps/ex1.mu.html create mode 100644 html/apps/ex10.mu.html create mode 100644 html/apps/ex11.mu.html create mode 100644 html/apps/ex12.mu.html create mode 100644 html/apps/ex2.mu.html create mode 100644 html/apps/ex3.mu.html create mode 100644 html/apps/ex4.mu.html create mode 100644 html/apps/ex5.mu.html create mode 100644 html/apps/ex6.mu.html create mode 100644 html/apps/ex7.mu.html create mode 100644 html/apps/ex8.mu.html create mode 100644 html/apps/ex9.mu.html create mode 100644 html/apps/hest-life.mu.html create mode 100644 html/apps/img.mu.html create mode 100644 html/apps/life.mu.html create mode 100644 html/apps/mandelbrot-fixed.mu.html create mode 100644 html/apps/mandelbrot-silhouette.mu.html create mode 100644 html/apps/mandelbrot.mu.html create mode 100644 html/apps/rpn.mu.html delete mode 100644 html/colors.mu.html delete mode 100644 html/ex1.mu.html delete mode 100644 html/ex10.mu.html delete mode 100644 html/ex11.mu.html delete mode 100644 html/ex2.mu.html delete mode 100644 html/ex3.mu.html delete mode 100644 html/ex4.mu.html delete mode 100644 html/ex5.mu.html delete mode 100644 html/ex6.mu.html delete mode 100644 html/ex7.mu.html delete mode 100644 html/ex8.mu.html delete mode 100644 html/ex9.mu.html delete mode 100644 html/hest-life.mu.html delete mode 100644 html/img.mu.html create mode 100644 html/linux/apps/advent2017/1a.mu.html create mode 100644 html/linux/apps/advent2020/1a.mu.html create mode 100644 html/linux/apps/advent2020/1b.mu.html create mode 100644 html/linux/apps/advent2020/2a.mu.html create mode 100644 html/linux/apps/advent2020/2b.mu.html create mode 100644 html/linux/apps/advent2020/3a.mu.html create mode 100644 html/linux/apps/advent2020/3b.mu.html create mode 100644 html/linux/apps/advent2020/4a.mu.html create mode 100644 html/linux/apps/advent2020/4b.mu.html create mode 100644 html/linux/apps/advent2020/5a.mu.html create mode 100644 html/linux/apps/advent2020/5b.mu.html create mode 100644 html/linux/apps/arith.mu.html create mode 100644 html/linux/apps/crenshaw2-1.subx.html create mode 100644 html/linux/apps/crenshaw2-1b.subx.html create mode 100644 html/linux/apps/ex1.mu.html create mode 100644 html/linux/apps/ex1.subx.html create mode 100644 html/linux/apps/ex10.subx.html create mode 100644 html/linux/apps/ex11.subx.html create mode 100644 html/linux/apps/ex12.subx.html create mode 100644 html/linux/apps/ex13.subx.html create mode 100644 html/linux/apps/ex14.subx.html create mode 100644 html/linux/apps/ex2.mu.html create mode 100644 html/linux/apps/ex2.subx.html create mode 100644 html/linux/apps/ex3.2.mu.html create mode 100644 html/linux/apps/ex3.mu.html create mode 100644 html/linux/apps/ex3.subx.html create mode 100644 html/linux/apps/ex4.subx.html create mode 100644 html/linux/apps/ex5.subx.html create mode 100644 html/linux/apps/ex6.subx.html create mode 100644 html/linux/apps/ex7.subx.html create mode 100644 html/linux/apps/ex8.subx.html create mode 100644 html/linux/apps/ex9.subx.html create mode 100644 html/linux/apps/factorial.mu.html create mode 100644 html/linux/apps/factorial.subx.html create mode 100644 html/linux/apps/factorial2.subx.html create mode 100644 html/linux/apps/factorial3.subx.html create mode 100644 html/linux/apps/factorial4.subx.html create mode 100644 html/linux/apps/hello.mu.html create mode 100644 html/linux/apps/parse-int.mu.html create mode 100644 html/linux/apps/print-file.mu.html create mode 100644 html/linux/apps/raytracing/1.mu.html create mode 100644 html/linux/apps/raytracing/2.mu.html create mode 100644 html/linux/apps/raytracing/3.mu.html create mode 100644 html/linux/apps/raytracing/color.mu.html create mode 100644 html/linux/apps/raytracing/ray.mu.html create mode 100644 html/linux/apps/raytracing/vec.mu.html create mode 100644 html/linux/apps/rpn.mu.html create mode 100644 html/linux/apps/texture.mu.html create mode 100644 html/linux/apps/tui.mu.html delete mode 100644 html/linux/arith.mu.html delete mode 100644 html/linux/ex1.mu.html delete mode 100644 html/linux/ex2.mu.html delete mode 100644 html/linux/ex3.2.mu.html delete mode 100644 html/linux/ex3.mu.html delete mode 100644 html/linux/factorial.mu.html delete mode 100644 html/linux/hello.mu.html delete mode 100644 html/linux/parse-int.mu.html delete mode 100644 html/linux/print-file.mu.html delete mode 100644 html/linux/rpn.mu.html delete mode 100644 html/linux/texture.mu.html delete mode 100644 html/linux/tui.mu.html delete mode 100644 html/mandelbrot-fixed.mu.html delete mode 100644 html/mandelbrot-silhouette.mu.html delete mode 100644 html/mandelbrot.mu.html delete mode 100644 html/rpn.mu.html diff --git a/html/101screen.subx.html b/html/101screen.subx.html index 9224d187..775988d0 100644 --- a/html/101screen.subx.html +++ b/html/101screen.subx.html @@ -1,14 +1,14 @@ - + - + Mu - 101screen.subx - - + + - + - - + + +https://github.com/akkartik/mu/blob/main/318debug-counter.subx +
+ 1 # A rudimentary counter that can be called from anywhere.
+ 2 
+ 3 == code
+ 4 
+ 5 count-event:
+ 6     # . prologue
+ 7     55/push-ebp
+ 8     89/<- %ebp 4/r32/esp
+ 9     #
+10     ff 0/subop/increment *Foo
+11 $count-event:end:
+12     # . epilogue
+13     89/<- %esp 5/r32/ebp
+14     5d/pop-to-ebp
+15     c3/return
+16 
+17 count-of-events:  # -> _/eax: int
+18     # . prologue
+19     55/push-ebp
+20     89/<- %ebp 4/r32/esp
+21     #
+22     8b/-> *Foo 0/r32/eax
+23 $count-of-events:end:
+24     # . epilogue
+25     89/<- %esp 5/r32/ebp
+26     5d/pop-to-ebp
+27     c3/return
+28 
+29 == data
+30 Foo:
+31   0/imm32
+
+ + + diff --git a/html/319timer.subx.html b/html/319timer.subx.html new file mode 100644 index 00000000..1409f834 --- /dev/null +++ b/html/319timer.subx.html @@ -0,0 +1,74 @@ + + + + +Mu - 319timer.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/319timer.subx +
+ 1 == code
+ 2 
+ 3 timer-counter:  # -> _/eax: int
+ 4     # . prologue
+ 5     55/push-ebp
+ 6     89/<- %ebp 4/r32/esp
+ 7     #
+ 8     8b/-> *Timer-counter 0/r32/eax
+ 9 $timer-counter:end:
+10     # . epilogue
+11     89/<- %esp 5/r32/ebp
+12     5d/pop-to-ebp
+13     c3/return
+
+ + + diff --git a/html/400.mu.html b/html/400.mu.html index 5febaa75..929aa511 100644 --- a/html/400.mu.html +++ b/html/400.mu.html @@ -1,29 +1,29 @@ - + - + Mu - 400.mu - - + + - + - - + + +https://github.com/akkartik/mu/blob/main/apps/*.subx +
+1 
+
+ + + diff --git a/html/apps/colors.mu.html b/html/apps/colors.mu.html new file mode 100644 index 00000000..2085fbdd --- /dev/null +++ b/html/apps/colors.mu.html @@ -0,0 +1,309 @@ + + + + +Mu - apps/colors.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/colors.mu +
+  1 # Return colors 'near' a given r/g/b value (expressed in hex)
+  2 # If we did this rigorously we'd need to implement cosines. So we won't.
+  3 #
+  4 # To build:
+  5 #   $ ./translate apps/colors.mu
+  6 #
+  7 # Example session:
+  8 #   $ qemu-system-i386 code.img
+  9 #   Enter 3 hex bytes for r, g, b (lowercase; no 0x prefix) separated by a single space> aa 0 aa
+ 10 #   5
+ 11 # This means only color 5 in the default palette is similar to #aa00aa.
+ 12 
+ 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+ 14   var in-storage: (stream byte 0x10)
+ 15   var in/esi: (addr stream byte) <- address in-storage
+ 16   {
+ 17     # print prompt
+ 18     var x/eax: int <- draw-text-rightward screen, "Enter 3 hex bytes for r, g, b (lowercase; no 0x prefix) separated by a single space> ", 0x10/x, 0x80/xmax, 0x28/y, 3/fg/cyan, 0/bg
+ 19     # read line from keyboard
+ 20     clear-stream in
+ 21     {
+ 22       draw-cursor screen, 0x20/space
+ 23       var key/eax: byte <- read-key keyboard
+ 24       compare key, 0xa/newline
+ 25       break-if-=
+ 26       compare key, 0
+ 27       loop-if-=
+ 28       var key2/eax: int <- copy key
+ 29       append-byte in, key2
+ 30       var g/eax: grapheme <- copy key2
+ 31       draw-grapheme-at-cursor screen, g, 0xf/fg, 0/bg
+ 32       move-cursor-right 0
+ 33       loop
+ 34     }
+ 35     clear-screen screen
+ 36     # parse
+ 37     var a/ecx: int <- copy 0
+ 38     var b/edx: int <- copy 0
+ 39     var c/ebx: int <- copy 0
+ 40     # a, b, c = r, g, b
+ 41     a, b, c <- parse in
+ 42 #?     set-cursor-position screen, 0x10/x, 0x1a/y
+ 43 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
+ 44 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+ 45 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
+ 46 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+ 47 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
+ 48     a, b, c <- hsl a, b, c
+ 49     # return all colors in the same quadrant in h, s and l
+ 50     print-nearby-colors screen, a, b, c
+ 51     # another metric
+ 52     var color/eax: int <- nearest-color-euclidean-hsl a, b, c
+ 53     set-cursor-position screen, 0x10/x, 0x26/y
+ 54     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "nearest (euclidean, h/s/l): ", 0xf/fg, 0/bg
+ 55     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, color, 7/fg, 0/bg
+ 56     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 0xf/fg, 0/bg
+ 57     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "               ", 0/fg, color
+ 58     #
+ 59     loop
+ 60   }
+ 61 }
+ 62 
+ 63 # read exactly 3 words in a single line
+ 64 # Each word consists of exactly 1 or 2 hex bytes. No hex prefix.
+ 65 fn parse in: (addr stream byte) -> _/ecx: int, _/edx: int, _/ebx: int {
+ 66   # read first byte of r
+ 67   var tmp/eax: byte <- read-byte in
+ 68   {
+ 69     var valid?/eax: boolean <- hex-digit? tmp
+ 70     compare valid?, 0/false
+ 71     break-if-!=
+ 72     abort "invalid byte 0 of r"
+ 73   }
+ 74   tmp <- fast-hex-digit-value tmp
+ 75   var r/ecx: int <- copy tmp
+ 76 #?   set-cursor-position 0/screen, 0x10/x, 0x10/y
+ 77 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
+ 78   # read second byte of r
+ 79   tmp <- read-byte in
+ 80   {
+ 81     {
+ 82       var valid?/eax: boolean <- hex-digit? tmp
+ 83       compare valid?, 0/false
+ 84     }
+ 85     break-if-=
+ 86     r <- shift-left 4
+ 87     tmp <- fast-hex-digit-value tmp
+ 88 #?     {
+ 89 #?       var foo/eax: int <- copy tmp
+ 90 #?       set-cursor-position 0/screen, 0x10/x, 0x11/y
+ 91 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
+ 92 #?     }
+ 93     r <- add tmp
+ 94 #?     {
+ 95 #?       set-cursor-position 0/screen, 0x10/x, 0x12/y
+ 96 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
+ 97 #?     }
+ 98     tmp <- read-byte in  # skip space
+ 99   }
+100   # read first byte of g
+101   var tmp/eax: byte <- read-byte in
+102   {
+103     var valid?/eax: boolean <- hex-digit? tmp
+104     compare valid?, 0/false
+105     break-if-!=
+106     abort "invalid byte 0 of g"
+107   }
+108   tmp <- fast-hex-digit-value tmp
+109   var g/edx: int <- copy tmp
+110 #?   set-cursor-position 0/screen, 0x10/x, 0x13/y
+111 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
+112   # read second byte of g
+113   tmp <- read-byte in
+114   {
+115     {
+116       var valid?/eax: boolean <- hex-digit? tmp
+117       compare valid?, 0/false
+118     }
+119     break-if-=
+120     g <- shift-left 4
+121     tmp <- fast-hex-digit-value tmp
+122 #?     {
+123 #?       var foo/eax: int <- copy tmp
+124 #?       set-cursor-position 0/screen, 0x10/x, 0x14/y
+125 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
+126 #?     }
+127     g <- add tmp
+128 #?     {
+129 #?       set-cursor-position 0/screen, 0x10/x, 0x15/y
+130 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
+131 #?     }
+132     tmp <- read-byte in  # skip space
+133   }
+134   # read first byte of b
+135   var tmp/eax: byte <- read-byte in
+136   {
+137     var valid?/eax: boolean <- hex-digit? tmp
+138     compare valid?, 0/false
+139     break-if-!=
+140     abort "invalid byte 0 of b"
+141   }
+142   tmp <- fast-hex-digit-value tmp
+143   var b/ebx: int <- copy tmp
+144 #?   set-cursor-position 0/screen, 0x10/x, 0x16/y
+145 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
+146   # read second byte of b
+147   {
+148     {
+149       var done?/eax: boolean <- stream-empty? in
+150       compare done?, 0/false
+151     }
+152     break-if-!=
+153     tmp <- read-byte in
+154     {
+155       var valid?/eax: boolean <- hex-digit? tmp
+156       compare valid?, 0/false
+157     }
+158     break-if-=
+159     b <- shift-left 4
+160     tmp <- fast-hex-digit-value tmp
+161 #?     {
+162 #?       var foo/eax: int <- copy tmp
+163 #?       set-cursor-position 0/screen, 0x10/x, 0x17/y
+164 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
+165 #?     }
+166     b <- add tmp
+167 #?     {
+168 #?       set-cursor-position 0/screen, 0x10/x, 0x18/y
+169 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
+170 #?     }
+171   }
+172   return r, g, b
+173 }
+174 
+175 # no error checking
+176 fn fast-hex-digit-value in: byte -> _/eax: byte {
+177   var result/eax: byte <- copy in
+178   compare result, 0x39
+179   {
+180     break-if->
+181     result <- subtract 0x30/0
+182     return result
+183   }
+184   result <- subtract 0x61/a
+185   result <- add 0xa/10
+186   return result
+187 }
+188 
+189 fn print-nearby-colors screen: (addr screen), h: int, s: int, l: int {
+190 #?   set-cursor-position screen, 0x10/x, 0x1c/y
+191 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
+192 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+193 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
+194 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+195 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
+196   # save just top 2 bits of each, so that we narrow down to 1/64th of the volume
+197   shift-right h, 6
+198   shift-right s, 6
+199   shift-right l, 6
+200 #?   set-cursor-position screen, 0x10/x, 0x1/y
+201 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
+202 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+203 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
+204 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+205 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
+206   var a/ecx: int <- copy 0
+207   var b/edx: int <- copy 0
+208   var c/ebx: int <- copy 0
+209   var color/eax: int <- copy 0
+210   var y/esi: int <- copy 2
+211   {
+212     compare color, 0x100
+213     break-if->=
+214     a, b, c <- color-rgb color
+215     a, b, c <- hsl a, b, c
+216     a <- shift-right 6
+217     b <- shift-right 6
+218     c <- shift-right 6
+219     {
+220       compare a, h
+221       break-if-!=
+222       compare b, s
+223       break-if-!=
+224       compare c, l
+225       break-if-!=
+226       set-cursor-position screen, 0x10/x, y
+227       draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, color, 7/fg, 0/bg
+228       set-cursor-position screen, 0x14/x, y
+229       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+230       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "               ", 0/fg, color
+231 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+232 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
+233 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+234 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
+235 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
+236 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
+237       y <- increment
+238     }
+239     color <- increment
+240     loop
+241   }
+242 }
+
+ + + diff --git a/html/apps/ex1.mu.html b/html/apps/ex1.mu.html new file mode 100644 index 00000000..cc21ce0f --- /dev/null +++ b/html/apps/ex1.mu.html @@ -0,0 +1,74 @@ + + + + +Mu - apps/ex1.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex1.mu +
+ 1 # The simplest possible bare-metal program.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex1.mu        # emits code.img
+ 5 # To run:
+ 6 #   qemu-system-i386 code.img
+ 7 # Or:
+ 8 #   bochs -f bochsrc               # bochsrc loads code.img
+ 9 #
+10 # Expected output: blank screen with no errors
+11 
+12 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+13   loop
+14 }
+
+ + + diff --git a/html/apps/ex10.mu.html b/html/apps/ex10.mu.html new file mode 100644 index 00000000..6f506cd3 --- /dev/null +++ b/html/apps/ex10.mu.html @@ -0,0 +1,105 @@ + + + + +Mu - apps/ex10.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex10.mu +
+ 1 # Demo of mouse support.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex10.mu       # emits code.img
+ 5 # To run:
+ 6 #   qemu-system-i386 code.img
+ 7 # Or:
+ 8 #   bochs -f bochsrc               # bochsrc loads code.img
+ 9 #
+10 # Expected output:
+11 #   Values between -256 and +255 as you move the mouse over the window.
+12 #   You might need to click on the window once.
+13 
+14 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+15   # repeatedly print out mouse driver results if non-zero
+16   $main:event-loop: {
+17     var dx/eax: int <- copy 0
+18     var dy/ecx: int <- copy 0
+19     dx, dy <- read-mouse-event
+20     {
+21       compare dx, 0
+22       break-if-!=
+23       compare dy, 0
+24       break-if-!=
+25       loop $main:event-loop
+26     }
+27     {
+28       var dummy1/eax: int <- copy 0
+29       var dummy2/ecx: int <- copy 0
+30       dummy1, dummy2 <- draw-text-wrapping-right-then-down-over-full-screen screen, "         ", 0/x, 0x10/y, 0x31/fg, 0/bg
+31     }
+32     {
+33       var dummy/ecx: int <- copy 0
+34       dx, dummy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen screen, dx, 0/x, 0x10/y, 0x31/fg, 0/bg
+35     }
+36     {
+37       var dummy/eax: int <- copy 0
+38       dummy, dy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen screen, dy, 5/x, 0x10/y, 0x31/fg, 0/bg
+39     }
+40     loop
+41   }
+42 }
+
+ + + diff --git a/html/apps/ex11.mu.html b/html/apps/ex11.mu.html new file mode 100644 index 00000000..e4ff1600 --- /dev/null +++ b/html/apps/ex11.mu.html @@ -0,0 +1,328 @@ + + + + +Mu - apps/ex11.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex11.mu +
+  1 # Demo of an interactive app: controlling a Bezier curve on screen
+  2 #
+  3 # To build a disk image:
+  4 #   ./translate apps/ex11.mu       # emits code.img
+  5 # To run:
+  6 #   qemu-system-i386 code.img
+  7 # Or:
+  8 #   bochs -f bochsrc               # bochsrc loads code.img
+  9 #
+ 10 # Expected output: a spline with 3 control points. Use `Tab` to switch cursor
+ 11 # between control points, and arrow keys to move the control point at the
+ 12 # cursor.
+ 13 
+ 14 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+ 15   var env-storage: environment
+ 16   var env/esi: (addr environment) <- address env-storage
+ 17   initialize-environment env, 0x200 0x20, 0x180 0x90, 0x180 0x160
+ 18   {
+ 19     render screen, env
+ 20     edit keyboard, env
+ 21     loop
+ 22   }
+ 23 }
+ 24 
+ 25 type environment {
+ 26   p0: (handle point)
+ 27   p1: (handle point)
+ 28   p2: (handle point)
+ 29   cursor: (handle point)  # one of p0, p1 or p2
+ 30 }
+ 31 
+ 32 type point {
+ 33   x: int
+ 34   y: int
+ 35 }
+ 36 
+ 37 fn render screen: (addr screen), _self: (addr environment) {
+ 38   clear-screen screen
+ 39   var self/esi: (addr environment) <- copy _self
+ 40   var tmp-ah/ecx: (addr handle point) <- get self, p0
+ 41   var tmp/eax: (addr point) <- lookup *tmp-ah
+ 42   var p0/ebx: (addr point) <- copy tmp
+ 43   tmp-ah <- get self, p1
+ 44   tmp <- lookup *tmp-ah
+ 45   var p1/edx: (addr point) <- copy tmp
+ 46   tmp-ah <- get self, p2
+ 47   tmp <- lookup *tmp-ah
+ 48   var p2/ecx: (addr point) <- copy tmp
+ 49   # control lines
+ 50   line    screen, p0, p1,                 7/color
+ 51   line    screen, p1, p2,                 7/color
+ 52   # curve above control lines
+ 53   bezier  screen, p0, p1, p2,             0xc/color
+ 54   # points above curve
+ 55   disc    screen, p0,           3/radius, 7/color   0xf/border
+ 56   disc    screen, p1,           3/radius, 7/color   0xf/border
+ 57   disc    screen, p2,           3/radius, 7/color   0xf/border
+ 58   # cursor last of all
+ 59   var cursor-ah/eax: (addr handle point) <- get self, cursor
+ 60   var cursor/eax: (addr point) <- lookup *cursor-ah
+ 61   cursor screen, cursor, 0xa/side, 3/color
+ 62 }
+ 63 
+ 64 fn bezier screen: (addr screen), _p0: (addr point), _p1: (addr point), _p2: (addr point), color: int {
+ 65   var p0/esi: (addr point) <- copy _p0
+ 66   var x0/ecx: (addr int) <- get p0, x
+ 67   var y0/edx: (addr int) <- get p0, y
+ 68   var p1/esi: (addr point) <- copy _p1
+ 69   var x1/ebx: (addr int) <- get p1, x
+ 70   var y1/eax: (addr int) <- get p1, y
+ 71   var p2/esi: (addr point) <- copy _p2
+ 72   var x2/edi: (addr int) <- get p2, x
+ 73   var y2/esi: (addr int) <- get p2, y
+ 74   draw-monotonic-bezier screen, *x0 *y0, *x1 *y1, *x2 *y2, color
+ 75 }
+ 76 
+ 77 fn cursor screen: (addr screen), _p: (addr point), side: int, color: int {
+ 78   var half-side/eax: int <- copy side
+ 79   half-side <- shift-right 1
+ 80   var p/esi: (addr point) <- copy _p
+ 81   var x-a/ecx: (addr int) <- get p, x
+ 82   var left-x/ecx: int <- copy *x-a
+ 83   left-x <- subtract half-side
+ 84   var y-a/edx: (addr int) <- get p, y
+ 85   var top-y/edx: int <- copy *y-a
+ 86   top-y <- subtract half-side
+ 87   var max/eax: int <- copy left-x
+ 88   max <- add side
+ 89   draw-horizontal-line screen, top-y, left-x, max, color
+ 90   max <- copy top-y
+ 91   max <- add side
+ 92   draw-vertical-line screen, left-x, top-y, max, color
+ 93   var right-x/ebx: int <- copy left-x
+ 94   right-x <- add side
+ 95   draw-vertical-line screen, right-x, top-y, max, color
+ 96   var bottom-y/edx: int <- copy top-y
+ 97   bottom-y <- add side
+ 98   draw-horizontal-line screen, bottom-y, left-x, right-x, color
+ 99 }
+100 
+101 fn edit keyboard: (addr keyboard), _self: (addr environment) {
+102   var self/esi: (addr environment) <- copy _self
+103   var key/eax: byte <- read-key keyboard
+104   compare key, 0
+105   loop-if-=
+106   {
+107     compare key, 9/tab
+108     break-if-!=
+109     toggle-cursor self
+110     return
+111   }
+112   {
+113     compare key, 0x80/left-arrow
+114     break-if-!=
+115     cursor-left self
+116     return
+117   }
+118   {
+119     compare key, 0x83/right-arrow
+120     break-if-!=
+121     cursor-right self
+122     return
+123   }
+124   {
+125     compare key, 0x81/down-arrow
+126     break-if-!=
+127     cursor-down self
+128     return
+129   }
+130   {
+131     compare key, 0x82/up-arrow
+132     break-if-!=
+133     cursor-up self
+134     return
+135   }
+136 }
+137 
+138 fn toggle-cursor _self: (addr environment) {
+139   var self/esi: (addr environment) <- copy _self
+140   var cursor-ah/edi: (addr handle point) <- get self, cursor
+141   var p0-ah/ecx: (addr handle point) <- get self, p0
+142   var p1-ah/edx: (addr handle point) <- get self, p1
+143   var p2-ah/ebx: (addr handle point) <- get self, p2
+144   {
+145     var p0?/eax: boolean <- handle-equal? *p0-ah, *cursor-ah
+146     compare p0?, 0/false
+147     break-if-=
+148     copy-object p1-ah, cursor-ah
+149     return
+150   }
+151   {
+152     var p1?/eax: boolean <- handle-equal? *p1-ah, *cursor-ah
+153     compare p1?, 0/false
+154     break-if-=
+155     copy-object p2-ah, cursor-ah
+156     return
+157   }
+158   {
+159     var p2?/eax: boolean <- handle-equal? *p2-ah, *cursor-ah
+160     compare p2?, 0/false
+161     break-if-=
+162     copy-object p0-ah, cursor-ah
+163     return
+164   }
+165   abort "lost cursor"
+166 }
+167 
+168 fn cursor-left _self: (addr environment) {
+169   var self/esi: (addr environment) <- copy _self
+170   var cursor-ah/esi: (addr handle point) <- get self, cursor
+171   var cursor/eax: (addr point) <- lookup *cursor-ah
+172   var cursor-x/eax: (addr int) <- get cursor, x
+173   compare *cursor-x, 0x20
+174   {
+175     break-if-<
+176     subtract-from *cursor-x, 0x20
+177   }
+178 }
+179 
+180 fn cursor-right _self: (addr environment) {
+181   var self/esi: (addr environment) <- copy _self
+182   var cursor-ah/esi: (addr handle point) <- get self, cursor
+183   var cursor/eax: (addr point) <- lookup *cursor-ah
+184   var cursor-x/eax: (addr int) <- get cursor, x
+185   compare *cursor-x, 0x3f0
+186   {
+187     break-if->
+188     add-to *cursor-x, 0x20
+189   }
+190 }
+191 
+192 fn cursor-up _self: (addr environment) {
+193   var self/esi: (addr environment) <- copy _self
+194   var cursor-ah/esi: (addr handle point) <- get self, cursor
+195   var cursor/eax: (addr point) <- lookup *cursor-ah
+196   var cursor-y/eax: (addr int) <- get cursor, y
+197   compare *cursor-y, 0x20
+198   {
+199     break-if-<
+200     subtract-from *cursor-y, 0x20
+201   }
+202 }
+203 
+204 fn cursor-down _self: (addr environment) {
+205   var self/esi: (addr environment) <- copy _self
+206   var cursor-ah/esi: (addr handle point) <- get self, cursor
+207   var cursor/eax: (addr point) <- lookup *cursor-ah
+208   var cursor-y/eax: (addr int) <- get cursor, y
+209   compare *cursor-y, 0x2f0
+210   {
+211     break-if->
+212     add-to *cursor-y, 0x20
+213   }
+214 }
+215 
+216 fn line screen: (addr screen), _p0: (addr point), _p1: (addr point), color: int {
+217   var p0/esi: (addr point) <- copy _p0
+218   var x0/ecx: (addr int) <- get p0, x
+219   var y0/edx: (addr int) <- get p0, y
+220   var p1/esi: (addr point) <- copy _p1
+221   var x1/ebx: (addr int) <- get p1, x
+222   var y1/eax: (addr int) <- get p1, y
+223   draw-line screen, *x0 *y0, *x1 *y1, color
+224 }
+225 
+226 fn disc screen: (addr screen), _p: (addr point), radius: int, color: int, border-color: int {
+227   var p/esi: (addr point) <- copy _p
+228   var x/ecx: (addr int) <- get p, x
+229   var y/edx: (addr int) <- get p, y
+230   draw-disc screen, *x *y, radius, color, border-color
+231 }
+232 
+233 fn initialize-environment _self: (addr environment), x0: int, y0: int, x1: int, y1: int, x2: int, y2: int {
+234   var self/esi: (addr environment) <- copy _self
+235   var p0-ah/eax: (addr handle point) <- get self, p0
+236   allocate p0-ah
+237   var p0/eax: (addr point) <- lookup *p0-ah
+238   initialize-point p0, x0 y0
+239   var p1-ah/eax: (addr handle point) <- get self, p1
+240   allocate p1-ah
+241   var p1/eax: (addr point) <- lookup *p1-ah
+242   initialize-point p1, x1 y1
+243   var p2-ah/eax: (addr handle point) <- get self, p2
+244   allocate p2-ah
+245   var p2/eax: (addr point) <- lookup *p2-ah
+246   initialize-point p2, x2 y2
+247   # cursor initially at p0
+248   var cursor-ah/edi: (addr handle point) <- get self, cursor
+249   var src-ah/esi: (addr handle point) <- get self, p0
+250   copy-object src-ah, cursor-ah
+251 }
+252 
+253 fn initialize-point _p: (addr point), x: int, y: int {
+254   var p/esi: (addr point) <- copy _p
+255   var dest/eax: (addr int) <- get p, x
+256   var src/ecx: int <- copy x
+257   copy-to *dest, src
+258   dest <- get p, y
+259   src <- copy y
+260   copy-to *dest, src
+261 }
+
+ + + diff --git a/html/apps/ex12.mu.html b/html/apps/ex12.mu.html new file mode 100644 index 00000000..b0b3a763 --- /dev/null +++ b/html/apps/ex12.mu.html @@ -0,0 +1,92 @@ + + + + +Mu - apps/ex12.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex12.mu +
+ 1 # Checking the timer.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex12.mu       # emits code.img
+ 5 # To run:
+ 6 #   qemu-system-i386 code.img
+ 7 # Or:
+ 8 #   bochs -f bochsrc               # bochsrc loads code.img
+ 9 #
+10 # Expected output: text with slowly updating colors
+11 
+12 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+13   var fg/ecx: int <- copy 0
+14   var prev-timer-counter/edx: int <- copy 0
+15   {
+16     var dummy/eax: int <- draw-text-rightward screen, "hello from baremetal Mu!", 0x10/x, 0x400/xmax, 0x10/y, fg, 0/bg
+17     # wait for timer to bump
+18     {
+19       var curr-timer-counter/eax: int <- timer-counter
+20       compare curr-timer-counter, prev-timer-counter
+21       loop-if-=
+22       prev-timer-counter <- copy curr-timer-counter
+23     }
+24     # switch color
+25     fg <- increment
+26     loop
+27   }
+28 }
+
+ + + diff --git a/html/apps/ex2.mu.html b/html/apps/ex2.mu.html new file mode 100644 index 00000000..6bd96247 --- /dev/null +++ b/html/apps/ex2.mu.html @@ -0,0 +1,92 @@ + + + + +Mu - apps/ex2.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex2.mu +
+ 1 # Test out the video mode by filling in the screen with pixels.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex2.mu        # emits code.img
+ 5 # To run:
+ 6 #   qemu-system-i386 code.img
+ 7 # Or:
+ 8 #   bochs -f bochsrc               # bochsrc loads code.img
+ 9 
+10 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+11   var y/eax: int <- copy 0
+12   {
+13     compare y, 0x300/screen-height=768
+14     break-if->=
+15     var x/edx: int <- copy 0
+16     {
+17       compare x, 0x400/screen-width=1024
+18       break-if->=
+19       var color/ecx: int <- copy x
+20       color <- and 0xff
+21       pixel screen x, y, color
+22       x <- increment
+23       loop
+24     }
+25     y <- increment
+26     loop
+27   }
+28 }
+
+ + + diff --git a/html/apps/ex3.mu.html b/html/apps/ex3.mu.html new file mode 100644 index 00000000..864032ce --- /dev/null +++ b/html/apps/ex3.mu.html @@ -0,0 +1,95 @@ + + + + +Mu - apps/ex3.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex3.mu +
+ 1 # Draw pixels in response to keyboard events, starting from the top-left
+ 2 # and in raster order.
+ 3 #
+ 4 # To build a disk image:
+ 5 #   ./translate apps/ex3.mu        # emits code.img
+ 6 # To run:
+ 7 #   qemu-system-i386 code.img
+ 8 # Or:
+ 9 #   bochs -f bochsrc               # bochsrc loads code.img
+10 #
+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 screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+15   var x/ecx: int <- copy 0
+16   var y/edx: int <- copy 0
+17   {
+18     var key/eax: byte <- read-key keyboard
+19     compare key, 0
+20     loop-if-=  # busy wait
+21     pixel-on-real-screen x, y, 0x31/green
+22     x <- increment
+23     compare x, 0x400/screen-width=1024
+24     {
+25       break-if-<
+26       y <- increment
+27       x <- copy 0
+28     }
+29     loop
+30   }
+31 }
+
+ + + diff --git a/html/apps/ex4.mu.html b/html/apps/ex4.mu.html new file mode 100644 index 00000000..eb7ee20a --- /dev/null +++ b/html/apps/ex4.mu.html @@ -0,0 +1,75 @@ + + + + +Mu - apps/ex4.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex4.mu +
+ 1 # Draw a character using the built-in font (GNU unifont)
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex4.mu        # emits code.img
+ 5 # To run:
+ 6 #   qemu-system-i386 code.img
+ 7 # Or:
+ 8 #   bochs -f bochsrc               # bochsrc loads code.img
+ 9 #
+10 # Expected output: letter 'A' in green near the top-left corner of screen
+11 
+12 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+13   draw-code-point screen, 0x41/A, 2/row, 1/col, 0xa/fg, 0/bg
+14 }
+
+ + + diff --git a/html/apps/ex5.mu.html b/html/apps/ex5.mu.html new file mode 100644 index 00000000..5c4ede6e --- /dev/null +++ b/html/apps/ex5.mu.html @@ -0,0 +1,78 @@ + + + + +Mu - apps/ex5.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex5.mu +
+ 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 apps/ex5.mu        # emits code.img
+ 6 # To run:
+ 7 #   qemu-system-i386 code.img
+ 8 # Or:
+ 9 #   bochs -f bochsrc               # bochsrc loads code.img
+10 #
+11 # Expected output: text in green near the top-left corner of screen
+12 
+13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+14   var dummy/eax: int <- draw-text-rightward screen, "hello from baremetal Mu!", 0x10/x, 0x400/xmax, 0x10/y, 0xa/fg, 0/bg
+15   dummy <- draw-text-rightward screen, "you shouldn't see this", 0x10/x, 0xa0/xmax, 0x30/y, 3/fg, 0/bg  # xmax is too narrow
+16 }
+
+ + + diff --git a/html/apps/ex6.mu.html b/html/apps/ex6.mu.html new file mode 100644 index 00000000..aa159ad5 --- /dev/null +++ b/html/apps/ex6.mu.html @@ -0,0 +1,95 @@ + + + + +Mu - apps/ex6.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex6.mu +
+ 1 # Drawing ASCII text incrementally.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex6.mu        # emits code.img
+ 5 # To run:
+ 6 #   qemu-system-i386 code.img
+ 7 # Or:
+ 8 #   bochs -f bochsrc               # bochsrc loads code.img
+ 9 #
+10 # Expected output: a box and text that doesn't overflow it
+11 
+12 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+13   # drawing text within a bounding box
+14   draw-box-on-real-screen 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 screen, "hello ",     0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
+18   x, y <- draw-text-wrapping-right-then-down screen, "from ",      0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
+19   x, y <- draw-text-wrapping-right-then-down screen, "baremetal ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
+20   x, y <- draw-text-wrapping-right-then-down screen, "Mu!",        0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
+21 
+22   # drawing at the cursor in multiple directions
+23   draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen, "abc", 0xa/fg, 0/bg
+24   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "def", 0xa/fg, 0/bg
+25 
+26   # test drawing near the edge
+27   x <- draw-text-rightward screen, "R", 0x7f/x, 0x80/xmax=screen-width, 0x18/y, 0xa/fg, 0/bg
+28   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "wrapped from R", 0xa/fg, 0/bg
+29 
+30   x <- draw-text-downward screen, "D", 0x20/x, 0x2f/y, 0x30/ymax=screen-height, 0xa/fg, 0/bg
+31   draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen, "wrapped from D", 0xa/fg, 0/bg
+32 }
+
+ + + diff --git a/html/apps/ex7.mu.html b/html/apps/ex7.mu.html new file mode 100644 index 00000000..2c99ddf5 --- /dev/null +++ b/html/apps/ex7.mu.html @@ -0,0 +1,108 @@ + + + + +Mu - apps/ex7.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex7.mu +
+ 1 # Cursor-based motions.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex7.mu        # emits code.img
+ 5 # To run:
+ 6 #   qemu-system-i386 code.img
+ 7 # Or:
+ 8 #   bochs -f bochsrc               # bochsrc loads code.img
+ 9 #
+10 # Expected output: an interactive game a bit like "snakes". Try pressing h, j,
+11 # k, l.
+12 
+13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+14   var space/eax: grapheme <- copy 0x20
+15   set-cursor-position screen, 0, 0
+16   {
+17     draw-cursor screen, space
+18     var key/eax: byte <- read-key keyboard
+19     {
+20       compare key, 0x68/h
+21       break-if-!=
+22       draw-code-point-at-cursor screen, 0x2d/dash, 0x31/fg, 0/bg
+23       move-cursor-left 0
+24     }
+25     {
+26       compare key, 0x6a/j
+27       break-if-!=
+28       draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x31/fg, 0/bg
+29       move-cursor-down 0
+30     }
+31     {
+32       compare key, 0x6b/k
+33       break-if-!=
+34       draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x31/fg, 0/bg
+35       move-cursor-up 0
+36     }
+37     {
+38       compare key, 0x6c/l
+39       break-if-!=
+40       var g/eax: code-point <- copy 0x2d/dash
+41       draw-code-point-at-cursor screen, 0x2d/dash, 0x31/fg, 0/bg
+42       move-cursor-right 0
+43     }
+44     loop
+45   }
+46 }
+
+ + + diff --git a/html/apps/ex8.mu.html b/html/apps/ex8.mu.html new file mode 100644 index 00000000..d218205a --- /dev/null +++ b/html/apps/ex8.mu.html @@ -0,0 +1,74 @@ + + + + +Mu - apps/ex8.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex8.mu +
+ 1 # Demo of floating-point support.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate apps/ex8.mu        # emits code.img
+ 5 # To run:
+ 6 #   bochs -f bochsrc               # bochsrc loads code.img
+ 7 # Set a breakpoint at 0x7c00 and start stepping.
+ 8 
+ 9 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+10   var n/eax: int <- copy 0
+11   var result/xmm0: float <- convert n
+12 }
+
+ + + diff --git a/html/apps/ex9.mu.html b/html/apps/ex9.mu.html new file mode 100644 index 00000000..54a158b2 --- /dev/null +++ b/html/apps/ex9.mu.html @@ -0,0 +1,115 @@ + + + + +Mu - apps/ex9.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/ex9.mu +
+ 1 # Demo of reading and writing to disk.
+ 2 #
+ 3 # Steps for trying it out:
+ 4 #   1. Translate this example into a disk image code.img.
+ 5 #       ./translate apps/ex9.mu
+ 6 #   2. Build a second disk image data.img containing some text.
+ 7 #       dd if=/dev/zero of=data.img count=20160
+ 8 #       echo 'abc def ghi' |dd of=data.img conv=notrunc
+ 9 #   3. Familiarize yourself with how the data disk looks within xxd:
+10 #       xxd data.img |head
+11 #   4. Run in an emulator, either Qemu or Bochs.
+12 #       qemu-system-i386 -hda code.img -hdb data.img
+13 #       bochs -f bochsrc.2disks
+14 #   5. Exit the emulator.
+15 #   6. Notice that the data disk now contains the word count of the original text.
+16 #       xxd data.img |head
+17 
+18 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+19   var text-storage: (stream byte 0x200)
+20   var text/esi: (addr stream byte) <- address text-storage
+21   load-sectors data-disk, 0/lba, 1/num-sectors, text
+22 
+23   var word-count/eax: int <- word-count text
+24 
+25   var result-storage: (stream byte 0x10)
+26   var result/edi: (addr stream byte) <- address result-storage
+27   write-int32-decimal result, word-count
+28   store-sectors data-disk, 0/lba, 1/num-sectors, result
+29 }
+30 
+31 fn word-count in: (addr stream byte) -> _/eax: int {
+32   var result/edi: int <- copy 0
+33   {
+34     var done?/eax: boolean <- stream-empty? in
+35     compare done?, 0/false
+36     break-if-!=
+37     var g/eax: grapheme <- read-grapheme in
+38     {
+39       compare g, 0x20/space
+40       break-if-!=
+41       result <- increment
+42     }
+43     {
+44       compare g, 0xa/newline
+45       break-if-!=
+46       result <- increment
+47     }
+48     loop
+49   }
+50   return result
+51 }
+
+ + + diff --git a/html/apps/hest-life.mu.html b/html/apps/hest-life.mu.html new file mode 100644 index 00000000..2fb30163 --- /dev/null +++ b/html/apps/hest-life.mu.html @@ -0,0 +1,1097 @@ + + + + +Mu - apps/hest-life.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/hest-life.mu +
+   1 # Conway's Game of Life in a Hestified way
+   2 #   https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
+   3 #   https://ivanish.ca/hest-podcast
+   4 #
+   5 # To build:
+   6 #   $ ./translate apps/hest-life.mu
+   7 # I run it on my 2.5GHz Linux laptop like this:
+   8 #   $ qemu-system-i386 code.img
+   9 #
+  10 # If things seem too fast or too slow on your computer, adjust the loop bounds
+  11 # in the function `linger` at the bottom. Its value will depend on how you
+  12 # accelerate Qemu (`-accel help`). Mu will eventually get a clock to obviate
+  13 # the need for this tuning.
+  14 #
+  15 # Keyboard shortcuts:
+  16 #   space: pause/resume
+  17 #   0: restart time
+  18 #   l: start looping from 0 to curren time
+  19 #   L: stop looping
+  20 #   +: zoom in
+  21 #   -: zoom out
+  22 
+  23 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+  24   var env-storage: environment
+  25   var env/esi: (addr environment) <- address env-storage
+  26   initialize-environment env
+  27   var second-buffer: screen
+  28   var second-screen/edi: (addr screen) <- address second-buffer
+  29   initialize-screen second-screen, 0x80, 0x30, 1/include-pixels
+  30   render second-screen, env
+  31   convert-graphemes-to-pixels second-screen
+  32   copy-pixels second-screen, screen
+  33   {
+  34     edit keyboard, env
+  35     var play?/eax: (addr boolean) <- get env, play?
+  36     compare *play?, 0/false
+  37     {
+  38       break-if-=
+  39       step env
+  40       clear-screen second-screen
+  41       render second-screen, env
+  42       convert-graphemes-to-pixels second-screen
+  43       copy-pixels second-screen, screen
+  44     }
+  45     linger env
+  46     loop
+  47   }
+  48 }
+  49 
+  50 type environment {
+  51   data: (handle array handle array cell)
+  52   zoom: int  # 0 = 1024 px per cell; 5 = 4px per cell; each step adjusts by a factor of 4
+  53   tick: int
+  54   play?: boolean
+  55   loop: int  # if non-zero, return tick to 0 after this point
+  56 }
+  57 
+  58 type cell {
+  59   curr: boolean
+  60   next: boolean
+  61 }
+  62 
+  63 fn render screen: (addr screen), _self: (addr environment) {
+  64   var self/esi: (addr environment) <- copy _self
+  65   var zoom/eax: (addr int) <- get self, zoom
+  66   compare *zoom, 0
+  67   {
+  68     break-if-!=
+  69     clear-screen screen
+  70     render0 screen, self
+  71   }
+  72   compare *zoom, 1
+  73   {
+  74     break-if-!=
+  75     clear-screen screen
+  76     render1 screen, self
+  77   }
+  78   compare *zoom, 4
+  79   {
+  80     break-if-!=
+  81     render4 screen, self
+  82   }
+  83   # clock
+  84   var tick-a/eax: (addr int) <- get self, tick
+  85   set-cursor-position screen, 0x78/x, 0/y
+  86   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, *tick-a, 7/fg 0/bg
+  87 }
+  88 
+  89 # Lots of hardcoded constants for now.
+  90 # TODO: split this up into a primitive to render a single cell and its
+  91 # incoming edges (but not the neighboring nodes they emanate from)
+  92 fn render0 screen: (addr screen), _self: (addr environment) {
+  93   var self/esi: (addr environment) <- copy _self
+  94   # cell border
+  95   draw-vertical-line   screen,  0xc0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
+  96   draw-vertical-line   screen, 0x340/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
+  97   draw-horizontal-line screen,  0x40/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
+  98   draw-horizontal-line screen, 0x2c0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
+  99   # neighboring inputs, corners
+ 100   var color/eax: int <- state-color self, 0x7f/cur-topleftx, 0x5f/cur-toplefty
+ 101   draw-rect screen,  0x90/xmin   0x10/ymin,    0xb0/xmax   0x30/ymax,  color
+ 102   color <- state-color self, 0x81/cur-toprightx, 0x5f/cur-toprighty
+ 103   draw-rect screen, 0x350/xmin   0x10/ymin,   0x370/xmax   0x30/ymax,  color
+ 104   color <- state-color self, 0x7f/cur-botleftx, 0x61/cur-botlefty
+ 105   draw-rect screen,  0x90/xmin  0x2d0/ymin,    0xb0/xmax  0x2f0/ymax,  color
+ 106   color <- state-color self, 0x81/cur-botrightx, 0x61/cur-botrighty
+ 107   draw-rect screen, 0x350/xmin  0x2d0/ymin,   0x370/xmax  0x2f0/ymax,  color
+ 108   # neighboring inputs, edges
+ 109   color <- state-color self, 0x80/cur-topx, 0x5f/cur-topy
+ 110   draw-rect screen, 0x1f0/xmin   0x10/ymin,   0x210/xmax   0x30/ymax,  color
+ 111   color <- state-color self, 0x7f/cur-leftx, 0x60/cur-lefty
+ 112   draw-rect screen,  0x90/xmin  0x170/ymin,    0xb0/xmax  0x190/ymax,  color
+ 113   color <- state-color self, 0x80/cur-botx, 0x61/cur-boty
+ 114   draw-rect screen, 0x1f0/xmin  0x2d0/ymin,   0x210/xmax  0x2f0/ymax,  color
+ 115   color <- state-color self, 0x81/cur-rightx, 0x60/cur-righty
+ 116   draw-rect screen, 0x350/xmin  0x170/ymin,   0x370/xmax  0x190/ymax,  color
+ 117   # sum node
+ 118   draw-rect screen, 0x170/xsmin 0x140/ysmin,  0x190/xsmax 0x160/ysmax, 0x40/color
+ 119   set-cursor-position screen, 0x2d/scol, 0x13/srow
+ 120   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "+", 0xf/color, 0/bg
+ 121   # conveyors from neighboring inputs to sum node
+ 122   draw-monotonic-bezier screen,  0xa0/x0  0x20/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
+ 123   draw-monotonic-bezier screen,  0xa0/x0 0x180/y0,   0xc0/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
+ 124   draw-monotonic-bezier screen,  0xa0/x0 0x2e0/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
+ 125   draw-monotonic-bezier screen, 0x200/x0  0x20/y0,  0x180/x1  0x90/y1,  0x180/xs 0x150/ys,  4/color
+ 126   draw-monotonic-bezier screen, 0x200/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
+ 127   draw-monotonic-bezier screen, 0x360/x0  0x20/y0,  0x180/x1  0xc0/y1,  0x180/xs 0x150/ys,  4/color
+ 128   draw-monotonic-bezier screen, 0x360/x0 0x180/y0,  0x35c/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
+ 129   draw-monotonic-bezier screen, 0x360/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
+ 130   # filter node
+ 131   draw-rect screen, 0x200/xfmin 0x1c0/yfmin, 0x220/xfmax 0x1e0/yfmax, 0x31/color
+ 132   set-cursor-position screen, 0x40/fcol, 0x1b/frow
+ 133   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "?", 0xf/color, 0/bg
+ 134   # conveyor from sum node to filter node
+ 135   draw-line screen 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 0xa2/color
+ 136   # cell outputs at corners
+ 137   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
+ 138   draw-rect screen,  0xd0/xmin  0x50/ymin,  0xf0/xmax  0x70/ymax, color
+ 139   draw-rect screen, 0x310/xmin  0x50/ymin, 0x330/xmax  0x70/ymax, color
+ 140   draw-rect screen,  0xd0/xmin 0x290/ymin,  0xf0/xmax 0x2b0/ymax, color
+ 141   draw-rect screen, 0x310/xmin 0x290/ymin, 0x330/xmax 0x2b0/ymax, color
+ 142   # cell outputs at edges
+ 143   draw-rect screen, 0x1f0/xmin  0x50/ymin, 0x210/xmax  0x70/ymax, color
+ 144   draw-rect screen,  0xd0/xmin 0x170/ymin,  0xf0/xmax 0x190/ymax, color
+ 145   draw-rect screen, 0x1f0/xmin 0x290/ymin, 0x210/xmax 0x2b0/ymax, color
+ 146   draw-rect screen, 0x310/xmin 0x170/ymin, 0x330/xmax 0x190/ymax, color
+ 147   # conveyors from filter to outputs
+ 148   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2,  0x2a/color
+ 149   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2,  0x2a/color
+ 150   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2,  0x2a/color
+ 151   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1  0x60/y1, 0x200/x2   0x60/y2,  0x2a/color
+ 152   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1 0x230/y1, 0x200/x2  0x2a0/y2,  0x2a/color
+ 153   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2,  0x2a/color
+ 154   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1  0x320/x2  0x180/y2,  0x2a/color
+ 155   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2,  0x2a/color
+ 156   # time-variant portion: 16 repeating steps
+ 157   var tick-a/eax: (addr int) <- get self, tick
+ 158   var progress/eax: int <- copy *tick-a
+ 159   progress <- and 0xf
+ 160   # 7 time steps for getting inputs to sum
+ 161   {
+ 162     compare progress, 7
+ 163     break-if->=
+ 164     var u/xmm7: float <- convert progress
+ 165     var six/eax: int <- copy 6
+ 166     var six-f/xmm0: float <- convert six
+ 167     u <- divide six-f
+ 168     # points on conveyors from neighboring cells
+ 169     draw-bezier-point screen, u,  0xa0/x0  0x20/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 170     draw-bezier-point screen, u,  0xa0/x0 0x180/y0,  0xc0/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 171     draw-bezier-point screen, u,  0xa0/x0 0x2e0/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 172     draw-bezier-point screen, u, 0x200/x0  0x20/y0, 0x180/x1  0x90/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 173     draw-bezier-point screen, u, 0x200/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 174     draw-bezier-point screen, u, 0x360/x0  0x20/y0, 0x180/x1  0xc0/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 175     draw-bezier-point screen, u, 0x360/x0 0x180/y0, 0x35c/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 176     draw-bezier-point screen, u, 0x360/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
+ 177     return
+ 178   }
+ 179   # two time steps for getting count to filter
+ 180   progress <- subtract 7
+ 181   {
+ 182     compare progress, 2
+ 183     break-if->=
+ 184     progress <- increment  # (0, 1) => (1, 2)
+ 185     var u/xmm7: float <- convert progress
+ 186     var three/eax: int <- copy 3
+ 187     var three-f/xmm0: float <- convert three
+ 188     u <- divide three-f
+ 189     draw-linear-point screen, u, 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 7/color, 4/radius
+ 190     set-cursor-position screen, 0x3a/scol, 0x18/srow
+ 191     var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
+ 192     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
+ 193     return
+ 194   }
+ 195   # final 7 time steps for updating output
+ 196   progress <- subtract 2
+ 197   # points on conveyors to outputs
+ 198   var u/xmm7: float <- convert progress
+ 199   var six/eax: int <- copy 6
+ 200   var six-f/xmm0: float <- convert six
+ 201   u <- divide six-f
+ 202   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2, 7/color, 4/radius
+ 203   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2, 7/color, 4/radius
+ 204   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2, 7/color, 4/radius
+ 205   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf  0x60/y1, 0x200/x2   0x60/y2, 7/color, 4/radius
+ 206   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf 0x230/y1, 0x200/x2  0x2a0/y2, 7/color, 4/radius
+ 207   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2, 7/color, 4/radius
+ 208   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1, 0x320/x2  0x180/y2, 7/color, 4/radius
+ 209   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2, 7/color, 4/radius
+ 210 }
+ 211 
+ 212 fn render1 screen: (addr screen), _self: (addr environment) {
+ 213   var self/esi: (addr environment) <- copy _self
+ 214   # cell borders
+ 215   draw-vertical-line   screen,  0xe0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
+ 216   draw-vertical-line   screen, 0x200/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
+ 217   draw-vertical-line   screen, 0x320/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
+ 218   draw-horizontal-line screen,  0x60/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
+ 219   draw-horizontal-line screen, 0x180/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
+ 220   draw-horizontal-line screen, 0x2a0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
+ 221   # cell 0: outputs
+ 222   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
+ 223   draw-rect screen,  0xe8/xmin  0x68/ymin, 0x118/xmax   0x98/ymax, color
+ 224   draw-rect screen,  0xe8/xmin  0xd0/ymin, 0x118/xmax  0x100/ymax, color
+ 225   draw-rect screen,  0xe8/xmin 0x148/ymin, 0x118/xmax  0x178/ymax, color
+ 226   draw-rect screen, 0x158/xmin  0x68/ymin, 0x188/xmax   0x98/ymax, color
+ 227   draw-rect screen, 0x158/xmin 0x148/ymin, 0x188/xmax  0x178/ymax, color
+ 228   draw-rect screen, 0x1c8/xmin  0x68/ymin, 0x1f8/xmax   0x98/ymax, color
+ 229   draw-rect screen, 0x1c8/xmin  0xd0/ymin, 0x1f8/xmax  0x100/ymax, color
+ 230   draw-rect screen, 0x1c8/xmin 0x148/ymin, 0x1f8/xmax  0x178/ymax, color
+ 231   # cell 1: outputs
+ 232   var color/eax: int <- state-color self, 0x81/curx, 0x60/cury
+ 233   draw-rect screen, 0x208/xmin  0x68/ymin, 0x238/xmax   0x98/ymax, color
+ 234   draw-rect screen, 0x208/xmin  0xd0/ymin, 0x238/xmax  0x100/ymax, color
+ 235   draw-rect screen, 0x208/xmin 0x148/ymin, 0x238/xmax  0x178/ymax, color
+ 236   draw-rect screen, 0x278/xmin  0x68/ymin, 0x2a8/xmax   0x98/ymax, color
+ 237   draw-rect screen, 0x278/xmin 0x148/ymin, 0x2a8/xmax  0x178/ymax, color
+ 238   draw-rect screen, 0x2e8/xmin  0x68/ymin, 0x318/xmax   0x98/ymax, color
+ 239   draw-rect screen, 0x2e8/xmin  0xd0/ymin, 0x318/xmax  0x100/ymax, color
+ 240   draw-rect screen, 0x2e8/xmin 0x148/ymin, 0x318/xmax  0x178/ymax, color
+ 241   # cell 2: outputs
+ 242   var color/eax: int <- state-color self, 0x80/curx, 0x61/cury
+ 243   draw-rect screen,  0xe8/xmin 0x188/ymin, 0x118/xmax  0x1b8/ymax, color
+ 244   draw-rect screen,  0xe8/xmin 0x1f0/ymin, 0x118/xmax  0x220/ymax, color
+ 245   draw-rect screen,  0xe8/xmin 0x268/ymin, 0x118/xmax  0x298/ymax, color
+ 246   draw-rect screen, 0x158/xmin 0x188/ymin, 0x188/xmax  0x1b8/ymax, color
+ 247   draw-rect screen, 0x158/xmin 0x268/ymin, 0x188/xmax  0x298/ymax, color
+ 248   draw-rect screen, 0x1c8/xmin 0x188/ymin, 0x1f8/xmax  0x1b8/ymax, color
+ 249   draw-rect screen, 0x1c8/xmin 0x1f0/ymin, 0x1f8/xmax  0x220/ymax, color
+ 250   draw-rect screen, 0x1c8/xmin 0x268/ymin, 0x1f8/xmax  0x298/ymax, color
+ 251   # cell 3: outputs
+ 252   var color/eax: int <- state-color self, 0x81/curx, 0x61/cury
+ 253   draw-rect screen, 0x208/xmin 0x188/ymin, 0x238/xmax  0x1b8/ymax, color
+ 254   draw-rect screen, 0x208/xmin 0x1f0/ymin, 0x238/xmax  0x220/ymax, color
+ 255   draw-rect screen, 0x208/xmin 0x268/ymin, 0x238/xmax  0x298/ymax, color
+ 256   draw-rect screen, 0x278/xmin 0x188/ymin, 0x2a8/xmax  0x1b8/ymax, color
+ 257   draw-rect screen, 0x278/xmin 0x268/ymin, 0x2a8/xmax  0x298/ymax, color
+ 258   draw-rect screen, 0x2e8/xmin 0x188/ymin, 0x318/xmax  0x1b8/ymax, color
+ 259   draw-rect screen, 0x2e8/xmin 0x1f0/ymin, 0x318/xmax  0x220/ymax, color
+ 260   draw-rect screen, 0x2e8/xmin 0x268/ymin, 0x318/xmax  0x298/ymax, color
+ 261   # neighboring nodes
+ 262   var color/eax: int <- state-color self, 0x7f/curx, 0x5f/cury
+ 263   draw-rect screen,  0xa8/xmin  0x28/ymin,  0xd8/xmax   0x58/ymax, color
+ 264   var color/eax: int <- state-color self, 0x80/curx, 0x5f/cury
+ 265   draw-rect screen, 0x158/xmin  0x28/ymin, 0x188/xmax   0x58/ymax, color
+ 266   draw-rect screen, 0x1c8/xmin  0x28/ymin, 0x1f8/xmax   0x58/ymax, color
+ 267   var color/eax: int <- state-color self, 0x81/curx, 0x5f/cury
+ 268   draw-rect screen, 0x208/xmin  0x28/ymin, 0x238/xmax   0x58/ymax, color
+ 269   draw-rect screen, 0x278/xmin  0x28/ymin, 0x2a8/xmax   0x58/ymax, color
+ 270   var color/eax: int <- state-color self, 0x82/curx, 0x5f/cury
+ 271   draw-rect screen, 0x328/xmin  0x28/ymin, 0x358/xmax   0x58/ymax, color
+ 272   var color/eax: int <- state-color self, 0x7f/curx, 0x60/cury
+ 273   draw-rect screen,  0xa8/xmin  0xd0/ymin,  0xd8/xmax  0x100/ymax, color
+ 274   draw-rect screen,  0xa8/xmin 0x148/ymin,  0xd8/xmax  0x178/ymax, color
+ 275   var color/eax: int <- state-color self, 0x82/curx, 0x60/cury
+ 276   draw-rect screen, 0x328/xmin  0xd0/ymin, 0x358/xmax  0x100/ymax, color
+ 277   draw-rect screen, 0x328/xmin 0x148/ymin, 0x358/xmax  0x178/ymax, color
+ 278   var color/eax: int <- state-color self, 0x7f/curx, 0x61/cury
+ 279   draw-rect screen,  0xa8/xmin 0x188/ymin,  0xd8/xmax  0x1b8/ymax, color
+ 280   draw-rect screen,  0xa8/xmin 0x1f0/ymin,  0xd8/xmax  0x220/ymax, color
+ 281   var color/eax: int <- state-color self, 0x82/curx, 0x61/cury
+ 282   draw-rect screen, 0x328/xmin 0x188/ymin, 0x358/xmax  0x1b8/ymax, color
+ 283   draw-rect screen, 0x328/xmin 0x1f0/ymin, 0x358/xmax  0x220/ymax, color
+ 284   var color/eax: int <- state-color self, 0x7f/curx, 0x62/cury
+ 285   draw-rect screen,  0xa8/xmin 0x2a8/ymin,  0xd8/xmax  0x2d8/ymax, color
+ 286   var color/eax: int <- state-color self, 0x80/curx, 0x62/cury
+ 287   draw-rect screen, 0x158/xmin 0x2a8/ymin, 0x188/xmax  0x2d8/ymax, color
+ 288   draw-rect screen, 0x1c8/xmin 0x2a8/ymin, 0x1f8/xmax  0x2d8/ymax, color
+ 289   var color/eax: int <- state-color self, 0x81/curx, 0x62/cury
+ 290   draw-rect screen, 0x208/xmin 0x2a8/ymin, 0x238/xmax  0x2d8/ymax, color
+ 291   draw-rect screen, 0x278/xmin 0x2a8/ymin, 0x2a8/xmax  0x2d8/ymax, color
+ 292   var color/eax: int <- state-color self, 0x82/curx, 0x62/cury
+ 293   draw-rect screen, 0x328/xmin 0x2a8/ymin, 0x358/xmax  0x2d8/ymax, color
+ 294   # cell 0: sum and filter nodes
+ 295   draw-rect screen, 0x148/xsmin  0xc8/ysmin, 0x158/xsmax  0xd8/ysmax, 0x40/color
+ 296   draw-rect screen, 0x180/xfmin  0xf8/yfmin, 0x190/xfmax 0x108/yfmax, 0x31/color
+ 297   # cell 1: sum and filter nodes
+ 298   draw-rect screen, 0x268/xsmin  0xc8/ysmin, 0x278/xsmax  0xd8/ysmax, 0x40/color
+ 299   draw-rect screen, 0x2a0/xfmin  0xf8/yfmin, 0x2b0/xfmax 0x108/yfmax, 0x31/color
+ 300   # cell 2: sum and filter nodes
+ 301   draw-rect screen, 0x148/xsmin 0x1e8/ysmin, 0x158/xsmax 0x1f8/ysmax, 0x40/color
+ 302   draw-rect screen, 0x180/xfmin 0x218/yfmin, 0x190/xfmax 0x228/yfmax, 0x31/color
+ 303   # cell 3: sum and filter nodes
+ 304   draw-rect screen, 0x268/xsmin 0x1e8/ysmin, 0x278/xsmax 0x1f8/ysmax, 0x40/color
+ 305   draw-rect screen, 0x2a0/xfmin 0x218/yfmin, 0x2b0/xfmax 0x228/yfmax, 0x31/color
+ 306   # neighbor counts
+ 307   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
+ 308   set-cursor-position screen, 0x2d, 0xe
+ 309   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
+ 310   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x60/cury
+ 311   set-cursor-position screen, 0x52, 0xe
+ 312   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
+ 313   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x61/cury
+ 314   set-cursor-position screen, 0x2d, 0x20
+ 315   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
+ 316   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x61/cury
+ 317   set-cursor-position screen, 0x52, 0x20
+ 318   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
+ 319   # cell 0: conveyors from neighboring inputs to sum node
+ 320   draw-monotonic-bezier screen,  0xc0/x0  0x40/y0,  0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
+ 321   draw-monotonic-bezier screen,  0xc0/x0  0xe8/y0,   0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
+ 322   draw-monotonic-bezier screen,  0xc0/x0 0x1a0/y0,   0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
+ 323   draw-monotonic-bezier screen, 0x170/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
+ 324   draw-monotonic-bezier screen, 0x170/x0 0x1a0/y0,  0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
+ 325   draw-monotonic-bezier screen, 0x220/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
+ 326   draw-monotonic-bezier screen, 0x220/x0  0xe8/y0,  0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys,  4/color
+ 327   draw-monotonic-bezier screen, 0x220/x0 0x1a0/y0,  0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
+ 328   # cell 0: conveyors from filter to outputs
+ 329   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2,  0x2a/color
+ 330   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2,  0x2a/color
+ 331   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2,  0x2a/color
+ 332   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1  0x80/y1, 0x170/x2  0x80/y2,  0x2a/color
+ 333   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1 0x160/y1, 0x170/x2 0x160/y2,  0x2a/color
+ 334   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2,  0x2a/color
+ 335   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1  0x1e0/x2  0xe8/y2,  0x2a/color
+ 336   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2,  0x2a/color
+ 337   # cell 0: time-variant portion: 16 repeating steps
+ 338   $render1:cell0: {
+ 339     var tick-a/eax: (addr int) <- get self, tick
+ 340     var progress/eax: int <- copy *tick-a
+ 341     progress <- and 0xf
+ 342     # cell 0: 7 time steps for getting inputs to sum
+ 343     {
+ 344       compare progress, 7
+ 345       break-if->=
+ 346       var u/xmm7: float <- convert progress
+ 347       var six/eax: int <- copy 6
+ 348       var six-f/xmm0: float <- convert six
+ 349       u <- divide six-f
+ 350       # points on conveyors from neighboring cells
+ 351       draw-bezier-point screen, u,  0xc0/x0  0x40/y0, 0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 352       draw-bezier-point screen, u,  0xc0/x0  0xe8/y0,  0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 353       draw-bezier-point screen, u,  0xc0/x0 0x1a0/y0,  0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 354       draw-bezier-point screen, u, 0x170/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 355       draw-bezier-point screen, u, 0x170/x0 0x1a0/y0, 0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 356       draw-bezier-point screen, u, 0x220/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 357       draw-bezier-point screen, u, 0x220/x0  0xe8/y0, 0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 358       draw-bezier-point screen, u, 0x220/x0 0x1a0/y0, 0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
+ 359       break $render1:cell0
+ 360     }
+ 361     # cell 0: two time steps for getting count to filter
+ 362     progress <- subtract 7
+ 363     {
+ 364       compare progress, 2
+ 365       break-if->=
+ 366       break $render1:cell0
+ 367     }
+ 368     # cell 0: final 7 time steps for updating output
+ 369     progress <- subtract 2
+ 370     # cell 0: points on conveyors to outputs
+ 371     var u/xmm7: float <- convert progress
+ 372     var six/eax: int <- copy 6
+ 373     var six-f/xmm0: float <- convert six
+ 374     u <- divide six-f
+ 375     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2, 7/color, 4/radius
+ 376     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2, 7/color, 4/radius
+ 377     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2, 7/color, 4/radius
+ 378     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf  0x80/y1, 0x170/x2  0x80/y2, 7/color, 4/radius
+ 379     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf 0x160/y1, 0x170/x2 0x160/y2, 7/color, 4/radius
+ 380     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2, 7/color, 4/radius
+ 381     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0xe8/y2, 7/color, 4/radius
+ 382     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2, 7/color, 4/radius
+ 383   }
+ 384   # cell 1: conveyors from neighboring inputs to sum node
+ 385   draw-monotonic-bezier screen, 0x1e0/x0  0x40/y0,  0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
+ 386   draw-monotonic-bezier screen, 0x1e0/x0  0xe8/y0,  0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
+ 387   draw-monotonic-bezier screen, 0x1e0/x0 0x1a0/y0,  0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
+ 388   draw-monotonic-bezier screen, 0x290/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
+ 389   draw-monotonic-bezier screen, 0x290/x0 0x1a0/y0,  0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
+ 390   draw-monotonic-bezier screen, 0x340/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
+ 391   draw-monotonic-bezier screen, 0x340/x0  0xe8/y0,  0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys,  4/color
+ 392   draw-monotonic-bezier screen, 0x340/x0 0x1a0/y0,  0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
+ 393   # cell 1: conveyors from filter to outputs
+ 394   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2,  0x2a/color
+ 395   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2,  0x2a/color
+ 396   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2,  0x2a/color
+ 397   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1  0x80/y1, 0x290/x2  0x80/y2,  0x2a/color
+ 398   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1 0x160/y1, 0x290/x2 0x160/y2,  0x2a/color
+ 399   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2,  0x2a/color
+ 400   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1  0x300/x2  0xe8/y2,  0x2a/color
+ 401   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2,  0x2a/color
+ 402   # cell 1: time-variant portion: 16 repeating steps
+ 403   $render1:cell1: {
+ 404     var tick-a/eax: (addr int) <- get self, tick
+ 405     var progress/eax: int <- copy *tick-a
+ 406     progress <- and 0xf
+ 407     # cell 1: 7 time steps for getting inputs to sum
+ 408     {
+ 409       compare progress, 7
+ 410       break-if->=
+ 411       var u/xmm7: float <- convert progress
+ 412       var six/eax: int <- copy 6
+ 413       var six-f/xmm0: float <- convert six
+ 414       u <- divide six-f
+ 415       # points on conveyors from neighboring cells
+ 416       draw-bezier-point screen, u, 0x1e0/x0  0x40/y0, 0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 417       draw-bezier-point screen, u, 0x1e0/x0  0xe8/y0, 0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 418       draw-bezier-point screen, u, 0x1e0/x0 0x1a0/y0, 0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 419       draw-bezier-point screen, u, 0x290/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 420       draw-bezier-point screen, u, 0x290/x0 0x1a0/y0, 0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 421       draw-bezier-point screen, u, 0x340/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 422       draw-bezier-point screen, u, 0x340/x0  0xe8/y0, 0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 423       draw-bezier-point screen, u, 0x340/x0 0x1a0/y0, 0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
+ 424       break $render1:cell1
+ 425     }
+ 426     # cell 1: two time steps for getting count to filter
+ 427     progress <- subtract 7
+ 428     {
+ 429       compare progress, 2
+ 430       break-if->=
+ 431       break $render1:cell1
+ 432     }
+ 433     # cell 1: final 7 time steps for updating output
+ 434     progress <- subtract 2
+ 435     # cell 1: points on conveyors to outputs
+ 436     var u/xmm7: float <- convert progress
+ 437     var six/eax: int <- copy 6
+ 438     var six-f/xmm0: float <- convert six
+ 439     u <- divide six-f
+ 440     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2, 7/color, 4/radius
+ 441     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2, 7/color, 4/radius
+ 442     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2, 7/color, 4/radius
+ 443     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf  0x80/y1, 0x290/x2  0x80/y2, 7/color, 4/radius
+ 444     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf 0x160/y1, 0x290/x2 0x160/y2, 7/color, 4/radius
+ 445     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2, 7/color, 4/radius
+ 446     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0xe8/y2, 7/color, 4/radius
+ 447     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2, 7/color, 4/radius
+ 448   }
+ 449   # cell 2: conveyors from neighboring inputs to sum node
+ 450   draw-monotonic-bezier screen,  0xc0/x0 0x160/y0,  0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
+ 451   draw-monotonic-bezier screen,  0xc0/x0 0x208/y0,   0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
+ 452   draw-monotonic-bezier screen,  0xc0/x0 0x2c0/y0,   0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
+ 453   draw-monotonic-bezier screen, 0x170/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
+ 454   draw-monotonic-bezier screen, 0x170/x0 0x2c0/y0,  0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
+ 455   draw-monotonic-bezier screen, 0x220/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
+ 456   draw-monotonic-bezier screen, 0x220/x0 0x208/y0,  0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys,  4/color
+ 457   draw-monotonic-bezier screen, 0x220/x0 0x2c0/y0,  0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
+ 458   # cell 2: conveyors from filter to outputs
+ 459   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2,  0x2a/color
+ 460   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2,  0x2a/color
+ 461   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2,  0x2a/color
+ 462   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x1a0/y1, 0x170/x2 0x1a0/y2,  0x2a/color
+ 463   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x280/y1, 0x170/x2 0x280/y2,  0x2a/color
+ 464   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2,  0x2a/color
+ 465   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1  0x1e0/x2 0x208/y2,  0x2a/color
+ 466   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2,  0x2a/color
+ 467   # cell 2: time-variant portion: 16 repeating steps
+ 468   $render1:cell2: {
+ 469     var tick-a/eax: (addr int) <- get self, tick
+ 470     var progress/eax: int <- copy *tick-a
+ 471     progress <- and 0xf
+ 472     # cell 2: 7 time steps for getting inputs to sum
+ 473     {
+ 474       compare progress, 7
+ 475       break-if->=
+ 476       var u/xmm7: float <- convert progress
+ 477       var six/eax: int <- copy 6
+ 478       var six-f/xmm0: float <- convert six
+ 479       u <- divide six-f
+ 480       # points on conveyors from neighboring cells
+ 481       draw-bezier-point screen, u,  0xc0/x0 0x160/y0, 0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 482       draw-bezier-point screen, u,  0xc0/x0 0x208/y0,  0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 483       draw-bezier-point screen, u,  0xc0/x0 0x2c0/y0,  0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 484       draw-bezier-point screen, u, 0x170/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 485       draw-bezier-point screen, u, 0x170/x0 0x2c0/y0, 0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 486       draw-bezier-point screen, u, 0x220/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 487       draw-bezier-point screen, u, 0x220/x0 0x208/y0, 0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 488       draw-bezier-point screen, u, 0x220/x0 0x2c0/y0, 0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
+ 489       break $render1:cell2
+ 490     }
+ 491     # cell 2: two time steps for getting count to filter
+ 492     progress <- subtract 7
+ 493     {
+ 494       compare progress, 2
+ 495       break-if->=
+ 496       break $render1:cell2
+ 497     }
+ 498     # cell 2: final 7 time steps for updating output
+ 499     progress <- subtract 2
+ 500     # cell 2: points on conveyors to outputs
+ 501     var u/xmm7: float <- convert progress
+ 502     var six/eax: int <- copy 6
+ 503     var six-f/xmm0: float <- convert six
+ 504     u <- divide six-f
+ 505     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2, 7/color, 4/radius
+ 506     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2, 7/color, 4/radius
+ 507     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2, 7/color, 4/radius
+ 508     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x1a0/y1, 0x170/x2 0x1a0/y2, 7/color, 4/radius
+ 509     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x280/y1, 0x170/x2 0x280/y2, 7/color, 4/radius
+ 510     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2, 7/color, 4/radius
+ 511     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x208/y2, 7/color, 4/radius
+ 512     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2, 7/color, 4/radius
+ 513   }
+ 514   # cell 3: conveyors from neighboring inputs to sum node
+ 515   draw-monotonic-bezier screen, 0x1e0/x0 0x160/y0,  0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
+ 516   draw-monotonic-bezier screen, 0x1e0/x0 0x208/y0,  0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
+ 517   draw-monotonic-bezier screen, 0x1e0/x0 0x2c0/y0,  0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
+ 518   draw-monotonic-bezier screen, 0x290/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
+ 519   draw-monotonic-bezier screen, 0x290/x0 0x2c0/y0,  0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
+ 520   draw-monotonic-bezier screen, 0x340/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
+ 521   draw-monotonic-bezier screen, 0x340/x0 0x208/y0,  0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys,  4/color
+ 522   draw-monotonic-bezier screen, 0x340/x0 0x2c0/y0,  0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
+ 523   # cell 3: conveyors from filter to outputs
+ 524   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2,  0x2a/color
+ 525   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2,  0x2a/color
+ 526   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2,  0x2a/color
+ 527   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x1a0/y1, 0x290/x2 0x1a0/y2,  0x2a/color
+ 528   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x280/y1, 0x290/x2 0x280/y2,  0x2a/color
+ 529   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2,  0x2a/color
+ 530   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1  0x300/x2 0x208/y2,  0x2a/color
+ 531   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2,  0x2a/color
+ 532   # cell 3: time-variant portion: 16 repeating steps
+ 533   $render1:cell3: {
+ 534     var tick-a/eax: (addr int) <- get self, tick
+ 535     var progress/eax: int <- copy *tick-a
+ 536     progress <- and 0xf
+ 537     # cell 3: 7 time steps for getting inputs to sum
+ 538     {
+ 539       compare progress, 7
+ 540       break-if->=
+ 541       var u/xmm7: float <- convert progress
+ 542       var six/eax: int <- copy 6
+ 543       var six-f/xmm0: float <- convert six
+ 544       u <- divide six-f
+ 545       # points on conveyors from neighboring cells
+ 546       draw-bezier-point screen, u, 0x1e0/x0 0x160/y0, 0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 547       draw-bezier-point screen, u, 0x1e0/x0 0x208/y0, 0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 548       draw-bezier-point screen, u, 0x1e0/x0 0x2c0/y0, 0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 549       draw-bezier-point screen, u, 0x290/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 550       draw-bezier-point screen, u, 0x290/x0 0x2c0/y0, 0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 551       draw-bezier-point screen, u, 0x340/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 552       draw-bezier-point screen, u, 0x340/x0 0x208/y0, 0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 553       draw-bezier-point screen, u, 0x340/x0 0x2c0/y0, 0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
+ 554       break $render1:cell3
+ 555     }
+ 556     # cell 3: two time steps for getting count to filter
+ 557     progress <- subtract 7
+ 558     {
+ 559       compare progress, 2
+ 560       break-if->=
+ 561       break $render1:cell3
+ 562     }
+ 563     # cell 3: final 7 time steps for updating output
+ 564     progress <- subtract 2
+ 565     # cell 3: points on conveyors to outputs
+ 566     var u/xmm7: float <- convert progress
+ 567     var six/eax: int <- copy 6
+ 568     var six-f/xmm0: float <- convert six
+ 569     u <- divide six-f
+ 570     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2, 7/color, 4/radius
+ 571     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2, 7/color, 4/radius
+ 572     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2, 7/color, 4/radius
+ 573     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x1a0/y1, 0x290/x2 0x1a0/y2, 7/color, 4/radius
+ 574     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x280/y1, 0x290/x2 0x280/y2, 7/color, 4/radius
+ 575     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2, 7/color, 4/radius
+ 576     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x208/y2, 7/color, 4/radius
+ 577     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2, 7/color, 4/radius
+ 578   }
+ 579 }
+ 580 
+ 581 fn draw-bezier-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int, radius: int {
+ 582   var _cy/eax: int <- bezier-point u, y0, y1, y2
+ 583   var cy/ecx: int <- copy _cy
+ 584   var cx/eax: int <- bezier-point u, x0, x1, x2
+ 585   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
+ 586 }
+ 587 
+ 588 fn draw-linear-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, color: int, radius: int {
+ 589   var _cy/eax: int <- line-point u, y0, y1
+ 590   var cy/ecx: int <- copy _cy
+ 591   var cx/eax: int <- line-point u, x0, x1
+ 592   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
+ 593 }
+ 594 
+ 595 fn edit keyboard: (addr keyboard), _self: (addr environment) {
+ 596   var self/esi: (addr environment) <- copy _self
+ 597   var key/eax: byte <- read-key keyboard
+ 598   # space: play/pause
+ 599   {
+ 600     compare key, 0x20/space
+ 601     break-if-!=
+ 602     var play?/eax: (addr boolean) <- get self, play?
+ 603     compare *play?, 0/false
+ 604     {
+ 605       break-if-=
+ 606       copy-to *play?, 0/false
+ 607       return
+ 608     }
+ 609     copy-to *play?, 1/true
+ 610     return
+ 611   }
+ 612   # 0: back to start
+ 613   {
+ 614     compare key, 0x30/0
+ 615     break-if-!=
+ 616     clear-environment self
+ 617     return
+ 618   }
+ 619   # l: loop from here to start
+ 620   {
+ 621     compare key, 0x6c/l
+ 622     break-if-!=
+ 623     var tick-a/eax: (addr int) <- get self, tick
+ 624     var tick/eax: int <- copy *tick-a
+ 625     var loop/ecx: (addr int) <- get self, loop
+ 626     copy-to *loop, tick
+ 627     return
+ 628   }
+ 629   # L: reset loop
+ 630   {
+ 631     compare key, 0x4c/L
+ 632     break-if-!=
+ 633     var loop/eax: (addr int) <- get self, loop
+ 634     copy-to *loop, 0
+ 635     return
+ 636   }
+ 637   # -: zoom out
+ 638   {
+ 639     compare key, 0x2d/-
+ 640     break-if-!=
+ 641     var zoom/eax: (addr int) <- get self, zoom
+ 642     compare *zoom, 1
+ 643     {
+ 644       break-if-!=
+ 645       copy-to *zoom, 4
+ 646     }
+ 647     compare *zoom, 0
+ 648     {
+ 649       break-if-!=
+ 650       copy-to *zoom, 1
+ 651     }
+ 652     # set tick to a multiple of zoom
+ 653     var tick-a/edx: (addr int) <- get self, tick
+ 654     clear-lowest-bits tick-a, *zoom
+ 655     return
+ 656   }
+ 657   # +: zoom in
+ 658   {
+ 659     compare key, 0x2b/+
+ 660     break-if-!=
+ 661     var zoom/eax: (addr int) <- get self, zoom
+ 662     compare *zoom, 1
+ 663     {
+ 664       break-if-!=
+ 665       copy-to *zoom, 0
+ 666     }
+ 667     compare *zoom, 4
+ 668     {
+ 669       break-if-!=
+ 670       copy-to *zoom, 1
+ 671     }
+ 672     # set tick to a multiple of zoom
+ 673     var tick-a/edx: (addr int) <- get self, tick
+ 674     clear-lowest-bits tick-a, *zoom
+ 675     return
+ 676   }
+ 677 }
+ 678 
+ 679 fn step _self: (addr environment) {
+ 680   var self/esi: (addr environment) <- copy _self
+ 681   var tick-a/ecx: (addr int) <- get self, tick
+ 682   var zoom/edx: (addr int) <- get self, zoom
+ 683   compare *zoom, 0
+ 684   {
+ 685     break-if-!=
+ 686     increment *tick-a
+ 687   }
+ 688   compare *zoom, 1
+ 689   {
+ 690     break-if-!=
+ 691     # I wanted to speed up time, but that doesn't seem very usable.
+ 692 #?     add-to *tick-a, 2
+ 693     increment *tick-a
+ 694   }
+ 695   compare *zoom, 4
+ 696   {
+ 697     break-if-!=
+ 698     add-to *tick-a, 0x10
+ 699   }
+ 700   var tick/eax: int <- copy *tick-a
+ 701   tick <- and 0xf
+ 702   compare tick, 0
+ 703   {
+ 704     break-if-!=
+ 705     step4 self
+ 706   }
+ 707   var loop-a/eax: (addr int) <- get self, loop
+ 708   compare *loop-a, 0
+ 709   {
+ 710     break-if-=
+ 711     var loop/eax: int <- copy *loop-a
+ 712     compare *tick-a, loop
+ 713     break-if-<
+ 714     clear-environment self
+ 715   }
+ 716 }
+ 717 
+ 718 fn initialize-environment _self: (addr environment) {
+ 719   var self/esi: (addr environment) <- copy _self
+ 720   var zoom/eax: (addr int) <- get self, zoom
+ 721   copy-to *zoom, 0
+ 722   var play?/eax: (addr boolean) <- get self, play?
+ 723   copy-to *play?, 1/true
+ 724   var data-ah/eax: (addr handle array handle array cell) <- get self, data
+ 725   populate data-ah, 0x100
+ 726   var data/eax: (addr array handle array cell) <- lookup *data-ah
+ 727   var y/ecx: int <- copy 0
+ 728   {
+ 729     compare y, 0xc0
+ 730     break-if->=
+ 731     var dest-ah/eax: (addr handle array cell) <- index data, y
+ 732     populate dest-ah, 0x100
+ 733     y <- increment
+ 734     loop
+ 735   }
+ 736   set self, 0x80, 0x5f, 1/alive
+ 737   set self, 0x81, 0x5f, 1/alive
+ 738   set self, 0x7f, 0x60, 1/alive
+ 739   set self, 0x80, 0x60, 1/alive
+ 740   set self, 0x80, 0x61, 1/alive
+ 741   flush self
+ 742 }
+ 743 
+ 744 fn clear-environment _self: (addr environment) {
+ 745   var self/esi: (addr environment) <- copy _self
+ 746   var tick/eax: (addr int) <- get self, tick
+ 747   copy-to *tick, 0
+ 748   # don't touch zoom or play settings
+ 749   var data-ah/eax: (addr handle array handle array cell) <- get self, data
+ 750   var data/eax: (addr array handle array cell) <- lookup *data-ah
+ 751   var y/ecx: int <- copy 0
+ 752   {
+ 753     compare y, 0xc0
+ 754     break-if->=
+ 755     var row-ah/eax: (addr handle array cell) <- index data, y
+ 756     var row/eax: (addr array cell) <- lookup *row-ah
+ 757     var x/edx: int <- copy 0
+ 758     {
+ 759       compare x, 0x100
+ 760       break-if->=
+ 761       var dest/eax: (addr cell) <- index row, x
+ 762       clear-object dest
+ 763       x <- increment
+ 764       loop
+ 765     }
+ 766     y <- increment
+ 767     loop
+ 768   }
+ 769   set self, 0x80, 0x5f, 1/alive
+ 770   set self, 0x81, 0x5f, 1/alive
+ 771   set self, 0x7f, 0x60, 1/alive
+ 772   set self, 0x80, 0x60, 1/alive
+ 773   set self, 0x80, 0x61, 1/alive
+ 774   flush self
+ 775 }
+ 776 
+ 777 fn set _self: (addr environment), _x: int, _y: int, _val: boolean {
+ 778   var self/esi: (addr environment) <- copy _self
+ 779   var data-ah/eax: (addr handle array handle array cell) <- get self, data
+ 780   var data/eax: (addr array handle array cell) <- lookup *data-ah
+ 781   var y/ecx: int <- copy _y
+ 782   var row-ah/eax: (addr handle array cell) <- index data, y
+ 783   var row/eax: (addr array cell) <- lookup *row-ah
+ 784   var x/ecx: int <- copy _x
+ 785   var cell/eax: (addr cell) <- index row, x
+ 786   var dest/eax: (addr boolean) <- get cell, next
+ 787   var val/ecx: boolean <- copy _val
+ 788   copy-to *dest, val
+ 789 }
+ 790 
+ 791 fn state _self: (addr environment), _x: int, _y: int -> _/eax: boolean {
+ 792   var self/esi: (addr environment) <- copy _self
+ 793   var x/ecx: int <- copy _x
+ 794   var y/edx: int <- copy _y
+ 795   # clip at the edge
+ 796   compare x, 0
+ 797   {
+ 798     break-if->=
+ 799     return 0/false
+ 800   }
+ 801   compare y, 0
+ 802   {
+ 803     break-if->=
+ 804     return 0/false
+ 805   }
+ 806   compare x, 0x100/width
+ 807   {
+ 808     break-if-<
+ 809     return 0/false
+ 810   }
+ 811   compare y, 0xc0/height
+ 812   {
+ 813     break-if-<
+ 814     return 0/false
+ 815   }
+ 816   var data-ah/eax: (addr handle array handle array cell) <- get self, data
+ 817   var data/eax: (addr array handle array cell) <- lookup *data-ah
+ 818   var row-ah/eax: (addr handle array cell) <- index data, y
+ 819   var row/eax: (addr array cell) <- lookup *row-ah
+ 820   var cell/eax: (addr cell) <- index row, x
+ 821   var src/eax: (addr boolean) <- get cell, curr
+ 822   return *src
+ 823 }
+ 824 
+ 825 fn state-color _self: (addr environment), x: int, y: int -> _/eax: int {
+ 826   var self/esi: (addr environment) <- copy _self
+ 827   var color/ecx: int <- copy 0x1a/dead
+ 828   {
+ 829     var state/eax: boolean <- state self, x, y
+ 830     compare state, 0/dead
+ 831     break-if-=
+ 832     color <- copy 0xf/alive
+ 833   }
+ 834   return color
+ 835 }
+ 836 
+ 837 fn flush  _self: (addr environment) {
+ 838   var self/esi: (addr environment) <- copy _self
+ 839   var data-ah/eax: (addr handle array handle array cell) <- get self, data
+ 840   var _data/eax: (addr array handle array cell) <- lookup *data-ah
+ 841   var data/esi: (addr array handle array cell) <- copy _data
+ 842   var y/ecx: int <- copy 0
+ 843   {
+ 844     compare y, 0xc0/height
+ 845     break-if->=
+ 846     var row-ah/eax: (addr handle array cell) <- index data, y
+ 847     var _row/eax: (addr array cell) <- lookup *row-ah
+ 848     var row/ebx: (addr array cell) <- copy _row
+ 849     var x/edx: int <- copy 0
+ 850     {
+ 851       compare x, 0x100/width
+ 852       break-if->=
+ 853       var cell-a/eax: (addr cell) <- index row, x
+ 854       var curr-a/edi: (addr boolean) <- get cell-a, curr
+ 855       var next-a/esi: (addr boolean) <- get cell-a, next
+ 856       var val/eax: boolean <- copy *next-a
+ 857       copy-to *curr-a, val
+ 858       copy-to *next-a, 0/dead
+ 859       x <- increment
+ 860       loop
+ 861     }
+ 862     y <- increment
+ 863     loop
+ 864   }
+ 865 }
+ 866 
+ 867 fn render4 screen: (addr screen), _self: (addr environment) {
+ 868   var self/esi: (addr environment) <- copy _self
+ 869   var y/ecx: int <- copy 0
+ 870   {
+ 871     compare y, 0xc0/height
+ 872     break-if->=
+ 873     var x/edx: int <- copy 0
+ 874     {
+ 875       compare x, 0x100/width
+ 876       break-if->=
+ 877       var state/eax: boolean <- state self, x, y
+ 878       compare state, 0/false
+ 879       {
+ 880         break-if-=
+ 881         render4-cell screen, x, y, 0xf/alive
+ 882       }
+ 883       compare state, 0/false
+ 884       {
+ 885         break-if-!=
+ 886         render4-cell screen, x, y, 0x1a/dead
+ 887       }
+ 888       x <- increment
+ 889       loop
+ 890     }
+ 891     y <- increment
+ 892     loop
+ 893   }
+ 894 }
+ 895 
+ 896 fn render4-cell screen: (addr screen), x: int, y: int, color: int {
+ 897   var xmin/eax: int <- copy x
+ 898   xmin <- shift-left 2
+ 899   var xmax/ecx: int <- copy xmin
+ 900   xmax <- add 4
+ 901   var ymin/edx: int <- copy y
+ 902   ymin <- shift-left 2
+ 903   var ymax/ebx: int <- copy ymin
+ 904   ymax <- add 4
+ 905   draw-rect screen, xmin ymin, xmax ymax, color
+ 906 }
+ 907 
+ 908 fn step4 _self: (addr environment) {
+ 909   var self/esi: (addr environment) <- copy _self
+ 910   var y/ecx: int <- copy 0
+ 911   {
+ 912     compare y, 0xc0/height
+ 913     break-if->=
+ 914     var x/edx: int <- copy 0
+ 915     {
+ 916       compare x, 0x100/width
+ 917       break-if->=
+ 918       var n/eax: int <- num-live-neighbors self, x, y
+ 919       # if neighbors < 2, die of loneliness
+ 920       {
+ 921         compare n, 2
+ 922         break-if->=
+ 923         set self, x, y, 0/dead
+ 924       }
+ 925       # if neighbors > 3, die of overcrowding
+ 926       {
+ 927         compare n, 3
+ 928         break-if-<=
+ 929         set self, x, y, 0/dead
+ 930       }
+ 931       # if neighbors = 2, preserve state
+ 932       {
+ 933         compare n, 2
+ 934         break-if-!=
+ 935         var old-state/eax: boolean <- state self, x, y
+ 936         set self, x, y, old-state
+ 937       }
+ 938       # if neighbors = 3, cell quickens to life
+ 939       {
+ 940         compare n, 3
+ 941         break-if-!=
+ 942         set self, x, y, 1/live
+ 943       }
+ 944       x <- increment
+ 945       loop
+ 946     }
+ 947     y <- increment
+ 948     loop
+ 949   }
+ 950   flush self
+ 951 }
+ 952 
+ 953 fn num-live-neighbors _self: (addr environment), x: int, y: int -> _/eax: int {
+ 954   var self/esi: (addr environment) <- copy _self
+ 955   var result/edi: int <- copy 0
+ 956   # row above: zig
+ 957   decrement y
+ 958   decrement x
+ 959   var s/eax: boolean <- state self, x, y
+ 960   {
+ 961     compare s, 0/false
+ 962     break-if-=
+ 963     result <- increment
+ 964   }
+ 965   increment x
+ 966   s <- state self, x, y
+ 967   {
+ 968     compare s, 0/false
+ 969     break-if-=
+ 970     result <- increment
+ 971   }
+ 972   increment x
+ 973   s <- state self, x, y
+ 974   {
+ 975     compare s, 0/false
+ 976     break-if-=
+ 977     result <- increment
+ 978   }
+ 979   # curr row: zag
+ 980   increment y
+ 981   s <- state self, x, y
+ 982   {
+ 983     compare s, 0/false
+ 984     break-if-=
+ 985     result <- increment
+ 986   }
+ 987   subtract-from x, 2
+ 988   s <- state self, x, y
+ 989   {
+ 990     compare s, 0/false
+ 991     break-if-=
+ 992     result <- increment
+ 993   }
+ 994   # row below: zig
+ 995   increment y
+ 996   s <- state self, x, y
+ 997   {
+ 998     compare s, 0/false
+ 999     break-if-=
+1000     result <- increment
+1001   }
+1002   increment x
+1003   s <- state self, x, y
+1004   {
+1005     compare s, 0/false
+1006     break-if-=
+1007     result <- increment
+1008   }
+1009   increment x
+1010   s <- state self, x, y
+1011   {
+1012     compare s, 0/false
+1013     break-if-=
+1014     result <- increment
+1015   }
+1016   return result
+1017 }
+1018 
+1019 fn linger _self: (addr environment) {
+1020   var self/esi: (addr environment) <- copy _self
+1021   var i/ecx: int <- copy 0
+1022   {
+1023     compare i, 0x10000000  # Kartik's Linux with -enable-kvm
+1024 #?     compare i, 0x8000000  # Kartik's Mac with -accel tcg
+1025     break-if->=
+1026     i <- increment
+1027     loop
+1028   }
+1029 }
+
+ + + diff --git a/html/apps/img.mu.html b/html/apps/img.mu.html new file mode 100644 index 00000000..e3117aa2 --- /dev/null +++ b/html/apps/img.mu.html @@ -0,0 +1,1217 @@ + + + + +Mu - apps/img.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/img.mu +
+   1 # load an image from disk and display it on screen
+   2 #
+   3 # To build:
+   4 #   $ ./translate apps/img.mu                       # generates code.img
+   5 # Load a pbm, pgm or ppm image (no more than 255 levels) in the data disk
+   6 #   $ dd if=/dev/zero of=data.img count=20160
+   7 #   $ dd if=x.pbm of=data.img conv=notrunc
+   8 # or
+   9 #   $ dd if=t.pgm of=data.img conv=notrunc
+  10 # or
+  11 #   $ dd if=snail.ppm of=data.img conv=notrunc
+  12 # To run:
+  13 #   $ qemu-system-i386 -hda code.img -hdb data.img
+  14 
+  15 type image {
+  16   type: int  # supported types:
+  17              #  1: portable bitmap (P1) - pixels 0 or 1
+  18              #  2: portable greymap (P2) - pixels 1-byte greyscale values
+  19              #  3: portable pixmap (P3) - pixels 3-byte rgb values
+  20   max: int
+  21   width: int
+  22   height: int
+  23   data: (handle array byte)
+  24 }
+  25 
+  26 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+  27   var img-storage: image
+  28   var img/esi: (addr image) <- address img-storage
+  29   load-image img, data-disk
+  30   render-image screen, img, 0/x, 0/y, 0x300/width, 0x300/height
+  31 }
+  32 
+  33 fn load-image self: (addr image), data-disk: (addr disk) {
+  34   # data-disk -> stream
+  35   var s-storage: (stream byte 0x200000)  # 512* 0x1000 sectors
+  36   var s/ebx: (addr stream byte) <- address s-storage
+  37   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading sectors from data disk", 3/fg, 0/bg
+  38   move-cursor-to-left-margin-of-next-line 0/screen
+  39   load-sectors data-disk, 0/lba, 0x100/sectors, s
+  40   load-sectors data-disk, 0x100/lba, 0x100/sectors, s
+  41   load-sectors data-disk, 0x200/lba, 0x100/sectors, s
+  42   load-sectors data-disk, 0x300/lba, 0x100/sectors, s
+  43   load-sectors data-disk, 0x400/lba, 0x100/sectors, s
+  44   load-sectors data-disk, 0x500/lba, 0x100/sectors, s
+  45   load-sectors data-disk, 0x600/lba, 0x100/sectors, s
+  46   load-sectors data-disk, 0x700/lba, 0x100/sectors, s
+  47   load-sectors data-disk, 0x800/lba, 0x100/sectors, s
+  48   load-sectors data-disk, 0x900/lba, 0x100/sectors, s
+  49   load-sectors data-disk, 0xa00/lba, 0x100/sectors, s
+  50   load-sectors data-disk, 0xb00/lba, 0x100/sectors, s
+  51   load-sectors data-disk, 0xc00/lba, 0x100/sectors, s
+  52   load-sectors data-disk, 0xd00/lba, 0x100/sectors, s
+  53   load-sectors data-disk, 0xe00/lba, 0x100/sectors, s
+  54   load-sectors data-disk, 0xf00/lba, 0x100/sectors, s
+  55   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "parsing", 3/fg, 0/bg
+  56   move-cursor-to-left-margin-of-next-line 0/screen
+  57   initialize-image self, s
+  58 }
+  59 
+  60 fn initialize-image _self: (addr image), in: (addr stream byte) {
+  61   var self/esi: (addr image) <- copy _self
+  62   var mode-storage: slice
+  63   var mode/ecx: (addr slice) <- address mode-storage
+  64   next-word in, mode
+  65   {
+  66     var P1?/eax: boolean <- slice-equal? mode, "P1"
+  67     compare P1?, 0/false
+  68     break-if-=
+  69     var type-a/eax: (addr int) <- get self, type
+  70     copy-to *type-a, 1/ppm
+  71     initialize-image-from-pbm self, in
+  72     return
+  73   }
+  74   {
+  75     var P2?/eax: boolean <- slice-equal? mode, "P2"
+  76     compare P2?, 0/false
+  77     break-if-=
+  78     var type-a/eax: (addr int) <- get self, type
+  79     copy-to *type-a, 2/pgm
+  80     initialize-image-from-pgm self, in
+  81     return
+  82   }
+  83   {
+  84     var P3?/eax: boolean <- slice-equal? mode, "P3"
+  85     compare P3?, 0/false
+  86     break-if-=
+  87     var type-a/eax: (addr int) <- get self, type
+  88     copy-to *type-a, 3/ppm
+  89     initialize-image-from-ppm self, in
+  90     return
+  91   }
+  92   abort "initialize-image: unrecognized image type"
+  93 }
+  94 
+  95 # dispatch to a few variants with mostly identical boilerplate
+  96 fn render-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+  97   var img/esi: (addr image) <- copy _img
+  98   var type-a/eax: (addr int) <- get img, type
+  99   {
+ 100     compare *type-a, 1/pbm
+ 101     break-if-!=
+ 102     render-pbm-image screen, img, xmin, ymin, width, height
+ 103     return
+ 104   }
+ 105   {
+ 106     compare *type-a, 2/pgm
+ 107     break-if-!=
+ 108     var img2-storage: image
+ 109     var img2/edi: (addr image) <- address img2-storage
+ 110     dither-pgm-unordered img, img2
+ 111     render-raw-image screen, img2, xmin, ymin, width, height
+ 112     return
+ 113   }
+ 114   {
+ 115     compare *type-a, 3/ppm
+ 116     break-if-!=
+ 117     var img2-storage: image
+ 118     var img2/edi: (addr image) <- address img2-storage
+ 119     dither-ppm-unordered img, img2
+ 120     render-raw-image screen, img2, xmin, ymin, width, height
+ 121     return
+ 122   }
+ 123   abort "render-image: unrecognized image type"
+ 124 }
+ 125 
+ 126 ## helpers
+ 127 
+ 128 # import a black-and-white ascii bitmap (each pixel is 0 or 1)
+ 129 fn initialize-image-from-pbm _self: (addr image), in: (addr stream byte) {
+ 130   var self/esi: (addr image) <- copy _self
+ 131   var curr-word-storage: slice
+ 132   var curr-word/ecx: (addr slice) <- address curr-word-storage
+ 133   # load width, height
+ 134   next-word in, curr-word
+ 135   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
+ 136   var width/edx: int <- copy tmp
+ 137   next-word in, curr-word
+ 138   tmp <- parse-decimal-int-from-slice curr-word
+ 139   var height/ebx: int <- copy tmp
+ 140   # save width, height
+ 141   var dest/eax: (addr int) <- get self, width
+ 142   copy-to *dest, width
+ 143   dest <- get self, height
+ 144   copy-to *dest, height
+ 145   # initialize data
+ 146   var capacity/edx: int <- copy width
+ 147   capacity <- multiply height
+ 148   var data-ah/edi: (addr handle array byte) <- get self, data
+ 149   populate data-ah, capacity
+ 150   var _data/eax: (addr array byte) <- lookup *data-ah
+ 151   var data/edi: (addr array byte) <- copy _data
+ 152   var i/ebx: int <- copy 0
+ 153   {
+ 154     compare i, capacity
+ 155     break-if->=
+ 156     next-word in, curr-word
+ 157     var src/eax: int <- parse-decimal-int-from-slice curr-word
+ 158     {
+ 159       var dest/ecx: (addr byte) <- index data, i
+ 160       copy-byte-to *dest, src
+ 161     }
+ 162     i <- increment
+ 163     loop
+ 164   }
+ 165 }
+ 166 
+ 167 # render a black-and-white ascii bitmap (each pixel is 0 or 1)
+ 168 fn render-pbm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+ 169   var img/esi: (addr image) <- copy _img
+ 170   # yratio = height/img->height
+ 171   var img-height-a/eax: (addr int) <- get img, height
+ 172   var img-height/xmm0: float <- convert *img-height-a
+ 173   var yratio/xmm1: float <- convert height
+ 174   yratio <- divide img-height
+ 175   # xratio = width/img->width
+ 176   var img-width-a/eax: (addr int) <- get img, width
+ 177   var img-width/ebx: int <- copy *img-width-a
+ 178   var img-width-f/xmm0: float <- convert img-width
+ 179   var xratio/xmm2: float <- convert width
+ 180   xratio <- divide img-width-f
+ 181   # esi = img->data
+ 182   var img-data-ah/eax: (addr handle array byte) <- get img, data
+ 183   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+ 184   var img-data/esi: (addr array byte) <- copy _img-data
+ 185   var len/edi: int <- length img-data
+ 186   #
+ 187   var one/eax: int <- copy 1
+ 188   var one-f/xmm3: float <- convert one
+ 189   var width-f/xmm4: float <- convert width
+ 190   var height-f/xmm5: float <- convert height
+ 191   var zero/eax: int <- copy 0
+ 192   var zero-f/xmm0: float <- convert zero
+ 193   var y/xmm6: float <- copy zero-f
+ 194   {
+ 195     compare y, height-f
+ 196     break-if-float>=
+ 197     var imgy-f/xmm5: float <- copy y
+ 198     imgy-f <- divide yratio
+ 199     var imgy/edx: int <- truncate imgy-f
+ 200     var x/xmm7: float <- copy zero-f
+ 201     {
+ 202       compare x, width-f
+ 203       break-if-float>=
+ 204       var imgx-f/xmm5: float <- copy x
+ 205       imgx-f <- divide xratio
+ 206       var imgx/ecx: int <- truncate imgx-f
+ 207       var idx/eax: int <- copy imgy
+ 208       idx <- multiply img-width
+ 209       idx <- add imgx
+ 210       # error info in case we rounded wrong and 'index' will fail bounds-check
+ 211       compare idx, len
+ 212       {
+ 213         break-if-<
+ 214         set-cursor-position 0/screen, 0x20/x 0x20/y
+ 215         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+ 216         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+ 217         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+ 218       }
+ 219       var src-a/eax: (addr byte) <- index img-data, idx
+ 220       var src/eax: byte <- copy-byte *src-a
+ 221       var color-int/eax: int <- copy src
+ 222       {
+ 223         compare color-int, 0/black
+ 224         break-if-=
+ 225         color-int <- copy 0xf/white
+ 226       }
+ 227       var screenx/ecx: int <- convert x
+ 228       screenx <- add xmin
+ 229       var screeny/edx: int <- convert y
+ 230       screeny <- add ymin
+ 231       pixel screen, screenx, screeny, color-int
+ 232       x <- add one-f
+ 233       loop
+ 234     }
+ 235     y <- add one-f
+ 236     loop
+ 237   }
+ 238 }
+ 239 
+ 240 # import a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255)
+ 241 fn initialize-image-from-pgm _self: (addr image), in: (addr stream byte) {
+ 242   var self/esi: (addr image) <- copy _self
+ 243   var curr-word-storage: slice
+ 244   var curr-word/ecx: (addr slice) <- address curr-word-storage
+ 245   # load width, height
+ 246   next-word in, curr-word
+ 247   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
+ 248   var width/edx: int <- copy tmp
+ 249   next-word in, curr-word
+ 250   tmp <- parse-decimal-int-from-slice curr-word
+ 251   var height/ebx: int <- copy tmp
+ 252   # check and save color levels
+ 253   next-word in, curr-word
+ 254   {
+ 255     tmp <- parse-decimal-int-from-slice curr-word
+ 256     compare tmp, 0xff
+ 257     break-if-=
+ 258     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "levels of grey is not 255; continuing and hoping for the best", 0x2b/fg 0/bg
+ 259   }
+ 260   var dest/edi: (addr int) <- get self, max
+ 261   copy-to *dest, tmp
+ 262   # save width, height
+ 263   dest <- get self, width
+ 264   copy-to *dest, width
+ 265   dest <- get self, height
+ 266   copy-to *dest, height
+ 267   # initialize data
+ 268   var capacity/edx: int <- copy width
+ 269   capacity <- multiply height
+ 270   var data-ah/edi: (addr handle array byte) <- get self, data
+ 271   populate data-ah, capacity
+ 272   var _data/eax: (addr array byte) <- lookup *data-ah
+ 273   var data/edi: (addr array byte) <- copy _data
+ 274   var i/ebx: int <- copy 0
+ 275   {
+ 276     compare i, capacity
+ 277     break-if->=
+ 278     next-word in, curr-word
+ 279     var src/eax: int <- parse-decimal-int-from-slice curr-word
+ 280     {
+ 281       var dest/ecx: (addr byte) <- index data, i
+ 282       copy-byte-to *dest, src
+ 283     }
+ 284     i <- increment
+ 285     loop
+ 286   }
+ 287 }
+ 288 
+ 289 # render a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255) by quantizing the shades
+ 290 fn render-pgm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+ 291   var img/esi: (addr image) <- copy _img
+ 292   # yratio = height/img->height
+ 293   var img-height-a/eax: (addr int) <- get img, height
+ 294   var img-height/xmm0: float <- convert *img-height-a
+ 295   var yratio/xmm1: float <- convert height
+ 296   yratio <- divide img-height
+ 297   # xratio = width/img->width
+ 298   var img-width-a/eax: (addr int) <- get img, width
+ 299   var img-width/ebx: int <- copy *img-width-a
+ 300   var img-width-f/xmm0: float <- convert img-width
+ 301   var xratio/xmm2: float <- convert width
+ 302   xratio <- divide img-width-f
+ 303   # esi = img->data
+ 304   var img-data-ah/eax: (addr handle array byte) <- get img, data
+ 305   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+ 306   var img-data/esi: (addr array byte) <- copy _img-data
+ 307   var len/edi: int <- length img-data
+ 308   #
+ 309   var one/eax: int <- copy 1
+ 310   var one-f/xmm3: float <- convert one
+ 311   var width-f/xmm4: float <- convert width
+ 312   var height-f/xmm5: float <- convert height
+ 313   var zero/eax: int <- copy 0
+ 314   var zero-f/xmm0: float <- convert zero
+ 315   var y/xmm6: float <- copy zero-f
+ 316   {
+ 317     compare y, height-f
+ 318     break-if-float>=
+ 319     var imgy-f/xmm5: float <- copy y
+ 320     imgy-f <- divide yratio
+ 321     var imgy/edx: int <- truncate imgy-f
+ 322     var x/xmm7: float <- copy zero-f
+ 323     {
+ 324       compare x, width-f
+ 325       break-if-float>=
+ 326       var imgx-f/xmm5: float <- copy x
+ 327       imgx-f <- divide xratio
+ 328       var imgx/ecx: int <- truncate imgx-f
+ 329       var idx/eax: int <- copy imgy
+ 330       idx <- multiply img-width
+ 331       idx <- add imgx
+ 332       # error info in case we rounded wrong and 'index' will fail bounds-check
+ 333       compare idx, len
+ 334       {
+ 335         break-if-<
+ 336         set-cursor-position 0/screen, 0x20/x 0x20/y
+ 337         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+ 338         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+ 339         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+ 340       }
+ 341       var src-a/eax: (addr byte) <- index img-data, idx
+ 342       var src/eax: byte <- copy-byte *src-a
+ 343       var color-int/eax: int <- nearest-grey src
+ 344       var screenx/ecx: int <- convert x
+ 345       screenx <- add xmin
+ 346       var screeny/edx: int <- convert y
+ 347       screeny <- add ymin
+ 348       pixel screen, screenx, screeny, color-int
+ 349       x <- add one-f
+ 350       loop
+ 351     }
+ 352     y <- add one-f
+ 353     loop
+ 354   }
+ 355 }
+ 356 
+ 357 fn nearest-grey level-255: byte -> _/eax: int {
+ 358   var result/eax: int <- copy level-255
+ 359   result <- shift-right 4
+ 360   result <- add 0x10
+ 361   return result
+ 362 }
+ 363 
+ 364 fn dither-pgm-unordered-monochrome _src: (addr image), _dest: (addr image) {
+ 365   var src/esi: (addr image) <- copy _src
+ 366   var dest/edi: (addr image) <- copy _dest
+ 367   # copy 'width'
+ 368   var src-width-a/eax: (addr int) <- get src, width
+ 369   var tmp/eax: int <- copy *src-width-a
+ 370   var src-width: int
+ 371   copy-to src-width, tmp
+ 372   {
+ 373     var dest-width-a/edx: (addr int) <- get dest, width
+ 374     copy-to *dest-width-a, tmp
+ 375   }
+ 376   # copy 'height'
+ 377   var src-height-a/eax: (addr int) <- get src, height
+ 378   var tmp/eax: int <- copy *src-height-a
+ 379   var src-height: int
+ 380   copy-to src-height, tmp
+ 381   {
+ 382     var dest-height-a/ecx: (addr int) <- get dest, height
+ 383     copy-to *dest-height-a, tmp
+ 384   }
+ 385   # transform 'data'
+ 386   var capacity/ebx: int <- copy src-width
+ 387   capacity <- multiply src-height
+ 388   var dest/edi: (addr image) <- copy _dest
+ 389   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
+ 390   populate dest-data-ah, capacity
+ 391   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
+ 392   var dest-data/edi: (addr array byte) <- copy _dest-data
+ 393   # needs a buffer to temporarily hold more than 256 levels of precision
+ 394   var errors-storage: (array int 0xc0000)
+ 395   var errors/ebx: (addr array int) <- address errors-storage
+ 396   var src-data-ah/eax: (addr handle array byte) <- get src, data
+ 397   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
+ 398   var src-data/esi: (addr array byte) <- copy _src-data
+ 399   var y/edx: int <- copy 0
+ 400   {
+ 401     compare y, src-height
+ 402     break-if->=
+ 403     var x/ecx: int <- copy 0
+ 404     {
+ 405       compare x, src-width
+ 406       break-if->=
+ 407       var curr/eax: byte <- _read-pgm-buffer src-data, x, y, src-width
+ 408       var curr-int/eax: int <- copy curr
+ 409       curr-int <- shift-left 0x10  # we have 32 bits; we'll use 16 bits for the fraction and leave 8 for unanticipated overflow
+ 410       var error/esi: int <- _read-dithering-error errors, x, y, src-width
+ 411       error <- add curr-int
+ 412       $_dither-pgm-unordered-monochrome:update-error: {
+ 413         compare error, 0x800000
+ 414         {
+ 415           break-if->=
+ 416           _write-raw-buffer dest-data, x, y, src-width, 0/black
+ 417           break $_dither-pgm-unordered-monochrome:update-error
+ 418         }
+ 419         _write-raw-buffer dest-data, x, y, src-width, 1/white
+ 420         error <- subtract 0xff0000
+ 421       }
+ 422       _diffuse-dithering-error-floyd-steinberg errors, x, y, src-width, src-height, error
+ 423       x <- increment
+ 424       loop
+ 425     }
+ 426     move-cursor-to-left-margin-of-next-line 0/screen
+ 427     y <- increment
+ 428     loop
+ 429   }
+ 430 }
+ 431 
+ 432 fn dither-pgm-unordered _src: (addr image), _dest: (addr image) {
+ 433   var src/esi: (addr image) <- copy _src
+ 434   var dest/edi: (addr image) <- copy _dest
+ 435   # copy 'width'
+ 436   var src-width-a/eax: (addr int) <- get src, width
+ 437   var tmp/eax: int <- copy *src-width-a
+ 438   var src-width: int
+ 439   copy-to src-width, tmp
+ 440   {
+ 441     var dest-width-a/edx: (addr int) <- get dest, width
+ 442     copy-to *dest-width-a, tmp
+ 443   }
+ 444   # copy 'height'
+ 445   var src-height-a/eax: (addr int) <- get src, height
+ 446   var tmp/eax: int <- copy *src-height-a
+ 447   var src-height: int
+ 448   copy-to src-height, tmp
+ 449   {
+ 450     var dest-height-a/ecx: (addr int) <- get dest, height
+ 451     copy-to *dest-height-a, tmp
+ 452   }
+ 453   # compute scaling factor 255/max
+ 454   var target-scale/eax: int <- copy 0xff
+ 455   var scale-f/xmm7: float <- convert target-scale
+ 456   var src-max-a/eax: (addr int) <- get src, max
+ 457   var tmp-f/xmm0: float <- convert *src-max-a
+ 458   scale-f <- divide tmp-f
+ 459   # transform 'data'
+ 460   var capacity/ebx: int <- copy src-width
+ 461   capacity <- multiply src-height
+ 462   var dest/edi: (addr image) <- copy _dest
+ 463   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
+ 464   populate dest-data-ah, capacity
+ 465   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
+ 466   var dest-data/edi: (addr array byte) <- copy _dest-data
+ 467   # needs a buffer to temporarily hold more than 256 levels of precision
+ 468   var errors-storage: (array int 0xc0000)
+ 469   var errors/ebx: (addr array int) <- address errors-storage
+ 470   var src-data-ah/eax: (addr handle array byte) <- get src, data
+ 471   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
+ 472   var src-data/esi: (addr array byte) <- copy _src-data
+ 473   var y/edx: int <- copy 0
+ 474   {
+ 475     compare y, src-height
+ 476     break-if->=
+ 477     var x/ecx: int <- copy 0
+ 478     {
+ 479       compare x, src-width
+ 480       break-if->=
+ 481       var initial-color/eax: byte <- _read-pgm-buffer src-data, x, y, src-width
+ 482       # . scale to 255 levels
+ 483       var initial-color-int/eax: int <- copy initial-color
+ 484       var initial-color-f/xmm0: float <- convert initial-color-int
+ 485       initial-color-f <- multiply scale-f
+ 486       initial-color-int <- convert initial-color-f
+ 487       var error/esi: int <- _read-dithering-error errors, x, y, src-width
+ 488       # error += (initial-color << 16)
+ 489       {
+ 490         var tmp/eax: int <- copy initial-color-int
+ 491         tmp <- shift-left 0x10  # we have 32 bits; we'll use 16 bits for the fraction and leave 8 for unanticipated overflow
+ 492         error <- add tmp
+ 493       }
+ 494       # nearest-color = nearest(error >> 16)
+ 495       var nearest-color/eax: int <- copy error
+ 496       nearest-color <- shift-right-signed 0x10
+ 497       {
+ 498         compare nearest-color, 0
+ 499         break-if->=
+ 500         nearest-color <- copy 0
+ 501       }
+ 502       {
+ 503         compare nearest-color, 0xf0
+ 504         break-if-<=
+ 505         nearest-color <- copy 0xf0
+ 506       }
+ 507       # . truncate last 4 bits
+ 508       nearest-color <- and 0xf0
+ 509       # error -= (nearest-color << 16)
+ 510       {
+ 511         var tmp/eax: int <- copy nearest-color
+ 512         tmp <- shift-left 0x10
+ 513         error <- subtract tmp
+ 514       }
+ 515       # color-index = (nearest-color >> 4 + 16)
+ 516       var color-index/eax: int <- copy nearest-color
+ 517       color-index <- shift-right 4
+ 518       color-index <- add 0x10
+ 519       var color-index-byte/eax: byte <- copy-byte color-index
+ 520       _write-raw-buffer dest-data, x, y, src-width, color-index-byte
+ 521       _diffuse-dithering-error-floyd-steinberg errors, x, y, src-width, src-height, error
+ 522       x <- increment
+ 523       loop
+ 524     }
+ 525     y <- increment
+ 526     loop
+ 527   }
+ 528 }
+ 529 
+ 530 # Use Floyd-Steinberg algorithm for diffusing error at x, y in a 2D grid of
+ 531 # dimensions (width, height)
+ 532 #
+ 533 # https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
+ 534 #
+ 535 # Error is currently a fixed-point number with 16-bit fraction. But
+ 536 # interestingly this function doesn't care about that.
+ 537 fn _diffuse-dithering-error-floyd-steinberg errors: (addr array int), x: int, y: int, width: int, height: int, error: int {
+ 538   {
+ 539     compare error, 0
+ 540     break-if-!=
+ 541     return
+ 542   }
+ 543   var width-1/esi: int <- copy width
+ 544   width-1 <- decrement
+ 545   var height-1/edi: int <- copy height
+ 546   height-1 <- decrement
+ 547   # delta = error/16
+ 548 #?   show-errors errors, width, height, x, y
+ 549   var delta/ecx: int <- copy error
+ 550   delta <- shift-right-signed 4
+ 551   # In Floyd-Steinberg, each pixel X transmits its errors to surrounding
+ 552   # pixels in the following proportion:
+ 553   #           X     7/16
+ 554   #     3/16  5/16  1/16
+ 555   var x/edx: int <- copy x
+ 556   {
+ 557     compare x, width-1
+ 558     break-if->=
+ 559     var tmp/eax: int <- copy 7
+ 560     tmp <- multiply delta
+ 561     var xright/edx: int <- copy x
+ 562     xright <- increment
+ 563     _accumulate-dithering-error errors, xright, y, width, tmp
+ 564   }
+ 565   var y/ebx: int <- copy y
+ 566   {
+ 567     compare y, height-1
+ 568     break-if-<
+ 569     return
+ 570   }
+ 571   var ybelow: int
+ 572   copy-to ybelow, y
+ 573   increment ybelow
+ 574   {
+ 575     compare x, 0
+ 576     break-if-<=
+ 577     var tmp/eax: int <- copy 3
+ 578     tmp <- multiply delta
+ 579     var xleft/edx: int <- copy x
+ 580     xleft <- decrement
+ 581     _accumulate-dithering-error errors, xleft, ybelow, width, tmp
+ 582   }
+ 583   {
+ 584     var tmp/eax: int <- copy 5
+ 585     tmp <- multiply delta
+ 586     _accumulate-dithering-error errors, x, ybelow, width, tmp
+ 587   }
+ 588   {
+ 589     compare x, width-1
+ 590     break-if->=
+ 591     var xright/edx: int <- copy x
+ 592     xright <- increment
+ 593     _accumulate-dithering-error errors, xright, ybelow, width, delta
+ 594   }
+ 595 #?   show-errors errors, width, height, x, y
+ 596 }
+ 597 
+ 598 fn _accumulate-dithering-error errors: (addr array int), x: int, y: int, width: int, error: int {
+ 599   var curr/esi: int <- _read-dithering-error errors, x, y, width
+ 600   curr <- add error
+ 601   _write-dithering-error errors, x, y, width, curr
+ 602 }
+ 603 
+ 604 fn _read-dithering-error _errors: (addr array int), x: int, y: int, width: int -> _/esi: int {
+ 605   var errors/esi: (addr array int) <- copy _errors
+ 606   var idx/ecx: int <- copy y
+ 607   idx <- multiply width
+ 608   idx <- add x
+ 609   var result-a/eax: (addr int) <- index errors, idx
+ 610   return *result-a
+ 611 }
+ 612 
+ 613 fn _write-dithering-error _errors: (addr array int), x: int, y: int, width: int, val: int {
+ 614   var errors/esi: (addr array int) <- copy _errors
+ 615   var idx/ecx: int <- copy y
+ 616   idx <- multiply width
+ 617   idx <- add x
+ 618 #?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 7/fg 0/bg
+ 619 #?   move-cursor-to-left-margin-of-next-line 0/screen
+ 620   var src/eax: int <- copy val
+ 621   var dest-a/edi: (addr int) <- index errors, idx
+ 622   copy-to *dest-a, src
+ 623 }
+ 624 
+ 625 fn _read-pgm-buffer _buf: (addr array byte), x: int, y: int, width: int -> _/eax: byte {
+ 626   var buf/esi: (addr array byte) <- copy _buf
+ 627   var idx/ecx: int <- copy y
+ 628   idx <- multiply width
+ 629   idx <- add x
+ 630   var result-a/eax: (addr byte) <- index buf, idx
+ 631   var result/eax: byte <- copy-byte *result-a
+ 632   return result
+ 633 }
+ 634 
+ 635 fn _write-raw-buffer _buf: (addr array byte), x: int, y: int, width: int, val: byte {
+ 636   var buf/esi: (addr array byte) <- copy _buf
+ 637   var idx/ecx: int <- copy y
+ 638   idx <- multiply width
+ 639   idx <- add x
+ 640   var src/eax: byte <- copy val
+ 641   var dest-a/edi: (addr byte) <- index buf, idx
+ 642   copy-byte-to *dest-a, src
+ 643 }
+ 644 
+ 645 # some debugging helpers
+ 646 fn show-errors errors: (addr array int), width: int, height: int, x: int, y: int {
+ 647   compare y, 1
+ 648   {
+ 649     break-if-=
+ 650     return
+ 651   }
+ 652   compare x, 0
+ 653   {
+ 654     break-if-=
+ 655     return
+ 656   }
+ 657   var y/edx: int <- copy 0
+ 658   {
+ 659     compare y, height
+ 660     break-if->=
+ 661     var x/ecx: int <- copy 0
+ 662     {
+ 663       compare x, width
+ 664       break-if->=
+ 665       var error/esi: int <- _read-dithering-error errors, x, y, width
+ 666       psd "e", error, 5/fg, x, y
+ 667       x <- increment
+ 668       loop
+ 669     }
+ 670     move-cursor-to-left-margin-of-next-line 0/screen
+ 671     y <- increment
+ 672     loop
+ 673   }
+ 674 }
+ 675 
+ 676 fn psd s: (addr array byte), d: int, fg: int, x: int, y: int {
+ 677   {
+ 678     compare y, 0x18
+ 679     break-if->=
+ 680     return
+ 681   }
+ 682   {
+ 683     compare y, 0x1c
+ 684     break-if-<=
+ 685     return
+ 686   }
+ 687   {
+ 688     compare x, 0x40
+ 689     break-if->=
+ 690     return
+ 691   }
+ 692 #?   {
+ 693 #?     compare x, 0x48
+ 694 #?     break-if-<=
+ 695 #?     return
+ 696 #?   }
+ 697   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, s, 7/fg 0/bg
+ 698   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, d, fg 0/bg
+ 699 }
+ 700 
+ 701 fn psx s: (addr array byte), d: int, fg: int, x: int, y: int {
+ 702 #?   {
+ 703 #?     compare y, 0x60
+ 704 #?     break-if->=
+ 705 #?     return
+ 706 #?   }
+ 707 #?   {
+ 708 #?     compare y, 0x6c
+ 709 #?     break-if-<=
+ 710 #?     return
+ 711 #?   }
+ 712   {
+ 713     compare x, 0x20
+ 714     break-if->=
+ 715     return
+ 716   }
+ 717 #?   {
+ 718 #?     compare x, 0x6c
+ 719 #?     break-if-<=
+ 720 #?     return
+ 721 #?   }
+ 722   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, s, 7/fg 0/bg
+ 723   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, d, fg 0/bg
+ 724 }
+ 725 
+ 726 # import a color ascii "pixmap" (each pixel consists of 3 shades of r/g/b from 0 to 255)
+ 727 fn initialize-image-from-ppm _self: (addr image), in: (addr stream byte) {
+ 728   var self/esi: (addr image) <- copy _self
+ 729   var curr-word-storage: slice
+ 730   var curr-word/ecx: (addr slice) <- address curr-word-storage
+ 731   # load width, height
+ 732   next-word in, curr-word
+ 733   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
+ 734   var width/edx: int <- copy tmp
+ 735   next-word in, curr-word
+ 736   tmp <- parse-decimal-int-from-slice curr-word
+ 737   var height/ebx: int <- copy tmp
+ 738   next-word in, curr-word
+ 739   # check color levels
+ 740   {
+ 741     tmp <- parse-decimal-int-from-slice curr-word
+ 742     compare tmp, 0xff
+ 743     break-if-=
+ 744     abort "initialize-image-from-ppm: supports exactly 255 levels per rgb channel"
+ 745   }
+ 746   var dest/edi: (addr int) <- get self, max
+ 747   copy-to *dest, tmp
+ 748   # save width, height
+ 749   dest <- get self, width
+ 750   copy-to *dest, width
+ 751   dest <- get self, height
+ 752   copy-to *dest, height
+ 753   # initialize data
+ 754   var capacity/edx: int <- copy width
+ 755   capacity <- multiply height
+ 756   # . multiply by 3 for the r/g/b channels
+ 757   var tmp/eax: int <- copy capacity
+ 758   tmp <- shift-left 1
+ 759   capacity <- add tmp
+ 760   #
+ 761   var data-ah/edi: (addr handle array byte) <- get self, data
+ 762   populate data-ah, capacity
+ 763   var _data/eax: (addr array byte) <- lookup *data-ah
+ 764   var data/edi: (addr array byte) <- copy _data
+ 765   var i/ebx: int <- copy 0
+ 766   {
+ 767     compare i, capacity
+ 768     break-if->=
+ 769     next-word in, curr-word
+ 770     var src/eax: int <- parse-decimal-int-from-slice curr-word
+ 771     {
+ 772       var dest/ecx: (addr byte) <- index data, i
+ 773       copy-byte-to *dest, src
+ 774     }
+ 775     i <- increment
+ 776     loop
+ 777   }
+ 778 }
+ 779 
+ 780 # import a color ascii "pixmap" (each pixel consists of 3 shades of r/g/b from 0 to 255)
+ 781 fn render-ppm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+ 782   var img/esi: (addr image) <- copy _img
+ 783   # yratio = height/img->height
+ 784   var img-height-a/eax: (addr int) <- get img, height
+ 785   var img-height/xmm0: float <- convert *img-height-a
+ 786   var yratio/xmm1: float <- convert height
+ 787   yratio <- divide img-height
+ 788   # xratio = width/img->width
+ 789   var img-width-a/eax: (addr int) <- get img, width
+ 790   var img-width/ebx: int <- copy *img-width-a
+ 791   var img-width-f/xmm0: float <- convert img-width
+ 792   var xratio/xmm2: float <- convert width
+ 793   xratio <- divide img-width-f
+ 794   # esi = img->data
+ 795   var img-data-ah/eax: (addr handle array byte) <- get img, data
+ 796   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+ 797   var img-data/esi: (addr array byte) <- copy _img-data
+ 798   var len/edi: int <- length img-data
+ 799   #
+ 800   var one/eax: int <- copy 1
+ 801   var one-f/xmm3: float <- convert one
+ 802   var width-f/xmm4: float <- convert width
+ 803   var height-f/xmm5: float <- convert height
+ 804   var zero/eax: int <- copy 0
+ 805   var zero-f/xmm0: float <- convert zero
+ 806   var y/xmm6: float <- copy zero-f
+ 807   {
+ 808     compare y, height-f
+ 809     break-if-float>=
+ 810     var imgy-f/xmm5: float <- copy y
+ 811     imgy-f <- divide yratio
+ 812     var imgy/edx: int <- truncate imgy-f
+ 813     var x/xmm7: float <- copy zero-f
+ 814     {
+ 815       compare x, width-f
+ 816       break-if-float>=
+ 817       var imgx-f/xmm5: float <- copy x
+ 818       imgx-f <- divide xratio
+ 819       var imgx/ecx: int <- truncate imgx-f
+ 820       var idx/eax: int <- copy imgy
+ 821       idx <- multiply img-width
+ 822       idx <- add imgx
+ 823       # . multiply by 3 for the r/g/b channels
+ 824       {
+ 825         var tmp/ecx: int <- copy idx
+ 826         tmp <- shift-left 1
+ 827         idx <- add tmp
+ 828       }
+ 829       # error info in case we rounded wrong and 'index' will fail bounds-check
+ 830       compare idx, len
+ 831       {
+ 832         break-if-<
+ 833         set-cursor-position 0/screen, 0x20/x 0x20/y
+ 834         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+ 835         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+ 836         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+ 837       }
+ 838       # r channel
+ 839       var r: int
+ 840       {
+ 841         var src-a/eax: (addr byte) <- index img-data, idx
+ 842         var src/eax: byte <- copy-byte *src-a
+ 843         copy-to r, src
+ 844       }
+ 845       idx <- increment
+ 846       # g channel
+ 847       var g: int
+ 848       {
+ 849         var src-a/eax: (addr byte) <- index img-data, idx
+ 850         var src/eax: byte <- copy-byte *src-a
+ 851         copy-to g, src
+ 852       }
+ 853       idx <- increment
+ 854       # b channel
+ 855       var b: int
+ 856       {
+ 857         var src-a/eax: (addr byte) <- index img-data, idx
+ 858         var src/eax: byte <- copy-byte *src-a
+ 859         copy-to b, src
+ 860       }
+ 861       idx <- increment
+ 862       # plot nearest color
+ 863       var color/eax: int <- nearest-color-euclidean r, g, b
+ 864       var screenx/ecx: int <- convert x
+ 865       screenx <- add xmin
+ 866       var screeny/edx: int <- convert y
+ 867       screeny <- add ymin
+ 868       pixel screen, screenx, screeny, color
+ 869       x <- add one-f
+ 870       loop
+ 871     }
+ 872     y <- add one-f
+ 873     loop
+ 874   }
+ 875 }
+ 876 
+ 877 fn dither-ppm-unordered _src: (addr image), _dest: (addr image) {
+ 878   var src/esi: (addr image) <- copy _src
+ 879   var dest/edi: (addr image) <- copy _dest
+ 880   # copy 'width'
+ 881   var src-width-a/eax: (addr int) <- get src, width
+ 882   var tmp/eax: int <- copy *src-width-a
+ 883   var src-width: int
+ 884   copy-to src-width, tmp
+ 885   {
+ 886     var dest-width-a/edx: (addr int) <- get dest, width
+ 887     copy-to *dest-width-a, tmp
+ 888   }
+ 889   # copy 'height'
+ 890   var src-height-a/eax: (addr int) <- get src, height
+ 891   var tmp/eax: int <- copy *src-height-a
+ 892   var src-height: int
+ 893   copy-to src-height, tmp
+ 894   {
+ 895     var dest-height-a/ecx: (addr int) <- get dest, height
+ 896     copy-to *dest-height-a, tmp
+ 897   }
+ 898   # compute scaling factor 255/max
+ 899   var target-scale/eax: int <- copy 0xff
+ 900   var scale-f/xmm7: float <- convert target-scale
+ 901   var src-max-a/eax: (addr int) <- get src, max
+ 902   var tmp-f/xmm0: float <- convert *src-max-a
+ 903   scale-f <- divide tmp-f
+ 904   # allocate 'data'
+ 905   var capacity/ebx: int <- copy src-width
+ 906   capacity <- multiply src-height
+ 907   var dest/edi: (addr image) <- copy _dest
+ 908   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
+ 909   populate dest-data-ah, capacity
+ 910   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
+ 911   var dest-data/edi: (addr array byte) <- copy _dest-data
+ 912   # error buffers per r/g/b channel
+ 913   var red-errors-storage: (array int 0xc0000)
+ 914   var tmp/eax: (addr array int) <- address red-errors-storage
+ 915   var red-errors: (addr array int)
+ 916   copy-to red-errors, tmp
+ 917   var green-errors-storage: (array int 0xc0000)
+ 918   var tmp/eax: (addr array int) <- address green-errors-storage
+ 919   var green-errors: (addr array int)
+ 920   copy-to green-errors, tmp
+ 921   var blue-errors-storage: (array int 0xc0000)
+ 922   var tmp/eax: (addr array int) <- address blue-errors-storage
+ 923   var blue-errors: (addr array int)
+ 924   copy-to blue-errors, tmp
+ 925   # transform 'data'
+ 926   var src-data-ah/eax: (addr handle array byte) <- get src, data
+ 927   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
+ 928   var src-data/esi: (addr array byte) <- copy _src-data
+ 929   var y/edx: int <- copy 0
+ 930   {
+ 931     compare y, src-height
+ 932     break-if->=
+ 933     var x/ecx: int <- copy 0
+ 934     {
+ 935       compare x, src-width
+ 936       break-if->=
+ 937       # - update errors and compute color levels for current pixel in each channel
+ 938       # update red-error with current image pixel
+ 939       var red-error: int
+ 940       {
+ 941         var tmp/esi: int <- _read-dithering-error red-errors, x, y, src-width
+ 942         copy-to red-error, tmp
+ 943       }
+ 944       {
+ 945         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 0/red, scale-f
+ 946         add-to red-error, tmp
+ 947       }
+ 948       # recompute red channel for current pixel
+ 949       var red-level: int
+ 950       {
+ 951         var tmp/eax: int <- _error-to-ppm-channel red-error
+ 952         copy-to red-level, tmp
+ 953       }
+ 954       # update green-error with current image pixel
+ 955       var green-error: int
+ 956       {
+ 957         var tmp/esi: int <- _read-dithering-error green-errors, x, y, src-width
+ 958         copy-to green-error, tmp
+ 959       }
+ 960       {
+ 961         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 1/green, scale-f
+ 962         add-to green-error, tmp
+ 963       }
+ 964       # recompute green channel for current pixel
+ 965       var green-level: int
+ 966       {
+ 967         var tmp/eax: int <- _error-to-ppm-channel green-error
+ 968         copy-to green-level, tmp
+ 969       }
+ 970       # update blue-error with current image pixel
+ 971       var blue-error: int
+ 972       {
+ 973         var tmp/esi: int <- _read-dithering-error blue-errors, x, y, src-width
+ 974         copy-to blue-error, tmp
+ 975       }
+ 976       {
+ 977         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 2/blue, scale-f
+ 978         add-to blue-error, tmp
+ 979       }
+ 980       # recompute blue channel for current pixel
+ 981       var blue-level: int
+ 982       {
+ 983         var tmp/eax: int <- _error-to-ppm-channel blue-error
+ 984         copy-to blue-level, tmp
+ 985       }
+ 986       # - figure out the nearest color
+ 987 #?       {
+ 988 #?         compare red-level, 0x80
+ 989 #?         break-if->
+ 990 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, red-level, 4/fg 0/bg
+ 991 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, green-level, 2/fg 0/bg
+ 992 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, blue-level, 9/fg 0/bg
+ 993 #?       }
+ 994       var nearest-color-index/eax: int <- nearest-color-euclidean red-level, green-level, blue-level
+ 995       {
+ 996         var nearest-color-index-byte/eax: byte <- copy-byte nearest-color-index
+ 997         _write-raw-buffer dest-data, x, y, src-width, nearest-color-index-byte
+ 998       }
+ 999       # - diffuse errors
+1000       var red-level: int
+1001       var green-level: int
+1002       var blue-level: int
+1003       {
+1004         var tmp-red-level/ecx: int <- copy 0
+1005         var tmp-green-level/edx: int <- copy 0
+1006         var tmp-blue-level/ebx: int <- copy 0
+1007         tmp-red-level, tmp-green-level, tmp-blue-level <- color-rgb nearest-color-index
+1008         copy-to red-level, tmp-red-level
+1009         copy-to green-level, tmp-green-level
+1010         copy-to blue-level, tmp-blue-level
+1011       }
+1012       # update red-error
+1013       var red-level-error/eax: int <- copy red-level
+1014       red-level-error <- shift-left 0x10
+1015       subtract-from red-error, red-level-error
+1016       _diffuse-dithering-error-floyd-steinberg red-errors, x, y, src-width, src-height, red-error
+1017       # update green-error
+1018       var green-level-error/eax: int <- copy green-level
+1019       green-level-error <- shift-left 0x10
+1020       subtract-from green-error, green-level-error
+1021       _diffuse-dithering-error-floyd-steinberg green-errors, x, y, src-width, src-height, green-error
+1022       # update blue-error
+1023       var blue-level-error/eax: int <- copy blue-level
+1024       blue-level-error <- shift-left 0x10
+1025       subtract-from blue-error, blue-level-error
+1026       _diffuse-dithering-error-floyd-steinberg blue-errors, x, y, src-width, src-height, blue-error
+1027       #
+1028       x <- increment
+1029       loop
+1030     }
+1031     y <- increment
+1032     loop
+1033   }
+1034 }
+1035 
+1036 # convert a single channel for a single image pixel to error space
+1037 fn _ppm-error buf: (addr array byte), x: int, y: int, width: int, channel: int, _scale-f: float -> _/eax: int {
+1038   # current image pixel
+1039   var initial-level/eax: byte <- _read-ppm-buffer buf, x, y, width, channel
+1040   # scale to 255 levels
+1041   var initial-level-int/eax: int <- copy initial-level
+1042   var initial-level-f/xmm0: float <- convert initial-level-int
+1043   var scale-f/xmm1: float <- copy _scale-f
+1044   initial-level-f <- multiply scale-f
+1045   initial-level-int <- convert initial-level-f
+1046   # switch to fixed-point with 16 bits of precision
+1047   initial-level-int <- shift-left 0x10
+1048   return initial-level-int
+1049 }
+1050 
+1051 fn _error-to-ppm-channel error: int -> _/eax: int {
+1052   # clamp(error >> 16)
+1053   var result/esi: int <- copy error
+1054   result <- shift-right-signed 0x10
+1055   {
+1056     compare result, 0
+1057     break-if->=
+1058     result <- copy 0
+1059   }
+1060   {
+1061     compare result, 0xff
+1062     break-if-<=
+1063     result <- copy 0xff
+1064   }
+1065   return result
+1066 }
+1067 
+1068 # read from a buffer containing alternating bytes from r/g/b channels
+1069 fn _read-ppm-buffer _buf: (addr array byte), x: int, y: int, width: int, channel: int -> _/eax: byte {
+1070   var buf/esi: (addr array byte) <- copy _buf
+1071   var idx/ecx: int <- copy y
+1072   idx <- multiply width
+1073   idx <- add x
+1074   var byte-idx/edx: int <- copy 3
+1075   byte-idx <- multiply idx
+1076   byte-idx <- add channel
+1077   var result-a/eax: (addr byte) <- index buf, byte-idx
+1078   var result/eax: byte <- copy-byte *result-a
+1079   return result
+1080 }
+1081 
+1082 # each byte in the image data is a color of the current palette
+1083 fn render-raw-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
+1084   var img/esi: (addr image) <- copy _img
+1085   # yratio = height/img->height
+1086   var img-height-a/eax: (addr int) <- get img, height
+1087   var img-height/xmm0: float <- convert *img-height-a
+1088   var yratio/xmm1: float <- convert height
+1089   yratio <- divide img-height
+1090   # xratio = width/img->width
+1091   var img-width-a/eax: (addr int) <- get img, width
+1092   var img-width/ebx: int <- copy *img-width-a
+1093   var img-width-f/xmm0: float <- convert img-width
+1094   var xratio/xmm2: float <- convert width
+1095   xratio <- divide img-width-f
+1096   # esi = img->data
+1097   var img-data-ah/eax: (addr handle array byte) <- get img, data
+1098   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
+1099   var img-data/esi: (addr array byte) <- copy _img-data
+1100   var len/edi: int <- length img-data
+1101   #
+1102   var one/eax: int <- copy 1
+1103   var one-f/xmm3: float <- convert one
+1104   var width-f/xmm4: float <- convert width
+1105   var height-f/xmm5: float <- convert height
+1106   var zero/eax: int <- copy 0
+1107   var zero-f/xmm0: float <- convert zero
+1108   var y/xmm6: float <- copy zero-f
+1109   {
+1110     compare y, height-f
+1111     break-if-float>=
+1112     var imgy-f/xmm5: float <- copy y
+1113     imgy-f <- divide yratio
+1114     var imgy/edx: int <- truncate imgy-f
+1115     var x/xmm7: float <- copy zero-f
+1116     {
+1117       compare x, width-f
+1118       break-if-float>=
+1119       var imgx-f/xmm5: float <- copy x
+1120       imgx-f <- divide xratio
+1121       var imgx/ecx: int <- truncate imgx-f
+1122       var idx/eax: int <- copy imgy
+1123       idx <- multiply img-width
+1124       idx <- add imgx
+1125       # error info in case we rounded wrong and 'index' will fail bounds-check
+1126       compare idx, len
+1127       {
+1128         break-if-<
+1129         set-cursor-position 0/screen, 0x20/x 0x20/y
+1130         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
+1131         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
+1132         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
+1133       }
+1134       var color-a/eax: (addr byte) <- index img-data, idx
+1135       var color/eax: byte <- copy-byte *color-a
+1136       var color-int/eax: int <- copy color
+1137       var screenx/ecx: int <- convert x
+1138       screenx <- add xmin
+1139       var screeny/edx: int <- convert y
+1140       screeny <- add ymin
+1141       pixel screen, screenx, screeny, color-int
+1142       x <- add one-f
+1143       loop
+1144     }
+1145     y <- add one-f
+1146     loop
+1147   }
+1148 }
+
+ + + diff --git a/html/apps/life.mu.html b/html/apps/life.mu.html new file mode 100644 index 00000000..cc262c2d --- /dev/null +++ b/html/apps/life.mu.html @@ -0,0 +1,320 @@ + + + + +Mu - apps/life.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/life.mu +
+  1 # Conway's Game of Life
+  2 #
+  3 # To build:
+  4 #   $ ./translate apps/life.mu
+  5 # To run:
+  6 #   $ qemu-system-i386 code.img
+  7 
+  8 fn state _grid: (addr array boolean), x: int, y: int -> _/eax: boolean {
+  9   # clip at the edge
+ 10   compare x, 0
+ 11   {
+ 12     break-if->=
+ 13     return 0/false
+ 14   }
+ 15   compare y, 0
+ 16   {
+ 17     break-if->=
+ 18     return 0/false
+ 19   }
+ 20   compare x, 0x100/width
+ 21   {
+ 22     break-if-<
+ 23     return 0/false
+ 24   }
+ 25   compare y, 0xc0/height
+ 26   {
+ 27     break-if-<
+ 28     return 0/false
+ 29   }
+ 30   var idx/eax: int <- copy y
+ 31   idx <- shift-left 8/log2width
+ 32   idx <- add x
+ 33   var grid/esi: (addr array boolean) <- copy _grid
+ 34   var result/eax: (addr boolean) <- index grid, idx
+ 35   return *result
+ 36 }
+ 37 
+ 38 fn set-state _grid: (addr array boolean), x: int, y: int, val: boolean {
+ 39   # don't bother checking bounds
+ 40   var idx/eax: int <- copy y
+ 41   idx <- shift-left 8/log2width
+ 42   idx <- add x
+ 43   var grid/esi: (addr array boolean) <- copy _grid
+ 44   var result/eax: (addr boolean) <- index grid, idx
+ 45   var src/ecx: boolean <- copy val
+ 46   copy-to *result, src
+ 47 }
+ 48 
+ 49 fn num-live-neighbors grid: (addr array boolean), x: int, y: int -> _/eax: int {
+ 50   var result/edi: int <- copy 0
+ 51   # row above: zig
+ 52   decrement y
+ 53   decrement x
+ 54   var s/eax: boolean <- state grid, x, y
+ 55   {
+ 56     compare s, 0/false
+ 57     break-if-=
+ 58     result <- increment
+ 59   }
+ 60   increment x
+ 61   s <- state grid, x, y
+ 62   {
+ 63     compare s, 0/false
+ 64     break-if-=
+ 65     result <- increment
+ 66   }
+ 67   increment x
+ 68   s <- state grid, x, y
+ 69   {
+ 70     compare s, 0/false
+ 71     break-if-=
+ 72     result <- increment
+ 73   }
+ 74   # curr row: zag
+ 75   increment y
+ 76   s <- state grid, x, y
+ 77   {
+ 78     compare s, 0/false
+ 79     break-if-=
+ 80     result <- increment
+ 81   }
+ 82   subtract-from x, 2
+ 83   s <- state grid, x, y
+ 84   {
+ 85     compare s, 0/false
+ 86     break-if-=
+ 87     result <- increment
+ 88   }
+ 89   # row below: zig
+ 90   increment y
+ 91   s <- state grid, x, y
+ 92   {
+ 93     compare s, 0/false
+ 94     break-if-=
+ 95     result <- increment
+ 96   }
+ 97   increment x
+ 98   s <- state grid, x, y
+ 99   {
+100     compare s, 0/false
+101     break-if-=
+102     result <- increment
+103   }
+104   increment x
+105   s <- state grid, x, y
+106   {
+107     compare s, 0/false
+108     break-if-=
+109     result <- increment
+110   }
+111   return result
+112 }
+113 
+114 fn step old-grid: (addr array boolean), new-grid: (addr array boolean) {
+115   var y/ecx: int <- copy 0
+116   {
+117     compare y, 0xc0/height
+118     break-if->=
+119     var x/edx: int <- copy 0
+120     {
+121       compare x, 0x100/width
+122       break-if->=
+123       var n/eax: int <- num-live-neighbors old-grid, x, y
+124       # if neighbors < 2, die of loneliness
+125       {
+126         compare n, 2
+127         break-if->=
+128         set-state new-grid, x, y, 0/dead
+129       }
+130       # if neighbors > 3, die of overcrowding
+131       {
+132         compare n, 3
+133         break-if-<=
+134         set-state new-grid, x, y, 0/dead
+135       }
+136       # if neighbors = 2, preserve state
+137       {
+138         compare n, 2
+139         break-if-!=
+140         var old-state/eax: boolean <- state old-grid, x, y
+141         set-state new-grid, x, y, old-state
+142       }
+143       # if neighbors = 3, cell quickens to life
+144       {
+145         compare n, 3
+146         break-if-!=
+147         set-state new-grid, x, y, 1/live
+148       }
+149       x <- increment
+150       loop
+151     }
+152     y <- increment
+153     loop
+154   }
+155 }
+156 
+157 # color a square of size 'side' starting at x*side, y*side
+158 fn render-square _x: int, _y: int, color: int {
+159   var y/edx: int <- copy _y
+160   y <- shift-left 2/log2side
+161   var side/ebx: int <- copy 1
+162   side <- shift-left 2/log2side
+163   var ymax/ecx: int <- copy y
+164   ymax <- add side
+165   {
+166     compare y, ymax
+167     break-if->=
+168     {
+169       var x/eax: int <- copy _x
+170       x <- shift-left 2/log2side
+171       var xmax/ecx: int <- copy x
+172       xmax <- add side
+173       {
+174         compare x, xmax
+175         break-if->=
+176         pixel-on-real-screen x, y, color
+177         x <- increment
+178         loop
+179       }
+180     }
+181     y <- increment
+182     loop
+183   }
+184 }
+185 
+186 fn render grid: (addr array boolean) {
+187   var y/ecx: int <- copy 0
+188   {
+189     compare y, 0xc0/height
+190     break-if->=
+191     var x/edx: int <- copy 0
+192     {
+193       compare x, 0x100/width
+194       break-if->=
+195       var state/eax: boolean <- state grid, x, y
+196       compare state, 0/false
+197       {
+198         break-if-=
+199         render-square x, y, 3/cyan
+200       }
+201       compare state, 0/false
+202       {
+203         break-if-!=
+204         render-square x, y, 0/black
+205       }
+206       x <- increment
+207       loop
+208     }
+209     y <- increment
+210     loop
+211   }
+212 }
+213 
+214 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+215 #?   # allocate on the stack
+216 #?   var grid1-storage: (array boolean 0xc000)  # width * height
+217 #?   var grid1/esi: (addr array boolean) <- address grid1-storage
+218 #?   var grid2-storage: (array boolean 0xc000)  # width * height
+219 #?   var grid2/edi: (addr array boolean) <- address grid2-storage
+220   # allocate on the heap
+221   var grid1-storage: (handle array boolean)
+222   var grid1-ah/eax: (addr handle array boolean) <- address grid1-storage
+223   populate grid1-ah, 0xc000  # width * height
+224   var _grid1/eax: (addr array boolean) <- lookup *grid1-ah
+225   var grid1/esi: (addr array boolean) <- copy _grid1
+226   var grid2-storage: (handle array boolean)
+227   var grid2-ah/eax: (addr handle array boolean) <- address grid2-storage
+228   populate grid2-ah, 0xc000  # width * height
+229   var _grid2/eax: (addr array boolean) <- lookup *grid2-ah
+230   var grid2/edi: (addr array boolean) <- copy _grid2
+231   # initialize grid1
+232   set-state grid1, 0x80, 0x5f, 1/live
+233   set-state grid1, 0x81, 0x5f, 1/live
+234   set-state grid1, 0x7f, 0x60, 1/live
+235   set-state grid1, 0x80, 0x60, 1/live
+236   set-state grid1, 0x80, 0x61, 1/live
+237   # render grid1
+238   render grid1
+239   {
+240     var key/eax: byte <- read-key keyboard
+241     compare key, 0
+242 #?     loop-if-=  # press key to step
+243     break-if-!=  # press key to quit  # comment this out to run under bochs; I'm not sure why there's a newline in the keyboard buffer
+244     # iter: grid1 -> grid2
+245     step grid1, grid2
+246     render grid2
+247     # iter: grid2 -> grid1
+248     step grid2, grid1
+249     render grid1
+250     loop
+251   }
+252 }
+
+ + + diff --git a/html/apps/mandelbrot-fixed.mu.html b/html/apps/mandelbrot-fixed.mu.html new file mode 100644 index 00000000..24f7ddc7 --- /dev/null +++ b/html/apps/mandelbrot-fixed.mu.html @@ -0,0 +1,330 @@ + + + + +Mu - apps/mandelbrot-fixed.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/mandelbrot-fixed.mu +
+  1 # Mandelbrot set using fixed-point numbers.
+  2 #
+  3 # Install:
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 # Build on Linux:
+  7 #   $ ./translate apps/mandelbrot-fixed.mu
+  8 # Build on other platforms (slow):
+  9 #   $ ./translate_emulated apps/mandelbrot-fixed.mu
+ 10 # Run:
+ 11 #   $ qemu-system-i386 code.img
+ 12 
+ 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+ 14   # Initially the viewport is centered at 0, 0 in the scene.
+ 15   var scene-cx-f: int
+ 16   var scene-cy-f: int
+ 17   # Initially the viewport shows a section of the scene 4 units wide.
+ 18   var scene-width-f: int
+ 19   copy-to scene-width-f, 0x400/4
+ 20   {
+ 21     mandelbrot screen scene-cx-f, scene-cy-f, scene-width-f
+ 22     # move at an angle slowly towards the edge
+ 23     var adj-f/eax: int <- multiply-fixed scene-width-f, 0x12/0.07
+ 24     subtract-from scene-cx-f, adj-f
+ 25     add-to scene-cy-f, adj-f
+ 26     # slowly shrink the scene width to zoom in
+ 27     var tmp-f/eax: int <- multiply-fixed scene-width-f, 0x80/0.5
+ 28     copy-to scene-width-f, tmp-f
+ 29     loop
+ 30   }
+ 31 }
+ 32 
+ 33 # Since they still look like int types, we'll append a '-f' suffix to variable
+ 34 # names to designate fixed-point numbers.
+ 35 
+ 36 fn int-to-fixed in: int -> _/eax: int {
+ 37   var result-f/eax: int <- copy in
+ 38   result-f <- shift-left 8/fixed-precision
+ 39   {
+ 40     break-if-not-overflow
+ 41     abort "int-to-fixed: overflow"
+ 42   }
+ 43   return result-f
+ 44 }
+ 45 
+ 46 fn fixed-to-int in-f: int -> _/eax: int {
+ 47   var result/eax: int <- copy in-f
+ 48   result <- shift-right-signed 8/fixed-precision
+ 49   return result
+ 50 }
+ 51 
+ 52 # The process of throwing bits away always adjusts a number towards -infinity.
+ 53 fn test-fixed-conversion {
+ 54   # 0
+ 55   var f/eax: int <- int-to-fixed 0
+ 56   var result/eax: int <- fixed-to-int f
+ 57   check-ints-equal result, 0, "F - test-fixed-conversion - 0"
+ 58   # 1
+ 59   var f/eax: int <- int-to-fixed 1
+ 60   var result/eax: int <- fixed-to-int f
+ 61   check-ints-equal result, 1, "F - test-fixed-conversion - 1"
+ 62   # -1
+ 63   var f/eax: int <- int-to-fixed -1
+ 64   var result/eax: int <- fixed-to-int f
+ 65   check-ints-equal result, -1, "F - test-fixed-conversion - -1"
+ 66   # 0.5 = 1/2
+ 67   var f/eax: int <- int-to-fixed 1
+ 68   f <- shift-right-signed 1
+ 69   var result/eax: int <- fixed-to-int f
+ 70   check-ints-equal result, 0, "F - test-fixed-conversion - 0.5"
+ 71   # -0.5 = -1/2
+ 72   var f/eax: int <- int-to-fixed -1
+ 73   f <- shift-right-signed 1
+ 74   var result/eax: int <- fixed-to-int f
+ 75   check-ints-equal result, -1, "F - test-fixed-conversion - -0.5"
+ 76   # 1.5 = 3/2
+ 77   var f/eax: int <- int-to-fixed 3
+ 78   f <- shift-right-signed 1
+ 79   var result/eax: int <- fixed-to-int f
+ 80   check-ints-equal result, 1, "F - test-fixed-conversion - 1.5"
+ 81   # -1.5 = -3/2
+ 82   var f/eax: int <- int-to-fixed -3
+ 83   f <- shift-right-signed 1
+ 84   var result/eax: int <- fixed-to-int f
+ 85   check-ints-equal result, -2, "F - test-fixed-conversion - -1.5"
+ 86   # 1.25 = 5/4
+ 87   var f/eax: int <- int-to-fixed 5
+ 88   f <- shift-right-signed 2
+ 89   var result/eax: int <- fixed-to-int f
+ 90   check-ints-equal result, 1, "F - test-fixed-conversion - 1.25"
+ 91   # -1.25 = -5/4
+ 92   var f/eax: int <- int-to-fixed -5
+ 93   f <- shift-right-signed 2
+ 94   var result/eax: int <- fixed-to-int f
+ 95   check-ints-equal result, -2, "F - test-fixed-conversion - -1.25"
+ 96 }
+ 97 
+ 98 # special routines for multiplying and dividing fixed-point numbers
+ 99 
+100 fn multiply-fixed a-f: int, b-f: int -> _/eax: int {
+101   var result/eax: int <- copy a-f
+102   result <- multiply b-f
+103   {
+104     break-if-not-overflow
+105     abort "multiply-fixed: overflow"
+106   }
+107   result <- shift-right-signed 8/fixed-precision
+108   return result
+109 }
+110 
+111 fn divide-fixed a-f: int, b-f: int -> _/eax: int {
+112   var result-f/eax: int <- copy a-f
+113   result-f <- shift-left 8/fixed-precision
+114   {
+115     break-if-not-overflow
+116     abort "divide-fixed: overflow"
+117   }
+118   var dummy-remainder/edx: int <- copy 0
+119   result-f, dummy-remainder <- integer-divide result-f, b-f
+120   return result-f
+121 }
+122 
+123 # multiplying or dividing by an integer can use existing instructions.
+124 
+125 # adding and subtracting two fixed-point numbers can use existing instructions.
+126 
+127 fn mandelbrot screen: (addr screen), scene-cx-f: int, scene-cy-f: int, scene-width-f: int {
+128   var a/eax: int <- copy 0
+129   var b/ecx: int <- copy 0
+130   a, b <- screen-size screen
+131   var width/esi: int <- copy a
+132   width <- shift-left 3/log2-font-width
+133   var height/edi: int <- copy b
+134   height <- shift-left 4/log2-font-height
+135   var y/ecx: int <- copy 0
+136   {
+137     compare y, height
+138     break-if->=
+139     var imaginary-f/ebx: int <- viewport-to-imaginary-f y, width, height, scene-cy-f, scene-width-f
+140     var x/eax: int <- copy 0
+141     {
+142       compare x, width
+143       break-if->=
+144       var real-f/edx: int <- viewport-to-real-f x, width, scene-cx-f, scene-width-f
+145       var iterations/esi: int <- mandelbrot-iterations-for-point real-f, imaginary-f, 0x400/max
+146       iterations <- shift-right 3
+147       var color/edx: int <- copy 0
+148       {
+149         var dummy/eax: int <- copy 0
+150         dummy, color <- integer-divide iterations, 0x18/24/size-of-cycle-0
+151         color <- add 0x20/cycle-0
+152       }
+153       pixel screen, x, y, color
+154       x <- increment
+155       loop
+156     }
+157     y <- increment
+158     loop
+159   }
+160 }
+161 
+162 fn mandelbrot-iterations-for-point real-f: int, imaginary-f: int, max: int -> _/esi: int {
+163   var x-f/esi: int <- copy 0
+164   var y-f/edi: int <- copy 0
+165   var iterations/ecx: int <- copy 0
+166   {
+167     var done?/eax: boolean <- mandelbrot-done? x-f, y-f
+168     compare done?, 0/false
+169     break-if-!=
+170     compare iterations, max
+171     break-if->=
+172     var x2-f/edx: int <- mandelbrot-x x-f, y-f, real-f
+173     var y2-f/ebx: int <- mandelbrot-y x-f, y-f, imaginary-f
+174     x-f <- copy x2-f
+175     y-f <- copy y2-f
+176     iterations <- increment
+177     loop
+178   }
+179   return iterations
+180 }
+181 
+182 fn mandelbrot-done? x-f: int, y-f: int -> _/eax: boolean {
+183   # x*x + y*y > 4
+184   var tmp-f/eax: int <- multiply-fixed x-f, x-f
+185   var result-f/ecx: int <- copy tmp-f
+186   tmp-f <- multiply-fixed y-f, y-f
+187   result-f <- add tmp-f
+188   compare result-f, 0x400/4
+189   {
+190     break-if->
+191     return 0/false
+192   }
+193   return 1/true
+194 }
+195 
+196 fn mandelbrot-x x-f: int, y-f: int, real-f: int -> _/edx: int {
+197   # x*x - y*y + real
+198   var tmp-f/eax: int <- multiply-fixed x-f, x-f
+199   var result-f/ecx: int <- copy tmp-f
+200   tmp-f <- multiply-fixed y-f, y-f
+201   result-f <- subtract tmp-f
+202   result-f <- add real-f
+203   return result-f
+204 }
+205 
+206 fn mandelbrot-y x-f: int, y-f: int, imaginary-f: int -> _/ebx: int {
+207   # 2*x*y + imaginary
+208   var result-f/eax: int <- copy x-f
+209   result-f <- shift-left 1/log2
+210   result-f <- multiply-fixed result-f, y-f
+211   result-f <- add imaginary-f
+212   return result-f
+213 }
+214 
+215 # Scale (x, y) pixel coordinates to a complex plane where the viewport width
+216 # ranges from -2 to +2. Viewport height just follows the viewport's aspect
+217 # ratio.
+218 
+219 fn viewport-to-real-f x: int, width: int, scene-cx-f: int, scene-width-f: int -> _/edx: int {
+220   # 0 in the viewport       goes to scene-cx - scene-width/2 
+221   # width in the viewport   goes to scene-cx + scene-width/2
+222   # Therefore:
+223   # x in the viewport       goes to (scene-cx - scene-width/2) + x*scene-width/width
+224   # At most two numbers being multiplied before a divide, so no risk of overflow.
+225   var result-f/eax: int <- int-to-fixed x
+226   result-f <- multiply-fixed result-f, scene-width-f
+227   var width-f/ecx: int <- copy width
+228   width-f <- shift-left 8/fixed-precision
+229   result-f <- divide-fixed result-f, width-f
+230   result-f <- add scene-cx-f
+231   var half-scene-width-f/ecx: int <- copy scene-width-f
+232   half-scene-width-f <- shift-right 1
+233   result-f <- subtract half-scene-width-f
+234   return result-f
+235 }
+236 
+237 fn viewport-to-imaginary-f y: int, width: int, height: int, scene-cy-f: int, scene-width-f: int -> _/ebx: int {
+238   # 0 in the viewport       goes to scene-cy - scene-width/2*height/width
+239   # height in the viewport  goes to scene-cy + scene-width/2*height/width
+240   # Therefore:
+241   # y in the viewport       goes to (scene-cy - scene-width/2*height/width) + y*scene-width/width
+242   #  scene-cy - scene-width/width * (height/2 + y)
+243   # At most two numbers being multiplied before a divide, so no risk of overflow.
+244   var result-f/eax: int <- int-to-fixed y
+245   result-f <- multiply-fixed result-f, scene-width-f
+246   var width-f/ecx: int <- copy width
+247   width-f <- shift-left 8/fixed-precision
+248   result-f <- divide-fixed result-f, width-f
+249   result-f <- add scene-cy-f
+250   var second-term-f/edx: int <- copy 0
+251   {
+252     var _second-term-f/eax: int <- copy scene-width-f
+253     _second-term-f <- shift-right 1
+254     var height-f/ebx: int <- copy height
+255     height-f <- shift-left 8/fixed-precision
+256     _second-term-f <- multiply-fixed _second-term-f, height-f
+257     _second-term-f <- divide-fixed _second-term-f, width-f
+258     second-term-f <- copy _second-term-f
+259   }
+260   result-f <- subtract second-term-f
+261   return result-f
+262 }
+
+ + + diff --git a/html/apps/mandelbrot-silhouette.mu.html b/html/apps/mandelbrot-silhouette.mu.html new file mode 100644 index 00000000..867d96b7 --- /dev/null +++ b/html/apps/mandelbrot-silhouette.mu.html @@ -0,0 +1,216 @@ + + + + +Mu - apps/mandelbrot-silhouette.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/mandelbrot-silhouette.mu +
+  1 # Mandelbrot set
+  2 #
+  3 # Install:
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 # Build on Linux:
+  7 #   $ ./translate apps/mandelbrot.mu
+  8 # Build on other platforms (slow):
+  9 #   $ ./translate_emulated apps/mandelbrot.mu
+ 10 # Run:
+ 11 #   $ qemu-system-i386 code.img
+ 12 
+ 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+ 14   mandelbrot screen
+ 15 }
+ 16 
+ 17 fn mandelbrot screen: (addr screen) {
+ 18   var a/eax: int <- copy 0
+ 19   var b/ecx: int <- copy 0
+ 20   a, b <- screen-size screen
+ 21   var width/esi: int <- copy a
+ 22   width <- shift-left 3/log2-font-width
+ 23   var height/edi: int <- copy b
+ 24   height <- shift-left 4/log2-font-height
+ 25   var y/ecx: int <- copy 0
+ 26   {
+ 27     compare y, height
+ 28     break-if->=
+ 29     var imaginary/xmm1: float <- viewport-to-imaginary y, width, height
+ 30     var x/edx: int <- copy 0
+ 31     {
+ 32       compare x, width
+ 33       break-if->=
+ 34       var real/xmm0: float <- viewport-to-real x, width
+ 35       var iterations/eax: int <- mandelbrot-iterations-for-point real, imaginary, 0x400/max
+ 36       compare iterations, 0x400/max
+ 37       {
+ 38         break-if->=
+ 39         pixel screen, x, y, 0xf/white
+ 40       }
+ 41       compare iterations, 0x400/max
+ 42       {
+ 43         break-if-<
+ 44         pixel screen, x, y, 0/black
+ 45       }
+ 46       x <- increment
+ 47       loop
+ 48     }
+ 49     y <- increment
+ 50     loop
+ 51   }
+ 52 }
+ 53 
+ 54 fn mandelbrot-iterations-for-point real: float, imaginary: float, max: int -> _/eax: int {
+ 55   var zero: float
+ 56   var x/xmm0: float <- copy zero
+ 57   var y/xmm1: float <- copy zero
+ 58   var iterations/ecx: int <- copy 0
+ 59   {
+ 60     var done?/eax: boolean <- mandelbrot-done? x, y
+ 61     compare done?, 0/false
+ 62     break-if-!=
+ 63     compare iterations, max
+ 64     break-if->=
+ 65     var newx/xmm2: float <- mandelbrot-x x, y, real
+ 66     var newy/xmm3: float <- mandelbrot-y x, y, imaginary
+ 67     x <- copy newx
+ 68     y <- copy newy
+ 69     iterations <- increment
+ 70     loop
+ 71   }
+ 72   return iterations
+ 73 }
+ 74 
+ 75 fn mandelbrot-done? x: float, y: float -> _/eax: boolean {
+ 76   # x*x + y*y > 4
+ 77   var x2/xmm0: float <- copy x
+ 78   x2 <- multiply x
+ 79   var y2/xmm1: float <- copy y
+ 80   y2 <- multiply y
+ 81   var sum/xmm0: float <- copy x2
+ 82   sum <- add y2
+ 83   var four/eax: int <- copy 4
+ 84   var four-f/xmm1: float <- convert four
+ 85   compare sum, four-f
+ 86   {
+ 87     break-if-float>
+ 88     return 0/false
+ 89   }
+ 90   return 1/true
+ 91 }
+ 92 
+ 93 fn mandelbrot-x x: float, y: float, real: float -> _/xmm2: float {
+ 94   # x*x - y*y + real
+ 95   var x2/xmm0: float <- copy x
+ 96   x2 <- multiply x
+ 97   var y2/xmm1: float <- copy y
+ 98   y2 <- multiply y
+ 99   var result/xmm0: float <- copy x2
+100   result <- subtract y2
+101   result <- add real
+102   return result
+103 }
+104 
+105 fn mandelbrot-y x: float, y: float, imaginary: float -> _/xmm3: float {
+106   # 2*x*y + imaginary
+107   var two/eax: int <- copy 2
+108   var result/xmm0: float <- convert two
+109   result <- multiply x
+110   result <- multiply y
+111   result <- add imaginary
+112   return result
+113 }
+114 
+115 # Scale (x, y) pixel coordinates to a complex plane where the viewport width
+116 # ranges from -2 to +2. Viewport height just follows the viewport's aspect
+117 # ratio.
+118 
+119 fn viewport-to-real x: int, width: int -> _/xmm0: float {
+120   # (x - width/2)*4/width
+121   var result/xmm0: float <- convert x
+122   var width-f/xmm1: float <- convert width
+123   var two/eax: int <- copy 2
+124   var two-f/xmm2: float <- convert two
+125   var half-width-f/xmm2: float <- reciprocal two-f
+126   half-width-f <- multiply width-f
+127   result <- subtract half-width-f
+128   var four/eax: int <- copy 4
+129   var four-f/xmm2: float <- convert four
+130   result <- multiply four-f
+131   result <- divide width-f
+132   return result
+133 }
+134 
+135 fn viewport-to-imaginary y: int, width: int, height: int -> _/xmm1: float {
+136   # (y - height/2)*4/width
+137   var result/xmm0: float <- convert y
+138   var height-f/xmm1: float <- convert height
+139   var half-height-f/xmm1: float <- copy height-f
+140   var two/eax: int <- copy 2
+141   var two-f/xmm2: float <- convert two
+142   half-height-f <- divide two-f
+143   result <- subtract half-height-f
+144   var four/eax: int <- copy 4
+145   var four-f/xmm1: float <- convert four
+146   result <- multiply four-f
+147   var width-f/xmm1: float <- convert width
+148   result <- divide width-f
+149   return result
+150 }
+
+ + + diff --git a/html/apps/mandelbrot.mu.html b/html/apps/mandelbrot.mu.html new file mode 100644 index 00000000..4f25d91b --- /dev/null +++ b/html/apps/mandelbrot.mu.html @@ -0,0 +1,246 @@ + + + + +Mu - apps/mandelbrot.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/mandelbrot.mu +
+  1 # Mandelbrot set
+  2 #
+  3 # Install:
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 # Build on Linux:
+  7 #   $ ./translate apps/mandelbrot.mu
+  8 # Build on other platforms (slow):
+  9 #   $ ./translate_emulated apps/mandelbrot.mu
+ 10 # Run:
+ 11 #   $ qemu-system-i386 code.img
+ 12 
+ 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+ 14   # Initially the viewport is centered at 0, 0 in the scene.
+ 15   var zero: float
+ 16   var scene-cx/xmm1: float <- copy zero
+ 17   var scene-cy/xmm2: float <- copy zero
+ 18   # Initially the viewport shows a section of the scene 4 units wide.
+ 19   # scene-width-scale = 0.5
+ 20   var scene-width-scale: float
+ 21   var dest/eax: (addr float) <- address scene-width-scale
+ 22   fill-in-rational dest, 1, 2
+ 23   # scene-width = 4
+ 24   var four: float
+ 25   var dest/eax: (addr float) <- address four
+ 26   fill-in-rational dest, 4, 1
+ 27   var scene-width/xmm3: float <- copy four
+ 28   {
+ 29     mandelbrot screen scene-cx, scene-cy, scene-width
+ 30     # move the center some % of the current screen-width
+ 31     var adj/xmm0: float <- rational 2, 0x1c/28
+ 32     adj <- multiply scene-width
+ 33     scene-cx <- subtract adj
+ 34     scene-cy <- add adj
+ 35     # slowly shrink the scene width to zoom in
+ 36     scene-width <- multiply scene-width-scale
+ 37     loop
+ 38   }
+ 39 }
+ 40 
+ 41 fn mandelbrot screen: (addr screen), scene-cx: float, scene-cy: float, scene-width: float {
+ 42   var a/eax: int <- copy 0
+ 43   var b/ecx: int <- copy 0
+ 44   a, b <- screen-size screen
+ 45   var width/esi: int <- copy a
+ 46   width <- shift-left 3/log2-font-width
+ 47   var height/edi: int <- copy b
+ 48   height <- shift-left 4/log2-font-height
+ 49   var y/ecx: int <- copy 0
+ 50   {
+ 51     compare y, height
+ 52     break-if->=
+ 53     var imaginary/xmm1: float <- viewport-to-imaginary y, width, height, scene-cy, scene-width
+ 54     var x/ebx: int <- copy 0
+ 55     {
+ 56       compare x, width
+ 57       break-if->=
+ 58       var real/xmm0: float <- viewport-to-real x, width, scene-cx, scene-width
+ 59       var iterations/eax: int <- mandelbrot-iterations-for-point real, imaginary, 0x400/max
+ 60       iterations <- shift-right 3
+ 61       var color/edx: int <- copy 0
+ 62       iterations, color <- integer-divide iterations, 0x18/24/size-of-cycle-0
+ 63       color <- add 0x20/cycle-0
+ 64       pixel screen, x, y, color
+ 65       x <- increment
+ 66       loop
+ 67     }
+ 68     y <- increment
+ 69     loop
+ 70   }
+ 71 }
+ 72 
+ 73 fn mandelbrot-iterations-for-point real: float, imaginary: float, max: int -> _/eax: int {
+ 74   var zero: float
+ 75   var x/xmm0: float <- copy zero
+ 76   var y/xmm1: float <- copy zero
+ 77   var iterations/ecx: int <- copy 0
+ 78   {
+ 79     var done?/eax: boolean <- mandelbrot-done? x, y
+ 80     compare done?, 0/false
+ 81     break-if-!=
+ 82     compare iterations, max
+ 83     break-if->=
+ 84     var newx/xmm2: float <- mandelbrot-x x, y, real
+ 85     var newy/xmm3: float <- mandelbrot-y x, y, imaginary
+ 86     x <- copy newx
+ 87     y <- copy newy
+ 88     iterations <- increment
+ 89     loop
+ 90   }
+ 91   return iterations
+ 92 }
+ 93 
+ 94 fn mandelbrot-done? x: float, y: float -> _/eax: boolean {
+ 95   # x*x + y*y > 4
+ 96   var x2/xmm0: float <- copy x
+ 97   x2 <- multiply x
+ 98   var y2/xmm1: float <- copy y
+ 99   y2 <- multiply y
+100   var sum/xmm0: float <- copy x2
+101   sum <- add y2
+102   var four/eax: int <- copy 4
+103   var four-f/xmm1: float <- convert four
+104   compare sum, four-f
+105   {
+106     break-if-float>
+107     return 0/false
+108   }
+109   return 1/true
+110 }
+111 
+112 fn mandelbrot-x x: float, y: float, real: float -> _/xmm2: float {
+113   # x*x - y*y + real
+114   var x2/xmm0: float <- copy x
+115   x2 <- multiply x
+116   var y2/xmm1: float <- copy y
+117   y2 <- multiply y
+118   var result/xmm0: float <- copy x2
+119   result <- subtract y2
+120   result <- add real
+121   return result
+122 }
+123 
+124 fn mandelbrot-y x: float, y: float, imaginary: float -> _/xmm3: float {
+125   # 2*x*y + imaginary
+126   var two/eax: int <- copy 2
+127   var result/xmm0: float <- convert two
+128   result <- multiply x
+129   result <- multiply y
+130   result <- add imaginary
+131   return result
+132 }
+133 
+134 # Scale (x, y) pixel coordinates to a complex plane where the viewport width
+135 # ranges from -2 to +2. Viewport height just follows the viewport's aspect
+136 # ratio.
+137 
+138 fn viewport-to-real x: int, width: int, scene-cx: float, scene-width: float -> _/xmm0: float {
+139   # 0 in the viewport       goes to scene-cx - scene-width/2 
+140   # width in the viewport   goes to scene-cx + scene-width/2
+141   # Therefore:
+142   # x in the viewport       goes to (scene-cx - scene-width/2) + x*scene-width/width
+143   # At most two numbers being multiplied before a divide, so no risk of overflow.
+144   var result/xmm0: float <- convert x
+145   result <- multiply scene-width
+146   var width-f/xmm1: float <- convert width
+147   result <- divide width-f
+148   result <- add scene-cx
+149   var two/eax: int <- copy 2
+150   var two-f/xmm2: float <- convert two
+151   var half-scene-width/xmm1: float <- copy scene-width
+152   half-scene-width <- divide two-f
+153   result <- subtract half-scene-width
+154   return result
+155 }
+156 
+157 fn viewport-to-imaginary y: int, width: int, height: int, scene-cy: float, scene-width: float -> _/xmm1: float {
+158   # 0 in the viewport       goes to scene-cy - scene-width/2*height/width
+159   # height in the viewport  goes to scene-cy + scene-width/2*height/width
+160   # Therefore:
+161   # y in the viewport       goes to (scene-cy - scene-width/2*height/width) + y*scene-width/width
+162   #  scene-cy - scene-width/width * (height/2 + y)
+163   # At most two numbers being multiplied before a divide, so no risk of overflow.
+164   var result/xmm0: float <- convert y
+165   result <- multiply scene-width
+166   var width-f/xmm1: float <- convert width
+167   result <- divide width-f
+168   result <- add scene-cy
+169   var two/eax: int <- copy 2
+170   var two-f/xmm2: float <- convert two
+171   var second-term/xmm1: float <- copy scene-width
+172   second-term <- divide two-f
+173   var height-f/xmm2: float <- convert height
+174   second-term <- multiply height-f
+175   var width-f/xmm2: float <- convert width
+176   second-term <- divide width-f
+177   result <- subtract second-term
+178   return result
+179 }
+
+ + + diff --git a/html/apps/rpn.mu.html b/html/apps/rpn.mu.html new file mode 100644 index 00000000..a81eb74e --- /dev/null +++ b/html/apps/rpn.mu.html @@ -0,0 +1,217 @@ + + + + +Mu - apps/rpn.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/apps/rpn.mu +
+  1 # Integer arithmetic using postfix notation
+  2 #
+  3 # Limitations:
+  4 #   Division not implemented yet.
+  5 #
+  6 # To build:
+  7 #   $ ./translate apps/rpn.mu
+  8 #
+  9 # Example session:
+ 10 #   $ qemu-system-i386 code.img
+ 11 #   > 4
+ 12 #   4
+ 13 #   > 5 3 -
+ 14 #   2
+ 15 #
+ 16 # Error handling is non-existent. This is just a prototype.
+ 17 
+ 18 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+ 19   var in-storage: (stream byte 0x80)
+ 20   var in/esi: (addr stream byte) <- address in-storage
+ 21   var y/ecx: int <- copy 0
+ 22   var space/edx: grapheme <- copy 0x20
+ 23   # read-eval-print loop
+ 24   {
+ 25     # print prompt
+ 26     var x/eax: int <- draw-text-rightward screen, "> ", 0/x, 0x80/xmax, y, 3/fg/cyan, 0/bg
+ 27     # read line from keyboard
+ 28     clear-stream in
+ 29     {
+ 30       draw-cursor screen, space
+ 31       var key/eax: byte <- read-key keyboard
+ 32       compare key, 0xa/newline
+ 33       break-if-=
+ 34       compare key, 0
+ 35       loop-if-=
+ 36       var key2/eax: int <- copy key
+ 37       append-byte in, key2
+ 38       var g/eax: grapheme <- copy key2
+ 39       draw-grapheme-at-cursor screen, g, 0xf/fg, 0/bg
+ 40       move-cursor-right 0
+ 41       loop
+ 42     }
+ 43     # clear cursor
+ 44     draw-grapheme-at-cursor screen, space, 3/fg/never-used, 0/bg
+ 45     # parse and eval
+ 46     var out/eax: int <- simplify in
+ 47     # print
+ 48     y <- increment
+ 49     out, y <- draw-int32-decimal-wrapping-right-then-down screen, out, 0/xmin, y, 0x80/xmax, 0x30/ymax, 0/x, y, 7/fg, 0/bg
+ 50     # newline
+ 51     y <- increment
+ 52     #
+ 53     loop
+ 54   }
+ 55 }
+ 56 
+ 57 type int-stack {
+ 58   data: (handle array int)
+ 59   top: int
+ 60 }
+ 61 
+ 62 fn simplify in: (addr stream byte) -> _/eax: int {
+ 63   var word-storage: slice
+ 64   var word/ecx: (addr slice) <- address word-storage
+ 65   var stack-storage: int-stack
+ 66   var stack/esi: (addr int-stack) <- address stack-storage
+ 67   initialize-int-stack stack, 0x10
+ 68   $simplify:word-loop: {
+ 69     next-word in, word
+ 70     var done?/eax: boolean <- slice-empty? word
+ 71     compare done?, 0
+ 72     break-if-!=
+ 73     # if word is an operator, perform it
+ 74     {
+ 75       var is-add?/eax: boolean <- slice-equal? word, "+"
+ 76       compare is-add?, 0
+ 77       break-if-=
+ 78       var _b/eax: int <- pop-int-stack stack
+ 79       var b/edx: int <- copy _b
+ 80       var a/eax: int <- pop-int-stack stack
+ 81       a <- add b
+ 82       push-int-stack stack, a
+ 83       loop $simplify:word-loop
+ 84     }
+ 85     {
+ 86       var is-sub?/eax: boolean <- slice-equal? word, "-"
+ 87       compare is-sub?, 0
+ 88       break-if-=
+ 89       var _b/eax: int <- pop-int-stack stack
+ 90       var b/edx: int <- copy _b
+ 91       var a/eax: int <- pop-int-stack stack
+ 92       a <- subtract b
+ 93       push-int-stack stack, a
+ 94       loop $simplify:word-loop
+ 95     }
+ 96     {
+ 97       var is-mul?/eax: boolean <- slice-equal? word, "*"
+ 98       compare is-mul?, 0
+ 99       break-if-=
+100       var _b/eax: int <- pop-int-stack stack
+101       var b/edx: int <- copy _b
+102       var a/eax: int <- pop-int-stack stack
+103       a <- multiply b
+104       push-int-stack stack, a
+105       loop $simplify:word-loop
+106     }
+107     # otherwise it's an int
+108     var n/eax: int <- parse-decimal-int-from-slice word
+109     push-int-stack stack, n
+110     loop
+111   }
+112   var result/eax: int <- pop-int-stack stack
+113   return result
+114 }
+115 
+116 fn initialize-int-stack _self: (addr int-stack), n: int {
+117   var self/esi: (addr int-stack) <- copy _self
+118   var d/edi: (addr handle array int) <- get self, data
+119   populate d, n
+120   var top/eax: (addr int) <- get self, top
+121   copy-to *top, 0
+122 }
+123 
+124 fn push-int-stack _self: (addr int-stack), _val: int {
+125   var self/esi: (addr int-stack) <- copy _self
+126   var top-addr/ecx: (addr int) <- get self, top
+127   var data-ah/edx: (addr handle array int) <- get self, data
+128   var data/eax: (addr array int) <- lookup *data-ah
+129   var top/edx: int <- copy *top-addr
+130   var dest-addr/edx: (addr int) <- index data, top
+131   var val/eax: int <- copy _val
+132   copy-to *dest-addr, val
+133   add-to *top-addr, 1
+134 }
+135 
+136 fn pop-int-stack _self: (addr int-stack) -> _/eax: int {
+137   var self/esi: (addr int-stack) <- copy _self
+138   var top-addr/ecx: (addr int) <- get self, top
+139   {
+140     compare *top-addr, 0
+141     break-if->
+142     return 0
+143   }
+144   subtract-from *top-addr, 1
+145   var data-ah/edx: (addr handle array int) <- get self, data
+146   var data/eax: (addr array int) <- lookup *data-ah
+147   var top/edx: int <- copy *top-addr
+148   var result-addr/eax: (addr int) <- index data, top
+149   var val/eax: int <- copy *result-addr
+150   return val
+151 }
+
+ + + diff --git a/html/boot.subx.html b/html/boot.subx.html index 5716fe64..2244181e 100644 --- a/html/boot.subx.html +++ b/html/boot.subx.html @@ -1,23 +1,23 @@ - + - + Mu - boot.subx - - + + - + - - - - -https://github.com/akkartik/mu/blob/main/colors.mu -
-  1 # Return colors 'near' a given r/g/b value (expressed in hex)
-  2 # If we did this rigorously we'd need to implement cosines. So we won't.
-  3 #
-  4 # To build:
-  5 #   $ ./translate colors.mu
-  6 #
-  7 # Example session:
-  8 #   $ qemu-system-i386 code.img
-  9 #   Enter 3 hex bytes for r, g, b (lowercase; no 0x prefix) separated by a single space> aa 0 aa
- 10 #   5
- 11 # This means only color 5 in the default palette is similar to #aa00aa.
- 12 
- 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
- 14   var in-storage: (stream byte 0x10)
- 15   var in/esi: (addr stream byte) <- address in-storage
- 16   {
- 17     # print prompt
- 18     var x/eax: int <- draw-text-rightward screen, "Enter 3 hex bytes for r, g, b (lowercase; no 0x prefix) separated by a single space> ", 0x10/x, 0x80/xmax, 0x28/y, 3/fg/cyan, 0/bg
- 19     # read line from keyboard
- 20     clear-stream in
- 21     {
- 22       draw-cursor screen, 0x20/space
- 23       var key/eax: byte <- read-key keyboard
- 24       compare key, 0xa/newline
- 25       break-if-=
- 26       compare key, 0
- 27       loop-if-=
- 28       var key2/eax: int <- copy key
- 29       append-byte in, key2
- 30       var g/eax: grapheme <- copy key2
- 31       draw-grapheme-at-cursor screen, g, 0xf/fg, 0/bg
- 32       move-cursor-right 0
- 33       loop
- 34     }
- 35     clear-screen screen
- 36     # parse
- 37     var a/ecx: int <- copy 0
- 38     var b/edx: int <- copy 0
- 39     var c/ebx: int <- copy 0
- 40     # a, b, c = r, g, b
- 41     a, b, c <- parse in
- 42 #?     set-cursor-position screen, 0x10/x, 0x1a/y
- 43 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
- 44 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
- 45 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
- 46 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
- 47 #?     draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
- 48     a, b, c <- hsl a, b, c
- 49     # return all colors in the same quadrant in h, s and l
- 50     print-nearby-colors screen, a, b, c
- 51     #
- 52     loop
- 53   }
- 54 }
- 55 
- 56 # read exactly 3 words in a single line
- 57 # Each word consists of exactly 1 or 2 hex bytes. No hex prefix.
- 58 fn parse in: (addr stream byte) -> _/ecx: int, _/edx: int, _/ebx: int {
- 59   # read first byte of r
- 60   var tmp/eax: byte <- read-byte in
- 61   {
- 62     var valid?/eax: boolean <- hex-digit? tmp
- 63     compare valid?, 0/false
- 64     break-if-!=
- 65     abort "invalid byte 0 of r"
- 66   }
- 67   tmp <- fast-hex-digit-value tmp
- 68   var r/ecx: int <- copy tmp
- 69 #?   set-cursor-position 0/screen, 0x10/x, 0x10/y
- 70 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
- 71   # read second byte of r
- 72   tmp <- read-byte in
- 73   {
- 74     {
- 75       var valid?/eax: boolean <- hex-digit? tmp
- 76       compare valid?, 0/false
- 77     }
- 78     break-if-=
- 79     r <- shift-left 4
- 80     tmp <- fast-hex-digit-value tmp
- 81 #?     {
- 82 #?       var foo/eax: int <- copy tmp
- 83 #?       set-cursor-position 0/screen, 0x10/x, 0x11/y
- 84 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
- 85 #?     }
- 86     r <- add tmp
- 87 #?     {
- 88 #?       set-cursor-position 0/screen, 0x10/x, 0x12/y
- 89 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, r, 7/fg, 0/bg
- 90 #?     }
- 91     tmp <- read-byte in  # skip space
- 92   }
- 93   # read first byte of g
- 94   var tmp/eax: byte <- read-byte in
- 95   {
- 96     var valid?/eax: boolean <- hex-digit? tmp
- 97     compare valid?, 0/false
- 98     break-if-!=
- 99     abort "invalid byte 0 of g"
-100   }
-101   tmp <- fast-hex-digit-value tmp
-102   var g/edx: int <- copy tmp
-103 #?   set-cursor-position 0/screen, 0x10/x, 0x13/y
-104 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
-105   # read second byte of g
-106   tmp <- read-byte in
-107   {
-108     {
-109       var valid?/eax: boolean <- hex-digit? tmp
-110       compare valid?, 0/false
-111     }
-112     break-if-=
-113     g <- shift-left 4
-114     tmp <- fast-hex-digit-value tmp
-115 #?     {
-116 #?       var foo/eax: int <- copy tmp
-117 #?       set-cursor-position 0/screen, 0x10/x, 0x14/y
-118 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
-119 #?     }
-120     g <- add tmp
-121 #?     {
-122 #?       set-cursor-position 0/screen, 0x10/x, 0x15/y
-123 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, g, 7/fg, 0/bg
-124 #?     }
-125     tmp <- read-byte in  # skip space
-126   }
-127   # read first byte of b
-128   var tmp/eax: byte <- read-byte in
-129   {
-130     var valid?/eax: boolean <- hex-digit? tmp
-131     compare valid?, 0/false
-132     break-if-!=
-133     abort "invalid byte 0 of b"
-134   }
-135   tmp <- fast-hex-digit-value tmp
-136   var b/ebx: int <- copy tmp
-137 #?   set-cursor-position 0/screen, 0x10/x, 0x16/y
-138 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
-139   # read second byte of b
-140   {
-141     {
-142       var done?/eax: boolean <- stream-empty? in
-143       compare done?, 0/false
-144     }
-145     break-if-!=
-146     tmp <- read-byte in
-147     {
-148       var valid?/eax: boolean <- hex-digit? tmp
-149       compare valid?, 0/false
-150     }
-151     break-if-=
-152     b <- shift-left 4
-153     tmp <- fast-hex-digit-value tmp
-154 #?     {
-155 #?       var foo/eax: int <- copy tmp
-156 #?       set-cursor-position 0/screen, 0x10/x, 0x17/y
-157 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg, 0/bg
-158 #?     }
-159     b <- add tmp
-160 #?     {
-161 #?       set-cursor-position 0/screen, 0x10/x, 0x18/y
-162 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, b, 7/fg, 0/bg
-163 #?     }
-164   }
-165   return r, g, b
-166 }
-167 
-168 # no error checking
-169 fn fast-hex-digit-value in: byte -> _/eax: byte {
-170   var result/eax: byte <- copy in
-171   compare result, 0x39
-172   {
-173     break-if->
-174     result <- subtract 0x30/0
-175     return result
-176   }
-177   result <- subtract 0x61/a
-178   result <- add 0xa/10
-179   return result
-180 }
-181 
-182 fn print-nearby-colors screen: (addr screen), h: int, s: int, l: int {
-183 #?   set-cursor-position screen, 0x10/x, 0x1c/y
-184 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
-185 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-186 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
-187 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-188 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
-189   # save just top 2 bits of each, so that we narrow down to 1/64th of the volume
-190   shift-right h, 6
-191   shift-right s, 6
-192   shift-right l, 6
-193 #?   set-cursor-position screen, 0x10/x, 0x1/y
-194 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, h, 7/fg, 0/bg
-195 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-196 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, s, 7/fg, 0/bg
-197 #?   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-198 #?   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, l, 7/fg, 0/bg
-199   var a/ecx: int <- copy 0
-200   var b/edx: int <- copy 0
-201   var c/ebx: int <- copy 0
-202   var color/eax: int <- copy 0
-203   var y/esi: int <- copy 2
-204   {
-205     compare color, 0x100
-206     break-if->=
-207     a, b, c <- color-rgb color
-208     a, b, c <- hsl a, b, c
-209     a <- shift-right 6
-210     b <- shift-right 6
-211     c <- shift-right 6
-212     {
-213       compare a, h
-214       break-if-!=
-215       compare b, s
-216       break-if-!=
-217       compare c, l
-218       break-if-!=
-219       set-cursor-position screen, 0x10/x, y
-220       draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, color, 7/fg, 0/bg
-221       set-cursor-position screen, 0x14/x, y
-222       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-223       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "               ", 0/fg, color
-224 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-225 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, a, 7/fg, 0/bg
-226 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-227 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, b, 7/fg, 0/bg
-228 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " ", 7/fg, 0/bg
-229 #?       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen, c, 7/fg, 0/bg
-230       y <- increment
-231     }
-232     color <- increment
-233     loop
-234   }
-235 }
-
- - - diff --git a/html/ex1.mu.html b/html/ex1.mu.html deleted file mode 100644 index fc07e235..00000000 --- a/html/ex1.mu.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - -Mu - ex1.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex1.mu -
-1 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-2   loop
-3 }
-
- - - diff --git a/html/ex10.mu.html b/html/ex10.mu.html deleted file mode 100644 index 2627880c..00000000 --- a/html/ex10.mu.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - -Mu - ex10.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex10.mu -
- 1 # Demo of mouse support.
- 2 #
- 3 # To build a disk image:
- 4 #   ./translate ex10.mu            # emits code.img
- 5 # To run:
- 6 #   qemu-system-i386 code.img
- 7 # Or:
- 8 #   bochs -f bochsrc               # bochsrc loads code.img
- 9 #
-10 # Expected output:
-11 #   Values between -256 and +255 as you move the mouse over the window.
-12 #   You might need to click on the window once.
-13 
-14 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-15   # repeatedly print out mouse driver results if non-zero
-16   $main:event-loop: {
-17     var dx/eax: int <- copy 0
-18     var dy/ecx: int <- copy 0
-19     dx, dy <- read-mouse-event
-20     {
-21       compare dx, 0
-22       break-if-!=
-23       compare dy, 0
-24       break-if-!=
-25       loop $main:event-loop
-26     }
-27     {
-28       var dummy1/eax: int <- copy 0
-29       var dummy2/ecx: int <- copy 0
-30       dummy1, dummy2 <- draw-text-wrapping-right-then-down-over-full-screen screen, "         ", 0/x, 0x10/y, 0x31/fg, 0/bg
-31     }
-32     {
-33       var dummy/ecx: int <- copy 0
-34       dx, dummy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen screen, dx, 0/x, 0x10/y, 0x31/fg, 0/bg
-35     }
-36     {
-37       var dummy/eax: int <- copy 0
-38       dummy, dy <- draw-int32-decimal-wrapping-right-then-down-over-full-screen screen, dy, 5/x, 0x10/y, 0x31/fg, 0/bg
-39     }
-40     loop
-41   }
-42 }
-
- - - diff --git a/html/ex11.mu.html b/html/ex11.mu.html deleted file mode 100644 index 8c0e2788..00000000 --- a/html/ex11.mu.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - -Mu - ex11.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex11.mu -
-  1 # Demo of an interactive app: controlling a Bezier curve on screen
-  2 #
-  3 # To build a disk image:
-  4 #   ./translate ex11.mu            # emits code.img
-  5 # To run:
-  6 #   qemu-system-i386 code.img
-  7 # Or:
-  8 #   bochs -f bochsrc               # bochsrc loads code.img
-  9 #
- 10 # Expected output: a spline with 3 control points. Use `Tab` to switch cursor
- 11 # between control points, and arrow keys to move the control point at the
- 12 # cursor.
- 13 
- 14 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
- 15   var env-storage: environment
- 16   var env/esi: (addr environment) <- address env-storage
- 17   initialize-environment env, 0x200 0x20, 0x180 0x90, 0x180 0x160
- 18   {
- 19     render screen, env
- 20     edit keyboard, env
- 21     loop
- 22   }
- 23 }
- 24 
- 25 type environment {
- 26   p0: (handle point)
- 27   p1: (handle point)
- 28   p2: (handle point)
- 29   cursor: (handle point)  # one of p0, p1 or p2
- 30 }
- 31 
- 32 type point {
- 33   x: int
- 34   y: int
- 35 }
- 36 
- 37 fn render screen: (addr screen), _self: (addr environment) {
- 38   clear-screen screen
- 39   var self/esi: (addr environment) <- copy _self
- 40   var tmp-ah/ecx: (addr handle point) <- get self, p0
- 41   var tmp/eax: (addr point) <- lookup *tmp-ah
- 42   var p0/ebx: (addr point) <- copy tmp
- 43   tmp-ah <- get self, p1
- 44   tmp <- lookup *tmp-ah
- 45   var p1/edx: (addr point) <- copy tmp
- 46   tmp-ah <- get self, p2
- 47   tmp <- lookup *tmp-ah
- 48   var p2/ecx: (addr point) <- copy tmp
- 49   # control lines
- 50   line    screen, p0, p1,                 7/color
- 51   line    screen, p1, p2,                 7/color
- 52   # curve above control lines
- 53   bezier  screen, p0, p1, p2,             0xc/color
- 54   # points above curve
- 55   disc    screen, p0,           3/radius, 7/color   0xf/border
- 56   disc    screen, p1,           3/radius, 7/color   0xf/border
- 57   disc    screen, p2,           3/radius, 7/color   0xf/border
- 58   # cursor last of all
- 59   var cursor-ah/eax: (addr handle point) <- get self, cursor
- 60   var cursor/eax: (addr point) <- lookup *cursor-ah
- 61   cursor screen, cursor, 0xa/side, 3/color
- 62 }
- 63 
- 64 fn bezier screen: (addr screen), _p0: (addr point), _p1: (addr point), _p2: (addr point), color: int {
- 65   var p0/esi: (addr point) <- copy _p0
- 66   var x0/ecx: (addr int) <- get p0, x
- 67   var y0/edx: (addr int) <- get p0, y
- 68   var p1/esi: (addr point) <- copy _p1
- 69   var x1/ebx: (addr int) <- get p1, x
- 70   var y1/eax: (addr int) <- get p1, y
- 71   var p2/esi: (addr point) <- copy _p2
- 72   var x2/edi: (addr int) <- get p2, x
- 73   var y2/esi: (addr int) <- get p2, y
- 74   draw-monotonic-bezier screen, *x0 *y0, *x1 *y1, *x2 *y2, color
- 75 }
- 76 
- 77 fn cursor screen: (addr screen), _p: (addr point), side: int, color: int {
- 78   var half-side/eax: int <- copy side
- 79   half-side <- shift-right 1
- 80   var p/esi: (addr point) <- copy _p
- 81   var x-a/ecx: (addr int) <- get p, x
- 82   var left-x/ecx: int <- copy *x-a
- 83   left-x <- subtract half-side
- 84   var y-a/edx: (addr int) <- get p, y
- 85   var top-y/edx: int <- copy *y-a
- 86   top-y <- subtract half-side
- 87   var max/eax: int <- copy left-x
- 88   max <- add side
- 89   draw-horizontal-line screen, top-y, left-x, max, color
- 90   max <- copy top-y
- 91   max <- add side
- 92   draw-vertical-line screen, left-x, top-y, max, color
- 93   var right-x/ebx: int <- copy left-x
- 94   right-x <- add side
- 95   draw-vertical-line screen, right-x, top-y, max, color
- 96   var bottom-y/edx: int <- copy top-y
- 97   bottom-y <- add side
- 98   draw-horizontal-line screen, bottom-y, left-x, right-x, color
- 99 }
-100 
-101 fn edit keyboard: (addr keyboard), _self: (addr environment) {
-102   var self/esi: (addr environment) <- copy _self
-103   var key/eax: byte <- read-key keyboard
-104   compare key, 0
-105   loop-if-=
-106   {
-107     compare key, 9/tab
-108     break-if-!=
-109     toggle-cursor self
-110     return
-111   }
-112   {
-113     compare key, 0x80/left-arrow
-114     break-if-!=
-115     cursor-left self
-116     return
-117   }
-118   {
-119     compare key, 0x83/right-arrow
-120     break-if-!=
-121     cursor-right self
-122     return
-123   }
-124   {
-125     compare key, 0x81/down-arrow
-126     break-if-!=
-127     cursor-down self
-128     return
-129   }
-130   {
-131     compare key, 0x82/up-arrow
-132     break-if-!=
-133     cursor-up self
-134     return
-135   }
-136 }
-137 
-138 fn toggle-cursor _self: (addr environment) {
-139   var self/esi: (addr environment) <- copy _self
-140   var cursor-ah/edi: (addr handle point) <- get self, cursor
-141   var p0-ah/ecx: (addr handle point) <- get self, p0
-142   var p1-ah/edx: (addr handle point) <- get self, p1
-143   var p2-ah/ebx: (addr handle point) <- get self, p2
-144   {
-145     var p0?/eax: boolean <- handle-equal? *p0-ah, *cursor-ah
-146     compare p0?, 0/false
-147     break-if-=
-148     copy-object p1-ah, cursor-ah
-149     return
-150   }
-151   {
-152     var p1?/eax: boolean <- handle-equal? *p1-ah, *cursor-ah
-153     compare p1?, 0/false
-154     break-if-=
-155     copy-object p2-ah, cursor-ah
-156     return
-157   }
-158   {
-159     var p2?/eax: boolean <- handle-equal? *p2-ah, *cursor-ah
-160     compare p2?, 0/false
-161     break-if-=
-162     copy-object p0-ah, cursor-ah
-163     return
-164   }
-165   abort "lost cursor"
-166 }
-167 
-168 fn cursor-left _self: (addr environment) {
-169   var self/esi: (addr environment) <- copy _self
-170   var cursor-ah/esi: (addr handle point) <- get self, cursor
-171   var cursor/eax: (addr point) <- lookup *cursor-ah
-172   var cursor-x/eax: (addr int) <- get cursor, x
-173   compare *cursor-x, 0x20
-174   {
-175     break-if-<
-176     subtract-from *cursor-x, 0x20
-177   }
-178 }
-179 
-180 fn cursor-right _self: (addr environment) {
-181   var self/esi: (addr environment) <- copy _self
-182   var cursor-ah/esi: (addr handle point) <- get self, cursor
-183   var cursor/eax: (addr point) <- lookup *cursor-ah
-184   var cursor-x/eax: (addr int) <- get cursor, x
-185   compare *cursor-x, 0x3f0
-186   {
-187     break-if->
-188     add-to *cursor-x, 0x20
-189   }
-190 }
-191 
-192 fn cursor-up _self: (addr environment) {
-193   var self/esi: (addr environment) <- copy _self
-194   var cursor-ah/esi: (addr handle point) <- get self, cursor
-195   var cursor/eax: (addr point) <- lookup *cursor-ah
-196   var cursor-y/eax: (addr int) <- get cursor, y
-197   compare *cursor-y, 0x20
-198   {
-199     break-if-<
-200     subtract-from *cursor-y, 0x20
-201   }
-202 }
-203 
-204 fn cursor-down _self: (addr environment) {
-205   var self/esi: (addr environment) <- copy _self
-206   var cursor-ah/esi: (addr handle point) <- get self, cursor
-207   var cursor/eax: (addr point) <- lookup *cursor-ah
-208   var cursor-y/eax: (addr int) <- get cursor, y
-209   compare *cursor-y, 0x2f0
-210   {
-211     break-if->
-212     add-to *cursor-y, 0x20
-213   }
-214 }
-215 
-216 fn line screen: (addr screen), _p0: (addr point), _p1: (addr point), color: int {
-217   var p0/esi: (addr point) <- copy _p0
-218   var x0/ecx: (addr int) <- get p0, x
-219   var y0/edx: (addr int) <- get p0, y
-220   var p1/esi: (addr point) <- copy _p1
-221   var x1/ebx: (addr int) <- get p1, x
-222   var y1/eax: (addr int) <- get p1, y
-223   draw-line screen, *x0 *y0, *x1 *y1, color
-224 }
-225 
-226 fn disc screen: (addr screen), _p: (addr point), radius: int, color: int, border-color: int {
-227   var p/esi: (addr point) <- copy _p
-228   var x/ecx: (addr int) <- get p, x
-229   var y/edx: (addr int) <- get p, y
-230   draw-disc screen, *x *y, radius, color, border-color
-231 }
-232 
-233 fn initialize-environment _self: (addr environment), x0: int, y0: int, x1: int, y1: int, x2: int, y2: int {
-234   var self/esi: (addr environment) <- copy _self
-235   var p0-ah/eax: (addr handle point) <- get self, p0
-236   allocate p0-ah
-237   var p0/eax: (addr point) <- lookup *p0-ah
-238   initialize-point p0, x0 y0
-239   var p1-ah/eax: (addr handle point) <- get self, p1
-240   allocate p1-ah
-241   var p1/eax: (addr point) <- lookup *p1-ah
-242   initialize-point p1, x1 y1
-243   var p2-ah/eax: (addr handle point) <- get self, p2
-244   allocate p2-ah
-245   var p2/eax: (addr point) <- lookup *p2-ah
-246   initialize-point p2, x2 y2
-247   # cursor initially at p0
-248   var cursor-ah/edi: (addr handle point) <- get self, cursor
-249   var src-ah/esi: (addr handle point) <- get self, p0
-250   copy-object src-ah, cursor-ah
-251 }
-252 
-253 fn initialize-point _p: (addr point), x: int, y: int {
-254   var p/esi: (addr point) <- copy _p
-255   var dest/eax: (addr int) <- get p, x
-256   var src/ecx: int <- copy x
-257   copy-to *dest, src
-258   dest <- get p, y
-259   src <- copy y
-260   copy-to *dest, src
-261 }
-
- - - diff --git a/html/ex2.mu.html b/html/ex2.mu.html deleted file mode 100644 index 12b20923..00000000 --- a/html/ex2.mu.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -Mu - ex2.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex2.mu -
- 1 # Test out the video mode by filling in the screen with pixels.
- 2 #
- 3 # To build a disk image:
- 4 #   ./translate ex2.mu             # emits code.img
- 5 # To run:
- 6 #   qemu-system-i386 code.img
- 7 # Or:
- 8 #   bochs -f bochsrc               # bochsrc loads code.img
- 9 
-10 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-11   var y/eax: int <- copy 0
-12   {
-13     compare y, 0x300/screen-height=768
-14     break-if->=
-15     var x/edx: int <- copy 0
-16     {
-17       compare x, 0x400/screen-width=1024
-18       break-if->=
-19       var color/ecx: int <- copy x
-20       color <- and 0xff
-21       pixel screen x, y, color
-22       x <- increment
-23       loop
-24     }
-25     y <- increment
-26     loop
-27   }
-28 }
-
- - - diff --git a/html/ex3.mu.html b/html/ex3.mu.html deleted file mode 100644 index 8a600e92..00000000 --- a/html/ex3.mu.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -Mu - ex3.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex3.mu -
- 1 # Draw pixels in response to keyboard events, starting from the top-left
- 2 # and in raster order.
- 3 #
- 4 # To build a disk image:
- 5 #   ./translate ex3.mu             # emits code.img
- 6 # To run:
- 7 #   qemu-system-i386 code.img
- 8 # Or:
- 9 #   bochs -f bochsrc               # bochsrc loads code.img
-10 #
-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 screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-15   var x/ecx: int <- copy 0
-16   var y/edx: int <- copy 0
-17   {
-18     var key/eax: byte <- read-key keyboard
-19     compare key, 0
-20     loop-if-=  # busy wait
-21     pixel-on-real-screen x, y, 0x31/green
-22     x <- increment
-23     compare x, 0x400/screen-width=1024
-24     {
-25       break-if-<
-26       y <- increment
-27       x <- copy 0
-28     }
-29     loop
-30   }
-31 }
-
- - - diff --git a/html/ex4.mu.html b/html/ex4.mu.html deleted file mode 100644 index 4b0f564f..00000000 --- a/html/ex4.mu.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - -Mu - ex4.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex4.mu -
- 1 # Draw a character using the built-in font (GNU unifont)
- 2 #
- 3 # To build a disk image:
- 4 #   ./translate ex4.mu             # emits code.img
- 5 # To run:
- 6 #   qemu-system-i386 code.img
- 7 # Or:
- 8 #   bochs -f bochsrc               # bochsrc loads code.img
- 9 #
-10 # Expected output: letter 'A' in green near the top-left corner of screen
-11 
-12 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-13   draw-code-point screen, 0x41/A, 2/row, 1/col, 0xa/fg, 0/bg
-14 }
-
- - - diff --git a/html/ex5.mu.html b/html/ex5.mu.html deleted file mode 100644 index cc216a53..00000000 --- a/html/ex5.mu.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - -Mu - ex5.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex5.mu -
- 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 ex5.mu             # emits code.img
- 6 # To run:
- 7 #   qemu-system-i386 code.img
- 8 # Or:
- 9 #   bochs -f bochsrc               # bochsrc loads code.img
-10 #
-11 # Expected output: text in green near the top-left corner of screen
-12 
-13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-14   var dummy/eax: int <- draw-text-rightward screen, "hello from baremetal Mu!", 0x10/x, 0x400/xmax, 0x10/y, 0xa/fg, 0/bg
-15   dummy <- draw-text-rightward screen, "you shouldn't see this", 0x10/x, 0xa0/xmax, 0x30/y, 3/fg, 0/bg  # xmax is too narrow
-16 }
-
- - - diff --git a/html/ex6.mu.html b/html/ex6.mu.html deleted file mode 100644 index df64aa9f..00000000 --- a/html/ex6.mu.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -Mu - ex6.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex6.mu -
- 1 # Drawing ASCII text incrementally.
- 2 #
- 3 # To build a disk image:
- 4 #   ./translate ex6.mu             # emits code.img
- 5 # To run:
- 6 #   qemu-system-i386 code.img
- 7 # Or:
- 8 #   bochs -f bochsrc               # bochsrc loads code.img
- 9 #
-10 # Expected output: a box and text that doesn't overflow it
-11 
-12 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-13   # drawing text within a bounding box
-14   draw-box-on-real-screen 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 screen, "hello ",     0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
-18   x, y <- draw-text-wrapping-right-then-down screen, "from ",      0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
-19   x, y <- draw-text-wrapping-right-then-down screen, "baremetal ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
-20   x, y <- draw-text-wrapping-right-then-down screen, "Mu!",        0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/fg, 0/bg
-21 
-22   # drawing at the cursor in multiple directions
-23   draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen, "abc", 0xa/fg, 0/bg
-24   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "def", 0xa/fg, 0/bg
-25 
-26   # test drawing near the edge
-27   x <- draw-text-rightward screen, "R", 0x7f/x, 0x80/xmax=screen-width, 0x18/y, 0xa/fg, 0/bg
-28   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "wrapped from R", 0xa/fg, 0/bg
-29 
-30   x <- draw-text-downward screen, "D", 0x20/x, 0x2f/y, 0x30/ymax=screen-height, 0xa/fg, 0/bg
-31   draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen, "wrapped from D", 0xa/fg, 0/bg
-32 }
-
- - - diff --git a/html/ex7.mu.html b/html/ex7.mu.html deleted file mode 100644 index 08050bc9..00000000 --- a/html/ex7.mu.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - -Mu - ex7.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex7.mu -
- 1 # Cursor-based motions.
- 2 #
- 3 # To build a disk image:
- 4 #   ./translate ex7.mu             # emits code.img
- 5 # To run:
- 6 #   qemu-system-i386 code.img
- 7 # Or:
- 8 #   bochs -f bochsrc               # bochsrc loads code.img
- 9 #
-10 # Expected output: an interactive game a bit like "snakes". Try pressing h, j,
-11 # k, l.
-12 
-13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-14   var space/eax: grapheme <- copy 0x20
-15   set-cursor-position screen, 0, 0
-16   {
-17     draw-cursor screen, space
-18     var key/eax: byte <- read-key keyboard
-19     {
-20       compare key, 0x68/h
-21       break-if-!=
-22       draw-code-point-at-cursor screen, 0x2d/dash, 0x31/fg, 0/bg
-23       move-cursor-left 0
-24     }
-25     {
-26       compare key, 0x6a/j
-27       break-if-!=
-28       draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x31/fg, 0/bg
-29       move-cursor-down 0
-30     }
-31     {
-32       compare key, 0x6b/k
-33       break-if-!=
-34       draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x31/fg, 0/bg
-35       move-cursor-up 0
-36     }
-37     {
-38       compare key, 0x6c/l
-39       break-if-!=
-40       var g/eax: code-point <- copy 0x2d/dash
-41       draw-code-point-at-cursor screen, 0x2d/dash, 0x31/fg, 0/bg
-42       move-cursor-right 0
-43     }
-44     loop
-45   }
-46 }
-
- - - diff --git a/html/ex8.mu.html b/html/ex8.mu.html deleted file mode 100644 index 5ae27a7b..00000000 --- a/html/ex8.mu.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - -Mu - ex8.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex8.mu -
- 1 # Demo of floating-point support.
- 2 #
- 3 # To build a disk image:
- 4 #   ./translate ex8.mu             # emits code.img
- 5 # To run:
- 6 #   bochs -f bochsrc               # bochsrc loads code.img
- 7 # Set a breakpoint at 0x7c00 and start stepping.
- 8 
- 9 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-10   var n/eax: int <- copy 0
-11   var result/xmm0: float <- convert n
-12 }
-
- - - diff --git a/html/ex9.mu.html b/html/ex9.mu.html deleted file mode 100644 index ac7e8b68..00000000 --- a/html/ex9.mu.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - -Mu - ex9.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/ex9.mu -
- 1 # Demo of reading and writing to disk.
- 2 #
- 3 # Steps for trying it out:
- 4 #   1. Translate this example into a disk image code.img.
- 5 #       ./translate ex9.mu
- 6 #   2. Build a second disk image data.img containing some text.
- 7 #       dd if=/dev/zero of=data.img count=20160
- 8 #       echo 'abc def ghi' |dd of=data.img conv=notrunc
- 9 #   3. Familiarize yourself with how the data disk looks within xxd:
-10 #       xxd data.img |head
-11 #   4. Run in an emulator, either Qemu or Bochs.
-12 #       qemu-system-i386 -hda code.img -hdb data.img
-13 #       bochs -f bochsrc.2disks
-14 #   5. Exit the emulator.
-15 #   6. Notice that the data disk now contains the word count of the original text.
-16 #       xxd data.img |head
-17 
-18 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-19   var text-storage: (stream byte 0x200)
-20   var text/esi: (addr stream byte) <- address text-storage
-21   load-sectors data-disk, 0/lba, 1/num-sectors, text
-22 
-23   var word-count/eax: int <- word-count text
-24 
-25   var result-storage: (stream byte 0x10)
-26   var result/edi: (addr stream byte) <- address result-storage
-27   write-int32-decimal result, word-count
-28   store-sectors data-disk, 0/lba, 1/num-sectors, result
-29 }
-30 
-31 fn word-count in: (addr stream byte) -> _/eax: int {
-32   var result/edi: int <- copy 0
-33   {
-34     var done?/eax: boolean <- stream-empty? in
-35     compare done?, 0/false
-36     break-if-!=
-37     var g/eax: grapheme <- read-grapheme in
-38     {
-39       compare g, 0x20/space
-40       break-if-!=
-41       result <- increment
-42     }
-43     {
-44       compare g, 0xa/newline
-45       break-if-!=
-46       result <- increment
-47     }
-48     loop
-49   }
-50   return result
-51 }
-
- - - diff --git a/html/hest-life.mu.html b/html/hest-life.mu.html deleted file mode 100644 index 41cd98f5..00000000 --- a/html/hest-life.mu.html +++ /dev/null @@ -1,1097 +0,0 @@ - - - - -Mu - hest-life.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/hest-life.mu -
-   1 # Conway's Game of Life in a Hestified way
-   2 #   https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
-   3 #   https://ivanish.ca/hest-podcast
-   4 #
-   5 # To build:
-   6 #   $ ./translate hest-life.mu
-   7 # I run it on my 2.5GHz Linux laptop like this:
-   8 #   $ qemu-system-i386 -enable-kvm code.img
-   9 #
-  10 # If things seem too fast or too slow on your computer, adjust the loop bounds
-  11 # in the function `linger` at the bottom. Its value will depend on how you
-  12 # accelerate Qemu. Mu will eventually get a clock to obviate the need for this
-  13 # tuning.
-  14 #
-  15 # Keyboard shortcuts:
-  16 #   space: pause/resume
-  17 #   0: restart time
-  18 #   l: start looping from 0 to curren time
-  19 #   L: stop looping
-  20 #   +: zoom in
-  21 #   -: zoom out
-  22 
-  23 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-  24   var env-storage: environment
-  25   var env/esi: (addr environment) <- address env-storage
-  26   initialize-environment env
-  27   var second-buffer: screen
-  28   var second-screen/edi: (addr screen) <- address second-buffer
-  29   initialize-screen second-screen, 0x80, 0x30, 1/include-pixels
-  30   render second-screen, env
-  31   convert-graphemes-to-pixels second-screen
-  32   copy-pixels second-screen, screen
-  33   {
-  34     edit keyboard, env
-  35     var play?/eax: (addr boolean) <- get env, play?
-  36     compare *play?, 0/false
-  37     {
-  38       break-if-=
-  39       step env
-  40       clear-screen second-screen
-  41       render second-screen, env
-  42       convert-graphemes-to-pixels second-screen
-  43       copy-pixels second-screen, screen
-  44     }
-  45     linger env
-  46     loop
-  47   }
-  48 }
-  49 
-  50 type environment {
-  51   data: (handle array handle array cell)
-  52   zoom: int  # 0 = 1024 px per cell; 5 = 4px per cell; each step adjusts by a factor of 4
-  53   tick: int
-  54   play?: boolean
-  55   loop: int  # if non-zero, return tick to 0 after this point
-  56 }
-  57 
-  58 type cell {
-  59   curr: boolean
-  60   next: boolean
-  61 }
-  62 
-  63 fn render screen: (addr screen), _self: (addr environment) {
-  64   var self/esi: (addr environment) <- copy _self
-  65   var zoom/eax: (addr int) <- get self, zoom
-  66   compare *zoom, 0
-  67   {
-  68     break-if-!=
-  69     clear-screen screen
-  70     render0 screen, self
-  71   }
-  72   compare *zoom, 1
-  73   {
-  74     break-if-!=
-  75     clear-screen screen
-  76     render1 screen, self
-  77   }
-  78   compare *zoom, 4
-  79   {
-  80     break-if-!=
-  81     render4 screen, self
-  82   }
-  83   # clock
-  84   var tick-a/eax: (addr int) <- get self, tick
-  85   set-cursor-position screen, 0x78/x, 0/y
-  86   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, *tick-a, 7/fg 0/bg
-  87 }
-  88 
-  89 # Lots of hardcoded constants for now.
-  90 # TODO: split this up into a primitive to render a single cell and its
-  91 # incoming edges (but not the neighboring nodes they emanate from)
-  92 fn render0 screen: (addr screen), _self: (addr environment) {
-  93   var self/esi: (addr environment) <- copy _self
-  94   # cell border
-  95   draw-vertical-line   screen,  0xc0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
-  96   draw-vertical-line   screen, 0x340/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
-  97   draw-horizontal-line screen,  0x40/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
-  98   draw-horizontal-line screen, 0x2c0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
-  99   # neighboring inputs, corners
- 100   var color/eax: int <- state-color self, 0x7f/cur-topleftx, 0x5f/cur-toplefty
- 101   draw-rect screen,  0x90/xmin   0x10/ymin,    0xb0/xmax   0x30/ymax,  color
- 102   color <- state-color self, 0x81/cur-toprightx, 0x5f/cur-toprighty
- 103   draw-rect screen, 0x350/xmin   0x10/ymin,   0x370/xmax   0x30/ymax,  color
- 104   color <- state-color self, 0x7f/cur-botleftx, 0x61/cur-botlefty
- 105   draw-rect screen,  0x90/xmin  0x2d0/ymin,    0xb0/xmax  0x2f0/ymax,  color
- 106   color <- state-color self, 0x81/cur-botrightx, 0x61/cur-botrighty
- 107   draw-rect screen, 0x350/xmin  0x2d0/ymin,   0x370/xmax  0x2f0/ymax,  color
- 108   # neighboring inputs, edges
- 109   color <- state-color self, 0x80/cur-topx, 0x5f/cur-topy
- 110   draw-rect screen, 0x1f0/xmin   0x10/ymin,   0x210/xmax   0x30/ymax,  color
- 111   color <- state-color self, 0x7f/cur-leftx, 0x60/cur-lefty
- 112   draw-rect screen,  0x90/xmin  0x170/ymin,    0xb0/xmax  0x190/ymax,  color
- 113   color <- state-color self, 0x80/cur-botx, 0x61/cur-boty
- 114   draw-rect screen, 0x1f0/xmin  0x2d0/ymin,   0x210/xmax  0x2f0/ymax,  color
- 115   color <- state-color self, 0x81/cur-rightx, 0x60/cur-righty
- 116   draw-rect screen, 0x350/xmin  0x170/ymin,   0x370/xmax  0x190/ymax,  color
- 117   # sum node
- 118   draw-rect screen, 0x170/xsmin 0x140/ysmin,  0x190/xsmax 0x160/ysmax, 0x40/color
- 119   set-cursor-position screen, 0x2d/scol, 0x13/srow
- 120   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "+", 0xf/color, 0/bg
- 121   # conveyors from neighboring inputs to sum node
- 122   draw-monotonic-bezier screen,  0xa0/x0  0x20/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
- 123   draw-monotonic-bezier screen,  0xa0/x0 0x180/y0,   0xc0/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
- 124   draw-monotonic-bezier screen,  0xa0/x0 0x2e0/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
- 125   draw-monotonic-bezier screen, 0x200/x0  0x20/y0,  0x180/x1  0x90/y1,  0x180/xs 0x150/ys,  4/color
- 126   draw-monotonic-bezier screen, 0x200/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
- 127   draw-monotonic-bezier screen, 0x360/x0  0x20/y0,  0x180/x1  0xc0/y1,  0x180/xs 0x150/ys,  4/color
- 128   draw-monotonic-bezier screen, 0x360/x0 0x180/y0,  0x35c/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
- 129   draw-monotonic-bezier screen, 0x360/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
- 130   # filter node
- 131   draw-rect screen, 0x200/xfmin 0x1c0/yfmin, 0x220/xfmax 0x1e0/yfmax, 0x31/color
- 132   set-cursor-position screen, 0x40/fcol, 0x1b/frow
- 133   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "?", 0xf/color, 0/bg
- 134   # conveyor from sum node to filter node
- 135   draw-line screen 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 0xa2/color
- 136   # cell outputs at corners
- 137   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
- 138   draw-rect screen,  0xd0/xmin  0x50/ymin,  0xf0/xmax  0x70/ymax, color
- 139   draw-rect screen, 0x310/xmin  0x50/ymin, 0x330/xmax  0x70/ymax, color
- 140   draw-rect screen,  0xd0/xmin 0x290/ymin,  0xf0/xmax 0x2b0/ymax, color
- 141   draw-rect screen, 0x310/xmin 0x290/ymin, 0x330/xmax 0x2b0/ymax, color
- 142   # cell outputs at edges
- 143   draw-rect screen, 0x1f0/xmin  0x50/ymin, 0x210/xmax  0x70/ymax, color
- 144   draw-rect screen,  0xd0/xmin 0x170/ymin,  0xf0/xmax 0x190/ymax, color
- 145   draw-rect screen, 0x1f0/xmin 0x290/ymin, 0x210/xmax 0x2b0/ymax, color
- 146   draw-rect screen, 0x310/xmin 0x170/ymin, 0x330/xmax 0x190/ymax, color
- 147   # conveyors from filter to outputs
- 148   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2,  0x2a/color
- 149   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2,  0x2a/color
- 150   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2,  0x2a/color
- 151   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1  0x60/y1, 0x200/x2   0x60/y2,  0x2a/color
- 152   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1 0x230/y1, 0x200/x2  0x2a0/y2,  0x2a/color
- 153   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2,  0x2a/color
- 154   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1  0x320/x2  0x180/y2,  0x2a/color
- 155   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2,  0x2a/color
- 156   # time-variant portion: 16 repeating steps
- 157   var tick-a/eax: (addr int) <- get self, tick
- 158   var progress/eax: int <- copy *tick-a
- 159   progress <- and 0xf
- 160   # 7 time steps for getting inputs to sum
- 161   {
- 162     compare progress, 7
- 163     break-if->=
- 164     var u/xmm7: float <- convert progress
- 165     var six/eax: int <- copy 6
- 166     var six-f/xmm0: float <- convert six
- 167     u <- divide six-f
- 168     # points on conveyors from neighboring cells
- 169     draw-bezier-point screen, u,  0xa0/x0  0x20/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
- 170     draw-bezier-point screen, u,  0xa0/x0 0x180/y0,  0xc0/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
- 171     draw-bezier-point screen, u,  0xa0/x0 0x2e0/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
- 172     draw-bezier-point screen, u, 0x200/x0  0x20/y0, 0x180/x1  0x90/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
- 173     draw-bezier-point screen, u, 0x200/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
- 174     draw-bezier-point screen, u, 0x360/x0  0x20/y0, 0x180/x1  0xc0/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
- 175     draw-bezier-point screen, u, 0x360/x0 0x180/y0, 0x35c/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
- 176     draw-bezier-point screen, u, 0x360/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
- 177     return
- 178   }
- 179   # two time steps for getting count to filter
- 180   progress <- subtract 7
- 181   {
- 182     compare progress, 2
- 183     break-if->=
- 184     progress <- increment  # (0, 1) => (1, 2)
- 185     var u/xmm7: float <- convert progress
- 186     var three/eax: int <- copy 3
- 187     var three-f/xmm0: float <- convert three
- 188     u <- divide three-f
- 189     draw-linear-point screen, u, 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 7/color, 4/radius
- 190     set-cursor-position screen, 0x3a/scol, 0x18/srow
- 191     var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
- 192     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
- 193     return
- 194   }
- 195   # final 7 time steps for updating output
- 196   progress <- subtract 2
- 197   # points on conveyors to outputs
- 198   var u/xmm7: float <- convert progress
- 199   var six/eax: int <- copy 6
- 200   var six-f/xmm0: float <- convert six
- 201   u <- divide six-f
- 202   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2, 7/color, 4/radius
- 203   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2, 7/color, 4/radius
- 204   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2, 7/color, 4/radius
- 205   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf  0x60/y1, 0x200/x2   0x60/y2, 7/color, 4/radius
- 206   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf 0x230/y1, 0x200/x2  0x2a0/y2, 7/color, 4/radius
- 207   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2, 7/color, 4/radius
- 208   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1, 0x320/x2  0x180/y2, 7/color, 4/radius
- 209   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2, 7/color, 4/radius
- 210 }
- 211 
- 212 fn render1 screen: (addr screen), _self: (addr environment) {
- 213   var self/esi: (addr environment) <- copy _self
- 214   # cell borders
- 215   draw-vertical-line   screen,  0xe0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
- 216   draw-vertical-line   screen, 0x200/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
- 217   draw-vertical-line   screen, 0x320/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
- 218   draw-horizontal-line screen,  0x60/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
- 219   draw-horizontal-line screen, 0x180/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
- 220   draw-horizontal-line screen, 0x2a0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
- 221   # cell 0: outputs
- 222   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
- 223   draw-rect screen,  0xe8/xmin  0x68/ymin, 0x118/xmax   0x98/ymax, color
- 224   draw-rect screen,  0xe8/xmin  0xd0/ymin, 0x118/xmax  0x100/ymax, color
- 225   draw-rect screen,  0xe8/xmin 0x148/ymin, 0x118/xmax  0x178/ymax, color
- 226   draw-rect screen, 0x158/xmin  0x68/ymin, 0x188/xmax   0x98/ymax, color
- 227   draw-rect screen, 0x158/xmin 0x148/ymin, 0x188/xmax  0x178/ymax, color
- 228   draw-rect screen, 0x1c8/xmin  0x68/ymin, 0x1f8/xmax   0x98/ymax, color
- 229   draw-rect screen, 0x1c8/xmin  0xd0/ymin, 0x1f8/xmax  0x100/ymax, color
- 230   draw-rect screen, 0x1c8/xmin 0x148/ymin, 0x1f8/xmax  0x178/ymax, color
- 231   # cell 1: outputs
- 232   var color/eax: int <- state-color self, 0x81/curx, 0x60/cury
- 233   draw-rect screen, 0x208/xmin  0x68/ymin, 0x238/xmax   0x98/ymax, color
- 234   draw-rect screen, 0x208/xmin  0xd0/ymin, 0x238/xmax  0x100/ymax, color
- 235   draw-rect screen, 0x208/xmin 0x148/ymin, 0x238/xmax  0x178/ymax, color
- 236   draw-rect screen, 0x278/xmin  0x68/ymin, 0x2a8/xmax   0x98/ymax, color
- 237   draw-rect screen, 0x278/xmin 0x148/ymin, 0x2a8/xmax  0x178/ymax, color
- 238   draw-rect screen, 0x2e8/xmin  0x68/ymin, 0x318/xmax   0x98/ymax, color
- 239   draw-rect screen, 0x2e8/xmin  0xd0/ymin, 0x318/xmax  0x100/ymax, color
- 240   draw-rect screen, 0x2e8/xmin 0x148/ymin, 0x318/xmax  0x178/ymax, color
- 241   # cell 2: outputs
- 242   var color/eax: int <- state-color self, 0x80/curx, 0x61/cury
- 243   draw-rect screen,  0xe8/xmin 0x188/ymin, 0x118/xmax  0x1b8/ymax, color
- 244   draw-rect screen,  0xe8/xmin 0x1f0/ymin, 0x118/xmax  0x220/ymax, color
- 245   draw-rect screen,  0xe8/xmin 0x268/ymin, 0x118/xmax  0x298/ymax, color
- 246   draw-rect screen, 0x158/xmin 0x188/ymin, 0x188/xmax  0x1b8/ymax, color
- 247   draw-rect screen, 0x158/xmin 0x268/ymin, 0x188/xmax  0x298/ymax, color
- 248   draw-rect screen, 0x1c8/xmin 0x188/ymin, 0x1f8/xmax  0x1b8/ymax, color
- 249   draw-rect screen, 0x1c8/xmin 0x1f0/ymin, 0x1f8/xmax  0x220/ymax, color
- 250   draw-rect screen, 0x1c8/xmin 0x268/ymin, 0x1f8/xmax  0x298/ymax, color
- 251   # cell 3: outputs
- 252   var color/eax: int <- state-color self, 0x81/curx, 0x61/cury
- 253   draw-rect screen, 0x208/xmin 0x188/ymin, 0x238/xmax  0x1b8/ymax, color
- 254   draw-rect screen, 0x208/xmin 0x1f0/ymin, 0x238/xmax  0x220/ymax, color
- 255   draw-rect screen, 0x208/xmin 0x268/ymin, 0x238/xmax  0x298/ymax, color
- 256   draw-rect screen, 0x278/xmin 0x188/ymin, 0x2a8/xmax  0x1b8/ymax, color
- 257   draw-rect screen, 0x278/xmin 0x268/ymin, 0x2a8/xmax  0x298/ymax, color
- 258   draw-rect screen, 0x2e8/xmin 0x188/ymin, 0x318/xmax  0x1b8/ymax, color
- 259   draw-rect screen, 0x2e8/xmin 0x1f0/ymin, 0x318/xmax  0x220/ymax, color
- 260   draw-rect screen, 0x2e8/xmin 0x268/ymin, 0x318/xmax  0x298/ymax, color
- 261   # neighboring nodes
- 262   var color/eax: int <- state-color self, 0x7f/curx, 0x5f/cury
- 263   draw-rect screen,  0xa8/xmin  0x28/ymin,  0xd8/xmax   0x58/ymax, color
- 264   var color/eax: int <- state-color self, 0x80/curx, 0x5f/cury
- 265   draw-rect screen, 0x158/xmin  0x28/ymin, 0x188/xmax   0x58/ymax, color
- 266   draw-rect screen, 0x1c8/xmin  0x28/ymin, 0x1f8/xmax   0x58/ymax, color
- 267   var color/eax: int <- state-color self, 0x81/curx, 0x5f/cury
- 268   draw-rect screen, 0x208/xmin  0x28/ymin, 0x238/xmax   0x58/ymax, color
- 269   draw-rect screen, 0x278/xmin  0x28/ymin, 0x2a8/xmax   0x58/ymax, color
- 270   var color/eax: int <- state-color self, 0x82/curx, 0x5f/cury
- 271   draw-rect screen, 0x328/xmin  0x28/ymin, 0x358/xmax   0x58/ymax, color
- 272   var color/eax: int <- state-color self, 0x7f/curx, 0x60/cury
- 273   draw-rect screen,  0xa8/xmin  0xd0/ymin,  0xd8/xmax  0x100/ymax, color
- 274   draw-rect screen,  0xa8/xmin 0x148/ymin,  0xd8/xmax  0x178/ymax, color
- 275   var color/eax: int <- state-color self, 0x82/curx, 0x60/cury
- 276   draw-rect screen, 0x328/xmin  0xd0/ymin, 0x358/xmax  0x100/ymax, color
- 277   draw-rect screen, 0x328/xmin 0x148/ymin, 0x358/xmax  0x178/ymax, color
- 278   var color/eax: int <- state-color self, 0x7f/curx, 0x61/cury
- 279   draw-rect screen,  0xa8/xmin 0x188/ymin,  0xd8/xmax  0x1b8/ymax, color
- 280   draw-rect screen,  0xa8/xmin 0x1f0/ymin,  0xd8/xmax  0x220/ymax, color
- 281   var color/eax: int <- state-color self, 0x82/curx, 0x61/cury
- 282   draw-rect screen, 0x328/xmin 0x188/ymin, 0x358/xmax  0x1b8/ymax, color
- 283   draw-rect screen, 0x328/xmin 0x1f0/ymin, 0x358/xmax  0x220/ymax, color
- 284   var color/eax: int <- state-color self, 0x7f/curx, 0x62/cury
- 285   draw-rect screen,  0xa8/xmin 0x2a8/ymin,  0xd8/xmax  0x2d8/ymax, color
- 286   var color/eax: int <- state-color self, 0x80/curx, 0x62/cury
- 287   draw-rect screen, 0x158/xmin 0x2a8/ymin, 0x188/xmax  0x2d8/ymax, color
- 288   draw-rect screen, 0x1c8/xmin 0x2a8/ymin, 0x1f8/xmax  0x2d8/ymax, color
- 289   var color/eax: int <- state-color self, 0x81/curx, 0x62/cury
- 290   draw-rect screen, 0x208/xmin 0x2a8/ymin, 0x238/xmax  0x2d8/ymax, color
- 291   draw-rect screen, 0x278/xmin 0x2a8/ymin, 0x2a8/xmax  0x2d8/ymax, color
- 292   var color/eax: int <- state-color self, 0x82/curx, 0x62/cury
- 293   draw-rect screen, 0x328/xmin 0x2a8/ymin, 0x358/xmax  0x2d8/ymax, color
- 294   # cell 0: sum and filter nodes
- 295   draw-rect screen, 0x148/xsmin  0xc8/ysmin, 0x158/xsmax  0xd8/ysmax, 0x40/color
- 296   draw-rect screen, 0x180/xfmin  0xf8/yfmin, 0x190/xfmax 0x108/yfmax, 0x31/color
- 297   # cell 1: sum and filter nodes
- 298   draw-rect screen, 0x268/xsmin  0xc8/ysmin, 0x278/xsmax  0xd8/ysmax, 0x40/color
- 299   draw-rect screen, 0x2a0/xfmin  0xf8/yfmin, 0x2b0/xfmax 0x108/yfmax, 0x31/color
- 300   # cell 2: sum and filter nodes
- 301   draw-rect screen, 0x148/xsmin 0x1e8/ysmin, 0x158/xsmax 0x1f8/ysmax, 0x40/color
- 302   draw-rect screen, 0x180/xfmin 0x218/yfmin, 0x190/xfmax 0x228/yfmax, 0x31/color
- 303   # cell 3: sum and filter nodes
- 304   draw-rect screen, 0x268/xsmin 0x1e8/ysmin, 0x278/xsmax 0x1f8/ysmax, 0x40/color
- 305   draw-rect screen, 0x2a0/xfmin 0x218/yfmin, 0x2b0/xfmax 0x228/yfmax, 0x31/color
- 306   # neighbor counts
- 307   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
- 308   set-cursor-position screen, 0x2d, 0xe
- 309   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
- 310   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x60/cury
- 311   set-cursor-position screen, 0x52, 0xe
- 312   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
- 313   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x61/cury
- 314   set-cursor-position screen, 0x2d, 0x20
- 315   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
- 316   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x61/cury
- 317   set-cursor-position screen, 0x52, 0x20
- 318   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
- 319   # cell 0: conveyors from neighboring inputs to sum node
- 320   draw-monotonic-bezier screen,  0xc0/x0  0x40/y0,  0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
- 321   draw-monotonic-bezier screen,  0xc0/x0  0xe8/y0,   0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
- 322   draw-monotonic-bezier screen,  0xc0/x0 0x1a0/y0,   0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
- 323   draw-monotonic-bezier screen, 0x170/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
- 324   draw-monotonic-bezier screen, 0x170/x0 0x1a0/y0,  0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
- 325   draw-monotonic-bezier screen, 0x220/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
- 326   draw-monotonic-bezier screen, 0x220/x0  0xe8/y0,  0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys,  4/color
- 327   draw-monotonic-bezier screen, 0x220/x0 0x1a0/y0,  0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
- 328   # cell 0: conveyors from filter to outputs
- 329   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2,  0x2a/color
- 330   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2,  0x2a/color
- 331   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2,  0x2a/color
- 332   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1  0x80/y1, 0x170/x2  0x80/y2,  0x2a/color
- 333   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1 0x160/y1, 0x170/x2 0x160/y2,  0x2a/color
- 334   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2,  0x2a/color
- 335   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1  0x1e0/x2  0xe8/y2,  0x2a/color
- 336   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2,  0x2a/color
- 337   # cell 0: time-variant portion: 16 repeating steps
- 338   $render1:cell0: {
- 339     var tick-a/eax: (addr int) <- get self, tick
- 340     var progress/eax: int <- copy *tick-a
- 341     progress <- and 0xf
- 342     # cell 0: 7 time steps for getting inputs to sum
- 343     {
- 344       compare progress, 7
- 345       break-if->=
- 346       var u/xmm7: float <- convert progress
- 347       var six/eax: int <- copy 6
- 348       var six-f/xmm0: float <- convert six
- 349       u <- divide six-f
- 350       # points on conveyors from neighboring cells
- 351       draw-bezier-point screen, u,  0xc0/x0  0x40/y0, 0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 352       draw-bezier-point screen, u,  0xc0/x0  0xe8/y0,  0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 353       draw-bezier-point screen, u,  0xc0/x0 0x1a0/y0,  0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 354       draw-bezier-point screen, u, 0x170/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 355       draw-bezier-point screen, u, 0x170/x0 0x1a0/y0, 0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 356       draw-bezier-point screen, u, 0x220/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 357       draw-bezier-point screen, u, 0x220/x0  0xe8/y0, 0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 358       draw-bezier-point screen, u, 0x220/x0 0x1a0/y0, 0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
- 359       break $render1:cell0
- 360     }
- 361     # cell 0: two time steps for getting count to filter
- 362     progress <- subtract 7
- 363     {
- 364       compare progress, 2
- 365       break-if->=
- 366       break $render1:cell0
- 367     }
- 368     # cell 0: final 7 time steps for updating output
- 369     progress <- subtract 2
- 370     # cell 0: points on conveyors to outputs
- 371     var u/xmm7: float <- convert progress
- 372     var six/eax: int <- copy 6
- 373     var six-f/xmm0: float <- convert six
- 374     u <- divide six-f
- 375     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2, 7/color, 4/radius
- 376     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2, 7/color, 4/radius
- 377     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2, 7/color, 4/radius
- 378     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf  0x80/y1, 0x170/x2  0x80/y2, 7/color, 4/radius
- 379     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf 0x160/y1, 0x170/x2 0x160/y2, 7/color, 4/radius
- 380     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2, 7/color, 4/radius
- 381     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0xe8/y2, 7/color, 4/radius
- 382     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2, 7/color, 4/radius
- 383   }
- 384   # cell 1: conveyors from neighboring inputs to sum node
- 385   draw-monotonic-bezier screen, 0x1e0/x0  0x40/y0,  0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
- 386   draw-monotonic-bezier screen, 0x1e0/x0  0xe8/y0,  0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
- 387   draw-monotonic-bezier screen, 0x1e0/x0 0x1a0/y0,  0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
- 388   draw-monotonic-bezier screen, 0x290/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
- 389   draw-monotonic-bezier screen, 0x290/x0 0x1a0/y0,  0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
- 390   draw-monotonic-bezier screen, 0x340/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
- 391   draw-monotonic-bezier screen, 0x340/x0  0xe8/y0,  0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys,  4/color
- 392   draw-monotonic-bezier screen, 0x340/x0 0x1a0/y0,  0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
- 393   # cell 1: conveyors from filter to outputs
- 394   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2,  0x2a/color
- 395   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2,  0x2a/color
- 396   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2,  0x2a/color
- 397   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1  0x80/y1, 0x290/x2  0x80/y2,  0x2a/color
- 398   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1 0x160/y1, 0x290/x2 0x160/y2,  0x2a/color
- 399   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2,  0x2a/color
- 400   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1  0x300/x2  0xe8/y2,  0x2a/color
- 401   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2,  0x2a/color
- 402   # cell 1: time-variant portion: 16 repeating steps
- 403   $render1:cell1: {
- 404     var tick-a/eax: (addr int) <- get self, tick
- 405     var progress/eax: int <- copy *tick-a
- 406     progress <- and 0xf
- 407     # cell 1: 7 time steps for getting inputs to sum
- 408     {
- 409       compare progress, 7
- 410       break-if->=
- 411       var u/xmm7: float <- convert progress
- 412       var six/eax: int <- copy 6
- 413       var six-f/xmm0: float <- convert six
- 414       u <- divide six-f
- 415       # points on conveyors from neighboring cells
- 416       draw-bezier-point screen, u, 0x1e0/x0  0x40/y0, 0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 417       draw-bezier-point screen, u, 0x1e0/x0  0xe8/y0, 0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 418       draw-bezier-point screen, u, 0x1e0/x0 0x1a0/y0, 0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 419       draw-bezier-point screen, u, 0x290/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 420       draw-bezier-point screen, u, 0x290/x0 0x1a0/y0, 0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 421       draw-bezier-point screen, u, 0x340/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 422       draw-bezier-point screen, u, 0x340/x0  0xe8/y0, 0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 423       draw-bezier-point screen, u, 0x340/x0 0x1a0/y0, 0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
- 424       break $render1:cell1
- 425     }
- 426     # cell 1: two time steps for getting count to filter
- 427     progress <- subtract 7
- 428     {
- 429       compare progress, 2
- 430       break-if->=
- 431       break $render1:cell1
- 432     }
- 433     # cell 1: final 7 time steps for updating output
- 434     progress <- subtract 2
- 435     # cell 1: points on conveyors to outputs
- 436     var u/xmm7: float <- convert progress
- 437     var six/eax: int <- copy 6
- 438     var six-f/xmm0: float <- convert six
- 439     u <- divide six-f
- 440     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2, 7/color, 4/radius
- 441     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2, 7/color, 4/radius
- 442     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2, 7/color, 4/radius
- 443     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf  0x80/y1, 0x290/x2  0x80/y2, 7/color, 4/radius
- 444     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf 0x160/y1, 0x290/x2 0x160/y2, 7/color, 4/radius
- 445     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2, 7/color, 4/radius
- 446     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0xe8/y2, 7/color, 4/radius
- 447     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2, 7/color, 4/radius
- 448   }
- 449   # cell 2: conveyors from neighboring inputs to sum node
- 450   draw-monotonic-bezier screen,  0xc0/x0 0x160/y0,  0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
- 451   draw-monotonic-bezier screen,  0xc0/x0 0x208/y0,   0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
- 452   draw-monotonic-bezier screen,  0xc0/x0 0x2c0/y0,   0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
- 453   draw-monotonic-bezier screen, 0x170/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
- 454   draw-monotonic-bezier screen, 0x170/x0 0x2c0/y0,  0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
- 455   draw-monotonic-bezier screen, 0x220/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
- 456   draw-monotonic-bezier screen, 0x220/x0 0x208/y0,  0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys,  4/color
- 457   draw-monotonic-bezier screen, 0x220/x0 0x2c0/y0,  0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
- 458   # cell 2: conveyors from filter to outputs
- 459   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2,  0x2a/color
- 460   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2,  0x2a/color
- 461   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2,  0x2a/color
- 462   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x1a0/y1, 0x170/x2 0x1a0/y2,  0x2a/color
- 463   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x280/y1, 0x170/x2 0x280/y2,  0x2a/color
- 464   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2,  0x2a/color
- 465   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1  0x1e0/x2 0x208/y2,  0x2a/color
- 466   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2,  0x2a/color
- 467   # cell 2: time-variant portion: 16 repeating steps
- 468   $render1:cell2: {
- 469     var tick-a/eax: (addr int) <- get self, tick
- 470     var progress/eax: int <- copy *tick-a
- 471     progress <- and 0xf
- 472     # cell 2: 7 time steps for getting inputs to sum
- 473     {
- 474       compare progress, 7
- 475       break-if->=
- 476       var u/xmm7: float <- convert progress
- 477       var six/eax: int <- copy 6
- 478       var six-f/xmm0: float <- convert six
- 479       u <- divide six-f
- 480       # points on conveyors from neighboring cells
- 481       draw-bezier-point screen, u,  0xc0/x0 0x160/y0, 0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 482       draw-bezier-point screen, u,  0xc0/x0 0x208/y0,  0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 483       draw-bezier-point screen, u,  0xc0/x0 0x2c0/y0,  0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 484       draw-bezier-point screen, u, 0x170/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 485       draw-bezier-point screen, u, 0x170/x0 0x2c0/y0, 0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 486       draw-bezier-point screen, u, 0x220/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 487       draw-bezier-point screen, u, 0x220/x0 0x208/y0, 0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 488       draw-bezier-point screen, u, 0x220/x0 0x2c0/y0, 0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
- 489       break $render1:cell2
- 490     }
- 491     # cell 2: two time steps for getting count to filter
- 492     progress <- subtract 7
- 493     {
- 494       compare progress, 2
- 495       break-if->=
- 496       break $render1:cell2
- 497     }
- 498     # cell 2: final 7 time steps for updating output
- 499     progress <- subtract 2
- 500     # cell 2: points on conveyors to outputs
- 501     var u/xmm7: float <- convert progress
- 502     var six/eax: int <- copy 6
- 503     var six-f/xmm0: float <- convert six
- 504     u <- divide six-f
- 505     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2, 7/color, 4/radius
- 506     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2, 7/color, 4/radius
- 507     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2, 7/color, 4/radius
- 508     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x1a0/y1, 0x170/x2 0x1a0/y2, 7/color, 4/radius
- 509     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x280/y1, 0x170/x2 0x280/y2, 7/color, 4/radius
- 510     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2, 7/color, 4/radius
- 511     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x208/y2, 7/color, 4/radius
- 512     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2, 7/color, 4/radius
- 513   }
- 514   # cell 3: conveyors from neighboring inputs to sum node
- 515   draw-monotonic-bezier screen, 0x1e0/x0 0x160/y0,  0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
- 516   draw-monotonic-bezier screen, 0x1e0/x0 0x208/y0,  0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
- 517   draw-monotonic-bezier screen, 0x1e0/x0 0x2c0/y0,  0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
- 518   draw-monotonic-bezier screen, 0x290/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
- 519   draw-monotonic-bezier screen, 0x290/x0 0x2c0/y0,  0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
- 520   draw-monotonic-bezier screen, 0x340/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
- 521   draw-monotonic-bezier screen, 0x340/x0 0x208/y0,  0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys,  4/color
- 522   draw-monotonic-bezier screen, 0x340/x0 0x2c0/y0,  0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
- 523   # cell 3: conveyors from filter to outputs
- 524   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2,  0x2a/color
- 525   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2,  0x2a/color
- 526   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2,  0x2a/color
- 527   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x1a0/y1, 0x290/x2 0x1a0/y2,  0x2a/color
- 528   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x280/y1, 0x290/x2 0x280/y2,  0x2a/color
- 529   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2,  0x2a/color
- 530   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1  0x300/x2 0x208/y2,  0x2a/color
- 531   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2,  0x2a/color
- 532   # cell 3: time-variant portion: 16 repeating steps
- 533   $render1:cell3: {
- 534     var tick-a/eax: (addr int) <- get self, tick
- 535     var progress/eax: int <- copy *tick-a
- 536     progress <- and 0xf
- 537     # cell 3: 7 time steps for getting inputs to sum
- 538     {
- 539       compare progress, 7
- 540       break-if->=
- 541       var u/xmm7: float <- convert progress
- 542       var six/eax: int <- copy 6
- 543       var six-f/xmm0: float <- convert six
- 544       u <- divide six-f
- 545       # points on conveyors from neighboring cells
- 546       draw-bezier-point screen, u, 0x1e0/x0 0x160/y0, 0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 547       draw-bezier-point screen, u, 0x1e0/x0 0x208/y0, 0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 548       draw-bezier-point screen, u, 0x1e0/x0 0x2c0/y0, 0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 549       draw-bezier-point screen, u, 0x290/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 550       draw-bezier-point screen, u, 0x290/x0 0x2c0/y0, 0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 551       draw-bezier-point screen, u, 0x340/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 552       draw-bezier-point screen, u, 0x340/x0 0x208/y0, 0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 553       draw-bezier-point screen, u, 0x340/x0 0x2c0/y0, 0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
- 554       break $render1:cell3
- 555     }
- 556     # cell 3: two time steps for getting count to filter
- 557     progress <- subtract 7
- 558     {
- 559       compare progress, 2
- 560       break-if->=
- 561       break $render1:cell3
- 562     }
- 563     # cell 3: final 7 time steps for updating output
- 564     progress <- subtract 2
- 565     # cell 3: points on conveyors to outputs
- 566     var u/xmm7: float <- convert progress
- 567     var six/eax: int <- copy 6
- 568     var six-f/xmm0: float <- convert six
- 569     u <- divide six-f
- 570     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2, 7/color, 4/radius
- 571     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2, 7/color, 4/radius
- 572     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2, 7/color, 4/radius
- 573     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x1a0/y1, 0x290/x2 0x1a0/y2, 7/color, 4/radius
- 574     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x280/y1, 0x290/x2 0x280/y2, 7/color, 4/radius
- 575     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2, 7/color, 4/radius
- 576     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x208/y2, 7/color, 4/radius
- 577     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2, 7/color, 4/radius
- 578   }
- 579 }
- 580 
- 581 fn draw-bezier-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int, radius: int {
- 582   var _cy/eax: int <- bezier-point u, y0, y1, y2
- 583   var cy/ecx: int <- copy _cy
- 584   var cx/eax: int <- bezier-point u, x0, x1, x2
- 585   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
- 586 }
- 587 
- 588 fn draw-linear-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, color: int, radius: int {
- 589   var _cy/eax: int <- line-point u, y0, y1
- 590   var cy/ecx: int <- copy _cy
- 591   var cx/eax: int <- line-point u, x0, x1
- 592   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
- 593 }
- 594 
- 595 fn edit keyboard: (addr keyboard), _self: (addr environment) {
- 596   var self/esi: (addr environment) <- copy _self
- 597   var key/eax: byte <- read-key keyboard
- 598   # space: play/pause
- 599   {
- 600     compare key, 0x20/space
- 601     break-if-!=
- 602     var play?/eax: (addr boolean) <- get self, play?
- 603     compare *play?, 0/false
- 604     {
- 605       break-if-=
- 606       copy-to *play?, 0/false
- 607       return
- 608     }
- 609     copy-to *play?, 1/true
- 610     return
- 611   }
- 612   # 0: back to start
- 613   {
- 614     compare key, 0x30/0
- 615     break-if-!=
- 616     clear-environment self
- 617     return
- 618   }
- 619   # l: loop from here to start
- 620   {
- 621     compare key, 0x6c/l
- 622     break-if-!=
- 623     var tick-a/eax: (addr int) <- get self, tick
- 624     var tick/eax: int <- copy *tick-a
- 625     var loop/ecx: (addr int) <- get self, loop
- 626     copy-to *loop, tick
- 627     return
- 628   }
- 629   # L: reset loop
- 630   {
- 631     compare key, 0x4c/L
- 632     break-if-!=
- 633     var loop/eax: (addr int) <- get self, loop
- 634     copy-to *loop, 0
- 635     return
- 636   }
- 637   # -: zoom out
- 638   {
- 639     compare key, 0x2d/-
- 640     break-if-!=
- 641     var zoom/eax: (addr int) <- get self, zoom
- 642     compare *zoom, 1
- 643     {
- 644       break-if-!=
- 645       copy-to *zoom, 4
- 646     }
- 647     compare *zoom, 0
- 648     {
- 649       break-if-!=
- 650       copy-to *zoom, 1
- 651     }
- 652     # set tick to a multiple of zoom
- 653     var tick-a/edx: (addr int) <- get self, tick
- 654     clear-lowest-bits tick-a, *zoom
- 655     return
- 656   }
- 657   # +: zoom in
- 658   {
- 659     compare key, 0x2b/+
- 660     break-if-!=
- 661     var zoom/eax: (addr int) <- get self, zoom
- 662     compare *zoom, 1
- 663     {
- 664       break-if-!=
- 665       copy-to *zoom, 0
- 666     }
- 667     compare *zoom, 4
- 668     {
- 669       break-if-!=
- 670       copy-to *zoom, 1
- 671     }
- 672     # set tick to a multiple of zoom
- 673     var tick-a/edx: (addr int) <- get self, tick
- 674     clear-lowest-bits tick-a, *zoom
- 675     return
- 676   }
- 677 }
- 678 
- 679 fn step _self: (addr environment) {
- 680   var self/esi: (addr environment) <- copy _self
- 681   var tick-a/ecx: (addr int) <- get self, tick
- 682   var zoom/edx: (addr int) <- get self, zoom
- 683   compare *zoom, 0
- 684   {
- 685     break-if-!=
- 686     increment *tick-a
- 687   }
- 688   compare *zoom, 1
- 689   {
- 690     break-if-!=
- 691     # I wanted to speed up time, but that doesn't seem very usable.
- 692 #?     add-to *tick-a, 2
- 693     increment *tick-a
- 694   }
- 695   compare *zoom, 4
- 696   {
- 697     break-if-!=
- 698     add-to *tick-a, 0x10
- 699   }
- 700   var tick/eax: int <- copy *tick-a
- 701   tick <- and 0xf
- 702   compare tick, 0
- 703   {
- 704     break-if-!=
- 705     step4 self
- 706   }
- 707   var loop-a/eax: (addr int) <- get self, loop
- 708   compare *loop-a, 0
- 709   {
- 710     break-if-=
- 711     var loop/eax: int <- copy *loop-a
- 712     compare *tick-a, loop
- 713     break-if-<
- 714     clear-environment self
- 715   }
- 716 }
- 717 
- 718 fn initialize-environment _self: (addr environment) {
- 719   var self/esi: (addr environment) <- copy _self
- 720   var zoom/eax: (addr int) <- get self, zoom
- 721   copy-to *zoom, 0
- 722   var play?/eax: (addr boolean) <- get self, play?
- 723   copy-to *play?, 1/true
- 724   var data-ah/eax: (addr handle array handle array cell) <- get self, data
- 725   populate data-ah, 0x100
- 726   var data/eax: (addr array handle array cell) <- lookup *data-ah
- 727   var y/ecx: int <- copy 0
- 728   {
- 729     compare y, 0xc0
- 730     break-if->=
- 731     var dest-ah/eax: (addr handle array cell) <- index data, y
- 732     populate dest-ah, 0x100
- 733     y <- increment
- 734     loop
- 735   }
- 736   set self, 0x80, 0x5f, 1/alive
- 737   set self, 0x81, 0x5f, 1/alive
- 738   set self, 0x7f, 0x60, 1/alive
- 739   set self, 0x80, 0x60, 1/alive
- 740   set self, 0x80, 0x61, 1/alive
- 741   flush self
- 742 }
- 743 
- 744 fn clear-environment _self: (addr environment) {
- 745   var self/esi: (addr environment) <- copy _self
- 746   var tick/eax: (addr int) <- get self, tick
- 747   copy-to *tick, 0
- 748   # don't touch zoom or play settings
- 749   var data-ah/eax: (addr handle array handle array cell) <- get self, data
- 750   var data/eax: (addr array handle array cell) <- lookup *data-ah
- 751   var y/ecx: int <- copy 0
- 752   {
- 753     compare y, 0xc0
- 754     break-if->=
- 755     var row-ah/eax: (addr handle array cell) <- index data, y
- 756     var row/eax: (addr array cell) <- lookup *row-ah
- 757     var x/edx: int <- copy 0
- 758     {
- 759       compare x, 0x100
- 760       break-if->=
- 761       var dest/eax: (addr cell) <- index row, x
- 762       clear-object dest
- 763       x <- increment
- 764       loop
- 765     }
- 766     y <- increment
- 767     loop
- 768   }
- 769   set self, 0x80, 0x5f, 1/alive
- 770   set self, 0x81, 0x5f, 1/alive
- 771   set self, 0x7f, 0x60, 1/alive
- 772   set self, 0x80, 0x60, 1/alive
- 773   set self, 0x80, 0x61, 1/alive
- 774   flush self
- 775 }
- 776 
- 777 fn set _self: (addr environment), _x: int, _y: int, _val: boolean {
- 778   var self/esi: (addr environment) <- copy _self
- 779   var data-ah/eax: (addr handle array handle array cell) <- get self, data
- 780   var data/eax: (addr array handle array cell) <- lookup *data-ah
- 781   var y/ecx: int <- copy _y
- 782   var row-ah/eax: (addr handle array cell) <- index data, y
- 783   var row/eax: (addr array cell) <- lookup *row-ah
- 784   var x/ecx: int <- copy _x
- 785   var cell/eax: (addr cell) <- index row, x
- 786   var dest/eax: (addr boolean) <- get cell, next
- 787   var val/ecx: boolean <- copy _val
- 788   copy-to *dest, val
- 789 }
- 790 
- 791 fn state _self: (addr environment), _x: int, _y: int -> _/eax: boolean {
- 792   var self/esi: (addr environment) <- copy _self
- 793   var x/ecx: int <- copy _x
- 794   var y/edx: int <- copy _y
- 795   # clip at the edge
- 796   compare x, 0
- 797   {
- 798     break-if->=
- 799     return 0/false
- 800   }
- 801   compare y, 0
- 802   {
- 803     break-if->=
- 804     return 0/false
- 805   }
- 806   compare x, 0x100/width
- 807   {
- 808     break-if-<
- 809     return 0/false
- 810   }
- 811   compare y, 0xc0/height
- 812   {
- 813     break-if-<
- 814     return 0/false
- 815   }
- 816   var data-ah/eax: (addr handle array handle array cell) <- get self, data
- 817   var data/eax: (addr array handle array cell) <- lookup *data-ah
- 818   var row-ah/eax: (addr handle array cell) <- index data, y
- 819   var row/eax: (addr array cell) <- lookup *row-ah
- 820   var cell/eax: (addr cell) <- index row, x
- 821   var src/eax: (addr boolean) <- get cell, curr
- 822   return *src
- 823 }
- 824 
- 825 fn state-color _self: (addr environment), x: int, y: int -> _/eax: int {
- 826   var self/esi: (addr environment) <- copy _self
- 827   var color/ecx: int <- copy 0x1a/dead
- 828   {
- 829     var state/eax: boolean <- state self, x, y
- 830     compare state, 0/dead
- 831     break-if-=
- 832     color <- copy 0xf/alive
- 833   }
- 834   return color
- 835 }
- 836 
- 837 fn flush  _self: (addr environment) {
- 838   var self/esi: (addr environment) <- copy _self
- 839   var data-ah/eax: (addr handle array handle array cell) <- get self, data
- 840   var _data/eax: (addr array handle array cell) <- lookup *data-ah
- 841   var data/esi: (addr array handle array cell) <- copy _data
- 842   var y/ecx: int <- copy 0
- 843   {
- 844     compare y, 0xc0/height
- 845     break-if->=
- 846     var row-ah/eax: (addr handle array cell) <- index data, y
- 847     var _row/eax: (addr array cell) <- lookup *row-ah
- 848     var row/ebx: (addr array cell) <- copy _row
- 849     var x/edx: int <- copy 0
- 850     {
- 851       compare x, 0x100/width
- 852       break-if->=
- 853       var cell-a/eax: (addr cell) <- index row, x
- 854       var curr-a/edi: (addr boolean) <- get cell-a, curr
- 855       var next-a/esi: (addr boolean) <- get cell-a, next
- 856       var val/eax: boolean <- copy *next-a
- 857       copy-to *curr-a, val
- 858       copy-to *next-a, 0/dead
- 859       x <- increment
- 860       loop
- 861     }
- 862     y <- increment
- 863     loop
- 864   }
- 865 }
- 866 
- 867 fn render4 screen: (addr screen), _self: (addr environment) {
- 868   var self/esi: (addr environment) <- copy _self
- 869   var y/ecx: int <- copy 0
- 870   {
- 871     compare y, 0xc0/height
- 872     break-if->=
- 873     var x/edx: int <- copy 0
- 874     {
- 875       compare x, 0x100/width
- 876       break-if->=
- 877       var state/eax: boolean <- state self, x, y
- 878       compare state, 0/false
- 879       {
- 880         break-if-=
- 881         render4-cell screen, x, y, 0xf/alive
- 882       }
- 883       compare state, 0/false
- 884       {
- 885         break-if-!=
- 886         render4-cell screen, x, y, 0x1a/dead
- 887       }
- 888       x <- increment
- 889       loop
- 890     }
- 891     y <- increment
- 892     loop
- 893   }
- 894 }
- 895 
- 896 fn render4-cell screen: (addr screen), x: int, y: int, color: int {
- 897   var xmin/eax: int <- copy x
- 898   xmin <- shift-left 2
- 899   var xmax/ecx: int <- copy xmin
- 900   xmax <- add 4
- 901   var ymin/edx: int <- copy y
- 902   ymin <- shift-left 2
- 903   var ymax/ebx: int <- copy ymin
- 904   ymax <- add 4
- 905   draw-rect screen, xmin ymin, xmax ymax, color
- 906 }
- 907 
- 908 fn step4 _self: (addr environment) {
- 909   var self/esi: (addr environment) <- copy _self
- 910   var y/ecx: int <- copy 0
- 911   {
- 912     compare y, 0xc0/height
- 913     break-if->=
- 914     var x/edx: int <- copy 0
- 915     {
- 916       compare x, 0x100/width
- 917       break-if->=
- 918       var n/eax: int <- num-live-neighbors self, x, y
- 919       # if neighbors < 2, die of loneliness
- 920       {
- 921         compare n, 2
- 922         break-if->=
- 923         set self, x, y, 0/dead
- 924       }
- 925       # if neighbors > 3, die of overcrowding
- 926       {
- 927         compare n, 3
- 928         break-if-<=
- 929         set self, x, y, 0/dead
- 930       }
- 931       # if neighbors = 2, preserve state
- 932       {
- 933         compare n, 2
- 934         break-if-!=
- 935         var old-state/eax: boolean <- state self, x, y
- 936         set self, x, y, old-state
- 937       }
- 938       # if neighbors = 3, cell quickens to life
- 939       {
- 940         compare n, 3
- 941         break-if-!=
- 942         set self, x, y, 1/live
- 943       }
- 944       x <- increment
- 945       loop
- 946     }
- 947     y <- increment
- 948     loop
- 949   }
- 950   flush self
- 951 }
- 952 
- 953 fn num-live-neighbors _self: (addr environment), x: int, y: int -> _/eax: int {
- 954   var self/esi: (addr environment) <- copy _self
- 955   var result/edi: int <- copy 0
- 956   # row above: zig
- 957   decrement y
- 958   decrement x
- 959   var s/eax: boolean <- state self, x, y
- 960   {
- 961     compare s, 0/false
- 962     break-if-=
- 963     result <- increment
- 964   }
- 965   increment x
- 966   s <- state self, x, y
- 967   {
- 968     compare s, 0/false
- 969     break-if-=
- 970     result <- increment
- 971   }
- 972   increment x
- 973   s <- state self, x, y
- 974   {
- 975     compare s, 0/false
- 976     break-if-=
- 977     result <- increment
- 978   }
- 979   # curr row: zag
- 980   increment y
- 981   s <- state self, x, y
- 982   {
- 983     compare s, 0/false
- 984     break-if-=
- 985     result <- increment
- 986   }
- 987   subtract-from x, 2
- 988   s <- state self, x, y
- 989   {
- 990     compare s, 0/false
- 991     break-if-=
- 992     result <- increment
- 993   }
- 994   # row below: zig
- 995   increment y
- 996   s <- state self, x, y
- 997   {
- 998     compare s, 0/false
- 999     break-if-=
-1000     result <- increment
-1001   }
-1002   increment x
-1003   s <- state self, x, y
-1004   {
-1005     compare s, 0/false
-1006     break-if-=
-1007     result <- increment
-1008   }
-1009   increment x
-1010   s <- state self, x, y
-1011   {
-1012     compare s, 0/false
-1013     break-if-=
-1014     result <- increment
-1015   }
-1016   return result
-1017 }
-1018 
-1019 fn linger _self: (addr environment) {
-1020   var self/esi: (addr environment) <- copy _self
-1021   var i/ecx: int <- copy 0
-1022   {
-1023     compare i, 0x10000000  # Kartik's Linux with -enable-kvm
-1024 #?     compare i, 0x8000000  # Kartik's Mac with -accel tcg
-1025     break-if->=
-1026     i <- increment
-1027     loop
-1028   }
-1029 }
-
- - - diff --git a/html/img.mu.html b/html/img.mu.html deleted file mode 100644 index 19bd7959..00000000 --- a/html/img.mu.html +++ /dev/null @@ -1,1217 +0,0 @@ - - - - -Mu - img.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/img.mu -
-   1 # load an image from disk and display it on screen
-   2 #
-   3 # To build:
-   4 #   $ ./translate shell/*.mu                        # generates code.img
-   5 # Load a pbm, pgm or ppm image (no more than 255 levels)
-   6 #   $ dd if=/dev/zero of=data.img count=20160
-   7 #   $ cat x.pbm |dd of=data.img conv=notrunc
-   8 # or
-   9 #   $ cat t.pgm |dd of=data.img conv=notrunc
-  10 # or
-  11 #   $ cat snail.ppm |dd of=data.img conv=notrunc
-  12 # To run:
-  13 #   $ qemu-system-i386 -hda code.img -hdb data.img
-  14 
-  15 type image {
-  16   type: int  # supported types:
-  17              #  1: portable bitmap (P1) - pixels 0 or 1
-  18              #  2: portable greymap (P2) - pixels 1-byte greyscale values
-  19              #  3: portable pixmap (P3) - pixels 3-byte rgb values
-  20   max: int
-  21   width: int
-  22   height: int
-  23   data: (handle array byte)
-  24 }
-  25 
-  26 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
-  27   var img-storage: image
-  28   var img/esi: (addr image) <- address img-storage
-  29   load-image img, data-disk
-  30   render-image screen, img, 0/x, 0/y, 0x300/width, 0x300/height
-  31 }
-  32 
-  33 fn load-image self: (addr image), data-disk: (addr disk) {
-  34   # data-disk -> stream
-  35   var s-storage: (stream byte 0x200000)  # 512* 0x1000 sectors
-  36   var s/ebx: (addr stream byte) <- address s-storage
-  37   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading sectors from data disk", 3/fg, 0/bg
-  38   move-cursor-to-left-margin-of-next-line 0/screen
-  39   load-sectors data-disk, 0/lba, 0x100/sectors, s
-  40   load-sectors data-disk, 0x100/lba, 0x100/sectors, s
-  41   load-sectors data-disk, 0x200/lba, 0x100/sectors, s
-  42   load-sectors data-disk, 0x300/lba, 0x100/sectors, s
-  43   load-sectors data-disk, 0x400/lba, 0x100/sectors, s
-  44   load-sectors data-disk, 0x500/lba, 0x100/sectors, s
-  45   load-sectors data-disk, 0x600/lba, 0x100/sectors, s
-  46   load-sectors data-disk, 0x700/lba, 0x100/sectors, s
-  47   load-sectors data-disk, 0x800/lba, 0x100/sectors, s
-  48   load-sectors data-disk, 0x900/lba, 0x100/sectors, s
-  49   load-sectors data-disk, 0xa00/lba, 0x100/sectors, s
-  50   load-sectors data-disk, 0xb00/lba, 0x100/sectors, s
-  51   load-sectors data-disk, 0xc00/lba, 0x100/sectors, s
-  52   load-sectors data-disk, 0xd00/lba, 0x100/sectors, s
-  53   load-sectors data-disk, 0xe00/lba, 0x100/sectors, s
-  54   load-sectors data-disk, 0xf00/lba, 0x100/sectors, s
-  55   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "parsing", 3/fg, 0/bg
-  56   move-cursor-to-left-margin-of-next-line 0/screen
-  57   initialize-image self, s
-  58 }
-  59 
-  60 fn initialize-image _self: (addr image), in: (addr stream byte) {
-  61   var self/esi: (addr image) <- copy _self
-  62   var mode-storage: slice
-  63   var mode/ecx: (addr slice) <- address mode-storage
-  64   next-word in, mode
-  65   {
-  66     var P1?/eax: boolean <- slice-equal? mode, "P1"
-  67     compare P1?, 0/false
-  68     break-if-=
-  69     var type-a/eax: (addr int) <- get self, type
-  70     copy-to *type-a, 1/ppm
-  71     initialize-image-from-pbm self, in
-  72     return
-  73   }
-  74   {
-  75     var P2?/eax: boolean <- slice-equal? mode, "P2"
-  76     compare P2?, 0/false
-  77     break-if-=
-  78     var type-a/eax: (addr int) <- get self, type
-  79     copy-to *type-a, 2/pgm
-  80     initialize-image-from-pgm self, in
-  81     return
-  82   }
-  83   {
-  84     var P3?/eax: boolean <- slice-equal? mode, "P3"
-  85     compare P3?, 0/false
-  86     break-if-=
-  87     var type-a/eax: (addr int) <- get self, type
-  88     copy-to *type-a, 3/ppm
-  89     initialize-image-from-ppm self, in
-  90     return
-  91   }
-  92   abort "initialize-image: unrecognized image type"
-  93 }
-  94 
-  95 # dispatch to a few variants with mostly identical boilerplate
-  96 fn render-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
-  97   var img/esi: (addr image) <- copy _img
-  98   var type-a/eax: (addr int) <- get img, type
-  99   {
- 100     compare *type-a, 1/pbm
- 101     break-if-!=
- 102     render-pbm-image screen, img, xmin, ymin, width, height
- 103     return
- 104   }
- 105   {
- 106     compare *type-a, 2/pgm
- 107     break-if-!=
- 108     var img2-storage: image
- 109     var img2/edi: (addr image) <- address img2-storage
- 110     dither-pgm-unordered img, img2
- 111     render-raw-image screen, img2, xmin, ymin, width, height
- 112     return
- 113   }
- 114   {
- 115     compare *type-a, 3/ppm
- 116     break-if-!=
- 117     var img2-storage: image
- 118     var img2/edi: (addr image) <- address img2-storage
- 119     dither-ppm-unordered img, img2
- 120     render-raw-image screen, img2, xmin, ymin, width, height
- 121     return
- 122   }
- 123   abort "render-image: unrecognized image type"
- 124 }
- 125 
- 126 ## helpers
- 127 
- 128 # import a black-and-white ascii bitmap (each pixel is 0 or 1)
- 129 fn initialize-image-from-pbm _self: (addr image), in: (addr stream byte) {
- 130   var self/esi: (addr image) <- copy _self
- 131   var curr-word-storage: slice
- 132   var curr-word/ecx: (addr slice) <- address curr-word-storage
- 133   # load width, height
- 134   next-word in, curr-word
- 135   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
- 136   var width/edx: int <- copy tmp
- 137   next-word in, curr-word
- 138   tmp <- parse-decimal-int-from-slice curr-word
- 139   var height/ebx: int <- copy tmp
- 140   # save width, height
- 141   var dest/eax: (addr int) <- get self, width
- 142   copy-to *dest, width
- 143   dest <- get self, height
- 144   copy-to *dest, height
- 145   # initialize data
- 146   var capacity/edx: int <- copy width
- 147   capacity <- multiply height
- 148   var data-ah/edi: (addr handle array byte) <- get self, data
- 149   populate data-ah, capacity
- 150   var _data/eax: (addr array byte) <- lookup *data-ah
- 151   var data/edi: (addr array byte) <- copy _data
- 152   var i/ebx: int <- copy 0
- 153   {
- 154     compare i, capacity
- 155     break-if->=
- 156     next-word in, curr-word
- 157     var src/eax: int <- parse-decimal-int-from-slice curr-word
- 158     {
- 159       var dest/ecx: (addr byte) <- index data, i
- 160       copy-byte-to *dest, src
- 161     }
- 162     i <- increment
- 163     loop
- 164   }
- 165 }
- 166 
- 167 # render a black-and-white ascii bitmap (each pixel is 0 or 1)
- 168 fn render-pbm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
- 169   var img/esi: (addr image) <- copy _img
- 170   # yratio = height/img->height
- 171   var img-height-a/eax: (addr int) <- get img, height
- 172   var img-height/xmm0: float <- convert *img-height-a
- 173   var yratio/xmm1: float <- convert height
- 174   yratio <- divide img-height
- 175   # xratio = width/img->width
- 176   var img-width-a/eax: (addr int) <- get img, width
- 177   var img-width/ebx: int <- copy *img-width-a
- 178   var img-width-f/xmm0: float <- convert img-width
- 179   var xratio/xmm2: float <- convert width
- 180   xratio <- divide img-width-f
- 181   # esi = img->data
- 182   var img-data-ah/eax: (addr handle array byte) <- get img, data
- 183   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
- 184   var img-data/esi: (addr array byte) <- copy _img-data
- 185   var len/edi: int <- length img-data
- 186   #
- 187   var one/eax: int <- copy 1
- 188   var one-f/xmm3: float <- convert one
- 189   var width-f/xmm4: float <- convert width
- 190   var height-f/xmm5: float <- convert height
- 191   var zero/eax: int <- copy 0
- 192   var zero-f/xmm0: float <- convert zero
- 193   var y/xmm6: float <- copy zero-f
- 194   {
- 195     compare y, height-f
- 196     break-if-float>=
- 197     var imgy-f/xmm5: float <- copy y
- 198     imgy-f <- divide yratio
- 199     var imgy/edx: int <- truncate imgy-f
- 200     var x/xmm7: float <- copy zero-f
- 201     {
- 202       compare x, width-f
- 203       break-if-float>=
- 204       var imgx-f/xmm5: float <- copy x
- 205       imgx-f <- divide xratio
- 206       var imgx/ecx: int <- truncate imgx-f
- 207       var idx/eax: int <- copy imgy
- 208       idx <- multiply img-width
- 209       idx <- add imgx
- 210       # error info in case we rounded wrong and 'index' will fail bounds-check
- 211       compare idx, len
- 212       {
- 213         break-if-<
- 214         set-cursor-position 0/screen, 0x20/x 0x20/y
- 215         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
- 216         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
- 217         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
- 218       }
- 219       var src-a/eax: (addr byte) <- index img-data, idx
- 220       var src/eax: byte <- copy-byte *src-a
- 221       var color-int/eax: int <- copy src
- 222       {
- 223         compare color-int, 0/black
- 224         break-if-=
- 225         color-int <- copy 0xf/white
- 226       }
- 227       var screenx/ecx: int <- convert x
- 228       screenx <- add xmin
- 229       var screeny/edx: int <- convert y
- 230       screeny <- add ymin
- 231       pixel screen, screenx, screeny, color-int
- 232       x <- add one-f
- 233       loop
- 234     }
- 235     y <- add one-f
- 236     loop
- 237   }
- 238 }
- 239 
- 240 # import a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255)
- 241 fn initialize-image-from-pgm _self: (addr image), in: (addr stream byte) {
- 242   var self/esi: (addr image) <- copy _self
- 243   var curr-word-storage: slice
- 244   var curr-word/ecx: (addr slice) <- address curr-word-storage
- 245   # load width, height
- 246   next-word in, curr-word
- 247   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
- 248   var width/edx: int <- copy tmp
- 249   next-word in, curr-word
- 250   tmp <- parse-decimal-int-from-slice curr-word
- 251   var height/ebx: int <- copy tmp
- 252   # check and save color levels
- 253   next-word in, curr-word
- 254   {
- 255     tmp <- parse-decimal-int-from-slice curr-word
- 256     compare tmp, 0xff
- 257     break-if-=
- 258     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "levels of grey is not 255; continuing and hoping for the best", 0x2b/fg 0/bg
- 259   }
- 260   var dest/edi: (addr int) <- get self, max
- 261   copy-to *dest, tmp
- 262   # save width, height
- 263   dest <- get self, width
- 264   copy-to *dest, width
- 265   dest <- get self, height
- 266   copy-to *dest, height
- 267   # initialize data
- 268   var capacity/edx: int <- copy width
- 269   capacity <- multiply height
- 270   var data-ah/edi: (addr handle array byte) <- get self, data
- 271   populate data-ah, capacity
- 272   var _data/eax: (addr array byte) <- lookup *data-ah
- 273   var data/edi: (addr array byte) <- copy _data
- 274   var i/ebx: int <- copy 0
- 275   {
- 276     compare i, capacity
- 277     break-if->=
- 278     next-word in, curr-word
- 279     var src/eax: int <- parse-decimal-int-from-slice curr-word
- 280     {
- 281       var dest/ecx: (addr byte) <- index data, i
- 282       copy-byte-to *dest, src
- 283     }
- 284     i <- increment
- 285     loop
- 286   }
- 287 }
- 288 
- 289 # render a greyscale ascii "greymap" (each pixel is a shade of grey from 0 to 255) by quantizing the shades
- 290 fn render-pgm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
- 291   var img/esi: (addr image) <- copy _img
- 292   # yratio = height/img->height
- 293   var img-height-a/eax: (addr int) <- get img, height
- 294   var img-height/xmm0: float <- convert *img-height-a
- 295   var yratio/xmm1: float <- convert height
- 296   yratio <- divide img-height
- 297   # xratio = width/img->width
- 298   var img-width-a/eax: (addr int) <- get img, width
- 299   var img-width/ebx: int <- copy *img-width-a
- 300   var img-width-f/xmm0: float <- convert img-width
- 301   var xratio/xmm2: float <- convert width
- 302   xratio <- divide img-width-f
- 303   # esi = img->data
- 304   var img-data-ah/eax: (addr handle array byte) <- get img, data
- 305   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
- 306   var img-data/esi: (addr array byte) <- copy _img-data
- 307   var len/edi: int <- length img-data
- 308   #
- 309   var one/eax: int <- copy 1
- 310   var one-f/xmm3: float <- convert one
- 311   var width-f/xmm4: float <- convert width
- 312   var height-f/xmm5: float <- convert height
- 313   var zero/eax: int <- copy 0
- 314   var zero-f/xmm0: float <- convert zero
- 315   var y/xmm6: float <- copy zero-f
- 316   {
- 317     compare y, height-f
- 318     break-if-float>=
- 319     var imgy-f/xmm5: float <- copy y
- 320     imgy-f <- divide yratio
- 321     var imgy/edx: int <- truncate imgy-f
- 322     var x/xmm7: float <- copy zero-f
- 323     {
- 324       compare x, width-f
- 325       break-if-float>=
- 326       var imgx-f/xmm5: float <- copy x
- 327       imgx-f <- divide xratio
- 328       var imgx/ecx: int <- truncate imgx-f
- 329       var idx/eax: int <- copy imgy
- 330       idx <- multiply img-width
- 331       idx <- add imgx
- 332       # error info in case we rounded wrong and 'index' will fail bounds-check
- 333       compare idx, len
- 334       {
- 335         break-if-<
- 336         set-cursor-position 0/screen, 0x20/x 0x20/y
- 337         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
- 338         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
- 339         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
- 340       }
- 341       var src-a/eax: (addr byte) <- index img-data, idx
- 342       var src/eax: byte <- copy-byte *src-a
- 343       var color-int/eax: int <- nearest-grey src
- 344       var screenx/ecx: int <- convert x
- 345       screenx <- add xmin
- 346       var screeny/edx: int <- convert y
- 347       screeny <- add ymin
- 348       pixel screen, screenx, screeny, color-int
- 349       x <- add one-f
- 350       loop
- 351     }
- 352     y <- add one-f
- 353     loop
- 354   }
- 355 }
- 356 
- 357 fn nearest-grey level-255: byte -> _/eax: int {
- 358   var result/eax: int <- copy level-255
- 359   result <- shift-right 4
- 360   result <- add 0x10
- 361   return result
- 362 }
- 363 
- 364 fn dither-pgm-unordered-monochrome _src: (addr image), _dest: (addr image) {
- 365   var src/esi: (addr image) <- copy _src
- 366   var dest/edi: (addr image) <- copy _dest
- 367   # copy 'width'
- 368   var src-width-a/eax: (addr int) <- get src, width
- 369   var tmp/eax: int <- copy *src-width-a
- 370   var src-width: int
- 371   copy-to src-width, tmp
- 372   {
- 373     var dest-width-a/edx: (addr int) <- get dest, width
- 374     copy-to *dest-width-a, tmp
- 375   }
- 376   # copy 'height'
- 377   var src-height-a/eax: (addr int) <- get src, height
- 378   var tmp/eax: int <- copy *src-height-a
- 379   var src-height: int
- 380   copy-to src-height, tmp
- 381   {
- 382     var dest-height-a/ecx: (addr int) <- get dest, height
- 383     copy-to *dest-height-a, tmp
- 384   }
- 385   # transform 'data'
- 386   var capacity/ebx: int <- copy src-width
- 387   capacity <- multiply src-height
- 388   var dest/edi: (addr image) <- copy _dest
- 389   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
- 390   populate dest-data-ah, capacity
- 391   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
- 392   var dest-data/edi: (addr array byte) <- copy _dest-data
- 393   # needs a buffer to temporarily hold more than 256 levels of precision
- 394   var errors-storage: (array int 0xc0000)
- 395   var errors/ebx: (addr array int) <- address errors-storage
- 396   var src-data-ah/eax: (addr handle array byte) <- get src, data
- 397   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
- 398   var src-data/esi: (addr array byte) <- copy _src-data
- 399   var y/edx: int <- copy 0
- 400   {
- 401     compare y, src-height
- 402     break-if->=
- 403     var x/ecx: int <- copy 0
- 404     {
- 405       compare x, src-width
- 406       break-if->=
- 407       var curr/eax: byte <- _read-pgm-buffer src-data, x, y, src-width
- 408       var curr-int/eax: int <- copy curr
- 409       curr-int <- shift-left 0x10  # we have 32 bits; we'll use 16 bits for the fraction and leave 8 for unanticipated overflow
- 410       var error/esi: int <- _read-dithering-error errors, x, y, src-width
- 411       error <- add curr-int
- 412       $_dither-pgm-unordered-monochrome:update-error: {
- 413         compare error, 0x800000
- 414         {
- 415           break-if->=
- 416           _write-raw-buffer dest-data, x, y, src-width, 0/black
- 417           break $_dither-pgm-unordered-monochrome:update-error
- 418         }
- 419         _write-raw-buffer dest-data, x, y, src-width, 1/white
- 420         error <- subtract 0xff0000
- 421       }
- 422       _diffuse-dithering-error-floyd-steinberg errors, x, y, src-width, src-height, error
- 423       x <- increment
- 424       loop
- 425     }
- 426     move-cursor-to-left-margin-of-next-line 0/screen
- 427     y <- increment
- 428     loop
- 429   }
- 430 }
- 431 
- 432 fn dither-pgm-unordered _src: (addr image), _dest: (addr image) {
- 433   var src/esi: (addr image) <- copy _src
- 434   var dest/edi: (addr image) <- copy _dest
- 435   # copy 'width'
- 436   var src-width-a/eax: (addr int) <- get src, width
- 437   var tmp/eax: int <- copy *src-width-a
- 438   var src-width: int
- 439   copy-to src-width, tmp
- 440   {
- 441     var dest-width-a/edx: (addr int) <- get dest, width
- 442     copy-to *dest-width-a, tmp
- 443   }
- 444   # copy 'height'
- 445   var src-height-a/eax: (addr int) <- get src, height
- 446   var tmp/eax: int <- copy *src-height-a
- 447   var src-height: int
- 448   copy-to src-height, tmp
- 449   {
- 450     var dest-height-a/ecx: (addr int) <- get dest, height
- 451     copy-to *dest-height-a, tmp
- 452   }
- 453   # compute scaling factor 255/max
- 454   var target-scale/eax: int <- copy 0xff
- 455   var scale-f/xmm7: float <- convert target-scale
- 456   var src-max-a/eax: (addr int) <- get src, max
- 457   var tmp-f/xmm0: float <- convert *src-max-a
- 458   scale-f <- divide tmp-f
- 459   # transform 'data'
- 460   var capacity/ebx: int <- copy src-width
- 461   capacity <- multiply src-height
- 462   var dest/edi: (addr image) <- copy _dest
- 463   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
- 464   populate dest-data-ah, capacity
- 465   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
- 466   var dest-data/edi: (addr array byte) <- copy _dest-data
- 467   # needs a buffer to temporarily hold more than 256 levels of precision
- 468   var errors-storage: (array int 0xc0000)
- 469   var errors/ebx: (addr array int) <- address errors-storage
- 470   var src-data-ah/eax: (addr handle array byte) <- get src, data
- 471   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
- 472   var src-data/esi: (addr array byte) <- copy _src-data
- 473   var y/edx: int <- copy 0
- 474   {
- 475     compare y, src-height
- 476     break-if->=
- 477     var x/ecx: int <- copy 0
- 478     {
- 479       compare x, src-width
- 480       break-if->=
- 481       var initial-color/eax: byte <- _read-pgm-buffer src-data, x, y, src-width
- 482       # . scale to 255 levels
- 483       var initial-color-int/eax: int <- copy initial-color
- 484       var initial-color-f/xmm0: float <- convert initial-color-int
- 485       initial-color-f <- multiply scale-f
- 486       initial-color-int <- convert initial-color-f
- 487       var error/esi: int <- _read-dithering-error errors, x, y, src-width
- 488       # error += (initial-color << 16)
- 489       {
- 490         var tmp/eax: int <- copy initial-color-int
- 491         tmp <- shift-left 0x10  # we have 32 bits; we'll use 16 bits for the fraction and leave 8 for unanticipated overflow
- 492         error <- add tmp
- 493       }
- 494       # nearest-color = nearest(error >> 16)
- 495       var nearest-color/eax: int <- copy error
- 496       nearest-color <- shift-right-signed 0x10
- 497       {
- 498         compare nearest-color, 0
- 499         break-if->=
- 500         nearest-color <- copy 0
- 501       }
- 502       {
- 503         compare nearest-color, 0xf0
- 504         break-if-<=
- 505         nearest-color <- copy 0xf0
- 506       }
- 507       # . truncate last 4 bits
- 508       nearest-color <- and 0xf0
- 509       # error -= (nearest-color << 16)
- 510       {
- 511         var tmp/eax: int <- copy nearest-color
- 512         tmp <- shift-left 0x10
- 513         error <- subtract tmp
- 514       }
- 515       # color-index = (nearest-color >> 4 + 16)
- 516       var color-index/eax: int <- copy nearest-color
- 517       color-index <- shift-right 4
- 518       color-index <- add 0x10
- 519       var color-index-byte/eax: byte <- copy-byte color-index
- 520       _write-raw-buffer dest-data, x, y, src-width, color-index-byte
- 521       _diffuse-dithering-error-floyd-steinberg errors, x, y, src-width, src-height, error
- 522       x <- increment
- 523       loop
- 524     }
- 525     y <- increment
- 526     loop
- 527   }
- 528 }
- 529 
- 530 # Use Floyd-Steinberg algorithm for diffusing error at x, y in a 2D grid of
- 531 # dimensions (width, height)
- 532 #
- 533 # https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html
- 534 #
- 535 # Error is currently a fixed-point number with 16-bit fraction. But
- 536 # interestingly this function doesn't care about that.
- 537 fn _diffuse-dithering-error-floyd-steinberg errors: (addr array int), x: int, y: int, width: int, height: int, error: int {
- 538   {
- 539     compare error, 0
- 540     break-if-!=
- 541     return
- 542   }
- 543   var width-1/esi: int <- copy width
- 544   width-1 <- decrement
- 545   var height-1/edi: int <- copy height
- 546   height-1 <- decrement
- 547   # delta = error/16
- 548 #?   show-errors errors, width, height, x, y
- 549   var delta/ecx: int <- copy error
- 550   delta <- shift-right-signed 4
- 551   # In Floyd-Steinberg, each pixel X transmits its errors to surrounding
- 552   # pixels in the following proportion:
- 553   #           X     7/16
- 554   #     3/16  5/16  1/16
- 555   var x/edx: int <- copy x
- 556   {
- 557     compare x, width-1
- 558     break-if->=
- 559     var tmp/eax: int <- copy 7
- 560     tmp <- multiply delta
- 561     var xright/edx: int <- copy x
- 562     xright <- increment
- 563     _accumulate-dithering-error errors, xright, y, width, tmp
- 564   }
- 565   var y/ebx: int <- copy y
- 566   {
- 567     compare y, height-1
- 568     break-if-<
- 569     return
- 570   }
- 571   var ybelow: int
- 572   copy-to ybelow, y
- 573   increment ybelow
- 574   {
- 575     compare x, 0
- 576     break-if-<=
- 577     var tmp/eax: int <- copy 3
- 578     tmp <- multiply delta
- 579     var xleft/edx: int <- copy x
- 580     xleft <- decrement
- 581     _accumulate-dithering-error errors, xleft, ybelow, width, tmp
- 582   }
- 583   {
- 584     var tmp/eax: int <- copy 5
- 585     tmp <- multiply delta
- 586     _accumulate-dithering-error errors, x, ybelow, width, tmp
- 587   }
- 588   {
- 589     compare x, width-1
- 590     break-if->=
- 591     var xright/edx: int <- copy x
- 592     xright <- increment
- 593     _accumulate-dithering-error errors, xright, ybelow, width, delta
- 594   }
- 595 #?   show-errors errors, width, height, x, y
- 596 }
- 597 
- 598 fn _accumulate-dithering-error errors: (addr array int), x: int, y: int, width: int, error: int {
- 599   var curr/esi: int <- _read-dithering-error errors, x, y, width
- 600   curr <- add error
- 601   _write-dithering-error errors, x, y, width, curr
- 602 }
- 603 
- 604 fn _read-dithering-error _errors: (addr array int), x: int, y: int, width: int -> _/esi: int {
- 605   var errors/esi: (addr array int) <- copy _errors
- 606   var idx/ecx: int <- copy y
- 607   idx <- multiply width
- 608   idx <- add x
- 609   var result-a/eax: (addr int) <- index errors, idx
- 610   return *result-a
- 611 }
- 612 
- 613 fn _write-dithering-error _errors: (addr array int), x: int, y: int, width: int, val: int {
- 614   var errors/esi: (addr array int) <- copy _errors
- 615   var idx/ecx: int <- copy y
- 616   idx <- multiply width
- 617   idx <- add x
- 618 #?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 7/fg 0/bg
- 619 #?   move-cursor-to-left-margin-of-next-line 0/screen
- 620   var src/eax: int <- copy val
- 621   var dest-a/edi: (addr int) <- index errors, idx
- 622   copy-to *dest-a, src
- 623 }
- 624 
- 625 fn _read-pgm-buffer _buf: (addr array byte), x: int, y: int, width: int -> _/eax: byte {
- 626   var buf/esi: (addr array byte) <- copy _buf
- 627   var idx/ecx: int <- copy y
- 628   idx <- multiply width
- 629   idx <- add x
- 630   var result-a/eax: (addr byte) <- index buf, idx
- 631   var result/eax: byte <- copy-byte *result-a
- 632   return result
- 633 }
- 634 
- 635 fn _write-raw-buffer _buf: (addr array byte), x: int, y: int, width: int, val: byte {
- 636   var buf/esi: (addr array byte) <- copy _buf
- 637   var idx/ecx: int <- copy y
- 638   idx <- multiply width
- 639   idx <- add x
- 640   var src/eax: byte <- copy val
- 641   var dest-a/edi: (addr byte) <- index buf, idx
- 642   copy-byte-to *dest-a, src
- 643 }
- 644 
- 645 # some debugging helpers
- 646 fn show-errors errors: (addr array int), width: int, height: int, x: int, y: int {
- 647   compare y, 1
- 648   {
- 649     break-if-=
- 650     return
- 651   }
- 652   compare x, 0
- 653   {
- 654     break-if-=
- 655     return
- 656   }
- 657   var y/edx: int <- copy 0
- 658   {
- 659     compare y, height
- 660     break-if->=
- 661     var x/ecx: int <- copy 0
- 662     {
- 663       compare x, width
- 664       break-if->=
- 665       var error/esi: int <- _read-dithering-error errors, x, y, width
- 666       psd "e", error, 5/fg, x, y
- 667       x <- increment
- 668       loop
- 669     }
- 670     move-cursor-to-left-margin-of-next-line 0/screen
- 671     y <- increment
- 672     loop
- 673   }
- 674 }
- 675 
- 676 fn psd s: (addr array byte), d: int, fg: int, x: int, y: int {
- 677   {
- 678     compare y, 0x18
- 679     break-if->=
- 680     return
- 681   }
- 682   {
- 683     compare y, 0x1c
- 684     break-if-<=
- 685     return
- 686   }
- 687   {
- 688     compare x, 0x40
- 689     break-if->=
- 690     return
- 691   }
- 692 #?   {
- 693 #?     compare x, 0x48
- 694 #?     break-if-<=
- 695 #?     return
- 696 #?   }
- 697   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, s, 7/fg 0/bg
- 698   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, d, fg 0/bg
- 699 }
- 700 
- 701 fn psx s: (addr array byte), d: int, fg: int, x: int, y: int {
- 702 #?   {
- 703 #?     compare y, 0x60
- 704 #?     break-if->=
- 705 #?     return
- 706 #?   }
- 707 #?   {
- 708 #?     compare y, 0x6c
- 709 #?     break-if-<=
- 710 #?     return
- 711 #?   }
- 712   {
- 713     compare x, 0x20
- 714     break-if->=
- 715     return
- 716   }
- 717 #?   {
- 718 #?     compare x, 0x6c
- 719 #?     break-if-<=
- 720 #?     return
- 721 #?   }
- 722   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, s, 7/fg 0/bg
- 723   draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, d, fg 0/bg
- 724 }
- 725 
- 726 # import a color ascii "pixmap" (each pixel consists of 3 shades of r/g/b from 0 to 255)
- 727 fn initialize-image-from-ppm _self: (addr image), in: (addr stream byte) {
- 728   var self/esi: (addr image) <- copy _self
- 729   var curr-word-storage: slice
- 730   var curr-word/ecx: (addr slice) <- address curr-word-storage
- 731   # load width, height
- 732   next-word in, curr-word
- 733   var tmp/eax: int <- parse-decimal-int-from-slice curr-word
- 734   var width/edx: int <- copy tmp
- 735   next-word in, curr-word
- 736   tmp <- parse-decimal-int-from-slice curr-word
- 737   var height/ebx: int <- copy tmp
- 738   next-word in, curr-word
- 739   # check color levels
- 740   {
- 741     tmp <- parse-decimal-int-from-slice curr-word
- 742     compare tmp, 0xff
- 743     break-if-=
- 744     abort "initialize-image-from-ppm: supports exactly 255 levels per rgb channel"
- 745   }
- 746   var dest/edi: (addr int) <- get self, max
- 747   copy-to *dest, tmp
- 748   # save width, height
- 749   dest <- get self, width
- 750   copy-to *dest, width
- 751   dest <- get self, height
- 752   copy-to *dest, height
- 753   # initialize data
- 754   var capacity/edx: int <- copy width
- 755   capacity <- multiply height
- 756   # . multiply by 3 for the r/g/b channels
- 757   var tmp/eax: int <- copy capacity
- 758   tmp <- shift-left 1
- 759   capacity <- add tmp
- 760   #
- 761   var data-ah/edi: (addr handle array byte) <- get self, data
- 762   populate data-ah, capacity
- 763   var _data/eax: (addr array byte) <- lookup *data-ah
- 764   var data/edi: (addr array byte) <- copy _data
- 765   var i/ebx: int <- copy 0
- 766   {
- 767     compare i, capacity
- 768     break-if->=
- 769     next-word in, curr-word
- 770     var src/eax: int <- parse-decimal-int-from-slice curr-word
- 771     {
- 772       var dest/ecx: (addr byte) <- index data, i
- 773       copy-byte-to *dest, src
- 774     }
- 775     i <- increment
- 776     loop
- 777   }
- 778 }
- 779 
- 780 # import a color ascii "pixmap" (each pixel consists of 3 shades of r/g/b from 0 to 255)
- 781 fn render-ppm-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
- 782   var img/esi: (addr image) <- copy _img
- 783   # yratio = height/img->height
- 784   var img-height-a/eax: (addr int) <- get img, height
- 785   var img-height/xmm0: float <- convert *img-height-a
- 786   var yratio/xmm1: float <- convert height
- 787   yratio <- divide img-height
- 788   # xratio = width/img->width
- 789   var img-width-a/eax: (addr int) <- get img, width
- 790   var img-width/ebx: int <- copy *img-width-a
- 791   var img-width-f/xmm0: float <- convert img-width
- 792   var xratio/xmm2: float <- convert width
- 793   xratio <- divide img-width-f
- 794   # esi = img->data
- 795   var img-data-ah/eax: (addr handle array byte) <- get img, data
- 796   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
- 797   var img-data/esi: (addr array byte) <- copy _img-data
- 798   var len/edi: int <- length img-data
- 799   #
- 800   var one/eax: int <- copy 1
- 801   var one-f/xmm3: float <- convert one
- 802   var width-f/xmm4: float <- convert width
- 803   var height-f/xmm5: float <- convert height
- 804   var zero/eax: int <- copy 0
- 805   var zero-f/xmm0: float <- convert zero
- 806   var y/xmm6: float <- copy zero-f
- 807   {
- 808     compare y, height-f
- 809     break-if-float>=
- 810     var imgy-f/xmm5: float <- copy y
- 811     imgy-f <- divide yratio
- 812     var imgy/edx: int <- truncate imgy-f
- 813     var x/xmm7: float <- copy zero-f
- 814     {
- 815       compare x, width-f
- 816       break-if-float>=
- 817       var imgx-f/xmm5: float <- copy x
- 818       imgx-f <- divide xratio
- 819       var imgx/ecx: int <- truncate imgx-f
- 820       var idx/eax: int <- copy imgy
- 821       idx <- multiply img-width
- 822       idx <- add imgx
- 823       # . multiply by 3 for the r/g/b channels
- 824       {
- 825         var tmp/ecx: int <- copy idx
- 826         tmp <- shift-left 1
- 827         idx <- add tmp
- 828       }
- 829       # error info in case we rounded wrong and 'index' will fail bounds-check
- 830       compare idx, len
- 831       {
- 832         break-if-<
- 833         set-cursor-position 0/screen, 0x20/x 0x20/y
- 834         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
- 835         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
- 836         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
- 837       }
- 838       # r channel
- 839       var r: int
- 840       {
- 841         var src-a/eax: (addr byte) <- index img-data, idx
- 842         var src/eax: byte <- copy-byte *src-a
- 843         copy-to r, src
- 844       }
- 845       idx <- increment
- 846       # g channel
- 847       var g: int
- 848       {
- 849         var src-a/eax: (addr byte) <- index img-data, idx
- 850         var src/eax: byte <- copy-byte *src-a
- 851         copy-to g, src
- 852       }
- 853       idx <- increment
- 854       # b channel
- 855       var b: int
- 856       {
- 857         var src-a/eax: (addr byte) <- index img-data, idx
- 858         var src/eax: byte <- copy-byte *src-a
- 859         copy-to b, src
- 860       }
- 861       idx <- increment
- 862       # plot nearest color
- 863       var color/eax: int <- nearest-color-euclidean r, g, b
- 864       var screenx/ecx: int <- convert x
- 865       screenx <- add xmin
- 866       var screeny/edx: int <- convert y
- 867       screeny <- add ymin
- 868       pixel screen, screenx, screeny, color
- 869       x <- add one-f
- 870       loop
- 871     }
- 872     y <- add one-f
- 873     loop
- 874   }
- 875 }
- 876 
- 877 fn dither-ppm-unordered _src: (addr image), _dest: (addr image) {
- 878   var src/esi: (addr image) <- copy _src
- 879   var dest/edi: (addr image) <- copy _dest
- 880   # copy 'width'
- 881   var src-width-a/eax: (addr int) <- get src, width
- 882   var tmp/eax: int <- copy *src-width-a
- 883   var src-width: int
- 884   copy-to src-width, tmp
- 885   {
- 886     var dest-width-a/edx: (addr int) <- get dest, width
- 887     copy-to *dest-width-a, tmp
- 888   }
- 889   # copy 'height'
- 890   var src-height-a/eax: (addr int) <- get src, height
- 891   var tmp/eax: int <- copy *src-height-a
- 892   var src-height: int
- 893   copy-to src-height, tmp
- 894   {
- 895     var dest-height-a/ecx: (addr int) <- get dest, height
- 896     copy-to *dest-height-a, tmp
- 897   }
- 898   # compute scaling factor 255/max
- 899   var target-scale/eax: int <- copy 0xff
- 900   var scale-f/xmm7: float <- convert target-scale
- 901   var src-max-a/eax: (addr int) <- get src, max
- 902   var tmp-f/xmm0: float <- convert *src-max-a
- 903   scale-f <- divide tmp-f
- 904   # allocate 'data'
- 905   var capacity/ebx: int <- copy src-width
- 906   capacity <- multiply src-height
- 907   var dest/edi: (addr image) <- copy _dest
- 908   var dest-data-ah/eax: (addr handle array byte) <- get dest, data
- 909   populate dest-data-ah, capacity
- 910   var _dest-data/eax: (addr array byte) <- lookup *dest-data-ah
- 911   var dest-data/edi: (addr array byte) <- copy _dest-data
- 912   # error buffers per r/g/b channel
- 913   var red-errors-storage: (array int 0xc0000)
- 914   var tmp/eax: (addr array int) <- address red-errors-storage
- 915   var red-errors: (addr array int)
- 916   copy-to red-errors, tmp
- 917   var green-errors-storage: (array int 0xc0000)
- 918   var tmp/eax: (addr array int) <- address green-errors-storage
- 919   var green-errors: (addr array int)
- 920   copy-to green-errors, tmp
- 921   var blue-errors-storage: (array int 0xc0000)
- 922   var tmp/eax: (addr array int) <- address blue-errors-storage
- 923   var blue-errors: (addr array int)
- 924   copy-to blue-errors, tmp
- 925   # transform 'data'
- 926   var src-data-ah/eax: (addr handle array byte) <- get src, data
- 927   var _src-data/eax: (addr array byte) <- lookup *src-data-ah
- 928   var src-data/esi: (addr array byte) <- copy _src-data
- 929   var y/edx: int <- copy 0
- 930   {
- 931     compare y, src-height
- 932     break-if->=
- 933     var x/ecx: int <- copy 0
- 934     {
- 935       compare x, src-width
- 936       break-if->=
- 937       # - update errors and compute color levels for current pixel in each channel
- 938       # update red-error with current image pixel
- 939       var red-error: int
- 940       {
- 941         var tmp/esi: int <- _read-dithering-error red-errors, x, y, src-width
- 942         copy-to red-error, tmp
- 943       }
- 944       {
- 945         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 0/red, scale-f
- 946         add-to red-error, tmp
- 947       }
- 948       # recompute red channel for current pixel
- 949       var red-level: int
- 950       {
- 951         var tmp/eax: int <- _error-to-ppm-channel red-error
- 952         copy-to red-level, tmp
- 953       }
- 954       # update green-error with current image pixel
- 955       var green-error: int
- 956       {
- 957         var tmp/esi: int <- _read-dithering-error green-errors, x, y, src-width
- 958         copy-to green-error, tmp
- 959       }
- 960       {
- 961         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 1/green, scale-f
- 962         add-to green-error, tmp
- 963       }
- 964       # recompute green channel for current pixel
- 965       var green-level: int
- 966       {
- 967         var tmp/eax: int <- _error-to-ppm-channel green-error
- 968         copy-to green-level, tmp
- 969       }
- 970       # update blue-error with current image pixel
- 971       var blue-error: int
- 972       {
- 973         var tmp/esi: int <- _read-dithering-error blue-errors, x, y, src-width
- 974         copy-to blue-error, tmp
- 975       }
- 976       {
- 977         var tmp/eax: int <- _ppm-error src-data, x, y, src-width, 2/blue, scale-f
- 978         add-to blue-error, tmp
- 979       }
- 980       # recompute blue channel for current pixel
- 981       var blue-level: int
- 982       {
- 983         var tmp/eax: int <- _error-to-ppm-channel blue-error
- 984         copy-to blue-level, tmp
- 985       }
- 986       # - figure out the nearest color
- 987 #?       {
- 988 #?         compare red-level, 0x80
- 989 #?         break-if->
- 990 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, red-level, 4/fg 0/bg
- 991 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, green-level, 2/fg 0/bg
- 992 #?         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, blue-level, 9/fg 0/bg
- 993 #?       }
- 994       var nearest-color-index/eax: int <- nearest-color-euclidean red-level, green-level, blue-level
- 995       {
- 996         var nearest-color-index-byte/eax: byte <- copy-byte nearest-color-index
- 997         _write-raw-buffer dest-data, x, y, src-width, nearest-color-index-byte
- 998       }
- 999       # - diffuse errors
-1000       var red-level: int
-1001       var green-level: int
-1002       var blue-level: int
-1003       {
-1004         var tmp-red-level/ecx: int <- copy 0
-1005         var tmp-green-level/edx: int <- copy 0
-1006         var tmp-blue-level/ebx: int <- copy 0
-1007         tmp-red-level, tmp-green-level, tmp-blue-level <- color-rgb nearest-color-index
-1008         copy-to red-level, tmp-red-level
-1009         copy-to green-level, tmp-green-level
-1010         copy-to blue-level, tmp-blue-level
-1011       }
-1012       # update red-error
-1013       var red-level-error/eax: int <- copy red-level
-1014       red-level-error <- shift-left 0x10
-1015       subtract-from red-error, red-level-error
-1016       _diffuse-dithering-error-floyd-steinberg red-errors, x, y, src-width, src-height, red-error
-1017       # update green-error
-1018       var green-level-error/eax: int <- copy green-level
-1019       green-level-error <- shift-left 0x10
-1020       subtract-from green-error, green-level-error
-1021       _diffuse-dithering-error-floyd-steinberg green-errors, x, y, src-width, src-height, green-error
-1022       # update blue-error
-1023       var blue-level-error/eax: int <- copy blue-level
-1024       blue-level-error <- shift-left 0x10
-1025       subtract-from blue-error, blue-level-error
-1026       _diffuse-dithering-error-floyd-steinberg blue-errors, x, y, src-width, src-height, blue-error
-1027       #
-1028       x <- increment
-1029       loop
-1030     }
-1031     y <- increment
-1032     loop
-1033   }
-1034 }
-1035 
-1036 # convert a single channel for a single image pixel to error space
-1037 fn _ppm-error buf: (addr array byte), x: int, y: int, width: int, channel: int, _scale-f: float -> _/eax: int {
-1038   # current image pixel
-1039   var initial-level/eax: byte <- _read-ppm-buffer buf, x, y, width, channel
-1040   # scale to 255 levels
-1041   var initial-level-int/eax: int <- copy initial-level
-1042   var initial-level-f/xmm0: float <- convert initial-level-int
-1043   var scale-f/xmm1: float <- copy _scale-f
-1044   initial-level-f <- multiply scale-f
-1045   initial-level-int <- convert initial-level-f
-1046   # switch to fixed-point with 16 bits of precision
-1047   initial-level-int <- shift-left 0x10
-1048   return initial-level-int
-1049 }
-1050 
-1051 fn _error-to-ppm-channel error: int -> _/eax: int {
-1052   # clamp(error >> 16)
-1053   var result/esi: int <- copy error
-1054   result <- shift-right-signed 0x10
-1055   {
-1056     compare result, 0
-1057     break-if->=
-1058     result <- copy 0
-1059   }
-1060   {
-1061     compare result, 0xff
-1062     break-if-<=
-1063     result <- copy 0xff
-1064   }
-1065   return result
-1066 }
-1067 
-1068 # read from a buffer containing alternating bytes from r/g/b channels
-1069 fn _read-ppm-buffer _buf: (addr array byte), x: int, y: int, width: int, channel: int -> _/eax: byte {
-1070   var buf/esi: (addr array byte) <- copy _buf
-1071   var idx/ecx: int <- copy y
-1072   idx <- multiply width
-1073   idx <- add x
-1074   var byte-idx/edx: int <- copy 3
-1075   byte-idx <- multiply idx
-1076   byte-idx <- add channel
-1077   var result-a/eax: (addr byte) <- index buf, byte-idx
-1078   var result/eax: byte <- copy-byte *result-a
-1079   return result
-1080 }
-1081 
-1082 # each byte in the image data is a color of the current palette
-1083 fn render-raw-image screen: (addr screen), _img: (addr image), xmin: int, ymin: int, width: int, height: int {
-1084   var img/esi: (addr image) <- copy _img
-1085   # yratio = height/img->height
-1086   var img-height-a/eax: (addr int) <- get img, height
-1087   var img-height/xmm0: float <- convert *img-height-a
-1088   var yratio/xmm1: float <- convert height
-1089   yratio <- divide img-height
-1090   # xratio = width/img->width
-1091   var img-width-a/eax: (addr int) <- get img, width
-1092   var img-width/ebx: int <- copy *img-width-a
-1093   var img-width-f/xmm0: float <- convert img-width
-1094   var xratio/xmm2: float <- convert width
-1095   xratio <- divide img-width-f
-1096   # esi = img->data
-1097   var img-data-ah/eax: (addr handle array byte) <- get img, data
-1098   var _img-data/eax: (addr array byte) <- lookup *img-data-ah
-1099   var img-data/esi: (addr array byte) <- copy _img-data
-1100   var len/edi: int <- length img-data
-1101   #
-1102   var one/eax: int <- copy 1
-1103   var one-f/xmm3: float <- convert one
-1104   var width-f/xmm4: float <- convert width
-1105   var height-f/xmm5: float <- convert height
-1106   var zero/eax: int <- copy 0
-1107   var zero-f/xmm0: float <- convert zero
-1108   var y/xmm6: float <- copy zero-f
-1109   {
-1110     compare y, height-f
-1111     break-if-float>=
-1112     var imgy-f/xmm5: float <- copy y
-1113     imgy-f <- divide yratio
-1114     var imgy/edx: int <- truncate imgy-f
-1115     var x/xmm7: float <- copy zero-f
-1116     {
-1117       compare x, width-f
-1118       break-if-float>=
-1119       var imgx-f/xmm5: float <- copy x
-1120       imgx-f <- divide xratio
-1121       var imgx/ecx: int <- truncate imgx-f
-1122       var idx/eax: int <- copy imgy
-1123       idx <- multiply img-width
-1124       idx <- add imgx
-1125       # error info in case we rounded wrong and 'index' will fail bounds-check
-1126       compare idx, len
-1127       {
-1128         break-if-<
-1129         set-cursor-position 0/screen, 0x20/x 0x20/y
-1130         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgx, 3/fg 0/bg
-1131         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, imgy, 4/fg 0/bg
-1132         draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, idx, 5/fg 0/bg
-1133       }
-1134       var color-a/eax: (addr byte) <- index img-data, idx
-1135       var color/eax: byte <- copy-byte *color-a
-1136       var color-int/eax: int <- copy color
-1137       var screenx/ecx: int <- convert x
-1138       screenx <- add xmin
-1139       var screeny/edx: int <- convert y
-1140       screeny <- add ymin
-1141       pixel screen, screenx, screeny, color-int
-1142       x <- add one-f
-1143       loop
-1144     }
-1145     y <- add one-f
-1146     loop
-1147   }
-1148 }
-
- - - diff --git a/html/life.mu.html b/html/life.mu.html index e08e9f9f..31281d9f 100644 --- a/html/life.mu.html +++ b/html/life.mu.html @@ -1,36 +1,36 @@ - + - + Mu - life.mu - - + + - + - - + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2017/1a.mu +
+ 1 # Advent of code 2017, problem 1a
+ 2 #   https://adventofcode.com/2017/day/1
+ 3 #
+ 4 # Mu solution by Sumeet Agarwal and Kartik Agaram
+ 5 #   https://archive.org/details/2021-06-02-akkartik-sumeet
+ 6 #
+ 7 # To build on Linux:
+ 8 #   $ git clone https://github.com/akkartik/mu
+ 9 #   $ cd mu/linux
+10 #   $ ./translate apps/advent2017/1a.mu            # emits a.elf
+11 # To run on Linux:
+12 #   Download https://adventofcode.com/2017/day/1/input
+13 #   $ ./a.elf < input
+14 # Type in the number returned at https://adventofcode.com/2017/day/1
+15 
+16 fn main -> _/ebx: int {
+17   var input_stream: (stream byte 0x8000)
+18   var input_stream_addr/esi: (addr stream byte) <- address input_stream
+19 
+20   var sum/edi: int <- copy 0
+21   read-line-from-real-keyboard input_stream_addr
+22 
+23   var temp/eax: int <- read_digit input_stream_addr
+24   var first_digit/ebx: int <- copy temp
+25   var this_digit/edx: int <- copy temp
+26 
+27   {
+28     var done?/eax: boolean <- stream-empty? input_stream_addr
+29     compare done?, 1
+30     break-if-=
+31 
+32     var next_digit/eax: int <- read_digit input_stream_addr
+33     # hacky newline check
+34     compare next_digit, 0
+35     break-if-<
+36 
+37     {
+38       compare this_digit, next_digit
+39       break-if-!=
+40       sum <- add this_digit
+41     }
+42 
+43     this_digit <- copy next_digit
+44 
+45     loop
+46   }
+47 
+48   # the last iteration will need to compare the last number to the first
+49   {
+50     compare this_digit, first_digit
+51     break-if-!=
+52     sum <- add this_digit
+53   }
+54 
+55   print-int32-decimal 0, sum
+56 
+57   return 0/ok
+58 }
+59 
+60 fn read_digit input_stream_addr: (addr stream byte) -> _/eax: int {
+61   var next_digit/eax: byte <- read-byte input_stream_addr
+62   next_digit <- subtract 0x30
+63   var next_digit/eax: int <- copy next_digit
+64   return next_digit
+65 }
+
+ + + diff --git a/html/linux/apps/advent2020/1a.mu.html b/html/linux/apps/advent2020/1a.mu.html new file mode 100644 index 00000000..e75fe8fc --- /dev/null +++ b/html/linux/apps/advent2020/1a.mu.html @@ -0,0 +1,165 @@ + + + + +Mu - linux/apps/advent2020/1a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/1a.mu +
+ 1 # https://adventofcode.com/2020/day/1
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/1a.mu
+ 7 #   $ ./a.elf < input
+ 8 #   found
+ 9 #   1353 667
+10 #   902451
+11 #
+12 # You'll need to register to download the 'input' file for yourself.
+13 
+14 fn main -> _/ebx: int {
+15   # data structure
+16   var numbers-storage: (array int 0x100)  # 256 ints
+17   var numbers/esi: (addr array int) <- address numbers-storage
+18   var numbers-index/ecx: int <- copy 0
+19   # phase 1: parse each line from stdin and add it to numbers
+20   {
+21     var line-storage: (stream byte 0x100)  # 256 bytes
+22     var line/edx: (addr stream byte) <- address line-storage
+23     {
+24 #?       print-string 0, "== iter\n"
+25       # read line from stdin
+26       clear-stream line
+27       read-line-from-real-keyboard line
+28       # if line is empty (not even a newline), quit
+29       var done?/eax: boolean <- stream-empty? line
+30       compare done?, 0/false
+31       break-if-!=
+32 #?       print-stream-to-real-screen line
+33       # convert line to int and append it to numbers
+34       var n/eax: int <- parse-decimal-int-from-stream line
+35 #?       print-int32-decimal 0, n
+36 #?       print-string 0, "\n"
+37       var dest/ebx: (addr int) <- index numbers, numbers-index
+38       copy-to *dest, n
+39       numbers-index <- increment
+40 #?       print-string 0, "== "
+41 #?       print-int32-decimal 0, numbers-index
+42 #?       print-string 0, "\n"
+43       loop
+44     }
+45   }
+46   # phase 2: for each number in the array, check if 2020-it is in the rest of
+47   # the array
+48   var i/eax: int <- copy 0
+49   {
+50     compare i, numbers-index
+51     break-if->=
+52     var src/ebx: (addr int) <- index numbers, i
+53 #?     print-int32-decimal 0, *src
+54 #?     print-string 0, "\n"
+55     var target/ecx: int <- copy 0x7e4  # 2020
+56     target <- subtract *src
+57     {
+58       var found?/eax: boolean <- find-after numbers, i, target
+59       compare found?, 0/false
+60       break-if-=
+61       print-string 0, "found\n"
+62       print-int32-decimal 0, *src
+63       print-string 0, " "
+64       print-int32-decimal 0, target
+65       print-string 0, "\n"
+66       target <- multiply *src
+67       print-int32-decimal 0, target
+68       print-string 0, "\n"
+69       return 0/success
+70     }
+71     i <- increment
+72     loop
+73   }
+74   return 1/not-found
+75 }
+76 
+77 fn find-after _numbers: (addr array int), start: int, _target: int -> _/eax: boolean {
+78   var numbers/esi: (addr array int) <- copy _numbers
+79   var target/edi: int <- copy _target
+80   var len/ecx: int <- length numbers
+81   var i/eax: int <- copy start
+82   i <- increment
+83   {
+84     compare i, len
+85     break-if->=
+86     var src/edx: (addr int) <- index numbers, i
+87     # if *src == target, return true
+88     compare *src, target
+89     {
+90       break-if-!=
+91       return 1/true
+92     }
+93     i <- increment
+94     loop
+95   }
+96   return 0/false
+97 }
+
+ + + diff --git a/html/linux/apps/advent2020/1b.mu.html b/html/linux/apps/advent2020/1b.mu.html new file mode 100644 index 00000000..4346642b --- /dev/null +++ b/html/linux/apps/advent2020/1b.mu.html @@ -0,0 +1,181 @@ + + + + +Mu - linux/apps/advent2020/1b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/1b.mu +
+  1 # https://adventofcode.com/2020/day/1
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/1b.mu
+  7 #   $ ./a.elf < input
+  8 #   found
+  9 #   143 407 1470
+ 10 #   85555470
+ 11 #
+ 12 # You'll need to register to download the 'input' file for yourself.
+ 13 
+ 14 fn main -> _/ebx: int {
+ 15   # data structure
+ 16   var numbers-storage: (array int 0x100)  # 256 ints
+ 17   var numbers/esi: (addr array int) <- address numbers-storage
+ 18   var numbers-index/ecx: int <- copy 0
+ 19   # phase 1: parse each line from stdin and add it to numbers
+ 20   {
+ 21     var line-storage: (stream byte 0x100)  # 256 bytes
+ 22     var line/edx: (addr stream byte) <- address line-storage
+ 23     {
+ 24 #?       print-string 0, "== iter\n"
+ 25       # read line from stdin
+ 26       clear-stream line
+ 27       read-line-from-real-keyboard line
+ 28       # if line is empty (not even a newline), quit
+ 29       var done?/eax: boolean <- stream-empty? line
+ 30       compare done?, 0/false
+ 31       break-if-!=
+ 32 #?       print-stream-to-real-screen line
+ 33       # convert line to int and append it to numbers
+ 34       var n/eax: int <- parse-decimal-int-from-stream line
+ 35 #?       print-int32-decimal 0, n
+ 36 #?       print-string 0, "\n"
+ 37       var dest/ebx: (addr int) <- index numbers, numbers-index
+ 38       copy-to *dest, n
+ 39       numbers-index <- increment
+ 40 #?       print-string 0, "== "
+ 41 #?       print-int32-decimal 0, numbers-index
+ 42 #?       print-string 0, "\n"
+ 43       loop
+ 44     }
+ 45   }
+ 46   # phase 2: for every pair of distinct numbers, check if the rest of the
+ 47   # array has 2020-it
+ 48   var i/edi: int <- copy 0
+ 49   {
+ 50     compare i, numbers-index
+ 51     break-if->=
+ 52     # for j from i+1 to end
+ 53     var j/edx: int <- copy i
+ 54     j <- increment
+ 55     {
+ 56       compare j, numbers-index
+ 57       break-if->=
+ 58       {
+ 59         compare i, j
+ 60         break-if-=
+ 61         var target/ebx: int <- copy 0x7e4  # 2020
+ 62         var src/edi: (addr int) <- index numbers, i
+ 63         target <- subtract *src
+ 64         var src2/ecx: (addr int) <- index numbers, j
+ 65         target <- subtract *src2
+ 66         {
+ 67           var found?/eax: boolean <- find-after numbers, j, target
+ 68           compare found?, 0/false
+ 69           break-if-=
+ 70           print-string 0, "found\n"
+ 71           print-int32-decimal 0, *src
+ 72           print-string 0, " "
+ 73           print-int32-decimal 0, *src2
+ 74           print-string 0, " "
+ 75           print-int32-decimal 0, target
+ 76           print-string 0, "\n"
+ 77           target <- multiply *src
+ 78           target <- multiply *src2
+ 79           print-int32-decimal 0, target
+ 80           print-string 0, "\n"
+ 81           return 0/success
+ 82         }
+ 83       }
+ 84       j <- increment
+ 85       loop
+ 86     }
+ 87     i <- increment
+ 88     loop
+ 89   }
+ 90   return 1/not-found
+ 91 }
+ 92 
+ 93 fn find-after _numbers: (addr array int), start: int, _target: int -> _/eax: boolean {
+ 94   var numbers/esi: (addr array int) <- copy _numbers
+ 95   var target/edi: int <- copy _target
+ 96   var len/ecx: int <- length numbers
+ 97   var i/eax: int <- copy start
+ 98   i <- increment
+ 99   {
+100     compare i, len
+101     break-if->=
+102     var src/edx: (addr int) <- index numbers, i
+103     # if *src == target, return true
+104     compare *src, target
+105     {
+106       break-if-!=
+107       return 1/true
+108     }
+109     i <- increment
+110     loop
+111   }
+112   return 0/false
+113 }
+
+ + + diff --git a/html/linux/apps/advent2020/2a.mu.html b/html/linux/apps/advent2020/2a.mu.html new file mode 100644 index 00000000..2e6e3488 --- /dev/null +++ b/html/linux/apps/advent2020/2a.mu.html @@ -0,0 +1,159 @@ + + + + +Mu - linux/apps/advent2020/2a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/2a.mu +
+ 1 # https://adventofcode.com/2020/day/2
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/2a.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var valid-password-count/edi: int <- copy 0
+13   var line-storage: (stream byte 0x100)  # 256 bytes
+14   var line/edx: (addr stream byte) <- address line-storage
+15   var slice-storage: slice
+16   var slice/ecx: (addr slice) <- address slice-storage
+17   {
+18     # read line from stdin
+19     clear-stream line
+20     read-line-from-real-keyboard line
+21     # if line is empty (not even a newline), quit
+22     var done?/eax: boolean <- stream-empty? line
+23     compare done?, 0/false
+24     break-if-!=
+25     print-stream-to-real-screen line
+26     # slice = next-token(line, '-')
+27     next-token line, 0x2d, slice
+28     # start = parse-int(slice)
+29     var _start/eax: int <- parse-decimal-int-from-slice slice
+30     var start/ebx: int <- copy _start
+31     var dash/eax: byte <- read-byte line  # skip '-'
+32     # slice = next-token(line, ' ')
+33     next-token line, 0x20, slice
+34     var _end/eax: int <- parse-decimal-int-from-slice slice
+35     var end/esi: int <- copy _end
+36     print-int32-decimal 0, start
+37     print-string 0, " "
+38     print-int32-decimal 0, end
+39     print-string 0, "\n"
+40     # letter = next non-space
+41     skip-chars-matching-whitespace line
+42     var letter/eax: byte <- read-byte line
+43     # skip some stuff
+44     {
+45       var colon/eax: byte <- read-byte line  # skip ':'
+46     }
+47     skip-chars-matching-whitespace line
+48     # now check the rest of the line
+49     var valid?/eax: boolean <- valid? start, end, letter, line
+50     compare valid?, 0/false
+51     {
+52       break-if-=
+53       print-string 0, "valid!\n"
+54       valid-password-count <- increment
+55     }
+56     loop
+57   }
+58   print-int32-decimal 0, valid-password-count
+59   print-string 0, "\n"
+60   return 0
+61 }
+62 
+63 fn valid? start: int, end: int, letter: byte, password: (addr stream byte) -> _/eax: boolean {
+64   var letter-count/edi: int <- copy 0
+65   # for every c in password
+66   #   if (c == letter)
+67   #     ++letter-count
+68   {
+69     var done?/eax: boolean <- stream-empty? password
+70     compare done?, 0/false
+71     break-if-!=
+72     var c/eax: byte <- read-byte password
+73     compare c, letter
+74     {
+75       break-if-!=
+76       letter-count <- increment
+77     }
+78     loop
+79   }
+80   # return (start <= letter-count <= end)
+81   compare letter-count, start
+82   {
+83     break-if->=
+84     return 0/false
+85   }
+86   compare letter-count, end
+87   {
+88     break-if-<=
+89     return 0/false
+90   }
+91   return 1/true
+92 }
+
+ + + diff --git a/html/linux/apps/advent2020/2b.mu.html b/html/linux/apps/advent2020/2b.mu.html new file mode 100644 index 00000000..604e06bb --- /dev/null +++ b/html/linux/apps/advent2020/2b.mu.html @@ -0,0 +1,190 @@ + + + + +Mu - linux/apps/advent2020/2b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/2b.mu +
+  1 # https://adventofcode.com/2020/day/2
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/2b.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   var valid-password-count/edi: int <- copy 0
+ 13   var line-storage: (stream byte 0x100)  # 256 bytes
+ 14   var line/edx: (addr stream byte) <- address line-storage
+ 15   var slice-storage: slice
+ 16   var slice/ecx: (addr slice) <- address slice-storage
+ 17   {
+ 18     # read line from stdin
+ 19     clear-stream line
+ 20     read-line-from-real-keyboard line
+ 21     # if line is empty (not even a newline), quit
+ 22     var done?/eax: boolean <- stream-empty? line
+ 23     compare done?, 0/false
+ 24     break-if-!=
+ 25     print-stream-to-real-screen line
+ 26     # slice = next-token(line, '-')
+ 27     next-token line, 0x2d, slice
+ 28     # pos1 = parse-int(slice)
+ 29     var _pos1/eax: int <- parse-decimal-int-from-slice slice
+ 30     var pos1/ebx: int <- copy _pos1
+ 31     var dash/eax: byte <- read-byte line  # skip '-'
+ 32     # slice = next-token(line, ' ')
+ 33     next-token line, 0x20, slice
+ 34     var _pos2/eax: int <- parse-decimal-int-from-slice slice
+ 35     var pos2/esi: int <- copy _pos2
+ 36     print-int32-decimal 0, pos1
+ 37     print-string 0, " "
+ 38     print-int32-decimal 0, pos2
+ 39     print-string 0, "\n"
+ 40     compare pos1, pos2
+ 41     {
+ 42       break-if-<=
+ 43       print-string 0, "out of order!\n"
+ 44       return 1
+ 45     }
+ 46     # letter = next non-space
+ 47     skip-chars-matching-whitespace line
+ 48     var letter/eax: byte <- read-byte line
+ 49     # skip some stuff
+ 50     {
+ 51       var colon/eax: byte <- read-byte line  # skip ':'
+ 52     }
+ 53     skip-chars-matching-whitespace line
+ 54     # now check the rest of the line
+ 55     var valid?/eax: boolean <- valid? pos1, pos2, letter, line
+ 56     compare valid?, 0/false
+ 57     {
+ 58       break-if-=
+ 59       print-string 0, "valid!\n"
+ 60       valid-password-count <- increment
+ 61     }
+ 62     loop
+ 63   }
+ 64   print-int32-decimal 0, valid-password-count
+ 65   print-string 0, "\n"
+ 66   return 0
+ 67 }
+ 68 
+ 69 # ideally password would be a random-access array
+ 70 # we'll just track an index
+ 71 # one benefit: we can easily start at 1
+ 72 fn valid? pos1: int, pos2: int, letter: byte, password: (addr stream byte) -> _/eax: boolean {
+ 73   var i/esi: int <- copy 1
+ 74   var letter-count/edi: int <- copy 0
+ 75   # while password stream isn't empty
+ 76   #   c = read byte from password
+ 77   #   if (c == letter)
+ 78   #     if (i == pos1)
+ 79   #       ++letter-count
+ 80   #     if (i == pos2)
+ 81   #       ++letter-count
+ 82   #     ++i
+ 83   {
+ 84 #?     print-string 0, "  "
+ 85 #?     print-int32-decimal 0, i
+ 86 #?     print-string 0, "\n"
+ 87     var done?/eax: boolean <- stream-empty? password
+ 88     compare done?, 0/false
+ 89     break-if-!=
+ 90     var c/eax: byte <- read-byte password
+ 91 #?     {
+ 92 #?       var c2/eax: int <- copy c
+ 93 #?       print-int32-decimal 0, c2
+ 94 #?       print-string 0, "\n"
+ 95 #?     }
+ 96     compare c, letter
+ 97     {
+ 98       break-if-!=
+ 99       compare i, pos1
+100       {
+101         break-if-!=
+102         letter-count <- increment
+103 #?         print-string 0, "  hit\n"
+104       }
+105       compare i, pos2
+106       {
+107         break-if-!=
+108         letter-count <- increment
+109 #?         print-string 0, "  hit\n"
+110       }
+111     }
+112     i <- increment
+113     loop
+114   }
+115   # return (letter-count == 1)
+116   compare letter-count, 1
+117   {
+118     break-if-!=
+119     return 1/true
+120   }
+121   return 0/false
+122 }
+
+ + + diff --git a/html/linux/apps/advent2020/3a.mu.html b/html/linux/apps/advent2020/3a.mu.html new file mode 100644 index 00000000..09d7f160 --- /dev/null +++ b/html/linux/apps/advent2020/3a.mu.html @@ -0,0 +1,175 @@ + + + + +Mu - linux/apps/advent2020/3a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/3a.mu +
+  1 # https://adventofcode.com/2020/day/3
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/3a.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   # represent trees in a 2D array of ints
+ 13   # wasteful since each tree is just one bit
+ 14   var trees-storage: (array int 0x2800)  # 10k ints
+ 15   var trees/esi: (addr array int) <- address trees-storage
+ 16   var trees-length/ecx: int <- copy 0
+ 17   var num-rows: int
+ 18   var width: int
+ 19   # phase 1: parse each row of trees from stdin
+ 20   {
+ 21     var line-storage: (stream byte 0x40)  # 64 bytes
+ 22     var line/edx: (addr stream byte) <- address line-storage
+ 23     {
+ 24       # read line from stdin
+ 25       clear-stream line
+ 26       read-line-from-real-keyboard line
+ 27       # if line is empty (not even a newline), quit
+ 28       var done?/eax: boolean <- stream-empty? line
+ 29       compare done?, 0/false
+ 30       break-if-!=
+ 31       # wastefully recompute width on every line
+ 32       # zero error-checking; we assume input lines are all equally long
+ 33       copy-to width, 0
+ 34       # turn each byte into a tree and append it
+ 35       $main:line-loop: {
+ 36         var done?/eax: boolean <- stream-empty? line
+ 37         compare done?, 0/false
+ 38         break-if-!=
+ 39 #?         print-int32-decimal 0, num-rows
+ 40 #?         print-string 0, " "
+ 41 #?         print-int32-decimal 0, width
+ 42 #?         print-string 0, "\n"
+ 43         var dest/ebx: (addr int) <- index trees, trees-length
+ 44         var c/eax: byte <- read-byte line
+ 45         # newline comes only at end of line
+ 46         compare c, 0xa/newline
+ 47         break-if-=
+ 48         # '#' = tree
+ 49         compare c, 0x23/hash
+ 50         {
+ 51           break-if-!=
+ 52           copy-to *dest, 1
+ 53         }
+ 54         # anything else = no tree
+ 55         {
+ 56           break-if-=
+ 57           copy-to *dest, 0
+ 58         }
+ 59         increment width
+ 60         trees-length <- increment
+ 61         loop
+ 62       }
+ 63       increment num-rows
+ 64       loop
+ 65     }
+ 66   }
+ 67   # phase 2: compute
+ 68   print-int32-decimal 0, num-rows
+ 69   print-string 0, "x"
+ 70   print-int32-decimal 0, width
+ 71   print-string 0, "\n"
+ 72   var row/ecx: int <- copy 0
+ 73   var col/edx: int <- copy 0
+ 74   var num-trees-hit/edi: int <- copy 0
+ 75   {
+ 76     compare row, num-rows
+ 77     break-if->=
+ 78     var curr/eax: int <- index2d trees, row, col, width
+ 79     compare curr, 0
+ 80     {
+ 81       break-if-=
+ 82       num-trees-hit <- increment
+ 83     }
+ 84     # right 3, down 1
+ 85     col <- add 3
+ 86     row <- add 1
+ 87     loop
+ 88   }
+ 89   print-int32-decimal 0, num-trees-hit
+ 90   print-string 0, "\n"
+ 91   return 0
+ 92 }
+ 93 
+ 94 fn index2d _arr: (addr array int), _row: int, _col: int, width: int -> _/eax: int {
+ 95   # handle repeating columns of trees
+ 96   var dummy/eax: int <- copy 0
+ 97   var col/edx: int <- copy 0
+ 98   dummy, col <- integer-divide _col, width
+ 99   # compute index
+100   var index/eax: int <- copy _row
+101   index <- multiply width
+102   index <- add col
+103   # look up array
+104   var arr/esi: (addr array int) <- copy _arr
+105   var src/eax: (addr int) <- index arr, index
+106   return *src
+107 }
+
+ + + diff --git a/html/linux/apps/advent2020/3b.mu.html b/html/linux/apps/advent2020/3b.mu.html new file mode 100644 index 00000000..ff64117f --- /dev/null +++ b/html/linux/apps/advent2020/3b.mu.html @@ -0,0 +1,205 @@ + + + + +Mu - linux/apps/advent2020/3b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/3b.mu +
+  1 # https://adventofcode.com/2020/day/3
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/3a.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   # represent trees in a 2D array of ints
+ 13   # wasteful since each tree is just one bit
+ 14   var trees-storage: (array int 0x2800)  # 10k ints
+ 15   var trees/esi: (addr array int) <- address trees-storage
+ 16   var trees-length/ecx: int <- copy 0
+ 17   var num-rows: int
+ 18   var width: int
+ 19   # phase 1: parse each row of trees from stdin
+ 20   {
+ 21     var line-storage: (stream byte 0x40)  # 64 bytes
+ 22     var line/edx: (addr stream byte) <- address line-storage
+ 23     {
+ 24       # read line from stdin
+ 25       clear-stream line
+ 26       read-line-from-real-keyboard line
+ 27       # if line is empty (not even a newline), quit
+ 28       var done?/eax: boolean <- stream-empty? line
+ 29       compare done?, 0/false
+ 30       break-if-!=
+ 31       # wastefully recompute width on every line
+ 32       # zero error-checking; we assume input lines are all equally long
+ 33       copy-to width, 0
+ 34       # turn each byte into a tree and append it
+ 35       $main:line-loop: {
+ 36         var done?/eax: boolean <- stream-empty? line
+ 37         compare done?, 0/false
+ 38         break-if-!=
+ 39 #?         print-int32-decimal 0, num-rows
+ 40 #?         print-string 0, " "
+ 41 #?         print-int32-decimal 0, width
+ 42 #?         print-string 0, "\n"
+ 43         var dest/ebx: (addr int) <- index trees, trees-length
+ 44         var c/eax: byte <- read-byte line
+ 45         # newline comes only at end of line
+ 46         compare c, 0xa/newline
+ 47         break-if-=
+ 48         # '#' = tree
+ 49         compare c, 0x23/hash
+ 50         {
+ 51           break-if-!=
+ 52           copy-to *dest, 1
+ 53         }
+ 54         # anything else = no tree
+ 55         {
+ 56           break-if-=
+ 57           copy-to *dest, 0
+ 58         }
+ 59         increment width
+ 60         trees-length <- increment
+ 61         loop
+ 62       }
+ 63       increment num-rows
+ 64       loop
+ 65     }
+ 66   }
+ 67   # phase 2: compute
+ 68   var product/edi: int <- copy 1
+ 69   var result/eax: int <- num-trees-hit trees, width, num-rows, 1, 1
+ 70   print-int32-decimal 0, result
+ 71   print-string 0, " x "
+ 72   product <- multiply result
+ 73   var result/eax: int <- num-trees-hit trees, width, num-rows, 3, 1
+ 74   print-int32-decimal 0, result
+ 75   print-string 0, " x "
+ 76   product <- multiply result
+ 77   var result/eax: int <- num-trees-hit trees, width, num-rows, 5, 1
+ 78   print-int32-decimal 0, result
+ 79   print-string 0, " x "
+ 80   product <- multiply result
+ 81   var result/eax: int <- num-trees-hit trees, width, num-rows, 7, 1
+ 82   print-int32-decimal 0, result
+ 83   print-string 0, " x "
+ 84   product <- multiply result
+ 85   var result/eax: int <- num-trees-hit trees, width, num-rows, 1, 2
+ 86   print-int32-decimal 0, result
+ 87   print-string 0, " = "
+ 88   product <- multiply result
+ 89   print-int32-hex 0, product
+ 90   print-string 0, "\n"
+ 91   return 0
+ 92 }
+ 93 
+ 94 fn num-trees-hit trees: (addr array int), width: int, num-rows: int, right: int, down: int -> _/eax: int {
+ 95 #?   print-string 0, "== "
+ 96 #?   print-int32-decimal 0, right
+ 97 #?   print-string 0, " "
+ 98 #?   print-int32-decimal 0, down
+ 99 #?   print-string 0, "\n"
+100   var row/ecx: int <- copy 0
+101   var col/edx: int <- copy 0
+102   var num-trees-hit/edi: int <- copy 0
+103   {
+104     compare row, num-rows
+105     break-if->=
+106 #?     print-int32-decimal 0, col
+107 #?     print-string 0, "\n"
+108     var curr/eax: int <- index2d trees, row, col, width
+109     compare curr, 0
+110     {
+111       break-if-=
+112       num-trees-hit <- increment
+113     }
+114     col <- add right
+115     row <- add down
+116     loop
+117   }
+118   return num-trees-hit
+119 }
+120 
+121 fn index2d _arr: (addr array int), _row: int, _col: int, width: int -> _/eax: int {
+122   # handle repeating columns of trees
+123   var dummy/eax: int <- copy 0
+124   var col/edx: int <- copy 0
+125   dummy, col <- integer-divide _col, width
+126 #?   print-string 0, "  "
+127 #?   print-int32-decimal 0, col
+128 #?   print-string 0, "\n"
+129   # compute index
+130   var index/eax: int <- copy _row
+131   index <- multiply width
+132   index <- add col
+133   # look up array
+134   var arr/esi: (addr array int) <- copy _arr
+135   var src/eax: (addr int) <- index arr, index
+136   return *src
+137 }
+
+ + + diff --git a/html/linux/apps/advent2020/4a.mu.html b/html/linux/apps/advent2020/4a.mu.html new file mode 100644 index 00000000..6f477717 --- /dev/null +++ b/html/linux/apps/advent2020/4a.mu.html @@ -0,0 +1,142 @@ + + + + +Mu - linux/apps/advent2020/4a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/4a.mu +
+ 1 # https://adventofcode.com/2020/day/4
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/4a.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var curr-passport-field-count/esi: int <- copy 0
+13   var valid-passport-count/edi: int <- copy 0
+14   var line-storage: (stream byte 0x100)  # 256 bytes
+15   var line/ecx: (addr stream byte) <- address line-storage
+16   var slice-storage: slice
+17   var slice/edx: (addr slice) <- address slice-storage
+18   $main:line-loop: {
+19     # read line from stdin
+20     clear-stream line
+21     read-line-from-real-keyboard line
+22     # if line is empty (not even a newline), quit
+23     var done?/eax: boolean <- stream-empty? line
+24     compare done?, 0/false
+25     break-if-!=
+26     print-stream-to-real-screen line
+27     # if line has just a newline, process passport
+28     skip-chars-matching-whitespace line
+29     var new-passport?/eax: boolean <- stream-empty? line
+30     {
+31       compare new-passport?, 0/false
+32       break-if-=
+33       compare curr-passport-field-count, 7
+34       {
+35         break-if-!=
+36         valid-passport-count <- increment
+37         print-string 0, "=> "
+38         print-int32-decimal 0, valid-passport-count
+39         print-string 0, "\n"
+40       }
+41       curr-passport-field-count <- copy 0
+42       loop $main:line-loop
+43     }
+44     $main:word-loop: {
+45       next-word line, slice
+46       var done?/eax: boolean <- slice-empty? slice
+47       compare done?, 0/false
+48       break-if-!=
+49       print-string 0, "  "
+50       print-slice-to-real-screen slice
+51       # treat cid as optional
+52       var optional?/eax: boolean <- slice-starts-with? slice, "cid:"
+53       compare optional?, 0/false
+54       {
+55         break-if-!=
+56         # otherwise assume there are no invalid fields and no duplicate fields
+57         curr-passport-field-count <- increment
+58         print-string 0, " => "
+59         print-int32-decimal 0, curr-passport-field-count
+60       }
+61       print-string 0, "\n"
+62       loop
+63     }
+64     loop
+65   }
+66   # process final passport
+67   compare curr-passport-field-count, 7
+68   {
+69     break-if-!=
+70     valid-passport-count <- increment
+71   }
+72   print-int32-decimal 0, valid-passport-count
+73   print-string 0, "\n"
+74   return 0
+75 }
+
+ + + diff --git a/html/linux/apps/advent2020/4b.mu.html b/html/linux/apps/advent2020/4b.mu.html new file mode 100644 index 00000000..47538296 --- /dev/null +++ b/html/linux/apps/advent2020/4b.mu.html @@ -0,0 +1,381 @@ + + + + +Mu - linux/apps/advent2020/4b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/4b.mu +
+  1 # https://adventofcode.com/2020/day/4
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/4b.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   var curr-passport-field-count/esi: int <- copy 0
+ 13   var valid-passport-count/edi: int <- copy 0
+ 14   var line-storage: (stream byte 0x100)  # 256 bytes
+ 15   var line/ecx: (addr stream byte) <- address line-storage
+ 16   var key-slice-storage: slice
+ 17   var key-slice/edx: (addr slice) <- address key-slice-storage
+ 18   var val-slice-storage: slice
+ 19   var val-slice/ebx: (addr slice) <- address val-slice-storage
+ 20   $main:line-loop: {
+ 21     # read line from stdin
+ 22     clear-stream line
+ 23     read-line-from-real-keyboard line
+ 24     # if line is empty (not even a newline), quit
+ 25     var done?/eax: boolean <- stream-empty? line
+ 26     compare done?, 0/false
+ 27     break-if-!=
+ 28     print-stream-to-real-screen line
+ 29     # if line has just a newline, process passport
+ 30     skip-chars-matching-whitespace line
+ 31     var new-passport?/eax: boolean <- stream-empty? line
+ 32     {
+ 33       compare new-passport?, 0/false
+ 34       break-if-=
+ 35       compare curr-passport-field-count, 7
+ 36       {
+ 37         break-if-!=
+ 38         valid-passport-count <- increment
+ 39         print-string 0, "=> "
+ 40         print-int32-decimal 0, valid-passport-count
+ 41         print-string 0, "\n"
+ 42       }
+ 43       curr-passport-field-count <- copy 0
+ 44       loop $main:line-loop
+ 45     }
+ 46     $main:word-loop: {
+ 47       skip-chars-matching-whitespace line
+ 48       var done?/eax: boolean <- stream-empty? line
+ 49       compare done?, 0/false
+ 50       break-if-!=
+ 51       next-token line, 0x3a, key-slice  # ':'
+ 52       var dummy/eax: byte <- read-byte line  # skip ':'
+ 53       next-raw-word line, val-slice
+ 54       print-slice-to-real-screen key-slice
+ 55       print-string 0, " : "
+ 56       print-slice-to-real-screen val-slice
+ 57       print-string 0, "\n"
+ 58       # treat cid as optional
+ 59       var cid?/eax: boolean <- slice-equal? key-slice, "cid"
+ 60       compare cid?, 0/false
+ 61       loop-if-!=
+ 62       # increment field count
+ 63       curr-passport-field-count <- increment
+ 64       # - validate fields one by one, setting curr-passport-field-count to impossibly high value to signal invalid
+ 65       # byr
+ 66       {
+ 67         var byr?/eax: boolean <- slice-equal? key-slice, "byr"
+ 68         compare byr?, 0/false
+ 69         break-if-=
+ 70         # 1920 <= byr <= 2002
+ 71         var byr/eax: int <- parse-decimal-int-from-slice val-slice
+ 72         compare byr, 0x780  # 1920
+ 73         {
+ 74           break-if->=
+ 75           print-string 0, "invalid\n"
+ 76           curr-passport-field-count <- copy 8
+ 77         }
+ 78         compare byr, 0x7d2  # 2002
+ 79         {
+ 80           break-if-<=
+ 81           print-string 0, "invalid\n"
+ 82           curr-passport-field-count <- copy 8
+ 83         }
+ 84       }
+ 85       # iyr
+ 86       {
+ 87         var iyr?/eax: boolean <- slice-equal? key-slice, "iyr"
+ 88         compare iyr?, 0/false
+ 89         break-if-=
+ 90         # 2010 <= iyr <= 2020
+ 91         var iyr/eax: int <- parse-decimal-int-from-slice val-slice
+ 92         compare iyr, 0x7da  # 2010
+ 93         {
+ 94           break-if->=
+ 95           print-string 0, "invalid\n"
+ 96           curr-passport-field-count <- copy 8
+ 97         }
+ 98         compare iyr, 0x7e4  # 2020
+ 99         {
+100           break-if-<=
+101           print-string 0, "invalid\n"
+102           curr-passport-field-count <- copy 8
+103         }
+104       }
+105       # eyr
+106       {
+107         var eyr?/eax: boolean <- slice-equal? key-slice, "eyr"
+108         compare eyr?, 0/false
+109         break-if-=
+110         # 2020 <= eyr <= 2030
+111         var eyr/eax: int <- parse-decimal-int-from-slice val-slice
+112         compare eyr, 0x7e4  # 2020
+113         {
+114           break-if->=
+115           print-string 0, "invalid\n"
+116           curr-passport-field-count <- copy 8
+117         }
+118         compare eyr, 0x7ee  # 2030
+119         {
+120           break-if-<=
+121           print-string 0, "invalid\n"
+122           curr-passport-field-count <- copy 8
+123         }
+124       }
+125       # hgt
+126       {
+127         var hgt?/eax: boolean <- slice-equal? key-slice, "hgt"
+128         compare hgt?, 0/false
+129         break-if-=
+130         # convert val
+131         var s: (handle array byte)
+132         var s2/eax: (addr handle array byte) <- address s
+133         _slice-to-string val-slice, s2
+134         var s3/eax: (addr array byte) <- lookup *s2
+135         var s4/ebx: (addr array byte) <- copy s3
+136         # check suffix
+137         var start/edx: int <- length s4
+138         start <- subtract 2  # luckily both 'in' and 'cm' have the same length
+139         {
+140           var suffix-h: (handle array byte)
+141           var suffix-ah/ecx: (addr handle array byte) <- address suffix-h
+142           substring s4, start, 2, suffix-ah
+143           var suffix/eax: (addr array byte) <- lookup *suffix-ah
+144           {
+145             var match?/eax: boolean <- string-equal? suffix, "in"
+146             compare match?, 0/false
+147             break-if-=
+148             # if suffix is "in", 59 <= val <= 96
+149             var num-h: (handle array byte)
+150             var num-ah/ecx: (addr handle array byte) <- address num-h
+151             substring s4, 0, start, num-ah
+152             var num/eax: (addr array byte) <- lookup *num-ah
+153             var val/eax: int <- parse-decimal-int num
+154             compare val, 0x3b  # 59
+155             {
+156               break-if->=
+157           print-string 0, "invalid\n"
+158               curr-passport-field-count <- copy 8
+159             }
+160             compare val, 0x60  # 96
+161             {
+162               break-if-<=
+163           print-string 0, "invalid\n"
+164               curr-passport-field-count <- copy 8
+165             }
+166             loop $main:word-loop
+167           }
+168           {
+169             var match?/eax: boolean <- string-equal? suffix, "cm"
+170             compare match?, 0/false
+171             break-if-=
+172             # if suffix is "cm", 150 <= val <= 193
+173             var num-h: (handle array byte)
+174             var num-ah/ecx: (addr handle array byte) <- address num-h
+175             substring s4, 0, start, num-ah
+176             var num/eax: (addr array byte) <- lookup *num-ah
+177             var val/eax: int <- parse-decimal-int num
+178             compare val, 0x96  # 150
+179             {
+180               break-if->=
+181           print-string 0, "invalid\n"
+182               curr-passport-field-count <- copy 8
+183             }
+184             compare val, 0xc1  # 193
+185             {
+186               break-if-<=
+187           print-string 0, "invalid\n"
+188               curr-passport-field-count <- copy 8
+189             }
+190             loop $main:word-loop
+191           }
+192           print-string 0, "invalid\n"
+193           curr-passport-field-count <- copy 8
+194           loop $main:word-loop
+195         }
+196       }
+197       # hcl
+198       {
+199         var hcl?/eax: boolean <- slice-equal? key-slice, "hcl"
+200         compare hcl?, 0/false
+201         break-if-=
+202         # convert val
+203         var s: (handle array byte)
+204         var s2/eax: (addr handle array byte) <- address s
+205         _slice-to-string val-slice, s2
+206         var s3/eax: (addr array byte) <- lookup *s2
+207         # check length
+208         var len/ebx: int <- length s3
+209         compare len, 7
+210         {
+211           break-if-=
+212           print-string 0, "invalid\n"
+213           curr-passport-field-count <- copy 8
+214           loop $main:word-loop
+215         }
+216         # check first byte
+217         {
+218           var c/eax: (addr byte) <- index s3, 0
+219           var c2/eax: byte <- copy-byte *c
+220           compare c2, 0x23/hash
+221           break-if-=
+222           print-string 0, "invalid2\n"
+223           curr-passport-field-count <- copy 8
+224           loop $main:word-loop
+225         }
+226         # check remaining bytes
+227         var i/ebx: int <- copy 1  # skip 0
+228         {
+229           compare i, 7
+230           break-if->=
+231           var c/eax: (addr byte) <- index s3, i
+232           {
+233             var c2/eax: byte <- copy-byte *c
+234             var valid?/eax: boolean <- hex-digit? c2
+235             compare valid?, 0
+236             loop-if-= $main:word-loop
+237           }
+238           i <- increment
+239           loop
+240         }
+241       }
+242       # ecl
+243       {
+244         var ecl?/eax: boolean <- slice-equal? key-slice, "ecl"
+245         compare ecl?, 0/false
+246         break-if-=
+247         var amb?/eax: boolean <- slice-equal? val-slice, "amb"
+248         compare amb?, 0/false
+249         loop-if-!= $main:word-loop
+250         var blu?/eax: boolean <- slice-equal? val-slice, "blu"
+251         compare blu?, 0/false
+252         loop-if-!= $main:word-loop
+253         var brn?/eax: boolean <- slice-equal? val-slice, "brn"
+254         compare brn?, 0/false
+255         loop-if-!= $main:word-loop
+256         var gry?/eax: boolean <- slice-equal? val-slice, "gry"
+257         compare gry?, 0/false
+258         loop-if-!= $main:word-loop
+259         var grn?/eax: boolean <- slice-equal? val-slice, "grn"
+260         compare grn?, 0/false
+261         loop-if-!= $main:word-loop
+262         var hzl?/eax: boolean <- slice-equal? val-slice, "hzl"
+263         compare hzl?, 0/false
+264         loop-if-!= $main:word-loop
+265         var oth?/eax: boolean <- slice-equal? val-slice, "oth"
+266         compare oth?, 0/false
+267         loop-if-!= $main:word-loop
+268         print-string 0, "invalid\n"
+269         curr-passport-field-count <- copy 8
+270       }
+271       # pid
+272       {
+273         var pid?/eax: boolean <- slice-equal? key-slice, "pid"
+274         compare pid?, 0/false
+275         break-if-=
+276         # convert val
+277         var s: (handle array byte)
+278         var s2/eax: (addr handle array byte) <- address s
+279         _slice-to-string val-slice, s2
+280         var s3/eax: (addr array byte) <- lookup *s2
+281         # check length
+282         var len/eax: int <- length s3
+283         compare len, 9
+284         {
+285           break-if-=
+286           print-string 0, "invalid\n"
+287           curr-passport-field-count <- copy 8
+288           loop $main:word-loop
+289         }
+290         # check valid decimal int
+291         # parse-decimal-int-from-slice currently returns 0 on invalid parse,
+292         # which isn't ideal but suffices for our purposes
+293         var val/eax: int <- parse-decimal-int-from-slice val-slice
+294         compare val, 0
+295         {
+296           break-if->
+297           print-string 0, "invalid\n"
+298           curr-passport-field-count <- copy 8
+299         }
+300       }
+301       loop
+302     }
+303     loop
+304   }
+305   # process final passport
+306   compare curr-passport-field-count, 7
+307   {
+308     break-if-!=
+309     valid-passport-count <- increment
+310   }
+311   print-int32-decimal 0, valid-passport-count
+312   print-string 0, "\n"
+313   return 0
+314 }
+
+ + + diff --git a/html/linux/apps/advent2020/5a.mu.html b/html/linux/apps/advent2020/5a.mu.html new file mode 100644 index 00000000..3c3b535d --- /dev/null +++ b/html/linux/apps/advent2020/5a.mu.html @@ -0,0 +1,146 @@ + + + + +Mu - linux/apps/advent2020/5a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/5a.mu +
+ 1 # https://adventofcode.com/2020/day/5
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/5a.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var line-storage: (stream byte 0x10)  # 16 bytes is enough
+13   var line/edx: (addr stream byte) <- address line-storage
+14   var max-seat-id/edi: int <- copy 0
+15   {
+16     # read line from stdin
+17     clear-stream line
+18     read-line-from-real-keyboard line
+19     print-stream-to-real-screen line
+20     # if line is empty (not even a newline), quit
+21     var done?/eax: boolean <- stream-empty? line
+22     compare done?, 0/false
+23     break-if-!=
+24     # process line
+25     var seat-id/eax: int <- convert-from-binary line
+26     compare seat-id, max-seat-id
+27     {
+28       break-if-<=
+29       max-seat-id <- copy seat-id
+30     }
+31     loop
+32   }
+33   print-int32-decimal 0, max-seat-id
+34   print-string 0, "\n"
+35   return 0
+36 }
+37 
+38 fn convert-from-binary in: (addr stream byte) -> _/eax: int {
+39   var result/edi: int <- copy 0
+40   var i/ecx: int <- copy 9  # loop counter and also exponent
+41   {
+42     compare i, 0
+43     break-if-<
+44     var c/eax: byte <- read-byte in
+45 #?     print-string 0, "char: "
+46 #?     {
+47 #?       var c2/eax: int <- copy c
+48 #?       print-int32-hex 0, c2
+49 #?     }
+50 #?     print-string 0, "\n"
+51     var bit/edx: int <- copy 0
+52     {
+53       compare c, 0x42/B
+54       break-if-!=
+55       bit <- copy 1
+56     }
+57     {
+58       compare c, 0x52/R
+59       break-if-!=
+60       bit <- copy 1
+61     }
+62 #?     print-string 0, "bit: "
+63 #?     print-int32-decimal 0, bit
+64 #?     print-string 0, "\n"
+65     var bit-value/eax: int <- repeated-shift-left bit, i
+66 #?     print-string 0, "bit value: "
+67 #?     print-int32-decimal 0, bit-value
+68 #?     print-string 0, "\n"
+69     result <- add bit-value
+70 #?     print-string 0, "result: "
+71 #?     print-int32-decimal 0, result
+72 #?     print-string 0, "\n"
+73     i <- decrement
+74     loop
+75   }
+76   print-int32-decimal 0, result
+77   print-string 0, "\n"
+78   return result
+79 }
+
+ + + diff --git a/html/linux/apps/advent2020/5b.mu.html b/html/linux/apps/advent2020/5b.mu.html new file mode 100644 index 00000000..b5e1892f --- /dev/null +++ b/html/linux/apps/advent2020/5b.mu.html @@ -0,0 +1,148 @@ + + + + +Mu - linux/apps/advent2020/5b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/5b.mu +
+ 1 # https://adventofcode.com/2020/day/5
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/5b.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var pass-storage: (array int 0x400)  # 1k ints
+13   var pass/esi: (addr array int) <- address pass-storage
+14   # phase 1: populate pass array
+15   var line-storage: (stream byte 0x10)  # 16 bytes is enough
+16   var line/edx: (addr stream byte) <- address line-storage
+17   {
+18     # read line from stdin
+19     clear-stream line
+20     read-line-from-real-keyboard line
+21     # if line is empty (not even a newline), quit
+22     var done?/eax: boolean <- stream-empty? line
+23     compare done?, 0/false
+24     break-if-!=
+25     # process line
+26     var seat-id/eax: int <- convert-from-binary line
+27     var dest/eax: (addr int) <- index pass, seat-id
+28     copy-to *dest, 1
+29     loop
+30   }
+31   # phase 2: skip empty seats
+32   var i/eax: int <- copy 0
+33   {
+34     compare i, 0x400
+35     break-if->=
+36     var src/ecx: (addr int) <- index pass, i
+37     compare *src, 0
+38     break-if-!=
+39     i <- increment
+40     loop
+41   }
+42   # phase 3: skip non-empty seats
+43   {
+44     compare i, 0x400
+45     break-if->=
+46     var src/ecx: (addr int) <- index pass, i
+47     compare *src, 0
+48     break-if-=
+49     i <- increment
+50     loop
+51   }
+52   print-int32-decimal 0, i
+53   print-string 0, "\n"
+54   return 0
+55 }
+56 
+57 fn convert-from-binary in: (addr stream byte) -> _/eax: int {
+58   var result/edi: int <- copy 0
+59   var i/ecx: int <- copy 9  # loop counter and also exponent
+60   {
+61     compare i, 0
+62     break-if-<
+63     var c/eax: byte <- read-byte in
+64     var bit/edx: int <- copy 0
+65     {
+66       compare c, 0x42/B
+67       break-if-!=
+68       bit <- copy 1
+69     }
+70     {
+71       compare c, 0x52/R
+72       break-if-!=
+73       bit <- copy 1
+74     }
+75     var bit-value/eax: int <- repeated-shift-left bit, i
+76     result <- add bit-value
+77     i <- decrement
+78     loop
+79   }
+80   return result
+81 }
+
+ + + diff --git a/html/linux/apps/arith.mu.html b/html/linux/apps/arith.mu.html new file mode 100644 index 00000000..fb6a9194 --- /dev/null +++ b/html/linux/apps/arith.mu.html @@ -0,0 +1,326 @@ + + + + +Mu - linux/apps/arith.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/arith.mu +
+  1 # Integer arithmetic using conventional precedence.
+  2 #
+  3 # Follows part 2 of Jack Crenshaw's "Let's build a compiler!"
+  4 #   https://compilers.iecc.com/crenshaw
+  5 #
+  6 # Limitations:
+  7 #   No division yet.
+  8 #
+  9 # To build:
+ 10 #   $ ./translate apps/arith.mu
+ 11 #
+ 12 # Example session:
+ 13 #   $ ./a.elf
+ 14 #   press ctrl-c or ctrl-d to exit
+ 15 #   > 1
+ 16 #   1
+ 17 #   > 1+1
+ 18 #   2
+ 19 #   > 1 + 1
+ 20 #   2
+ 21 #   > 1+2 +3
+ 22 #   6
+ 23 #   > 1+2 *3
+ 24 #   7
+ 25 #   > (1+2) *3
+ 26 #   9
+ 27 #   > 1 + 3*4
+ 28 #   13
+ 29 #   > ^D
+ 30 #   $
+ 31 #
+ 32 # Error handling is non-existent. This is just a prototype.
+ 33 
+ 34 fn main -> _/ebx: int {
+ 35   enable-keyboard-immediate-mode
+ 36   var look/esi: grapheme <- copy 0  # lookahead
+ 37   var n/eax: int <- copy 0  # result of each expression
+ 38   print-string 0/screen, "press ctrl-c or ctrl-d to exit\n"
+ 39   # read-eval-print loop
+ 40   {
+ 41     # print prompt
+ 42     print-string 0/screen, "> "
+ 43     # read and eval
+ 44     n, look <- simplify  # we explicitly thread 'look' everywhere
+ 45     # if (look == 0) break
+ 46     compare look, 0
+ 47     break-if-=
+ 48     # print
+ 49     print-int32-decimal 0/screen, n
+ 50     print-string 0/screen, "\n"
+ 51     #
+ 52     loop
+ 53   }
+ 54   enable-keyboard-type-mode
+ 55   return 0
+ 56 }
+ 57 
+ 58 fn simplify -> _/eax: int, _/esi: grapheme {
+ 59   # prime the pump
+ 60   var look/esi: grapheme <- get-char
+ 61   # do it
+ 62   var result/eax: int <- copy 0
+ 63   result, look <- expression look
+ 64   return result, look
+ 65 }
+ 66 
+ 67 fn expression _look: grapheme -> _/eax: int, _/esi: grapheme {
+ 68   var look/esi: grapheme <- copy _look
+ 69   # read arg
+ 70   var result/eax: int <- copy 0
+ 71   result, look <- term look
+ 72   $expression:loop: {
+ 73     # while next non-space char in ['+', '-']
+ 74     look <- skip-spaces look
+ 75     {
+ 76       var continue?/eax: boolean <- add-or-sub? look
+ 77       compare continue?, 0/false
+ 78       break-if-= $expression:loop
+ 79     }
+ 80     # read operator
+ 81     var op/ecx: grapheme <- copy 0
+ 82     op, look <- operator look
+ 83     # read next arg
+ 84     var second/edx: int <- copy 0
+ 85     look <- skip-spaces look
+ 86     {
+ 87       var tmp/eax: int <- copy 0
+ 88       tmp, look <- term look
+ 89       second <- copy tmp
+ 90     }
+ 91     # reduce
+ 92     $expression:perform-op: {
+ 93       {
+ 94         compare op, 0x2b/+
+ 95         break-if-!=
+ 96         result <- add second
+ 97         break $expression:perform-op
+ 98       }
+ 99       {
+100         compare op, 0x2d/minus
+101         break-if-!=
+102         result <- subtract second
+103         break $expression:perform-op
+104       }
+105     }
+106     loop
+107   }
+108   look <- skip-spaces look
+109   return result, look
+110 }
+111 
+112 fn term _look: grapheme -> _/eax: int, _/esi: grapheme {
+113   var look/esi: grapheme <- copy _look
+114   # read arg
+115   look <- skip-spaces look
+116   var result/eax: int <- copy 0
+117   result, look <- factor look
+118   $term:loop: {
+119     # while next non-space char in ['*', '/']
+120     look <- skip-spaces look
+121     {
+122       var continue?/eax: boolean <- mul-or-div? look
+123       compare continue?, 0/false
+124       break-if-= $term:loop
+125     }
+126     # read operator
+127     var op/ecx: grapheme <- copy 0
+128     op, look <- operator look
+129     # read next arg
+130     var second/edx: int <- copy 0
+131     look <- skip-spaces look
+132     {
+133       var tmp/eax: int <- copy 0
+134       tmp, look <- factor look
+135       second <- copy tmp
+136     }
+137     # reduce
+138     $term:perform-op: {
+139       {
+140         compare op, 0x2a/*
+141         break-if-!=
+142         result <- multiply second
+143         break $term:perform-op
+144       }
+145 #?       {
+146 #?         compare op, 0x2f/slash
+147 #?         break-if-!=
+148 #?         result <- divide second  # not in Mu yet
+149 #?         break $term:perform-op
+150 #?       }
+151     }
+152     loop
+153   }
+154   return result, look
+155 }
+156 
+157 fn factor _look: grapheme -> _/eax: int, _/esi: grapheme {
+158   var look/esi: grapheme <- copy _look  # should be a no-op
+159   look <- skip-spaces look
+160   # if next char is not '(', parse a number
+161   compare look, 0x28/open-paren
+162   {
+163     break-if-=
+164     var result/eax: int <- copy 0
+165     result, look <- num look
+166     return result, look
+167   }
+168   # otherwise recurse
+169   look <- get-char  # '('
+170   var result/eax: int <- copy 0
+171   result, look <- expression look
+172   look <- skip-spaces look
+173   look <- get-char  # ')'
+174   return result, look
+175 }
+176 
+177 fn mul-or-div? c: grapheme -> _/eax: boolean {
+178   compare c, 0x2a/*
+179   {
+180     break-if-!=
+181     return 1/true
+182   }
+183   compare c, 0x2f/slash
+184   {
+185     break-if-!=
+186     return 1/true
+187   }
+188   return 0/false
+189 }
+190 
+191 fn add-or-sub? c: grapheme -> _/eax: boolean {
+192   compare c, 0x2b/+
+193   {
+194     break-if-!=
+195     return 1/true
+196   }
+197   compare c, 0x2d/minus
+198   {
+199     break-if-!=
+200     return 1/true
+201   }
+202   return 0/false
+203 }
+204 
+205 fn operator _look: grapheme -> _/ecx: grapheme, _/esi: grapheme {
+206   var op/ecx: grapheme <- copy _look
+207   var look/esi: grapheme <- get-char
+208   return op, look
+209 }
+210 
+211 fn num _look: grapheme -> _/eax: int, _/esi: grapheme {
+212   var look/esi: grapheme <- copy _look
+213   var result/edi: int <- copy 0
+214   {
+215     var first-digit/eax: int <- to-decimal-digit look
+216     result <- copy first-digit
+217   }
+218   {
+219     look <- get-char
+220     # done?
+221     var digit?/eax: boolean <- decimal-digit? look
+222     compare digit?, 0/false
+223     break-if-=
+224     # result *= 10
+225     {
+226       var ten/eax: int <- copy 0xa
+227       result <- multiply ten
+228     }
+229     # result += digit(look)
+230     var digit/eax: int <- to-decimal-digit look
+231     result <- add digit
+232     loop
+233   }
+234   return result, look
+235 }
+236 
+237 fn skip-spaces _look: grapheme -> _/esi: grapheme {
+238   var look/esi: grapheme <- copy _look  # should be a no-op
+239   {
+240     compare look, 0x20
+241     break-if-!=
+242     look <- get-char
+243     loop
+244   }
+245   return look
+246 }
+247 
+248 fn get-char -> _/esi: grapheme {
+249   var look/eax: grapheme <- read-key-from-real-keyboard
+250   print-grapheme-to-real-screen look
+251   compare look, 4
+252   {
+253     break-if-!=
+254     print-string 0/screen, "^D\n"
+255     syscall_exit
+256   }
+257   return look
+258 }
+
+ + + diff --git a/html/linux/apps/crenshaw2-1.subx.html b/html/linux/apps/crenshaw2-1.subx.html new file mode 100644 index 00000000..191ff721 --- /dev/null +++ b/html/linux/apps/crenshaw2-1.subx.html @@ -0,0 +1,621 @@ + + + + +Mu - linux/apps/crenshaw2-1.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/crenshaw2-1.subx +
+  1 # Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas
+  2 # which corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt
+  3 # except that we support hex digits.
+  4 #
+  5 # To run:
+  6 #   $ bootstrap/bootstrap translate [01]*.subx apps/crenshaw2-1.subx -o crenshaw2-1
+  7 #   $ echo '3'  |bootstrap/bootstrap run crenshaw2-1
+  8 # Expected output:
+  9 #   # syscall(exit, 3)
+ 10 #   bb/copy-to-ebx  3/imm32
+ 11 #   b8/copy-to-eax  1/imm32/exit
+ 12 #   cd/syscall  0x80/imm8
+ 13 #
+ 14 # To run the generated output:
+ 15 #   $ echo '3'  |bootstrap/bootstrap run crenshaw2-1 > z1.subx
+ 16 #   $ bootstrap/bootstrap translate z1.subx -o z1
+ 17 #   $ bootstrap/bootstrap run z1
+ 18 #   $ echo $?
+ 19 #   3
+ 20 #
+ 21 # Stdin must contain just a single hex digit. Other input will print an error:
+ 22 #   $ echo 'xyz'  |bootstrap/bootstrap run crenshaw2-1
+ 23 #   Error: integer expected
+ 24 #
+ 25 # Names in this file sometimes follow Crenshaw's original rather than my usual
+ 26 # naming conventions.
+ 27 
+ 28 == code
+ 29 #   instruction                     effective address                                                   register    displacement    immediate
+ 30 # . op          subop               mod             rm32          base        index         scale       r32
+ 31 # . 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
+ 32 
+ 33 Entry:  # run tests if necessary, call 'compile' if not
+ 34     # . prologue
+ 35     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 36 
+ 37     # initialize heap
+ 38     # . Heap = new-segment(Heap-size)
+ 39     # . . push args
+ 40     68/push  Heap/imm32
+ 41     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+ 42     # . . call
+ 43     e8/call  new-segment/disp32
+ 44     # . . discard args
+ 45     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 46 
+ 47     # - if argc > 1 and argv[1] == "test", then return run_tests()
+ 48     # if (argc <= 1) goto run-main
+ 49     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
+ 50     7e/jump-if-<=  $run-main/disp8
+ 51     # if (!kernel-string-equal?(argv[1], "test")) goto run-main
+ 52     # . eax = kernel-string-equal?(argv[1], "test")
+ 53     # . . push args
+ 54     68/push  "test"/imm32
+ 55     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 56     # . . call
+ 57     e8/call  kernel-string-equal?/disp32
+ 58     # . . discard args
+ 59     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 60     # . if (eax == false) goto run-main
+ 61     3d/compare-eax-and  0/imm32/false
+ 62     74/jump-if-=  $run-main/disp8
+ 63     # run-tests()
+ 64     e8/call  run-tests/disp32
+ 65     # syscall(exit, *Num-test-failures)
+ 66     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+ 67     eb/jump  $main:end/disp8
+ 68 $run-main:
+ 69     # - otherwise read a program from stdin and emit its translation to stdout
+ 70     # . compile(Stdin, 1/stdout, 2/stderr, ed)
+ 71     # . . push args
+ 72     68/push  0/imm32/exit-descriptor
+ 73     68/push  2/imm32/stderr
+ 74     68/push  1/imm32/stdout
+ 75     68/push  Stdin/imm32
+ 76     # . . call
+ 77     e8/call  compile/disp32
+ 78     # . . discard args
+ 79     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 80     # syscall(exit, 0)
+ 81     bb/copy-to-ebx  0/imm32
+ 82 $main:end:
+ 83     e8/call  syscall_exit/disp32
+ 84 
+ 85 # the main entry point
+ 86 compile:  # in: (addr buffered-file), out: fd or (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+ 87     # . prologue
+ 88     55/push-ebp
+ 89     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 90     # . save registers
+ 91     50/push-eax
+ 92     51/push-ecx
+ 93     # prime the pump
+ 94     # . Look = get-char(in)
+ 95     # . . push args
+ 96     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+ 97     # . . call
+ 98     e8/call  get-char/disp32
+ 99     # . . discard args
+100     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+101     # var num/ecx: (stream byte 7)
+102     # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes.
+103     # Sizing the stream just right buys us overflow-handling for free inside 'get-num'.
+104     # Add 12 bytes for 'read', 'write' and 'size' fields, for a total of 19 bytes, or 0x13 in hex.
+105     # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point.
+106     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x13/imm32        # subtract from esp
+107     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+108     # initialize the stream
+109     # . num->size = 7
+110     c7          0/subop/copy        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           8/disp8         7/imm32           # copy to *(ecx+8)
+111     # . clear-stream(num)
+112     # . . push args
+113     51/push-ecx
+114     # . . call
+115     e8/call  clear-stream/disp32
+116     # . . discard args
+117     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+118     # read a digit from 'in' into 'num'
+119     # . get-num(in, num, err, ed)
+120     # . . push args
+121     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+122     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+123     51/push-ecx/num
+124     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+125     # . . call
+126     e8/call  get-num/disp32
+127     # . . discard args
+128     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+129     # render 'num' into the following template on 'out':
+130     #   bb/copy-to-ebx  _num_
+131     #   b8/copy-to-eax  1/imm32/exit
+132     #   cd/syscall  0x80/imm8
+133     #
+134     # . write(out, "bb/copy-to-ebx  ")
+135     # . . push args
+136     68/push  "bb/copy-to-ebx  "/imm32
+137     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+138     # . . call
+139     e8/call  write/disp32
+140     # . . discard args
+141     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+142     # . write-stream(out, num)
+143     # . . push args
+144     51/push-ecx/num
+145     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+146     # . . call
+147     e8/call  write-stream/disp32
+148     # . . discard args
+149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+150     # . write(out, Newline)
+151     # . . push args
+152     68/push  Newline/imm32
+153     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+154     # . . call
+155     e8/call  write/disp32
+156     # . . discard args
+157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+158     # . write(out, "b8/copy-to-eax  1/imm32/exit\n")
+159     # . . push args
+160     68/push  "b8/copy-to-eax  1/imm32/exit\n"/imm32
+161     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+162     # . . call
+163     e8/call  write/disp32
+164     # . . discard args
+165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+166     # . write(out, "cd/syscall  0x80/imm8\n")
+167     # . . push args
+168     68/push  "cd/syscall  0x80/imm8\n"/imm32
+169     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+170     # . . call
+171     e8/call  write/disp32
+172     # . . discard args
+173     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+174 $compile:end:
+175     # . restore registers
+176     59/pop-to-ecx
+177     58/pop-to-eax
+178     # . epilogue
+179     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+180     5d/pop-to-ebp
+181     c3/return
+182 
+183 # Read a single digit into 'out'. Abort if there are none, or if there is no
+184 # space in 'out'.
+185 # Input comes from the global variable 'Look' (first byte) and the argument
+186 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit.
+187 get-num:  # in: (addr buffered-file), out: (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+188     # pseudocode:
+189     #   if (!digit?(Look)) expected(ed, err, "integer")
+190     #   if out->write >= out->size
+191     #     write(err, "Error: too many digits in number\n")
+192     #     stop(ed, 1)
+193     #   out->data[out->write] = LSB(Look)
+194     #   ++out->write
+195     #   Look = get-char(in)
+196     #
+197     # registers:
+198     #   in: esi
+199     #   out: edi
+200     #   out->write: ecx (cached copy; need to keep in sync)
+201     #   out->size: edx
+202     #   temporaries: eax, ebx
+203     # We can't allocate Look to a register because it gets written implicitly in
+204     # get-char in each iteration of the loop. (Thereby demonstrating that it's
+205     # not the right interface for us. But we'll keep it just to follow Crenshaw.)
+206     #
+207     # . prologue
+208     55/push-ebp
+209     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+210     # - if (digit?(Look)) expected(ed, err, "integer")
+211     # . eax = digit?(Look)
+212     # . . push args
+213     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+214     # . . call
+215     e8/call  digit?/disp32
+216     # . . discard args
+217     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+218     # . if (eax == false)
+219     3d/compare-eax-and  0/imm32/false
+220     75/jump-if-!=  $get-num:main/disp8
+221     # . expected(ed, err, "integer")
+222     # . . push args
+223     68/push  "integer"/imm32
+224     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+225     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+226     # . . call
+227     e8/call  expected/disp32  # never returns
+228     # . . discard args
+229     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+230 $get-num:main:
+231     # - otherwise read a digit
+232     # . save registers
+233     50/push-eax
+234     51/push-ecx
+235     52/push-edx
+236     53/push-ebx
+237     56/push-esi
+238     57/push-edi
+239     # read necessary variables to registers
+240     # esi = in
+241     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+242     # edi = out
+243     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
+244     # ecx = out->write
+245     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+246     # edx = out->size
+247     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
+248 $get-num:loop:
+249     # if (out->write >= out->size) error
+250     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # compare edx with ecx
+251     7d/jump-if-<  $get-num:stage2/disp8
+252     # . error(ed, err, msg)  # TODO: show full number
+253     # . . push args
+254     68/push  "get-num: too many digits in number"/imm32
+255     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+256     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+257     # . . call
+258     e8/call  error/disp32  # never returns
+259     # . . discard args
+260     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+261 $get-num:stage2:
+262     # out->data[out->write] = LSB(Look)
+263     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
+264     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy *Look to eax
+265     88/copy-byte                    0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/AL    .               .                 # copy byte at AL to *ebx
+266     # ++out->write
+267     41/increment-ecx
+268     # Look = get-char(in)
+269     # . . push args
+270     56/push-esi
+271     # . . call
+272     e8/call  get-char/disp32
+273     # . . discard args
+274     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+275 $get-num:loop-end:
+276     # persist necessary variables from registers
+277     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy ecx to *edi
+278 $get-num:end:
+279     # . restore registers
+280     5f/pop-to-edi
+281     5e/pop-to-esi
+282     5b/pop-to-ebx
+283     5a/pop-to-edx
+284     59/pop-to-ecx
+285     58/pop-to-eax
+286     # . epilogue
+287     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+288     5d/pop-to-ebp
+289     c3/return
+290 
+291 test-get-num-reads-single-digit:
+292     # - check that get-num returns first character if it's a digit
+293     # This test uses exit-descriptors. Use ebp for setting up local variables.
+294     55/push-ebp
+295     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+296     # clear all streams
+297     # . clear-stream(_test-stream)
+298     # . . push args
+299     68/push  _test-stream/imm32
+300     # . . call
+301     e8/call  clear-stream/disp32
+302     # . . discard args
+303     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+304     # . clear-stream($_test-buffered-file->buffer)
+305     # . . push args
+306     68/push  $_test-buffered-file->buffer/imm32
+307     # . . call
+308     e8/call  clear-stream/disp32
+309     # . . discard args
+310     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+311     # . clear-stream(_test-output-stream)
+312     # . . push args
+313     68/push  _test-output-stream/imm32
+314     # . . call
+315     e8/call  clear-stream/disp32
+316     # . . discard args
+317     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+318     # . clear-stream(_test-error-stream)
+319     # . . push args
+320     68/push  _test-error-stream/imm32
+321     # . . call
+322     e8/call  clear-stream/disp32
+323     # . . discard args
+324     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+325     # initialize 'in'
+326     # . write(_test-stream, "3")
+327     # . . push args
+328     68/push  "3"/imm32
+329     68/push  _test-stream/imm32
+330     # . . call
+331     e8/call  write/disp32
+332     # . . discard args
+333     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+334     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+335     # . var ed/eax: exit-descriptor
+336     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+337     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+338     # . tailor-exit-descriptor(ed, 16)
+339     # . . push args
+340     68/push  0x10/imm32/nbytes-of-args-for-get-num
+341     50/push-eax/ed
+342     # . . call
+343     e8/call  tailor-exit-descriptor/disp32
+344     # . . discard args
+345     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+346     # prime the pump
+347     # . get-char(_test-buffered-file)
+348     # . . push args
+349     68/push  _test-buffered-file/imm32
+350     # . . call
+351     e8/call  get-char/disp32
+352     # . . discard args
+353     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+354     # get-num(in, out, err, ed)
+355     # . . push args
+356     50/push-eax/ed
+357     68/push  _test-error-stream/imm32
+358     68/push  _test-output-stream/imm32
+359     68/push  _test-buffered-file/imm32
+360     # . . call
+361     e8/call  get-num/disp32
+362     # registers except esp may be clobbered at this point
+363     # . . discard args
+364     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+365     # check-ints-equal(*_test-output-stream->data, '3', msg)
+366     # . . push args
+367     68/push  "F - test-get-num-reads-single-digit"/imm32
+368     68/push  0x33/imm32
+369     b8/copy-to-eax  _test-output-stream/imm32
+370     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+371     # . . call
+372     e8/call  check-ints-equal/disp32
+373     # . . discard args
+374     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+375     # . reclaim locals
+376     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+377     5d/pop-to-ebp
+378     c3/return
+379 
+380 test-get-num-aborts-on-non-digit-in-Look:
+381     # - check that get-num returns first character if it's a digit
+382     # This test uses exit-descriptors. Use ebp for setting up local variables.
+383     55/push-ebp
+384     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+385     # clear all streams
+386     # . clear-stream(_test-stream)
+387     # . . push args
+388     68/push  _test-stream/imm32
+389     # . . call
+390     e8/call  clear-stream/disp32
+391     # . . discard args
+392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+393     # . clear-stream($_test-buffered-file->buffer)
+394     # . . push args
+395     68/push  $_test-buffered-file->buffer/imm32
+396     # . . call
+397     e8/call  clear-stream/disp32
+398     # . . discard args
+399     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+400     # . clear-stream(_test-output-stream)
+401     # . . push args
+402     68/push  _test-output-stream/imm32
+403     # . . call
+404     e8/call  clear-stream/disp32
+405     # . . discard args
+406     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+407     # . clear-stream(_test-error-stream)
+408     # . . push args
+409     68/push  _test-error-stream/imm32
+410     # . . call
+411     e8/call  clear-stream/disp32
+412     # . . discard args
+413     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+414     # initialize 'in'
+415     # . write(_test-stream, "3")
+416     # . . push args
+417     68/push  "3"/imm32
+418     68/push  _test-stream/imm32
+419     # . . call
+420     e8/call  write/disp32
+421     # . . discard args
+422     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+423     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+424     # . var ed/eax: exit-descriptor
+425     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+426     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+427     # . tailor-exit-descriptor(ed, 16)
+428     # . . push args
+429     68/push  0x10/imm32/nbytes-of-args-for-get-num
+430     50/push-eax/ed
+431     # . . call
+432     e8/call  tailor-exit-descriptor/disp32
+433     # . . discard args
+434     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+435     # *don't* prime the pump
+436     # get-num(in, out, err, ed)
+437     # . . push args
+438     50/push-eax/ed
+439     68/push  _test-error-stream/imm32
+440     68/push  _test-output-stream/imm32
+441     68/push  _test-buffered-file/imm32
+442     # . . call
+443     e8/call  get-num/disp32
+444     # registers except esp may be clobbered at this point
+445     # . . discard args
+446     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+447     # check that get-num tried to call exit(1)
+448     # . check-ints-equal(ed->value, 2, msg)  # i.e. stop was called with value 1
+449     # . . push args
+450     68/push  "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
+451     68/push  2/imm32
+452     # . . push ed->value
+453     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+454     # . . call
+455     e8/call  check-ints-equal/disp32
+456     # . . discard args
+457     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+458     # . reclaim locals
+459     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+460     5d/pop-to-ebp
+461     c3/return
+462 
+463 ## helpers
+464 
+465 # write(f, "Error: "+s+" expected\n") then stop(ed, 1)
+466 expected:  # ed: (addr exit-descriptor), f: fd or (addr stream byte), s: (addr array byte)
+467     # . prologue
+468     55/push-ebp
+469     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+470     # write(f, "Error: ")
+471     # . . push args
+472     68/push  "Error: "/imm32
+473     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+474     # . . call
+475     e8/call  write/disp32
+476     # . . discard args
+477     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+478     # write(f, s)
+479     # . . push args
+480     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+481     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+482     # . . call
+483     e8/call  write/disp32
+484     # . . discard args
+485     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+486     # write(f, " expected\n")
+487     # . . push args
+488     68/push  " expected\n"/imm32
+489     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+490     # . . call
+491     e8/call  write/disp32
+492     # . . discard args
+493     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+494     # stop(ed, 1)
+495     # . . push args
+496     68/push  1/imm32
+497     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+498     # . . call
+499     e8/call  stop/disp32
+500     # should never get past this point
+501 $expected:dead-end:
+502     # . epilogue
+503     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+504     5d/pop-to-ebp
+505     c3/return
+506 
+507 # read a byte from 'f', and save it in 'Look'
+508 get-char:  # f: (addr buffered-file)
+509     # . prologue
+510     55/push-ebp
+511     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+512     # . save registers
+513     50/push-eax
+514     # eax = read-byte-buffered(f)
+515     # . . push args
+516     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+517     # . . call
+518     e8/call  read-byte-buffered/disp32
+519     # . . discard args
+520     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+521     # save eax to Look
+522     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy eax to *Look
+523 $get-char:end:
+524     # . restore registers
+525     58/pop-to-eax
+526     # . epilogue
+527     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+528     5d/pop-to-ebp
+529     c3/return
+530 
+531 digit?:  # c: int -> eax: boolean
+532     # . prologue
+533     55/push-ebp
+534     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+535     # eax = false
+536     b8/copy-to-eax  0/imm32
+537     # if (c < '0') return false
+538     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x30/imm32        # compare *(ebp+8)
+539     7c/jump-if-<  $digit?:end/disp8
+540     # if (c > '9') return false
+541     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x39/imm32        # compare *(ebp+8)
+542     7f/jump-if->  $digit?:end/disp8
+543     # otherwise return true
+544     b8/copy-to-eax  1/imm32
+545 $digit?:end:
+546     # . epilogue
+547     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+548     5d/pop-to-ebp
+549     c3/return
+550 
+551 == data
+552 
+553 Look:  # (char with some extra padding)
+554     0/imm32
+555 
+556 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/crenshaw2-1b.subx.html b/html/linux/apps/crenshaw2-1b.subx.html new file mode 100644 index 00000000..8a50be2c --- /dev/null +++ b/html/linux/apps/crenshaw2-1b.subx.html @@ -0,0 +1,815 @@ + + + + +Mu - linux/apps/crenshaw2-1b.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/crenshaw2-1b.subx +
+  1 # Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas
+  2 # which corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt
+  3 # except that we support hex numbers of multiple digits.
+  4 #
+  5 # To run:
+  6 #   $ bootstrap/bootstrap translate [01]*.subx apps/crenshaw2-1b.subx -o crenshaw2-1b
+  7 #   $ echo '1a'  |bootstrap/bootstrap run crenshaw2-1b
+  8 # Expected output:
+  9 #   # syscall(exit, 1a)
+ 10 #   bb/copy-to-ebx  3/imm32
+ 11 #   b8/copy-to-eax  1/imm32/exit
+ 12 #   cd/syscall  0x80/imm8
+ 13 #
+ 14 # To run the generated output:
+ 15 #   $ echo '1a'  |bootstrap/bootstrap run crenshaw2-1b > z1.subx
+ 16 #   $ bootstrap/bootstrap translate z1.subx -o z1
+ 17 #   $ bootstrap/bootstrap run z1
+ 18 #   $ echo $?
+ 19 #   26  # 0x1a in decimal
+ 20 #
+ 21 # Stdin must contain just a single hex digit. Other input will print an error:
+ 22 #   $ echo 'xyz'  |bootstrap/bootstrap run crenshaw2-1b
+ 23 #   Error: integer expected
+ 24 #
+ 25 # Names in this file sometimes follow Crenshaw's original rather than my usual
+ 26 # naming conventions.
+ 27 
+ 28 == code
+ 29 #   instruction                     effective address                                                   register    displacement    immediate
+ 30 # . op          subop               mod             rm32          base        index         scale       r32
+ 31 # . 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
+ 32 
+ 33 Entry:  # run tests if necessary, call 'compile' if not
+ 34     # . prologue
+ 35     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 36 
+ 37     # initialize heap
+ 38     # . Heap = new-segment(Heap-size)
+ 39     # . . push args
+ 40     68/push  Heap/imm32
+ 41     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+ 42     # . . call
+ 43     e8/call  new-segment/disp32
+ 44     # . . discard args
+ 45     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 46 
+ 47     # - if argc > 1 and argv[1] == "test", then return run_tests()
+ 48     # if (argc <= 1) goto run-main
+ 49     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
+ 50     7e/jump-if-<=  $run-main/disp8
+ 51     # if (!kernel-string-equal?(argv[1], "test")) goto run-main
+ 52     # . eax = kernel-string-equal?(argv[1], "test")
+ 53     # . . push args
+ 54     68/push  "test"/imm32
+ 55     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 56     # . . call
+ 57     e8/call  kernel-string-equal?/disp32
+ 58     # . . discard args
+ 59     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 60     # . if (eax == false) goto run-main
+ 61     3d/compare-eax-and  0/imm32/false
+ 62     74/jump-if-=  $run-main/disp8
+ 63     # run-tests()
+ 64     e8/call  run-tests/disp32
+ 65     # syscall(exit, *Num-test-failures)
+ 66     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+ 67     eb/jump  $main:end/disp8
+ 68 $run-main:
+ 69     # - otherwise read a program from stdin and emit its translation to stdout
+ 70     # . compile(Stdin, 1/stdout, 2/stderr, 0)
+ 71     # . . push args
+ 72     68/push  0/imm32/exit-descriptor
+ 73     68/push  2/imm32/stderr
+ 74     68/push  1/imm32/stdout
+ 75     68/push  Stdin/imm32
+ 76     # . . call
+ 77     e8/call  compile/disp32
+ 78     # . . discard args
+ 79     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 80     # syscall(exit, 0)
+ 81     bb/copy-to-ebx  0/imm32
+ 82 $main:end:
+ 83     e8/call  syscall_exit/disp32
+ 84 
+ 85 # the main entry point
+ 86 compile:  # in: (addr buffered-file), out: fd or (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+ 87     # . prologue
+ 88     55/push-ebp
+ 89     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 90     # . save registers
+ 91     50/push-eax
+ 92     51/push-ecx
+ 93     # prime the pump
+ 94     # . Look = get-char(in)
+ 95     # . . push args
+ 96     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+ 97     # . . call
+ 98     e8/call  get-char/disp32
+ 99     # . . discard args
+100     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+101     # var num/ecx: (stream byte 7)
+102     # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes.
+103     # Sizing the stream just right buys us overflow-handling for free inside 'get-num'.
+104     # Add 12 bytes for 'read', 'write' and 'size' fields, for a total of 19 bytes, or 0x13 in hex.
+105     # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point.
+106     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x13/imm32        # subtract from esp
+107     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+108     # initialize the stream
+109     # . num->size = 7
+110     c7          0/subop/copy        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           8/disp8         7/imm32           # copy to *(ecx+8)
+111     # . clear-stream(num)
+112     # . . push args
+113     51/push-ecx
+114     # . . call
+115     e8/call  clear-stream/disp32
+116     # . . discard args
+117     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+118     # read a digit from 'in' into 'num'
+119     # . get-num(in, num, err, ed)
+120     # . . push args
+121     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+122     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+123     51/push-ecx/num
+124     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+125     # . . call
+126     e8/call  get-num/disp32
+127     # . . discard args
+128     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+129     # render 'num' into the following template on 'out':
+130     #   bb/copy-to-ebx  _num_
+131     #   b8/copy-to-eax  1/imm32/exit
+132     #   cd/syscall  0x80/imm8
+133     #
+134     # . write(out, "bb/copy-to-ebx  ")
+135     # . . push args
+136     68/push  "bb/copy-to-ebx  "/imm32
+137     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+138     # . . call
+139     e8/call  write/disp32
+140     # . . discard args
+141     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+142     # . write-stream(out, num)
+143     # . . push args
+144     51/push-ecx/num
+145     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+146     # . . call
+147     e8/call  write-stream/disp32
+148     # . . discard args
+149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+150     # . write(out, Newline)
+151     # . . push args
+152     68/push  Newline/imm32
+153     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+154     # . . call
+155     e8/call  write/disp32
+156     # . . discard args
+157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+158     # . write(out, "b8/copy-to-eax  1/imm32/exit\n")
+159     # . . push args
+160     68/push  "b8/copy-to-eax  1/imm32/exit\n"/imm32
+161     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+162     # . . call
+163     e8/call  write/disp32
+164     # . . discard args
+165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+166     # . write(out, "cd/syscall  0x80/imm8\n")
+167     # . . push args
+168     68/push  "cd/syscall  0x80/imm8\n"/imm32
+169     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+170     # . . call
+171     e8/call  write/disp32
+172     # . . discard args
+173     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+174 $compile:end:
+175     # . restore registers
+176     59/pop-to-ecx
+177     58/pop-to-eax
+178     # . epilogue
+179     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+180     5d/pop-to-ebp
+181     c3/return
+182 
+183 # Read a sequence of digits into 'out'. Abort if there are none, or if there is
+184 # no space in 'out'.
+185 # Input comes from the global variable 'Look' (first byte) and the argument
+186 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit.
+187 get-num:  # in: (addr buffered-file), out: (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+188     # pseudocode:
+189     #   if (!digit?(Look)) expected(ed, err, "integer")
+190     #   do
+191     #     if out->write >= out->size
+192     #       write(err, "Error: too many digits in number\n")
+193     #       stop(ed, 1)
+194     #     out->data[out->write] = LSB(Look)
+195     #     ++out->write
+196     #     Look = get-char(in)
+197     #   while digit?(Look)
+198     # This is complicated because I don't want to hard-code the error strategy in
+199     # a general helper like write-byte-buffered. Maybe I should just create a
+200     # local helper.
+201     #
+202     # within the loop we'll try to keep things in registers:
+203     #   in: esi
+204     #   out: edi
+205     #   out->write: ecx (cached copy; need to keep in sync)
+206     #   out->size: edx
+207     #   temporaries: eax, ebx
+208     # We can't allocate Look to a register because it gets written implicitly in
+209     # get-char in each iteration of the loop. (Thereby demonstrating that it's
+210     # not the right interface for us. But we'll keep it just to follow Crenshaw.)
+211     #
+212     # . prologue
+213     55/push-ebp
+214     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+215     # - if (digit?(Look)) expected(ed, err, "integer")
+216     # . eax = digit?(Look)
+217     # . . push args
+218     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+219     # . . call
+220     e8/call  digit?/disp32
+221     # . . discard args
+222     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+223     # . if (eax == false)
+224     3d/compare-eax-and  0/imm32/false
+225     75/jump-if-!=  $get-num:main/disp8
+226     # . expected(ed, err, "integer")
+227     # . . push args
+228     68/push  "integer"/imm32
+229     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+230     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+231     # . . call
+232     e8/call  expected/disp32  # never returns
+233     # . . discard args
+234     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+235 $get-num:main:
+236     # - otherwise read a digit
+237     # . save registers
+238     50/push-eax
+239     51/push-ecx
+240     52/push-edx
+241     53/push-ebx
+242     56/push-esi
+243     57/push-edi
+244     # read necessary variables to registers
+245     # esi = in
+246     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+247     # edi = out
+248     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
+249     # ecx = out->write
+250     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+251     # edx = out->size
+252     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
+253 $get-num:loop:
+254     # if (out->write >= out->size) error
+255     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # compare edx with ecx
+256     7d/jump-if-<  $get-num:loop-stage2/disp8
+257     # . error(ed, err, msg)  # TODO: show full number
+258     # . . push args
+259     68/push  "get-num: too many digits in number"/imm32
+260     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+261     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+262     # . . call
+263     e8/call  error/disp32  # never returns
+264     # . . discard args
+265     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+266 $get-num:loop-stage2:
+267     # out->data[out->write] = LSB(Look)
+268     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
+269     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy *Look to eax
+270     88/copy-byte                    0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/AL    .               .                 # copy byte at AL to *ebx
+271     # ++out->write
+272     41/increment-ecx
+273     # Look = get-char(in)
+274     # . . push args
+275     56/push-esi
+276     # . . call
+277     e8/call  get-char/disp32
+278     # . . discard args
+279     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+280     # if (digit?(Look)) loop
+281     # . eax = digit?(Look)
+282     # . . push args
+283     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+284     # . . call
+285     e8/call  digit?/disp32
+286     # . . discard args
+287     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+288     # . if (eax != false) loop
+289     3d/compare-eax-and  0/imm32/false
+290     0f 85/jump-if-!=  $get-num:loop/disp32
+291 $get-num:loop-end:
+292     # persist necessary variables from registers
+293     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy ecx to *edi
+294 $get-num:end:
+295     # . restore registers
+296     5f/pop-to-edi
+297     5e/pop-to-esi
+298     5b/pop-to-ebx
+299     5a/pop-to-edx
+300     59/pop-to-ecx
+301     58/pop-to-eax
+302     # . epilogue
+303     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+304     5d/pop-to-ebp
+305     c3/return
+306 
+307 test-get-num-reads-single-digit:
+308     # - check that get-num returns first character if it's a digit
+309     # This test uses exit-descriptors. Use ebp for setting up local variables.
+310     55/push-ebp
+311     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+312     # clear all streams
+313     # . clear-stream(_test-stream)
+314     # . . push args
+315     68/push  _test-stream/imm32
+316     # . . call
+317     e8/call  clear-stream/disp32
+318     # . . discard args
+319     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+320     # . clear-stream($_test-buffered-file->buffer)
+321     # . . push args
+322     68/push  $_test-buffered-file->buffer/imm32
+323     # . . call
+324     e8/call  clear-stream/disp32
+325     # . . discard args
+326     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+327     # . clear-stream(_test-output-stream)
+328     # . . push args
+329     68/push  _test-output-stream/imm32
+330     # . . call
+331     e8/call  clear-stream/disp32
+332     # . . discard args
+333     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+334     # . clear-stream(_test-error-stream)
+335     # . . push args
+336     68/push  _test-error-stream/imm32
+337     # . . call
+338     e8/call  clear-stream/disp32
+339     # . . discard args
+340     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+341     # initialize 'in'
+342     # . write(_test-stream, "3")
+343     # . . push args
+344     68/push  "3"/imm32
+345     68/push  _test-stream/imm32
+346     # . . call
+347     e8/call  write/disp32
+348     # . . discard args
+349     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+350     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+351     # . var ed/eax: exit-descriptor
+352     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+353     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+354     # . tailor-exit-descriptor(ed, 16)
+355     # . . push args
+356     68/push  0x10/imm32/nbytes-of-args-for-get-num
+357     50/push-eax/ed
+358     # . . call
+359     e8/call  tailor-exit-descriptor/disp32
+360     # . . discard args
+361     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+362     # prime the pump
+363     # . get-char(_test-buffered-file)
+364     # . . push args
+365     68/push  _test-buffered-file/imm32
+366     # . . call
+367     e8/call  get-char/disp32
+368     # . . discard args
+369     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+370     # get-num(in, out, err, ed)
+371     # . . push args
+372     50/push-eax/ed
+373     68/push  _test-error-stream/imm32
+374     68/push  _test-output-stream/imm32
+375     68/push  _test-buffered-file/imm32
+376     # . . call
+377     e8/call  get-num/disp32
+378     # registers except esp may be clobbered at this point
+379     # . . discard args
+380     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+381     # check-ints-equal(*_test-output-stream->data, '3', msg)
+382     # . . push args
+383     68/push  "F - test-get-num-reads-single-digit"/imm32
+384     68/push  0x33/imm32
+385     b8/copy-to-eax  _test-output-stream/imm32
+386     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+387     # . . call
+388     e8/call  check-ints-equal/disp32
+389     # . . discard args
+390     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+391     # . reclaim locals
+392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+393     5d/pop-to-ebp
+394     c3/return
+395 
+396 test-get-num-aborts-on-non-digit-in-Look:
+397     # - check that get-num returns first character if it's a digit
+398     # This test uses exit-descriptors. Use ebp for setting up local variables.
+399     55/push-ebp
+400     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+401     # clear all streams
+402     # . clear-stream(_test-stream)
+403     # . . push args
+404     68/push  _test-stream/imm32
+405     # . . call
+406     e8/call  clear-stream/disp32
+407     # . . discard args
+408     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+409     # . clear-stream($_test-buffered-file->buffer)
+410     # . . push args
+411     68/push  $_test-buffered-file->buffer/imm32
+412     # . . call
+413     e8/call  clear-stream/disp32
+414     # . . discard args
+415     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+416     # . clear-stream(_test-output-stream)
+417     # . . push args
+418     68/push  _test-output-stream/imm32
+419     # . . call
+420     e8/call  clear-stream/disp32
+421     # . . discard args
+422     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+423     # . clear-stream(_test-error-stream)
+424     # . . push args
+425     68/push  _test-error-stream/imm32
+426     # . . call
+427     e8/call  clear-stream/disp32
+428     # . . discard args
+429     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+430     # initialize 'in'
+431     # . write(_test-stream, "3")
+432     # . . push args
+433     68/push  "3"/imm32
+434     68/push  _test-stream/imm32
+435     # . . call
+436     e8/call  write/disp32
+437     # . . discard args
+438     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+439     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+440     # . var ed/eax: exit-descriptor
+441     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+442     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+443     # . tailor-exit-descriptor(ed, 16)
+444     # . . push args
+445     68/push  0x10/imm32/nbytes-of-args-for-get-num
+446     50/push-eax/ed
+447     # . . call
+448     e8/call  tailor-exit-descriptor/disp32
+449     # . . discard args
+450     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+451     # *don't* prime the pump
+452     # get-num(in, out, err, ed)
+453     # . . push args
+454     50/push-eax/ed
+455     68/push  _test-error-stream/imm32
+456     68/push  _test-output-stream/imm32
+457     68/push  _test-buffered-file/imm32
+458     # . . call
+459     e8/call  get-num/disp32
+460     # registers except esp may be clobbered at this point
+461     # . . discard args
+462     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+463     # check that get-num tried to call exit(1)
+464     # . check-ints-equal(ed->value, 2, msg)  # i.e. stop was called with value 1
+465     # . . push args
+466     68/push  "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
+467     68/push  2/imm32
+468     # . . push ed->value
+469     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+470     # . . call
+471     e8/call  check-ints-equal/disp32
+472     # . . discard args
+473     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+474     # . reclaim locals
+475     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+476     5d/pop-to-ebp
+477     c3/return
+478 
+479 test-get-num-reads-multiple-digits:
+480     # - check that get-num returns all initial digits until it encounters a non-digit
+481     # This test uses exit-descriptors. Use ebp for setting up local variables.
+482     55/push-ebp
+483     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+484     # clear all streams
+485     # . clear-stream(_test-stream)
+486     # . . push args
+487     68/push  _test-stream/imm32
+488     # . . call
+489     e8/call  clear-stream/disp32
+490     # . . discard args
+491     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+492     # . clear-stream($_test-buffered-file->buffer)
+493     # . . push args
+494     68/push  $_test-buffered-file->buffer/imm32
+495     # . . call
+496     e8/call  clear-stream/disp32
+497     # . . discard args
+498     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+499     # . clear-stream(_test-output-stream)
+500     # . . push args
+501     68/push  _test-output-stream/imm32
+502     # . . call
+503     e8/call  clear-stream/disp32
+504     # . . discard args
+505     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+506     # . clear-stream(_test-error-stream)
+507     # . . push args
+508     68/push  _test-error-stream/imm32
+509     # . . call
+510     e8/call  clear-stream/disp32
+511     # . . discard args
+512     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+513     # initialize 'in'
+514     # . write(_test-stream, "3456 x")
+515     # . . push args
+516     68/push  "3456"/imm32
+517     68/push  _test-stream/imm32
+518     # . . call
+519     e8/call  write/disp32
+520     # . . discard args
+521     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+522     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+523     # . var ed/eax: exit-descriptor
+524     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+525     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+526     # . tailor-exit-descriptor(ed, 16)
+527     # . . push args
+528     68/push  0x10/imm32/nbytes-of-args-for-get-num
+529     50/push-eax/ed
+530     # . . call
+531     e8/call  tailor-exit-descriptor/disp32
+532     # . . discard args
+533     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+534     # prime the pump
+535     # . get-char(_test-buffered-file)
+536     # . . push args
+537     68/push  _test-buffered-file/imm32
+538     # . . call
+539     e8/call  get-char/disp32
+540     # . . discard args
+541     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+542     # get-num(in, out, err, ed)
+543     # . . push args
+544     50/push-eax/ed
+545     68/push  _test-error-stream/imm32
+546     68/push  _test-output-stream/imm32
+547     68/push  _test-buffered-file/imm32
+548     # . . call
+549     e8/call  get-num/disp32
+550     # registers except esp may be clobbered at this point
+551     # . . discard args
+552     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+553     # check-ints-equal(*_test-output-stream->data, '3456', msg)
+554     # . . push args
+555     68/push  "F - test-get-num-reads-multiple-digits"/imm32
+556     68/push  0x36353433/imm32
+557     b8/copy-to-eax  _test-output-stream/imm32
+558     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+559     # . . call
+560     e8/call  check-ints-equal/disp32
+561     # . . discard args
+562     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+563     # . reclaim locals
+564     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+565     5d/pop-to-ebp
+566     c3/return
+567 
+568 test-get-num-reads-multiple-digits-followed-by-nondigit:
+569     # - check that get-num returns all initial digits until it encounters a non-digit
+570     # This test uses exit-descriptors. Use ebp for setting up local variables.
+571     55/push-ebp
+572     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+573     # clear all streams
+574     # . clear-stream(_test-stream)
+575     # . . push args
+576     68/push  _test-stream/imm32
+577     # . . call
+578     e8/call  clear-stream/disp32
+579     # . . discard args
+580     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+581     # . clear-stream($_test-buffered-file->buffer)
+582     # . . push args
+583     68/push  $_test-buffered-file->buffer/imm32
+584     # . . call
+585     e8/call  clear-stream/disp32
+586     # . . discard args
+587     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+588     # . clear-stream(_test-output-stream)
+589     # . . push args
+590     68/push  _test-output-stream/imm32
+591     # . . call
+592     e8/call  clear-stream/disp32
+593     # . . discard args
+594     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+595     # . clear-stream(_test-error-stream)
+596     # . . push args
+597     68/push  _test-error-stream/imm32
+598     # . . call
+599     e8/call  clear-stream/disp32
+600     # . . discard args
+601     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+602     # initialize 'in'
+603     # . write(_test-stream, "3456 x")
+604     # . . push args
+605     68/push  "3456 x"/imm32
+606     68/push  _test-stream/imm32
+607     # . . call
+608     e8/call  write/disp32
+609     # . . discard args
+610     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+611     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+612     # . var ed/eax: exit-descriptor
+613     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+614     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+615     # . tailor-exit-descriptor(ed, 16)
+616     # . . push args
+617     68/push  0x10/imm32/nbytes-of-args-for-get-num
+618     50/push-eax/ed
+619     # . . call
+620     e8/call  tailor-exit-descriptor/disp32
+621     # . . discard args
+622     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+623     # prime the pump
+624     # . get-char(_test-buffered-file)
+625     # . . push args
+626     68/push  _test-buffered-file/imm32
+627     # . . call
+628     e8/call  get-char/disp32
+629     # . . discard args
+630     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+631     # get-num(in, out, err, ed)
+632     # . . push args
+633     50/push-eax/ed
+634     68/push  _test-error-stream/imm32
+635     68/push  _test-output-stream/imm32
+636     68/push  _test-buffered-file/imm32
+637     # . . call
+638     e8/call  get-num/disp32
+639     # registers except esp may be clobbered at this point
+640     # . . discard args
+641     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+642     # check-ints-equal(*_test-output-stream->data, '3456', msg)
+643     # . . push args
+644     68/push  "F - test-get-num-reads-multiple-digits-followed-by-nondigit"/imm32
+645     68/push  0x36353433/imm32
+646     b8/copy-to-eax  _test-output-stream/imm32
+647     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+648     # . . call
+649     e8/call  check-ints-equal/disp32
+650     # . . discard args
+651     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+652     # . reclaim locals
+653     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+654     5d/pop-to-ebp
+655     c3/return
+656 
+657 ## helpers
+658 
+659 # write(f, "Error: "+s+" expected\n") then stop(ed, 1)
+660 expected:  # ed: (addr exit-descriptor), f: fd or (addr stream byte), s: (addr array byte)
+661     # . prologue
+662     55/push-ebp
+663     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+664     # write(f, "Error: ")
+665     # . . push args
+666     68/push  "Error: "/imm32
+667     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+668     # . . call
+669     e8/call  write/disp32
+670     # . . discard args
+671     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+672     # write(f, s)
+673     # . . push args
+674     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+675     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+676     # . . call
+677     e8/call  write/disp32
+678     # . . discard args
+679     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+680     # write(f, " expected\n")
+681     # . . push args
+682     68/push  " expected\n"/imm32
+683     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+684     # . . call
+685     e8/call  write/disp32
+686     # . . discard args
+687     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+688     # stop(ed, 1)
+689     # . . push args
+690     68/push  1/imm32
+691     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+692     # . . call
+693     e8/call  stop/disp32
+694     # should never get past this point
+695 $expected:dead-end:
+696     # . epilogue
+697     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+698     5d/pop-to-ebp
+699     c3/return
+700 
+701 # read a byte from 'f', and save it in 'Look'
+702 get-char:  # f: (addr buffered-file)
+703     # . prologue
+704     55/push-ebp
+705     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+706     # . save registers
+707     50/push-eax
+708     # eax = read-byte-buffered(f)
+709     # . . push args
+710     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+711     # . . call
+712     e8/call  read-byte-buffered/disp32
+713     # . . discard args
+714     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+715     # save eax to Look
+716     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy eax to *Look
+717 $get-char:end:
+718     # . restore registers
+719     58/pop-to-eax
+720     # . epilogue
+721     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+722     5d/pop-to-ebp
+723     c3/return
+724 
+725 digit?:  # c: int -> eax: boolean
+726     # . prologue
+727     55/push-ebp
+728     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+729     # eax = false
+730     b8/copy-to-eax  0/imm32
+731     # if (c < '0') return false
+732     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x30/imm32        # compare *(ebp+8)
+733     7c/jump-if-<  $digit?:end/disp8
+734     # if (c > '9') return false
+735     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x39/imm32        # compare *(ebp+8)
+736     7f/jump-if->  $digit?:end/disp8
+737     # otherwise return true
+738     b8/copy-to-eax  1/imm32
+739 $digit?:end:
+740     # . epilogue
+741     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+742     5d/pop-to-ebp
+743     c3/return
+744 
+745 == data
+746 
+747 Look:  # (char with some extra padding)
+748     0/imm32
+749 
+750 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex1.mu.html b/html/linux/apps/ex1.mu.html new file mode 100644 index 00000000..bf1644a4 --- /dev/null +++ b/html/linux/apps/ex1.mu.html @@ -0,0 +1,77 @@ + + + + +Mu - linux/apps/ex1.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex1.mu +
+ 1 # First example: return the answer to the Ultimate Question of Life, the
+ 2 # Universe, and Everything.
+ 3 #
+ 4 # Same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
+ 5 #
+ 6 # To run:
+ 7 #   $ ./translate apps/ex1.mu
+ 8 #   $ ./a.elf
+ 9 # Expected result:
+10 #   $ echo $?
+11 #   42
+12 
+13 fn main -> _/ebx: int {
+14   return 0x2a  # Mu requires hexadecimal
+15 }
+
+ + + diff --git a/html/linux/apps/ex1.subx.html b/html/linux/apps/ex1.subx.html new file mode 100644 index 00000000..678f74c9 --- /dev/null +++ b/html/linux/apps/ex1.subx.html @@ -0,0 +1,79 @@ + + + + +Mu - linux/apps/ex1.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex1.subx +
+ 1 # First example: return the answer to the Ultimate Question of Life, the
+ 2 # Universe, and Everything.
+ 3 #
+ 4 # Same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
+ 5 #
+ 6 # To run:
+ 7 #   $ bootstrap/bootstrap translate apps/ex1.subx -o ex1
+ 8 #   $ bootstrap/bootstrap run ex1
+ 9 # Expected result:
+10 #   $ echo $?
+11 #   42
+12 
+13 == code
+14 
+15 Entry:
+16 # exit(42)
+17 bb/copy-to-ebx  0x2a/imm32  # 42 in hex
+18 e8/call  syscall_exit/disp32
+19 
+20 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex10.subx.html b/html/linux/apps/ex10.subx.html new file mode 100644 index 00000000..c359244c --- /dev/null +++ b/html/linux/apps/ex10.subx.html @@ -0,0 +1,132 @@ + + + + +Mu - linux/apps/ex10.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex10.subx +
+ 1 # String comparison: return 1 iff the two args passed in at the commandline are equal.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex10.subx -o ex10
+ 5 #   $ bootstrap/bootstrap run ex10 abc abd
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   0  # false
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 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
+14 
+15 Entry:  # return argv-equal(argv[1], argv[2])
+16 #       At the start of a SubX program:
+17 #         argc: *esp
+18 #         argv[0]: *(esp+4)
+19 #         argv[1]: *(esp+8)
+20 #         ...
+21     # . prologue
+22     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+23     # argv-equal(argv[1], argv[2])
+24     # . . push argv[2]
+25     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+26     # . . push argv[1]
+27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+28     # . . call
+29     e8/call argv-equal/disp32
+30     # exit(eax)
+31     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+32     e8/call  syscall_exit/disp32
+33 
+34 # compare two null-terminated ascii strings
+35 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
+36 argv-equal:  # (s1, s2): null-terminated ascii strings -> eax: boolean
+37     # initialize s1 (ecx) and s2 (edx)
+38     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           1/r32/ecx   4/disp8         .                 # copy *(esp+4) to ecx
+39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   8/disp8         .                 # copy *(esp+8) to edx
+40 $argv-equal:loop:
+41     # c1/eax, c2/ebx = *s1, *s2
+42     b8/copy-to-eax  0/imm32
+43     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+44     bb/copy-to-ebx  0/imm32
+45     8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           3/r32/BL    .               .                 # copy byte at *edx to BL
+46     # if (c1 == 0) break
+47     3d/compare-eax-and  0/imm32/null
+48     74/jump-if-=  $argv-equal:break/disp8
+49     # if (c1 != c2) return false
+50     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+51     75/jump-if-!=  $argv-equal:false/disp8
+52     # ++s1, ++s2
+53     41/increment-ecx
+54     42/increment-edx
+55     # end while
+56     eb/jump  $argv-equal:loop/disp8
+57 $argv-equal:break:
+58     # if (c2 == 0) return true
+59     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0/imm32/null      # compare ebx
+60     75/jump-if-!=  $argv-equal:false/disp8
+61 $argv-equal:success:
+62     b8/copy-to-eax  1/imm32
+63     c3/return
+64     # return false
+65 $argv-equal:false:
+66     b8/copy-to-eax  0/imm32
+67     c3/return
+68 
+69 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex11.subx.html b/html/linux/apps/ex11.subx.html new file mode 100644 index 00000000..f101f852 --- /dev/null +++ b/html/linux/apps/ex11.subx.html @@ -0,0 +1,421 @@ + + + + +Mu - linux/apps/ex11.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex11.subx +
+  1 # Null-terminated vs size-prefixed ascii strings.
+  2 #
+  3 # By default we create strings with a 4-byte size prefix rather than a null suffix.
+  4 # However we still need null-prefixed strings when interacting with the Linux
+  5 # kernel in a few places. This layer implements a function for comparing
+  6 # a null-terminated 'kernel string' with a size-prefixed 'SubX string'.
+  7 #
+  8 # To run:
+  9 #   $ bootstrap/bootstrap translate apps/ex11.subx -o ex11
+ 10 #   $ bootstrap/bootstrap run ex11  # runs a series of tests
+ 11 #   ......  # all tests pass
+ 12 #
+ 13 # (We can't yet run the tests when given a "test" commandline argument,
+ 14 # because checking for it would require the function being tested! Breakage
+ 15 # would cause tests to not run, rather than to fail as we'd like.)
+ 16 
+ 17 == code
+ 18 #   instruction                     effective address                                                   register    displacement    immediate
+ 19 # . op          subop               mod             rm32          base        index         scale       r32
+ 20 # . 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
+ 21 
+ 22 Entry:  # run all tests
+ 23     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+ 24     # exit(eax)
+ 25     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+ 26     e8/call  syscall_exit/disp32
+ 27 
+ 28 # compare a null-terminated ascii string with a more idiomatic size-prefixed byte array
+ 29 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
+ 30 kernel-string-equal?:  # s: null-terminated ascii string, benchmark: size-prefixed ascii string -> eax: boolean
+ 31     # pseudocode:
+ 32     #   n = benchmark->size
+ 33     #   s1 = s
+ 34     #   s2 = benchmark->data
+ 35     #   i = 0
+ 36     #   while i < n
+ 37     #     c1 = *s1
+ 38     #     c2 = *s2
+ 39     #     if (c1 == 0) return false
+ 40     #     if (c1 != c2) return false
+ 41     #     ++s1, ++s2, ++i
+ 42     #   return *s1 == 0
+ 43     #
+ 44     # registers:
+ 45     #   i: ecx
+ 46     #   n: edx
+ 47     #   s1: edi
+ 48     #   s2: esi
+ 49     #   c1: eax
+ 50     #   c2: ebx
+ 51     #
+ 52     # . prologue
+ 53     55/push-ebp
+ 54     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 55     # . save registers
+ 56     51/push-ecx
+ 57     52/push-edx
+ 58     53/push-ebx
+ 59     56/push-esi
+ 60     57/push-edi
+ 61     # s1/edi = s
+ 62     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 63     # n/edx = benchmark->size
+ 64     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+ 65     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
+ 66     # s2/esi = benchmark->data
+ 67     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+ 68     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
+ 69     # i/ecx = c1/eax = c2/ebx = 0
+ 70     b9/copy-to-ecx  0/imm32/exit
+ 71     b8/copy-to-eax  0/imm32
+ 72     bb/copy-to-ebx  0/imm32
+ 73 $kernel-string-equal?:loop:
+ 74     # if (i >= n) break
+ 75     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 76     7d/jump-if->=  $kernel-string-equal?:break/disp8
+ 77     # c1 = *s1
+ 78     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+ 79     # c2 = *s2
+ 80     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
+ 81     # if (c1 == 0) return false
+ 82     3d/compare-eax-and  0/imm32/null
+ 83     74/jump-if-=  $kernel-string-equal?:false/disp8
+ 84     # if (c1 != c2) return false
+ 85     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+ 86     75/jump-if-!=  $kernel-string-equal?:false/disp8
+ 87     # ++i
+ 88     41/increment-ecx
+ 89     # ++s1
+ 90     47/increment-edi
+ 91     # ++s2
+ 92     46/increment-esi
+ 93     eb/jump  $kernel-string-equal?:loop/disp8
+ 94 $kernel-string-equal?:break:
+ 95     # return *s1 == 0
+ 96     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+ 97     3d/compare-eax-and  0/imm32/null
+ 98     75/jump-if-!=  $kernel-string-equal?:false/disp8
+ 99 $kernel-string-equal?:true:
+100     b8/copy-to-eax  1/imm32
+101     eb/jump  $kernel-string-equal?:end/disp8
+102 $kernel-string-equal?:false:
+103     b8/copy-to-eax  0/imm32
+104 $kernel-string-equal?:end:
+105     # . restore registers
+106     5f/pop-to-edi
+107     5e/pop-to-esi
+108     5b/pop-to-ebx
+109     5a/pop-to-edx
+110     59/pop-to-ecx
+111     # . epilogue
+112     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+113     5d/pop-to-ebp
+114     c3/return
+115 
+116 # - tests
+117 
+118 test-compare-null-kernel-string-with-empty-array:
+119     # eax = kernel-string-equal?(Null-kernel-string, "")
+120     # . . push args
+121     68/push  ""/imm32
+122     68/push  Null-kernel-string/imm32
+123     # . . call
+124     e8/call  kernel-string-equal?/disp32
+125     # . . discard args
+126     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+127     # check-ints-equal(eax, 1, msg)
+128     # . . push args
+129     68/push  "F - test-compare-null-kernel-string-with-empty-array"/imm32
+130     68/push  1/imm32/true
+131     50/push-eax
+132     # . . call
+133     e8/call  check-ints-equal/disp32
+134     # . . discard args
+135     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+136     c3/return
+137 
+138 test-compare-null-kernel-string-with-non-empty-array:
+139     # eax = kernel-string-equal?(Null-kernel-string, "Abc")
+140     # . . push args
+141     68/push  "Abc"/imm32
+142     68/push  Null-kernel-string/imm32
+143     # . . call
+144     e8/call  kernel-string-equal?/disp32
+145     # . . discard args
+146     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+147     # check-ints-equal(eax, 0, msg)
+148     # . . push args
+149     68/push  "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
+150     68/push  0/imm32/false
+151     50/push-eax
+152     # . . call
+153     e8/call  check-ints-equal/disp32
+154     # . . discard args
+155     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+156     c3/return
+157 
+158 test-compare-kernel-string-with-equal-array:
+159     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
+160     # . . push args
+161     68/push  "Abc"/imm32
+162     68/push  _test-Abc-kernel-string/imm32
+163     # . . call
+164     e8/call  kernel-string-equal?/disp32
+165     # . . discard args
+166     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+167     # check-ints-equal(eax, 1, msg)
+168     # . . push args
+169     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+170     68/push  1/imm32/true
+171     50/push-eax
+172     # . . call
+173     e8/call  check-ints-equal/disp32
+174     # . . discard args
+175     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+176     c3/return
+177 
+178 test-compare-kernel-string-with-inequal-array:
+179     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
+180     # . . push args
+181     68/push  "Adc"/imm32
+182     68/push  _test-Abc-kernel-string/imm32
+183     # . . call
+184     e8/call  kernel-string-equal?/disp32
+185     # . . discard args
+186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+187     # check-ints-equal(eax, 0, msg)
+188     # . . push args
+189     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+190     68/push  0/imm32/false
+191     50/push-eax
+192     # . . call
+193     e8/call  check-ints-equal/disp32
+194     # . . discard args
+195     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+196     c3/return
+197 
+198 test-compare-kernel-string-with-empty-array:
+199     # eax = kernel-string-equal?(_test-Abc-kernel-string, "")
+200     # . . push args
+201     68/push  ""/imm32
+202     68/push  _test-Abc-kernel-string/imm32
+203     # . . call
+204     e8/call  kernel-string-equal?/disp32
+205     # . . discard args
+206     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+207     # check-ints-equal(eax, 0, msg)
+208     # . . push args
+209     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+210     68/push  0/imm32/false
+211     50/push-eax
+212     # . . call
+213     e8/call  check-ints-equal/disp32
+214     # . . discard args
+215     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+216     c3/return
+217 
+218 test-compare-kernel-string-with-shorter-array:
+219     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
+220     # . . push args
+221     68/push  "Ab"/imm32
+222     68/push  _test-Abc-kernel-string/imm32
+223     # . . call
+224     e8/call  kernel-string-equal?/disp32
+225     # . . discard args
+226     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+227     # check-ints-equal(eax, 0, msg)
+228     # . . push args
+229     68/push  "F - test-compare-kernel-string-with-shorter-array"/imm32
+230     68/push  0/imm32/false
+231     50/push-eax
+232     # . . call
+233     e8/call  check-ints-equal/disp32
+234     # . . discard args
+235     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+236     c3/return
+237 
+238 test-compare-kernel-string-with-longer-array:
+239     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
+240     # . . push args
+241     68/push  "Abcd"/imm32
+242     68/push  _test-Abc-kernel-string/imm32
+243     # . . call
+244     e8/call  kernel-string-equal?/disp32
+245     # . . discard args
+246     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+247     # check-ints-equal(eax, 0, msg)
+248     # . . push args
+249     68/push  "F - test-compare-kernel-string-with-longer-array"/imm32
+250     68/push  0/imm32/false
+251     50/push-eax
+252     # . . call
+253     e8/call  check-ints-equal/disp32
+254     # . . discard args
+255     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+256     c3/return
+257 
+258 # - helpers
+259 
+260 # print msg to stderr if a != b, otherwise print "."
+261 check-ints-equal:  # (a: int, b: int, msg: (addr array byte)) -> boolean
+262     # . prologue
+263     55/push-ebp
+264     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+265     # . save registers
+266     51/push-ecx
+267     53/push-ebx
+268     # load args into eax, ebx and ecx
+269     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+270     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
+271     # if (eax == b/ebx) print('.') and return
+272     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+273     75/jump-if-unequal  $check-ints-equal:else/disp8
+274     # . write-stderr('.')
+275     # . . push args
+276     68/push  "."/imm32
+277     # . . call
+278     e8/call  write-stderr/disp32
+279     # . . discard args
+280     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+281     # . return
+282     eb/jump  $check-ints-equal:end/disp8
+283     # otherwise print(msg)
+284 $check-ints-equal:else:
+285     # copy msg into ecx
+286     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8       .                # copy *(ebp+16) to ecx
+287     # print(ecx)
+288     # . . push args
+289     51/push-ecx
+290     # . . call
+291     e8/call  write-stderr/disp32
+292     # . . discard args
+293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+294     # print newline
+295     # . . push args
+296     68/push  Newline/imm32
+297     # . . call
+298     e8/call  write-stderr/disp32
+299     # . . discard args
+300     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+301 $check-ints-equal:end:
+302     # . restore registers
+303     5b/pop-to-ebx
+304     59/pop-to-ecx
+305     # end
+306     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+307     5d/pop-to-ebp
+308     c3/return
+309 
+310 write-stderr:  # s: (addr array byte) -> <void>
+311     # . prologue
+312     55/push-ebp
+313     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+314     # . save registers
+315     50/push-eax
+316     51/push-ecx
+317     52/push-edx
+318     53/push-ebx
+319     # syscall(write, 2/stderr, (data) s+4, (size) *s)
+320     # . . fd = 2 (stderr)
+321     bb/copy-to-ebx  2/imm32
+322     # . . x = s+4
+323     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+324     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
+325     # . . size = *s
+326     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   8/disp8         .                 # copy *(ebp+8) to edx
+327     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
+328     # . . syscall
+329     e8/call  syscall_write/disp32
+330     # . restore registers
+331     5b/pop-to-ebx
+332     5a/pop-to-edx
+333     59/pop-to-ecx
+334     58/pop-to-eax
+335     # . end
+336     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+337     5d/pop-to-ebp
+338     c3/return
+339 
+340 == data
+341 
+342 Newline:
+343     # size
+344     1/imm32
+345     # data
+346     0a/newline
+347 
+348 # for kernel-string-equal tests
+349 Null-kernel-string:
+350     00/null
+351 
+352 _test-Abc-kernel-string:
+353     41/A 62/b 63/c 00/null
+354 
+355 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex12.subx.html b/html/linux/apps/ex12.subx.html new file mode 100644 index 00000000..12b09331 --- /dev/null +++ b/html/linux/apps/ex12.subx.html @@ -0,0 +1,104 @@ + + + + +Mu - linux/apps/ex12.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex12.subx +
+ 1 # Example showing mmap syscall.
+ 2 # Create a new segment using mmap, save the address, write to it.
+ 3 #
+ 4 # To run:
+ 5 #   $ bootstrap/bootstrap translate apps/ex12.subx -o ex12
+ 6 #   $ bootstrap/bootstrap run ex12
+ 7 # You shouldn't get a segmentation fault.
+ 8 
+ 9 == code
+10 #   instruction                     effective address                                                   register    displacement    immediate
+11 # . op          subop               mod             rm32          base        index         scale       r32
+12 # . 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
+13 
+14 Entry:
+15     # mmap(Mmap-new-segment->len)
+16     bb/copy-to-ebx  Mmap-new-segment/imm32
+17     e8/call  syscall_mmap/disp32
+18 
+19     # write to *eax to check that we have access to the newly-allocated segment
+20     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0x34/imm32        # copy to *eax
+21 
+22     # exit(eax)
+23     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+24     e8/call  syscall_exit/disp32
+25 
+26 == data
+27 
+28 # various constants used here were found in the Linux sources (search for file mman-common.h)
+29 Mmap-new-segment:  # type mmap_arg_struct
+30     # addr
+31     0/imm32
+32     # len
+33     0x100/imm32
+34     # protection flags
+35     3/imm32  # PROT_READ | PROT_WRITE
+36     # sharing flags
+37     0x22/imm32  # MAP_PRIVATE | MAP_ANONYMOUS
+38     # fd
+39     -1/imm32  # since MAP_ANONYMOUS is specified
+40     # offset
+41     0/imm32  # since MAP_ANONYMOUS is specified
+42 
+43 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex13.subx.html b/html/linux/apps/ex13.subx.html new file mode 100644 index 00000000..c0181b6c --- /dev/null +++ b/html/linux/apps/ex13.subx.html @@ -0,0 +1,87 @@ + + + + +Mu - linux/apps/ex13.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex13.subx +
+ 1 # Compare 3 and 3.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex13.subx -o ex13
+ 5 #   $ bootstrap/bootstrap run ex13
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   1
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 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
+14 
+15 Entry:
+16     b8/copy-to-eax  3/imm32
+17     3d/compare-eax-and  3/imm32
+18     0f 94/set-if-=                  3/mod/direct    3/rm32/ebx    .           .             .           .           .               .                 # set ebx to ZF
+19     81 4/subop/and                  3/mod/direct    3/rm32/ebx    .           .             .           .           .               0xff/imm32        # AND with eax
+20 
+21 $exit:
+22     # exit(ebx)
+23     e8/call  syscall_exit/disp32
+24 
+25 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex14.subx.html b/html/linux/apps/ex14.subx.html new file mode 100644 index 00000000..fd76cdc3 --- /dev/null +++ b/html/linux/apps/ex14.subx.html @@ -0,0 +1,88 @@ + + + + +Mu - linux/apps/ex14.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex14.subx +
+ 1 # Multiply 2 numbers.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex14.subx -o ex14
+ 5 #   $ bootstrap/bootstrap run ex14
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   6
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 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
+14 
+15 Entry:
+16     b8/copy-to-eax  1/imm32
+17     b9/copy-to-ecx  2/imm32
+18     bb/copy-to-ebx  3/imm32
+19 
+20     69/multiply                     3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx                   3/imm32           # ebx = ecx * 3
+21 
+22 $exit:
+23     # exit(ebx)
+24     e8/call  syscall_exit/disp32
+25 
+26 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex2.mu.html b/html/linux/apps/ex2.mu.html new file mode 100644 index 00000000..48ee0e00 --- /dev/null +++ b/html/linux/apps/ex2.mu.html @@ -0,0 +1,83 @@ + + + + +Mu - linux/apps/ex2.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex2.mu +
+ 1 # Add 3 and 4, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/ex2.mu
+ 5 #   $ ./a.elf
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   7
+ 9 
+10 fn main -> _/ebx: int {
+11   var result/eax: int <- do-add 3 4
+12   return result
+13 }
+14 
+15 fn do-add a: int, b: int -> _/eax: int {
+16   var result/ecx: int <- copy a
+17   result <- add b
+18   return result
+19 }
+
+ + + diff --git a/html/linux/apps/ex2.subx.html b/html/linux/apps/ex2.subx.html new file mode 100644 index 00000000..519b4b73 --- /dev/null +++ b/html/linux/apps/ex2.subx.html @@ -0,0 +1,79 @@ + + + + +Mu - linux/apps/ex2.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex2.subx +
+ 1 # Add 3 and 4, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex2.subx -o ex2
+ 5 #   $ bootstrap/bootstrap run ex2
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   2
+ 9 
+10 == code
+11 
+12 Entry:
+13 # ebx = 3
+14 bb/copy-to-ebx  3/imm32
+15 # add 4 to ebx
+16 81 0/subop/add 3/mod/direct 3/rm32/ebx 4/imm32
+17 # exit(ebx)
+18 e8/call  syscall_exit/disp32
+19 
+20 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex3.2.mu.html b/html/linux/apps/ex3.2.mu.html new file mode 100644 index 00000000..98c6a027 --- /dev/null +++ b/html/linux/apps/ex3.2.mu.html @@ -0,0 +1,98 @@ + + + + +Mu - linux/apps/ex3.2.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex3.2.mu +
+ 1 # Unnecessarily use an array to sum 1..10
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/ex3.2.mu
+ 5 #   $ ./a.elf
+ 6 #   $ echo $?
+ 7 #   55
+ 8 
+ 9 fn main -> _/ebx: int {
+10   # populate a
+11   var a: (array int 0xb)  # 11; we waste index 0
+12   var i/ecx: int <- copy 1
+13   {
+14     compare i, 0xb
+15     break-if->=
+16     var x/eax: (addr int) <- index a, i
+17     copy-to *x, i
+18     i <- increment
+19     loop
+20   }
+21   # sum
+22   var result/edx: int <- copy 0
+23   i <- copy 1
+24   {
+25     compare i, 0xb
+26     break-if->=
+27     var x/eax: (addr int) <- index a, i
+28     result <- add *x
+29     i <- increment
+30     loop
+31   }
+32   return result
+33 }
+
+ + + diff --git a/html/linux/apps/ex3.mu.html b/html/linux/apps/ex3.mu.html new file mode 100644 index 00000000..9da58562 --- /dev/null +++ b/html/linux/apps/ex3.mu.html @@ -0,0 +1,84 @@ + + + + +Mu - linux/apps/ex3.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex3.mu +
+ 1 # Add the first 10 numbers, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate ex3.mu
+ 5 #   $ ./a.elf
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   55
+ 9 
+10 fn main -> _/ebx: int {
+11   var result/ebx: int <- copy 0
+12   var i/eax: int <- copy 1
+13   {
+14     compare i, 0xa
+15     break-if->
+16     result <- add i
+17     i <- increment
+18     loop
+19   }
+20   return result
+21 }
+
+ + + diff --git a/html/linux/apps/ex3.subx.html b/html/linux/apps/ex3.subx.html new file mode 100644 index 00000000..0810bdc8 --- /dev/null +++ b/html/linux/apps/ex3.subx.html @@ -0,0 +1,98 @@ + + + + +Mu - linux/apps/ex3.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex3.subx +
+ 1 # Add the first 10 numbers, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex3.subx -o ex3
+ 5 #   $ bootstrap/bootstrap run ex3
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   55
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 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
+14 
+15 Entry:
+16     # result: ebx = 0
+17     bb/copy-to-ebx  0/imm32
+18     # counter: ecx = 1
+19     b9/copy-to-ecx  1/imm32
+20 
+21 $loop:
+22     # if (counter > 10) break
+23     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0xa/imm32         # compare ecx
+24     7f/jump-if->  $exit/disp8
+25     # result += counter
+26     01/add                          3/mod/direct    3/rm32/ebx    .           .             .           1/r32/ecx   .               .                 # add ecx to ebx
+27     # ++counter
+28     41/increment-ecx
+29     # loop
+30     eb/jump  $loop/disp8
+31 
+32 $exit:
+33     # exit(ebx)
+34     e8/call  syscall_exit/disp32
+35 
+36 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex4.subx.html b/html/linux/apps/ex4.subx.html new file mode 100644 index 00000000..1b3bd941 --- /dev/null +++ b/html/linux/apps/ex4.subx.html @@ -0,0 +1,99 @@ + + + + +Mu - linux/apps/ex4.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex4.subx +
+ 1 # Read a character from stdin, save it to a global, write it to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex4.subx -o ex4
+ 5 #   $ bootstrap/bootstrap run ex4
+ 6 
+ 7 == data
+ 8 
+ 9 # the global variable we save to
+10 X:
+11     0/imm32  # space for read() to write to
+12 
+13 == code
+14 
+15 Entry:
+16 # read(stdin, X, 1)
+17 # . fd = 0 (stdin)
+18 bb/copy-to-ebx  0/imm32
+19 # . data = X (location to write result to)
+20 b9/copy-to-ecx  X/imm32
+21 # . size = 1 character
+22 ba/copy-to-edx  1/imm32
+23 # . syscall
+24 e8/call  syscall_read/disp32
+25 
+26 # write(stdout, X, 1)
+27 # . fd = 1 (stdout)
+28 bb/copy-to-ebx  1/imm32
+29 # . initialize X (location to read from)
+30 b9/copy-to-ecx  X/imm32
+31 # . size = 1 character
+32 ba/copy-to-edx  1/imm32
+33 # . syscall
+34 e8/call  syscall_write/disp32
+35 
+36 # exit(ebx)
+37 e8/call  syscall_exit/disp32
+38 
+39 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex5.subx.html b/html/linux/apps/ex5.subx.html new file mode 100644 index 00000000..949e207c --- /dev/null +++ b/html/linux/apps/ex5.subx.html @@ -0,0 +1,101 @@ + + + + +Mu - linux/apps/ex5.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex5.subx +
+ 1 # Read a character from stdin, save it to a local on the stack, write it to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex5.subx -o ex5
+ 5 #   $ bootstrap/bootstrap run ex5
+ 6 
+ 7 == code
+ 8 #   instruction                     effective address                                                   register    displacement    immediate
+ 9 # . op          subop               mod             rm32          base        index         scale       r32
+10 # . 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
+11 
+12 Entry:
+13 
+14     # allocate x on the stack
+15     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # subtract from esp
+16 
+17     # read(stdin, x, 1)
+18     # . fd = 0 (stdin)
+19     bb/copy-to-ebx  0/imm32
+20     # . data = x (location to write result to)
+21     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
+22     # . size = 1 character
+23     ba/copy-to-edx  1/imm32
+24     # . syscall
+25     e8/call  syscall_read/disp32
+26 
+27     # syscall(write, stdout, x, 1)
+28     # . fd = 1 (stdout)
+29     bb/copy-to-ebx  1/imm32
+30     # . data = x (location to read from)
+31     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
+32     # . size = 1 character
+33     ba/copy-to-edx  1/imm32
+34     # . syscall
+35     e8/call  syscall_write/disp32
+36 
+37     # exit(ebx)
+38     e8/call  syscall_exit/disp32
+39 
+40 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex6.subx.html b/html/linux/apps/ex6.subx.html new file mode 100644 index 00000000..5aa4fd53 --- /dev/null +++ b/html/linux/apps/ex6.subx.html @@ -0,0 +1,96 @@ + + + + +Mu - linux/apps/ex6.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex6.subx +
+ 1 # Print out a (global variable) string to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex6.subx -o ex6
+ 5 #   $ bootstrap/bootstrap run ex6
+ 6 #   Hello, world!
+ 7 
+ 8 == code
+ 9 
+10 # . op          subop               mod             rm32          base        index         scale       r32
+11 # . 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
+12 
+13 Entry:
+14     # write(stdout, X, Size)
+15     # . fd = 1 (stdout)
+16     bb/copy-to-ebx  1/imm32
+17     # . initialize X (location to write result to)
+18     b9/copy-to-ecx  X/imm32
+19     # . initialize Size
+20     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           2/r32/edx   Size/disp32     .                 # copy *Size to edx
+21     # . syscall
+22     e8/call  syscall_write/disp32
+23 
+24     # exit(ebx)
+25     e8/call  syscall_exit/disp32
+26 
+27 == data
+28 
+29 Size:  # size of string
+30     0x0d/imm32  # 13
+31 X:  # string to print
+32     48 65 6c 6c 6f 20 77 6f 72 6c 64 21 0a       00
+33 #   H  e  l  l  o  ␣  w  o  r  l  d  !  newline  null
+34 
+35 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex7.subx.html b/html/linux/apps/ex7.subx.html new file mode 100644 index 00000000..b2a87263 --- /dev/null +++ b/html/linux/apps/ex7.subx.html @@ -0,0 +1,159 @@ + + + + +Mu - linux/apps/ex7.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex7.subx +
+ 1 # Example showing file syscalls.
+ 2 #
+ 3 # Create a file, open it for writing, write a character to it, close it, open
+ 4 # it for reading, read a character from it, close it, delete it, and return
+ 5 # the character read.
+ 6 #
+ 7 # To run:
+ 8 #   $ bootstrap/bootstrap translate apps/ex7.subx -o ex7
+ 9 #   $ bootstrap/bootstrap run ex7
+10 # Expected result:
+11 #   $ echo $?
+12 #   97
+13 
+14 == code
+15 #   instruction                     effective address                                                   register    displacement    immediate
+16 # . op          subop               mod             rm32          base        index         scale       r32
+17 # . 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
+18 
+19 Entry:
+20     # creat(Filename)
+21     bb/copy-to-ebx  Filename/imm32
+22     b9/copy-to-ecx  0x180/imm32/fixed-perms
+23     e8/call  syscall_creat/disp32
+24 
+25     # stream = open(Filename, O_WRONLY, 0)  # we can't use 'fd' because it looks like a hex byte
+26     bb/copy-to-ebx  Filename/imm32
+27     b9/copy-to-ecx  1/imm32/wronly
+28     ba/copy-to-edx  0x180/imm32/fixed-perms
+29     e8/call  syscall_open/disp32
+30     # save stream
+31     bb/copy-to-ebx  Stream/imm32
+32     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
+33 
+34     # write(Stream, "a", 1)
+35     # . load stream
+36     bb/copy-to-ebx  Stream/imm32
+37     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+38     # .
+39     b9/copy-to-ecx  A/imm32
+40     ba/copy-to-edx  1/imm32/size
+41     e8/call  syscall_write/disp32
+42 
+43     # close(Stream)
+44     # . load stream
+45     bb/copy-to-ebx  Stream/imm32
+46     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+47     # .
+48     e8/call  syscall_close/disp32
+49 
+50     # stream = open(Filename, O_RDONLY, 0)
+51     bb/copy-to-ebx  Filename/imm32
+52     b9/copy-to-ecx  0/imm32/rdonly
+53     ba/copy-to-edx  0x180/imm32/fixed-perms
+54     e8/call  syscall_open/disp32
+55     # . save Stream
+56     bb/copy-to-ebx  Stream/imm32
+57     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
+58 
+59     # read(Stream, B, 1)
+60     # . load stream
+61     bb/copy-to-ebx  Stream/imm32
+62     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+63     # .
+64     b9/copy-to-ecx  B/imm32
+65     ba/copy-to-edx  1/imm32/size
+66     e8/call  syscall_read/disp32
+67 
+68     # close(Stream)
+69     # . load stream
+70     bb/copy-to-ebx  Stream/imm32
+71     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+72     #
+73     e8/call  syscall_close/disp32
+74 
+75     # unlink(filename)
+76     bb/copy-to-ebx  Filename/imm32
+77     e8/call  syscall_unlink/disp32
+78 
+79     # exit(b)
+80     # . load b
+81     bb/copy-to-ebx  B/imm32
+82     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+83     #
+84     e8/call  syscall_exit/disp32
+85 
+86 == data
+87 
+88 Stream:
+89     0/imm32
+90 A:
+91     61/imm32/A
+92 B:
+93     0/imm32
+94 Filename:
+95     2e 66 6f 6f 00 00 00 00
+96 #   .  f  o  o  null
+97 
+98 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex8.subx.html b/html/linux/apps/ex8.subx.html new file mode 100644 index 00000000..86d16571 --- /dev/null +++ b/html/linux/apps/ex8.subx.html @@ -0,0 +1,123 @@ + + + + +Mu - linux/apps/ex8.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex8.subx +
+ 1 # Example reading commandline arguments: compute length of first arg.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex8.subx -o ex8
+ 5 #   $ bootstrap/bootstrap run ex8 abc de fghi
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   3  # length of 'abc'
+ 9 #
+10 # At the start of a SubX program:
+11 #   argc: *esp
+12 #   argv[0]: *(esp+4)
+13 #   argv[1]: *(esp+8)
+14 #   ...
+15 # Locals start from esp-4 downwards.
+16 
+17 == code
+18 #   instruction                     effective address                                                   register    displacement    immediate
+19 # . op          subop               mod             rm32          base        index         scale       r32
+20 # . 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
+21 
+22 Entry:
+23     # . prologue
+24     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+25     # eax = ascii-length(argv[1])
+26     # . . push args
+27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+28     # . . call
+29     e8/call  ascii-length/disp32
+30     # . . discard args
+31     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+32 
+33     # exit(eax)
+34     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+35     e8/call  syscall_exit/disp32
+36 
+37 ascii-length:  # s: (addr array byte) -> n/eax
+38     # edx = s
+39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   4/disp8         .                 # copy *(esp+4) to edx
+40     # var result/eax = 0
+41     b8/copy-to-eax  0/imm32
+42 $ascii-length:loop:
+43     # var c/ecx = *s
+44     8a/copy-byte                    0/mod/*         2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
+45     # if (c == '\0') break
+46     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32/null      # compare ecx
+47     74/jump-if-=  $ascii-length:end/disp8
+48     # ++s
+49     42/increment-edx
+50     # ++result
+51     40/increment-eax
+52     # loop
+53     eb/jump  $ascii-length:loop/disp8
+54 $ascii-length:end:
+55     # return eax
+56     c3/return
+57 
+58 == data
+59 
+60 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex9.subx.html b/html/linux/apps/ex9.subx.html new file mode 100644 index 00000000..3a79d9d9 --- /dev/null +++ b/html/linux/apps/ex9.subx.html @@ -0,0 +1,114 @@ + + + + +Mu - linux/apps/ex9.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex9.subx +
+ 1 # Example showing arg order on the stack.
+ 2 #
+ 3 # Show difference between ascii codes of first letter of first arg and first
+ 4 # letter of second arg.
+ 5 #
+ 6 # To run:
+ 7 #   $ bootstrap/bootstrap translate apps/ex9.subx -o ex9
+ 8 #   $ bootstrap/bootstrap run ex9 z x
+ 9 # Expected result:
+10 #   $ echo $?
+11 #   2
+12 #
+13 # At the start of a SubX program:
+14 #   argc: *esp
+15 #   argv[0]: *(esp+4)
+16 #   argv[1]: *(esp+8)
+17 #   ...
+18 # Locals start from esp-4 downwards.
+19 
+20 == code
+21 #   instruction                     effective address                                                   register    displacement    immediate
+22 # . op          subop               mod             rm32          base        index         scale       r32
+23 # . 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
+24 
+25 Entry:
+26     # . prologue
+27     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+28     # ascii-difference(argv[1], argv[2])
+29     # . . push argv[2]
+30     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+31     # . . push argv[1]
+32     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+33     # . . call
+34     e8/call  ascii-difference/disp32
+35     # . . discard args
+36     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+37     # exit(eax)
+38     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+39     e8/call  syscall_exit/disp32
+40 
+41 ascii-difference:  # (s1, s2): null-terminated ascii strings
+42     # a = first letter of s1 (ecx)
+43     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           0/r32/eax   4/disp8         .                 # copy *(esp+4) to eax
+44     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           0/r32/eax   .               .                 # copy *eax to eax
+45     # b = first letter of s2 (edx)
+46     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           1/r32/ecx   8/disp8                           # copy *(esp+8) to ecx
+47     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # copy *ecx to ecx
+48     # a-b
+49     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+50     c3/return
+51 
+52 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/factorial.mu.html b/html/linux/apps/factorial.mu.html new file mode 100644 index 00000000..3e626b6d --- /dev/null +++ b/html/linux/apps/factorial.mu.html @@ -0,0 +1,125 @@ + + + + +Mu - linux/apps/factorial.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial.mu +
+ 1 # compute the factorial of 5, and return the result in the exit code
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/factorial.mu
+ 5 #   $ ./a.elf
+ 6 #   $ echo $?
+ 7 #   120
+ 8 #
+ 9 # You can also run the automated test suite:
+10 #   $ ./a.elf test
+11 # Expected output:
+12 #   ........
+13 # Every '.' indicates a passing test. Failing tests get a 'F'.
+14 # There's only one test in this file, but you'll also see tests running from
+15 # Mu's standard library.
+16 #
+17 # Compare factorial4.subx
+18 
+19 fn factorial n: int -> _/eax: int {
+20   compare n, 1
+21   # if (n <= 1) return 1
+22   {
+23     break-if->
+24     return 1
+25   }
+26   # n > 1; return n * factorial(n-1)
+27   var tmp/ecx: int <- copy n
+28   tmp <- decrement
+29   var result/eax: int <- factorial tmp
+30   result <- multiply n
+31   return result
+32 }
+33 
+34 fn test-factorial {
+35   var result/eax: int <- factorial 5
+36   check-ints-equal result, 0x78, "F - test-factorial"
+37 }
+38 
+39 fn main args-on-stack: (addr array addr array byte) -> _/ebx: int {
+40   var args/eax: (addr array addr array byte) <- copy args-on-stack
+41   # len = length(args)
+42   var len/ecx: int <- length args
+43   # if (len <= 1) return factorial(5)
+44   compare len, 1
+45   {
+46     break-if->
+47     var exit-status/eax: int <- factorial 5
+48     return exit-status
+49   }
+50   # if (args[1] == "test") run-tests()
+51   var tmp2/ecx: (addr addr array byte) <- index args, 1
+52   var tmp3/eax: boolean <- string-equal? *tmp2, "test"
+53   compare tmp3, 0
+54   {
+55     break-if-=
+56     run-tests
+57     # TODO: get at Num-test-failures somehow
+58   }
+59   return 0
+60 }
+
+ + + diff --git a/html/linux/apps/factorial.subx.html b/html/linux/apps/factorial.subx.html new file mode 100644 index 00000000..c8f08ab6 --- /dev/null +++ b/html/linux/apps/factorial.subx.html @@ -0,0 +1,217 @@ + + + + +Mu - linux/apps/factorial.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial.subx +
+  1 ## compute the factorial of 5, and print the result
+  2 #
+  3 # To run:
+  4 #   $ bootstrap/bootstrap translate [01]*.subx apps/factorial.subx -o factorial
+  5 #   $ bootstrap/bootstrap run factorial
+  6 # Expected result:
+  7 #   $ echo $?
+  8 #   120
+  9 #
+ 10 # You can also run the automated test suite:
+ 11 #   $ bootstrap/bootstrap run factorial test
+ 12 # Expected output:
+ 13 #   ........
+ 14 # Every '.' indicates a passing test. Failing tests get a 'F'.
+ 15 
+ 16 == code
+ 17 #   instruction                     effective address                                                   register    displacement    immediate
+ 18 # . op          subop               mod             rm32          base        index         scale       r32
+ 19 # . 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
+ 20 
+ 21 factorial:  # n: int -> _/eax: int
+ 22     # . prologue
+ 23     55/push-ebp
+ 24     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 25     51/push-ecx
+ 26     # if (n <= 1) return 1
+ 27     b8/copy-to-eax  1/imm32
+ 28     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         1/imm32           # compare *(ebp+8)
+ 29     7e/jump-if-<=  $factorial:end/disp8
+ 30     # var ecx: int = n-1
+ 31     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+ 32     49/decrement-ecx
+ 33     # var eax: int = factorial(n-1)
+ 34     # . . push args
+ 35     51/push-ecx
+ 36     # . . call
+ 37     e8/call  factorial/disp32
+ 38     # . . discard args
+ 39     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 40     # return n * factorial(n-1)
+ 41     f7          4/subop/multiply    1/mod/*+disp8   5/rm32/ebp    .           .                                     8/disp8         .                 # multiply *(ebp+8) into eax
+ 42     # TODO: check for overflow
+ 43 $factorial:end:
+ 44     # restore registers
+ 45     59/pop-to-ecx
+ 46     # . epilogue
+ 47     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 48     5d/pop-to-ebp
+ 49     c3/return
+ 50 
+ 51 test-factorial:
+ 52     # factorial(5)
+ 53     # . . push args
+ 54     68/push  5/imm32
+ 55     # . . call
+ 56     e8/call  factorial/disp32
+ 57     # . . discard args
+ 58     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 59     # check-ints-equal(eax, 120, msg)
+ 60     # . . push args
+ 61     68/push  "F - test-factorial"/imm32
+ 62     68/push  0x78/imm32/expected-120
+ 63     50/push-eax
+ 64     # . . call
+ 65     e8/call  check-ints-equal/disp32
+ 66     # . . discard args
+ 67     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 68     # end
+ 69     c3/return
+ 70 
+ 71 Entry:  # run tests if necessary, compute `factorial(5)` if not
+ 72     # . prologue
+ 73     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 74 
+ 75     # initialize heap (needed by tests elsewhere)
+ 76     # . Heap = new-segment(Heap-size)
+ 77     # . . push args
+ 78     68/push  Heap/imm32
+ 79     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+ 80     # . . call
+ 81     e8/call  new-segment/disp32
+ 82     # . . discard args
+ 83     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 84 
+ 85     # if (argc <= 1) return factorial(5)
+ 86 $run-main:
+ 87     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
+ 88     7f/jump-if->  $main:run-tests/disp8
+ 89     # eax = factorial(5)
+ 90     # . . push args
+ 91     68/push  5/imm32
+ 92     # . . call
+ 93     e8/call  factorial/disp32
+ 94     # . . discard args
+ 95     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 96     # var buffer/ecx: (stream byte 10)  # number of decimal digits a 32-bit number can have
+ 97     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa/imm32         # subtract from esp
+ 98     68/push  0xa/imm32/decimal-digits-in-32bit-number
+ 99     68/push  0/imm32/read
+100     68/push  0/imm32/write
+101     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+102     # write-int32-decimal(buffer, eax)
+103     # . . push args
+104     50/push-eax
+105     51/push-ecx
+106     # . . call
+107     e8/call  write-int32-decimal/disp32
+108     # . . discard args
+109     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+110     # write-stream(stderr, buffer)
+111     # . . push args
+112     51/push-ecx
+113     68/push  2/imm32/stderr
+114     # . . call
+115     e8/call  write-stream/disp32
+116     # . . discard args
+117     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+118     # write(stderr, Newline)
+119     # . . push args
+120     68/push  Newline/imm32
+121     68/push  2/imm32/stderr
+122     # . . call
+123     e8/call  write/disp32
+124     # . . discard args
+125     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+126     #
+127     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+128     eb/jump  $main:end/disp8
+129 $main:run-tests:
+130     # otherwise if first arg is "test", then return run_tests()
+131     # if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
+132     # . eax = kernel-string-equal?(argv[1], "test")
+133     # . . push args
+134     68/push  "test"/imm32
+135     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+136     # . . call
+137     e8/call  kernel-string-equal?/disp32
+138     # . . discard args
+139     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+140     # . if (eax == false) goto do-nothing
+141     3d/compare-eax-and  0/imm32/false
+142     74/jump-if-=  $main:do-nothing/disp8
+143     # run-tests()
+144     e8/call  run-tests/disp32
+145     # exit(*Num-test-failures)
+146     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+147     eb/jump  $main:end/disp8
+148 $main:do-nothing:
+149     bb/copy-to-ebx  0/imm32
+150 $main:end:
+151     e8/call  syscall_exit/disp32
+152 
+153 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/factorial2.subx.html b/html/linux/apps/factorial2.subx.html new file mode 100644 index 00000000..72331748 --- /dev/null +++ b/html/linux/apps/factorial2.subx.html @@ -0,0 +1,185 @@ + + + + +Mu - linux/apps/factorial2.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial2.subx +
+  1 ## compute the factorial of 5, and return the result in the exit code
+  2 #
+  3 # Uses syntax sugar for:
+  4 #   rm32 operands
+  5 #
+  6 # To run:
+  7 #   $ ./translate_subx init.linux [01]*.subx apps/factorial2.subx -o factorial
+  8 #   $ bootstrap/bootstrap run factorial
+  9 # Expected result:
+ 10 #   $ echo $?
+ 11 #   120
+ 12 #
+ 13 # You can also run the automated test suite:
+ 14 #   $ bootstrap/bootstrap run factorial test
+ 15 # Expected output:
+ 16 #   ........
+ 17 # Every '.' indicates a passing test. Failing tests get a 'F'.
+ 18 #
+ 19 # Compare factorial.subx
+ 20 
+ 21 == code
+ 22 
+ 23 factorial:  # n: int -> _/eax: int
+ 24     # . prologue
+ 25     55/push-ebp
+ 26     89/<- %ebp 4/r32/esp
+ 27     # save registers
+ 28     51/push-ecx
+ 29     # if (n <= 1) return 1
+ 30     b8/copy-to-eax 1/imm32
+ 31     81 7/subop/compare *(ebp+8) 1/imm32
+ 32     7e/jump-if-<= $factorial:end/disp8
+ 33     # n > 1; return n * factorial(n-1)
+ 34     8b/-> *(ebp+8) 1/r32/ecx
+ 35     49/decrement-ecx
+ 36     # var tmp/eax: int = factorial(n-1)
+ 37     # . . push args
+ 38     51/push-ecx
+ 39     # . . call
+ 40     e8/call factorial/disp32
+ 41     # . . discard args
+ 42     81 0/subop/add %esp 4/imm32
+ 43     # return n * tmp
+ 44     f7 4/subop/multiply-into-eax *(ebp+8)
+ 45     # TODO: check for overflow
+ 46 $factorial:end:
+ 47     # restore registers
+ 48     59/pop-to-ecx
+ 49     # . epilogue
+ 50     89/<- %esp 5/r32/ebp
+ 51     5d/pop-to-ebp
+ 52     c3/return
+ 53 
+ 54 test-factorial:
+ 55     # factorial(5)
+ 56     # . . push args
+ 57     68/push 5/imm32
+ 58     # . . call
+ 59     e8/call factorial/disp32
+ 60     # . . discard args
+ 61     81 0/subop/add %esp 4/imm32
+ 62     # check-ints-equal(eax, 120, msg)
+ 63     # . . push args
+ 64     68/push "F - test-factorial"/imm32
+ 65     68/push 0x78/imm32/expected-120
+ 66     50/push-eax
+ 67     # . . call
+ 68     e8/call check-ints-equal/disp32
+ 69     # . . discard args
+ 70     81 0/subop/add %esp 0xc/imm32
+ 71     # end
+ 72     c3/return
+ 73 
+ 74 Entry:  # run tests if necessary, compute `factorial(5)` if not
+ 75     # . prologue
+ 76     89/<- %ebp 4/r32/esp
+ 77 
+ 78     # initialize heap (needed by tests elsewhere)
+ 79     # . Heap = new-segment(Heap-size)
+ 80     # . . push args
+ 81     68/push Heap/imm32
+ 82     ff 6/subop/push *Heap-size
+ 83     # . . call
+ 84     e8/call new-segment/disp32
+ 85     # . . discard args
+ 86     81 0/subop/add %esp 8/imm32
+ 87 
+ 88     # if (argc <= 1) return factorial(5)
+ 89     81 7/subop/compare *ebp 1/imm32
+ 90     7f/jump-if-> $main:run-tests/disp8
+ 91     # . . push args
+ 92     68/push 5/imm32
+ 93     # . . call
+ 94     e8/call factorial/disp32
+ 95     # . . discard args
+ 96     81 0/subop/add %esp 4/imm32
+ 97     # .
+ 98     89/<- %ebx 0/r32/eax
+ 99     eb/jump $main:end/disp8
+100 $main:run-tests:
+101     # otherwise if first arg is "test", then return run_tests()
+102     # if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
+103     # . eax = kernel-string-equal?(argv[1], "test")
+104     # . . push args
+105     68/push "test"/imm32
+106     ff 6/subop/push *(ebp+8)
+107     # . . call
+108     e8/call kernel-string-equal?/disp32
+109     # . . discard args
+110     81 0/subop/add %esp 8/imm32
+111     # . if (eax == false) goto do-nothing
+112     3d/compare-eax-and 0/imm32/false
+113     74/jump-if-= $main:do-nothing/disp8
+114     # run-tests()
+115     e8/call run-tests/disp32
+116     # exit(*Num-test-failures)
+117     8b/-> *Num-test-failures 3/r32/ebx
+118     eb/jump $main:end/disp8
+119 $main:do-nothing:
+120     bb/copy-to-ebx 0/imm32
+121 $main:end:
+122     e8/call  syscall_exit/disp32
+
+ + + diff --git a/html/linux/apps/factorial3.subx.html b/html/linux/apps/factorial3.subx.html new file mode 100644 index 00000000..93cf4e55 --- /dev/null +++ b/html/linux/apps/factorial3.subx.html @@ -0,0 +1,142 @@ + + + + +Mu - linux/apps/factorial3.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial3.subx +
+ 1 ## compute the factorial of 5, and return the result in the exit code
+ 2 #
+ 3 # Uses syntax sugar for:
+ 4 #   rm32 operands
+ 5 #   function calls
+ 6 #
+ 7 # To run:
+ 8 #   $ ./translate_subx init.linux [01]*.subx apps/factorial3.subx -o factorial
+ 9 #   $ bootstrap/bootstrap run factorial
+10 # Expected result:
+11 #   $ echo $?
+12 #   120
+13 #
+14 # You can also run the automated test suite:
+15 #   $ bootstrap/bootstrap run factorial test
+16 # Expected output:
+17 #   ........
+18 # Every '.' indicates a passing test. Failing tests get a 'F'.
+19 #
+20 # Compare factorial2.subx
+21 
+22 == code
+23 
+24 factorial:  # n: int -> _/eax: int
+25     # . prologue
+26     55/push-ebp
+27     89/<- %ebp 4/r32/esp
+28     # save registers
+29     51/push-ecx
+30     # if (n <= 1) return 1
+31     b8/copy-to-eax 1/imm32
+32     81 7/subop/compare *(ebp+8) 1/imm32
+33     7e/jump-if-<= $factorial:end/disp8
+34     # n > 1; return n * factorial(n-1)
+35     8b/-> *(ebp+8) 1/r32/ecx
+36     49/decrement-ecx
+37     (factorial %ecx)  # => eax
+38     f7 4/subop/multiply-into-eax *(ebp+8)
+39     # TODO: check for overflow
+40 $factorial:end:
+41     # restore registers
+42     59/pop-to-ecx
+43     # . epilogue
+44     89/<- %esp 5/r32/ebp
+45     5d/pop-to-ebp
+46     c3/return
+47 
+48 test-factorial:
+49     (factorial 5)
+50     (check-ints-equal %eax 0x78 "F - test-factorial")
+51     c3/return
+52 
+53 Entry:  # run tests if necessary, compute `factorial(5)` if not
+54     # . prologue
+55     89/<- %ebp 4/r32/esp
+56 
+57     # initialize heap (needed by tests elsewhere)
+58     (new-segment *Heap-size Heap)
+59 
+60     # if (argc <= 1) return factorial(5)
+61     81 7/subop/compare *ebp 1/imm32
+62     7f/jump-if-> $main:run-tests/disp8
+63     (factorial 5)  # => eax
+64     89/<- %ebx 0/r32/eax
+65     eb/jump $main:end/disp8
+66 $main:run-tests:
+67     # otherwise if first arg is "test", then return run_tests()
+68     # if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
+69     (kernel-string-equal? *(ebp+8) "test")  # => eax
+70     3d/compare-eax-and 0/imm32/false
+71     74/jump-if-= $main:do-nothing/disp8
+72     #
+73     (run-tests)
+74     # exit(*Num-test-failures)
+75     8b/-> *Num-test-failures 3/r32/ebx
+76     eb/jump $main:end/disp8
+77 $main:do-nothing:
+78     bb/copy-to-ebx 0/imm32
+79 $main:end:
+80     e8/call  syscall_exit/disp32
+
+ + + diff --git a/html/linux/apps/factorial4.subx.html b/html/linux/apps/factorial4.subx.html new file mode 100644 index 00000000..879a7a44 --- /dev/null +++ b/html/linux/apps/factorial4.subx.html @@ -0,0 +1,150 @@ + + + + +Mu - linux/apps/factorial4.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial4.subx +
+ 1 ## compute the factorial of 5, and return the result in the exit code
+ 2 #
+ 3 # Uses syntax sugar for:
+ 4 #   rm32 operands
+ 5 #   function calls
+ 6 #   control flow
+ 7 #
+ 8 # To run:
+ 9 #   $ ./translate_subx init.linux [01]*.subx apps/factorial4.subx -o factorial
+10 #   $ bootstrap/bootstrap run factorial
+11 # Expected result:
+12 #   $ echo $?
+13 #   120
+14 #
+15 # You can also run the automated test suite:
+16 #   $ bootstrap/bootstrap run factorial test
+17 # Expected output:
+18 #   ........
+19 # Every '.' indicates a passing test. Failing tests get a 'F'.
+20 #
+21 # Compare factorial3.subx
+22 
+23 == code
+24 
+25 factorial:  # n: int -> _/eax: int
+26     # . prologue
+27     55/push-ebp
+28     89/<- %ebp 4/r32/esp
+29     # save registers
+30     51/push-ecx
+31     # if (n <= 1) return 1
+32     81 7/subop/compare *(ebp+8) 1/imm32
+33     {
+34       7f/jump-if-> break/disp8
+35       b8/copy-to-eax 1/imm32
+36       eb/jump $factorial:end/disp8
+37     }
+38     # n > 1; return n * factorial(n-1)
+39     8b/-> *(ebp+8) 1/r32/ecx
+40     49/decrement-ecx
+41     (factorial %ecx)  # => eax
+42     f7 4/subop/multiply-into-eax *(ebp+8)
+43     # TODO: check for overflow
+44 $factorial:end:
+45     # restore registers
+46     59/pop-to-ecx
+47     # . epilogue
+48     89/<- %esp 5/r32/ebp
+49     5d/pop-to-ebp
+50     c3/return
+51 
+52 test-factorial:
+53     (factorial 5)
+54     (check-ints-equal %eax 0x78 "F - test-factorial")
+55     c3/return
+56 
+57 Entry:  # run tests if necessary, compute `factorial(5)` if not
+58     # . prologue
+59     89/<- %ebp 4/r32/esp
+60 
+61     # initialize heap (needed by tests elsewhere)
+62     (new-segment *Heap-size Heap)
+63 
+64     # if (argc <= 1) return factorial(5)
+65     {
+66       # if (argc > 1) break
+67       81 7/subop/compare *ebp 1/imm32
+68       7f/jump-if-> break/disp8
+69       # ebx = factorial(5)
+70       (factorial 5)  # => eax
+71       89/<- %ebx 0/r32/eax
+72       eb/jump $main:end/disp8
+73     }
+74     # otherwise if first arg is "test", then return run_tests()
+75     {
+76       # if (!kernel-string-equal?(argv[1], "test")) break
+77       (kernel-string-equal? *(ebp+8) "test")  # => eax
+78       3d/compare-eax-and 0/imm32/false
+79       74/jump-if-= break/disp8
+80       #
+81       (run-tests)
+82       # exit(*Num-test-failures)
+83       8b/-> *Num-test-failures 3/r32/ebx
+84       eb/jump $main:end/disp8
+85     }
+86     bb/copy-to-ebx 0/imm32
+87 $main:end:
+88     e8/call  syscall_exit/disp32
+
+ + + diff --git a/html/linux/apps/hello.mu.html b/html/linux/apps/hello.mu.html new file mode 100644 index 00000000..b7033551 --- /dev/null +++ b/html/linux/apps/hello.mu.html @@ -0,0 +1,72 @@ + + + + +Mu - linux/apps/hello.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/hello.mu +
+ 1 # Meaningless conventional example.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/hello.mu
+ 5 #   $ ./a.elf
+ 6 
+ 7 fn main -> _/ebx: int {
+ 8   print-string 0/screen, "Hello world!\n"
+ 9   return 0
+10 }
+
+ + + diff --git a/html/linux/apps/parse-int.mu.html b/html/linux/apps/parse-int.mu.html new file mode 100644 index 00000000..0ba861a7 --- /dev/null +++ b/html/linux/apps/parse-int.mu.html @@ -0,0 +1,114 @@ + + + + +Mu - linux/apps/parse-int.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/parse-int.mu +
+ 1 # parse a decimal int at the commandline
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/parse-int.mu
+ 5 #   $ ./a.elf 123
+ 6 #   $ echo $?
+ 7 #   123
+ 8 
+ 9 fn main _args: (addr array addr array byte) -> _/ebx: int {
+10   # if no args, print a message and exit
+11   var args/esi: (addr array addr array byte) <- copy _args
+12   var n/ecx: int <- length args
+13   compare n, 1
+14   {
+15     break-if->
+16     print-string 0/screen, "usage: parse-int <integer>\n"
+17     return 1
+18   }
+19   # otherwise parse the first arg as an integer
+20   var in/ecx: (addr addr array byte) <- index args, 1
+21   var out/eax: int <- parse-int *in
+22   return out
+23 }
+24 
+25 fn parse-int _in: (addr array byte) -> _/eax: int {
+26   var in/esi: (addr array byte) <- copy _in
+27   var len/edx: int <- length in
+28   var i/ecx: int <- copy 0
+29   var result/edi: int <- copy 0
+30   {
+31     compare i, len
+32     break-if->=
+33     # result *= 10
+34     var ten/eax: int <- copy 0xa
+35     result <- multiply ten
+36     # c = in[i]
+37     var tmp/ebx: (addr byte) <- index in, i
+38     var c/eax: byte <- copy-byte *tmp
+39     #
+40     var g/eax: grapheme <- copy c
+41     var digit/eax: int <- to-decimal-digit g
+42     result <- add digit
+43     i <- increment
+44     loop
+45   }
+46   return result
+47 }
+
+ + + diff --git a/html/linux/apps/print-file.mu.html b/html/linux/apps/print-file.mu.html new file mode 100644 index 00000000..21dfc9d2 --- /dev/null +++ b/html/linux/apps/print-file.mu.html @@ -0,0 +1,104 @@ + + + + +Mu - linux/apps/print-file.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/print-file.mu +
+ 1 # accept a filename on the commandline, read it and print it out to screen
+ 2 # only ascii right now, just like the rest of Mu
+ 3 #
+ 4 # To run:
+ 5 #   $ ./translate apps/print-file.mu
+ 6 #   $ echo abc > x
+ 7 #   $ ./a.elf x
+ 8 #   abc
+ 9 
+10 fn main _args: (addr array addr array byte) -> _/ebx: int {
+11   var args/eax: (addr array addr array byte) <- copy _args
+12   var n/ecx: int <- length args
+13   compare n, 1
+14   {
+15     break-if->
+16     print-string 0/screen, "usage: cat <filename>\n"
+17     return 0
+18   }
+19   {
+20     break-if-<=
+21     var filename/edx: (addr addr array byte) <- index args 1
+22     var in: (handle buffered-file)
+23     {
+24       var addr-in/eax: (addr handle buffered-file) <- address in
+25       open *filename, 0/read-only, addr-in
+26     }
+27     var _in-addr/eax: (addr buffered-file) <- lookup in
+28     var in-addr/ecx: (addr buffered-file) <- copy _in-addr
+29     {
+30       var c/eax: byte <- read-byte-buffered in-addr
+31       compare c, 0xffffffff/end-of-file
+32       break-if-=
+33       var g/eax: grapheme <- copy c
+34       print-grapheme 0/screen, g
+35       loop
+36     }
+37   }
+38   return 0
+39 }
+
+ + + diff --git a/html/linux/apps/raytracing/1.mu.html b/html/linux/apps/raytracing/1.mu.html new file mode 100644 index 00000000..f7464218 --- /dev/null +++ b/html/linux/apps/raytracing/1.mu.html @@ -0,0 +1,95 @@ + + + + +Mu - linux/apps/raytracing/1.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/1.mu +
+ 1 # Listing 1 of https://raytracing.github.io/books/RayTracingInOneWeekend.html
+ 2 # (simplified)
+ 3 #
+ 4 # To run (on Linux):
+ 5 #   $ git clone https://github.com/akkartik/mu
+ 6 #   $ cd mu/linux
+ 7 #   $ ./translate apps/raytracing/1.mu
+ 8 #   $ ./a.elf > 1.ppm
+ 9 
+10 fn main -> _/ebx: int {
+11   print-string 0, "P3\n256 256\n255\n"
+12   var j/ecx: int <- copy 0xff
+13   {
+14     compare j, 0
+15     break-if-<
+16     var i/eax: int <- copy 0
+17     {
+18       compare i, 0xff
+19       break-if->
+20       print-int32-decimal 0, i
+21       print-string 0, " "
+22       print-int32-decimal 0, j
+23       print-string 0, " 64\n"
+24       i <- increment
+25       loop
+26     }
+27     j <- decrement
+28     loop
+29   }
+30   return 0
+31 }
+
+ + + diff --git a/html/linux/apps/raytracing/2.mu.html b/html/linux/apps/raytracing/2.mu.html new file mode 100644 index 00000000..6ae05c81 --- /dev/null +++ b/html/linux/apps/raytracing/2.mu.html @@ -0,0 +1,153 @@ + + + + +Mu - linux/apps/raytracing/2.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/2.mu +
+ 1 # Listing 7 of https://raytracing.github.io/books/RayTracingInOneWeekend.html
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu/linux
+ 6 #   $ ./translate apps/raytracing/2.mu
+ 7 #   $ ./a.elf > 2.ppm
+ 8 
+ 9 fn main -> _/ebx: int {
+10   print-string 0, "P3\n256 256\n255\n"
+11   var _four/edx: int <- copy 4
+12   var four/xmm1: float <- convert _four
+13   var one-fourth/xmm1: float <- reciprocal four
+14   var max/edx: int <- copy 0xff
+15   var image-size/xmm2: float <- convert max
+16   var j/ecx: int <- copy 0xff
+17   {
+18     compare j, 0
+19     break-if-<
+20     var i/eax: int <- copy 0
+21     {
+22       compare i, 0xff
+23       break-if->
+24       var c: rgb
+25       # compute r
+26       var tmp/xmm0: float <- convert i
+27       tmp <- divide image-size
+28       var r-addr/edx: (addr float) <- get c, r
+29       copy-to *r-addr, tmp
+30 #?       var tmp2/ebx: int <- reinterpret *r-addr
+31 #?       print-int32-hex 0, tmp2
+32 #?       print-string 0, "\n"
+33       # compute g
+34       tmp <- convert j
+35       tmp <- divide image-size
+36       var g-addr/edx: (addr float) <- get c, g
+37       copy-to *g-addr, tmp
+38       # compute b
+39       var b-addr/edx: (addr float) <- get c, b
+40       copy-to *b-addr, one-fourth
+41       # emit
+42       var c-addr/edx: (addr rgb) <- address c
+43       print-rgb 0, c-addr
+44       i <- increment
+45       loop
+46     }
+47     j <- decrement
+48     loop
+49   }
+50   return 0
+51 }
+52 
+53 type rgb {
+54   # components normalized to within [0.0, 1.0]
+55   r: float
+56   g: float
+57   b: float
+58 }
+59 
+60 # print translating to [0, 256)
+61 fn print-rgb screen: (addr screen), _c: (addr rgb) {
+62   var c/esi: (addr rgb) <- copy _c
+63   var n/ecx: int <- copy 0xff  # turns out 255 works just as well as 255.999, which is lucky because we don't have floating-point literals
+64   var xn/xmm1: float <- convert n
+65   # print 255 * c->r
+66   var result/xmm0: float <- copy xn
+67   var src-addr/eax: (addr float) <- get c, r
+68   result <- multiply *src-addr
+69   var result-int/edx: int <- convert result
+70   print-int32-decimal screen, result-int
+71   print-string screen, " "
+72   # print 255 * c->g
+73   src-addr <- get c, g
+74   result <- copy xn
+75   result <- multiply *src-addr
+76   result-int <- convert result
+77   print-int32-decimal screen, result-int
+78   print-string screen, " "
+79   # print 255 * c->b
+80   src-addr <- get c, b
+81   result <- copy xn
+82   result <- multiply *src-addr
+83   result-int <- convert result
+84   print-int32-decimal screen, result-int
+85   print-string screen, "\n"
+86 }
+
+ + + diff --git a/html/linux/apps/raytracing/3.mu.html b/html/linux/apps/raytracing/3.mu.html new file mode 100644 index 00000000..c43df3a4 --- /dev/null +++ b/html/linux/apps/raytracing/3.mu.html @@ -0,0 +1,554 @@ + + + + +Mu - linux/apps/raytracing/3.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/3.mu +
+  1 # Listing 9 of https://raytracing.github.io/books/RayTracingInOneWeekend.html
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu/linux
+  6 #   $ ./translate apps/raytracing/3.mu
+  7 #   $ ./a.elf > 3.ppm
+  8 
+  9 fn ray-color _in: (addr ray), _out: (addr rgb) {
+ 10   var in/esi: (addr ray) <- copy _in
+ 11   var out/edi: (addr rgb) <- copy _out
+ 12   var dir/eax: (addr vec3) <- get in, dir
+ 13 #?   print-string 0, "r.dir: "
+ 14 #?   print-vec3 0, dir
+ 15 #?   print-string 0, "\n"
+ 16   var unit-storage: vec3
+ 17   var unit/ecx: (addr vec3) <- address unit-storage
+ 18   vec3-unit dir, unit
+ 19 #?   print-string 0, "r.dir normalized: "
+ 20 #?   print-vec3 0, unit
+ 21 #?   print-string 0, "\n"
+ 22   var y-addr/eax: (addr float) <- get unit, y
+ 23   # t = (dir.y + 1.0) / 2.0
+ 24   var t/xmm0: float <- copy *y-addr
+ 25   var one/eax: int <- copy 1
+ 26   var one-f/xmm1: float <- convert one
+ 27   t <- add one-f
+ 28   var two/eax: int <- copy 2
+ 29   var two-f/xmm2: float <- convert two
+ 30   t <- divide two-f
+ 31 #?   print-string 0, "t: "
+ 32 #?   print-float-hex 0, t
+ 33 #?   print-string 0, "\n"
+ 34   # whitening = (1.0 - t) * white
+ 35   var whitening-storage: rgb
+ 36   var whitening/ecx: (addr rgb) <- address whitening-storage
+ 37   rgb-white whitening
+ 38   var one-minus-t/xmm3: float <- copy one-f
+ 39   one-minus-t <- subtract t
+ 40   rgb-scale-up whitening, one-minus-t
+ 41 #?   print-string 0, "whitening: "
+ 42 #?   print-rgb-raw 0, whitening
+ 43 #?   print-string 0, "\n"
+ 44   # out = t * (0.5, 0.7, 1.0)
+ 45   var dest/eax: (addr float) <- get out, r
+ 46   fill-in-rational dest, 5, 0xa
+ 47   dest <- get out, g
+ 48   fill-in-rational dest, 7, 0xa
+ 49   dest <- get out, b
+ 50   copy-to *dest, one-f
+ 51   rgb-scale-up out, t
+ 52 #?   print-string 0, "base: "
+ 53 #?   print-rgb-raw 0, out
+ 54 #?   print-string 0, "\n"
+ 55   # blend with whitening
+ 56   rgb-add-to out, whitening
+ 57 #?   print-string 0, "result: "
+ 58 #?   print-rgb-raw 0, out
+ 59 #?   print-string 0, "\n"
+ 60 }
+ 61 
+ 62 fn main -> _/ebx: int {
+ 63 
+ 64   # image
+ 65   #   width = 400
+ 66   #   height = 400 * 9/16 = 225
+ 67   var aspect: float
+ 68   var aspect-addr/eax: (addr float) <- address aspect
+ 69   fill-in-rational aspect-addr, 0x10, 9  # 16/9
+ 70 #?   print-string 0, "aspect ratio: "
+ 71 #?   print-float-hex 0, aspect
+ 72 #?   print-string 0, " "
+ 73 #?   {
+ 74 #?     var foo2/ebx: int <- reinterpret aspect
+ 75 #?     print-int32-hex 0, foo2
+ 76 #?   }
+ 77 #?   print-string 0, "\n"
+ 78 
+ 79   # camera
+ 80 
+ 81   # viewport-height = 2.0
+ 82   var tmp/eax: int <- copy 2
+ 83   var two-f/xmm4: float <- convert tmp
+ 84   var viewport-height/xmm7: float <- copy two-f
+ 85 #?   print-string 0, "viewport height: "
+ 86 #?   print-float-hex 0, viewport-height
+ 87 #?   print-string 0, " "
+ 88 #?   {
+ 89 #?     var foo: float
+ 90 #?     copy-to foo, viewport-height
+ 91 #?     var foo2/ebx: int <- reinterpret foo
+ 92 #?     print-int32-hex 0, foo2
+ 93 #?   }
+ 94 #?   print-string 0, "\n"
+ 95   # viewport-width = aspect * viewport-height
+ 96   var viewport-width/xmm6: float <- convert tmp
+ 97   viewport-width <- multiply aspect
+ 98 #?   print-string 0, "viewport width: "
+ 99 #?   print-float-hex 0, viewport-width
+100 #?   print-string 0, " "
+101 #?   {
+102 #?     var foo: float
+103 #?     copy-to foo, viewport-width
+104 #?     var foo2/ebx: int <- reinterpret foo
+105 #?     print-int32-hex 0, foo2
+106 #?   }
+107 #?   print-string 0, "\n"
+108   # focal-length = 1.0
+109   tmp <- copy 1
+110   var focal-length/xmm5: float <- convert tmp
+111 
+112   # origin = point3(0, 0, 0)
+113   var origin-storage: vec3
+114   var origin/edi: (addr vec3) <- address origin-storage
+115   # horizontal = vec3(viewport-width, 0, 0)
+116   var horizontal-storage: vec3
+117   var dest/eax: (addr float) <- get horizontal-storage, x
+118   copy-to *dest, viewport-width
+119   var horizontal/ebx: (addr vec3) <- address horizontal-storage
+120   # vertical = vec3(0, viewport-height, 0)
+121   var vertical-storage: vec3
+122   dest <- get vertical-storage, y
+123   copy-to *dest, viewport-height
+124   var vertical/edx: (addr vec3) <- address vertical-storage
+125   # lower-left-corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal-length)
+126   # . lower-left-corner = origin
+127   var lower-left-corner-storage: vec3
+128   var lower-left-corner/esi: (addr vec3) <- address lower-left-corner-storage
+129   copy-object origin, lower-left-corner
+130   # . lower-left-corner -= horizontal/2
+131   var tmp2: vec3
+132   var tmp2-addr/eax: (addr vec3) <- address tmp2
+133   copy-object horizontal, tmp2-addr
+134   vec3-scale-down tmp2-addr, two-f
+135   vec3-subtract-from lower-left-corner, tmp2-addr
+136   # . lower-left-corner -= vertical/2
+137   copy-object vertical, tmp2-addr
+138   vec3-scale-down tmp2-addr, two-f
+139   vec3-subtract-from lower-left-corner, tmp2-addr
+140   # . lower-left-corner -= vec3(0, 0, focal-length)
+141   var dest2/ecx: (addr float) <- get lower-left-corner, z
+142   var tmp3/xmm0: float <- copy *dest2
+143   tmp3 <- subtract focal-length
+144   copy-to *dest2, tmp3
+145   # phew!
+146 
+147   # render
+148 
+149   # live variables at this point:
+150   #   origin (edi)
+151   #   lower-left-corner (esi)
+152   #   horizontal (ebx)
+153   #   vertical (edx)
+154   # floating-point registers are all free
+155   print-string 0, "P3\n400 225\n255\n"  # 225 = image height
+156   var tmp/eax: int <- copy 0x18f # image width - 1
+157   var image-width-1/xmm7: float <- convert tmp
+158   tmp <- copy 0xe0  # image height - 1
+159   var image-height-1/xmm6: float <- convert tmp
+160   #
+161   var j/ecx: int <- copy 0xe0  # 224
+162   {
+163     compare j, 0
+164     break-if-<
+165     var i/eax: int <- copy 0
+166     {
+167       compare i, 0x190  # 400 = image width
+168       break-if->=
+169       # u = i / (image-width - 1)
+170       var u/xmm0: float <- convert i
+171       u <- divide image-width-1
+172 #?       print-string 0, "u: "
+173 #?       print-float-hex 0, u
+174 #?       print-string 0, "\n"
+175       # v = j / (image-height - 1)
+176       var v/xmm1: float <- convert j
+177       v <- divide image-height-1
+178       # r = ray(origin, lower-left-corner + u*horizontal + v*vertical - origin)
+179       var r-storage: ray
+180       # . . we're running out of int registers now,
+181       # . . but luckily we don't need i and j in the rest of this loop iteration,
+182       # . . so we'll just spill them in a block
+183       {
+184         # . r.orig = origin
+185         var r/eax: (addr ray) <- address r-storage
+186         var dest/ecx: (addr vec3) <- get r, orig
+187         copy-object origin, dest
+188         # . r.dir = lower-left-corner
+189         dest <- get r, dir
+190         copy-object lower-left-corner, dest
+191         # . r.dir += horizontal*u
+192         var tmp-vec3: vec3
+193         var tmp/eax: (addr vec3) <- address tmp-vec3
+194         copy-object horizontal, tmp
+195         vec3-scale-up tmp, u
+196         vec3-add-to dest, tmp
+197         # . r.dir += vertical*v
+198         copy-object vertical, tmp
+199         vec3-scale-up tmp, v
+200         vec3-add-to dest, tmp
+201         # . r.dir -= origin
+202         vec3-subtract-from dest, origin
+203 #?         print-string 0, "ray direction: "
+204 #?         print-vec3 0, dest
+205 #?         print-string 0, "\n"
+206       }
+207       # pixel-color = ray-color(r)
+208       var c-storage: rgb
+209       var c/ecx: (addr rgb) <- address c-storage
+210       {
+211         var r/eax: (addr ray) <- address r-storage
+212         ray-color r, c
+213         # write color
+214         print-rgb 0, c
+215 #?         print-rgb-raw 0, c
+216 #?         print-string 0, "\n"
+217       }
+218       i <- increment
+219       loop
+220     }
+221     j <- decrement
+222     loop
+223   }
+224   return 0
+225 }
+226 
+227 type ray {
+228   orig: vec3  # point
+229   dir: vec3
+230 }
+231 
+232 # A little different from the constructor at https://raytracing.github.io/books/RayTracingInOneWeekend.html
+233 # We immediately normalize the direction vector so we don't have to keep doing
+234 # so.
+235 fn initialize-ray _self: (addr ray), o: (addr vec3), d: (addr vec3) {
+236   var self/esi: (addr ray) <- copy _self
+237   var dest/eax: (addr vec3) <- get self, orig
+238   copy-object o, dest
+239   dest <- get self, dir
+240   vec3-unit d, dest
+241 }
+242 
+243 fn ray-at _self: (addr ray), t: float, out: (addr vec3) {
+244   var self/esi: (addr ray) <- copy _self
+245   var src/eax: (addr vec3) <- get self, dir
+246   copy-object src, out
+247   vec3-scale-up out, t
+248   src <- get self, orig
+249   vec3-add-to out, src
+250 }
+251 
+252 type rgb {
+253   # components normalized to within [0.0, 1.0]
+254   r: float
+255   g: float
+256   b: float
+257 }
+258 
+259 # print translating to [0, 256)
+260 fn print-rgb screen: (addr screen), _c: (addr rgb) {
+261   var c/esi: (addr rgb) <- copy _c
+262   var xn: float
+263   var xn-addr/ecx: (addr float) <- address xn
+264   fill-in-rational xn-addr, 0x3e7ff, 0x3e8  # 255999 / 1000
+265   # print 255.999 * c->r
+266   var result/xmm0: float <- copy xn
+267   var src-addr/eax: (addr float) <- get c, r
+268   result <- multiply *src-addr
+269   var result-int/edx: int <- truncate result
+270   print-int32-decimal screen, result-int
+271   print-string screen, " "
+272   # print 255.999 * c->g
+273   src-addr <- get c, g
+274   result <- copy xn
+275   result <- multiply *src-addr
+276   result-int <- truncate result
+277   print-int32-decimal screen, result-int
+278   print-string screen, " "
+279   # print 255.999 * c->b
+280   src-addr <- get c, b
+281   result <- copy xn
+282   result <- multiply *src-addr
+283   result-int <- truncate result
+284   print-int32-decimal screen, result-int
+285   print-string screen, "\n"
+286 }
+287 
+288 fn print-rgb-raw screen: (addr screen), _v: (addr rgb) {
+289   var v/esi: (addr rgb) <- copy _v
+290   print-string screen, "("
+291   var tmp/eax: (addr float) <- get v, r
+292   print-float-hex screen, *tmp
+293   print-string screen, ", "
+294   tmp <- get v, g
+295   print-float-hex screen, *tmp
+296   print-string screen, ", "
+297   tmp <- get v, b
+298   print-float-hex screen, *tmp
+299   print-string screen, ")"
+300 }
+301 
+302 fn rgb-white _c: (addr rgb) {
+303   var c/esi: (addr rgb) <- copy _c
+304   var one/eax: int <- copy 1
+305   var one-f/xmm0: float <- convert one
+306   var dest/edi: (addr float) <- get c, r
+307   copy-to *dest, one-f
+308   dest <- get c, g
+309   copy-to *dest, one-f
+310   dest <- get c, b
+311   copy-to *dest, one-f
+312 }
+313 
+314 fn rgb-add-to _c1: (addr rgb), _c2: (addr rgb) {
+315   var c1/edi: (addr rgb) <- copy _c1
+316   var c2/esi: (addr rgb) <- copy _c2
+317   # c1.r += c2.r
+318   var arg1/eax: (addr float) <- get c1, r
+319   var arg2/ecx: (addr float) <- get c2, r
+320   var result/xmm0: float <- copy *arg1
+321   result <- add *arg2
+322   copy-to *arg1, result
+323   # c1.g += c2.g
+324   arg1 <- get c1, g
+325   arg2 <- get c2, g
+326   result <- copy *arg1
+327   result <- add *arg2
+328   copy-to *arg1, result
+329   # c1.b += c2.b
+330   arg1 <- get c1, b
+331   arg2 <- get c2, b
+332   result <- copy *arg1
+333   result <- add *arg2
+334   copy-to *arg1, result
+335 }
+336 
+337 fn rgb-scale-up _c1: (addr rgb), f: float {
+338   var c1/edi: (addr rgb) <- copy _c1
+339   # c1.r *= f
+340   var dest/eax: (addr float) <- get c1, r
+341   var result/xmm0: float <- copy *dest
+342   result <- multiply f
+343   copy-to *dest, result
+344   # c1.g *= f
+345   dest <- get c1, g
+346   result <- copy *dest
+347   result <- multiply f
+348   copy-to *dest, result
+349   # c1.b *= f
+350   dest <- get c1, b
+351   result <- copy *dest
+352   result <- multiply f
+353   copy-to *dest, result
+354 }
+355 
+356 type vec3 {
+357   x: float
+358   y: float
+359   z: float
+360 }
+361 
+362 fn print-vec3 screen: (addr screen), _v: (addr vec3) {
+363   var v/esi: (addr vec3) <- copy _v
+364   print-string screen, "("
+365   var tmp/eax: (addr float) <- get v, x
+366   print-float-hex screen, *tmp
+367   print-string screen, ", "
+368   tmp <- get v, y
+369   print-float-hex screen, *tmp
+370   print-string screen, ", "
+371   tmp <- get v, z
+372   print-float-hex screen, *tmp
+373   print-string screen, ")"
+374 }
+375 
+376 fn vec3-add-to _v1: (addr vec3), _v2: (addr vec3) {
+377   var v1/edi: (addr vec3) <- copy _v1
+378   var v2/esi: (addr vec3) <- copy _v2
+379   # v1.x += v2.x
+380   var arg1/eax: (addr float) <- get v1, x
+381   var arg2/ecx: (addr float) <- get v2, x
+382   var result/xmm0: float <- copy *arg1
+383   result <- add *arg2
+384   copy-to *arg1, result
+385   # v1.y += v2.y
+386   arg1 <- get v1, y
+387   arg2 <- get v2, y
+388   result <- copy *arg1
+389   result <- add *arg2
+390   copy-to *arg1, result
+391   # v1.z += v2.z
+392   arg1 <- get v1, z
+393   arg2 <- get v2, z
+394   result <- copy *arg1
+395   result <- add *arg2
+396   copy-to *arg1, result
+397 }
+398 
+399 fn vec3-subtract-from v1: (addr vec3), v2: (addr vec3) {
+400   var tmp-storage: vec3
+401   var tmp/eax: (addr vec3) <- address tmp-storage
+402   copy-object v2, tmp
+403   vec3-negate tmp
+404   vec3-add-to v1, tmp
+405 }
+406 
+407 fn vec3-negate v: (addr vec3) {
+408   var negative-one/eax: int <- copy -1
+409   var negative-one-f/xmm0: float <- convert negative-one
+410   vec3-scale-up v, negative-one-f
+411 }
+412 
+413 fn vec3-scale-up _v: (addr vec3), f: float {
+414   var v/edi: (addr vec3) <- copy _v
+415   # v.x *= f
+416   var dest/eax: (addr float) <- get v, x
+417   var result/xmm0: float <- copy *dest
+418   result <- multiply f
+419   copy-to *dest, result
+420   # v.y *= f
+421   dest <- get v, y
+422   result <- copy *dest
+423   result <- multiply f
+424   copy-to *dest, result
+425   # v.z *= f
+426   dest <- get v, z
+427   result <- copy *dest
+428   result <- multiply f
+429   copy-to *dest, result
+430 }
+431 
+432 fn vec3-scale-down _v: (addr vec3), f: float {
+433   var v/edi: (addr vec3) <- copy _v
+434   # v.x /= f
+435   var dest/eax: (addr float) <- get v, x
+436   var result/xmm0: float <- copy *dest
+437   result <- divide f
+438   copy-to *dest, result
+439   # v.y /= f
+440   dest <- get v, y
+441   result <- copy *dest
+442   result <- divide f
+443   copy-to *dest, result
+444   # v.z /= f
+445   dest <- get v, z
+446   result <- copy *dest
+447   result <- divide f
+448   copy-to *dest, result
+449 }
+450 
+451 fn vec3-unit in: (addr vec3), out: (addr vec3) {
+452   var len/xmm0: float <- vec3-length in
+453 #?   print-string 0, "len: "
+454 #?   print-float-hex 0, len
+455 #?   print-string 0, "\n"
+456   copy-object in, out
+457   vec3-scale-down out, len
+458 }
+459 
+460 fn vec3-length v: (addr vec3) -> _/xmm0: float {
+461   var result/xmm0: float <- vec3-length-squared v
+462   result <- square-root result
+463   return result
+464 }
+465 
+466 fn vec3-length-squared _v: (addr vec3) -> _/xmm0: float {
+467   var v/esi: (addr vec3) <- copy _v
+468   # result = v.x * v.x
+469   var src/eax: (addr float) <- get v, x
+470   var tmp/xmm1: float <- copy *src
+471   tmp <- multiply tmp
+472   var result/xmm0: float <- copy tmp
+473   # result += v.y * v.y
+474   src <- get v, y
+475   tmp <- copy *src
+476   tmp <- multiply tmp
+477   result <- add tmp
+478   # result += v.z * v.z
+479   src <- get v, z
+480   tmp <- copy *src
+481   tmp <- multiply tmp
+482   result <- add tmp
+483   return result
+484 }
+
+ + + diff --git a/html/linux/apps/raytracing/color.mu.html b/html/linux/apps/raytracing/color.mu.html new file mode 100644 index 00000000..dc60a456 --- /dev/null +++ b/html/linux/apps/raytracing/color.mu.html @@ -0,0 +1,100 @@ + + + + +Mu - linux/apps/raytracing/color.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/color.mu +
+ 1 type rgb {
+ 2   # components normalized to within [0.0, 1.0]
+ 3   r: float
+ 4   g: float
+ 5   b: float
+ 6 }
+ 7 
+ 8 # print translating to [0, 256)
+ 9 fn print-rgb screen: (addr screen), _c: (addr rgb) {
+10   var c/esi: (addr rgb) <- copy _c
+11   var xn: float
+12   var xn-addr/ecx: (addr float) <- address xn
+13   fill-in-rational xn-addr, 0x3e7ff, 0x3e8  # 255999 / 1000
+14   # print 255.999 * c->r
+15   var result/xmm0: float <- copy xn
+16   var src-addr/eax: (addr float) <- get c, r
+17   result <- multiply *src-addr
+18   var result-int/edx: int <- truncate result
+19   print-int32-decimal screen, result-int
+20   print-string screen, " "
+21   # print 255.999 * c->g
+22   src-addr <- get c, g
+23   result <- copy xn
+24   result <- multiply *src-addr
+25   result-int <- truncate result
+26   print-int32-decimal screen, result-int
+27   print-string screen, " "
+28   # print 255.999 * c->b
+29   src-addr <- get c, b
+30   result <- copy xn
+31   result <- multiply *src-addr
+32   result-int <- truncate result
+33   print-int32-decimal screen, result-int
+34   print-string screen, "\n"
+35 }
+
+ + + diff --git a/html/linux/apps/raytracing/ray.mu.html b/html/linux/apps/raytracing/ray.mu.html new file mode 100644 index 00000000..5400c1f2 --- /dev/null +++ b/html/linux/apps/raytracing/ray.mu.html @@ -0,0 +1,86 @@ + + + + +Mu - linux/apps/raytracing/ray.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/ray.mu +
+ 1 type ray {
+ 2   orig: vec3  # point
+ 3   dir: vec3
+ 4 }
+ 5 
+ 6 # A little different from the constructor at https://raytracing.github.io/books/RayTracingInOneWeekend.html
+ 7 # We immediately normalize the direction vector so we don't have to keep doing
+ 8 # so.
+ 9 fn initialize-ray _self: (addr ray), o: (addr vec3), d: (addr vec3) {
+10   var self/esi: (addr ray) <- copy _self
+11   var dest/eax: (addr vec3) <- get self, orig
+12   copy-object o, dest
+13   dest <- get self, dir
+14   vec3-unit d, dest
+15 }
+16 
+17 fn ray-at _self: (addr ray), t: float, out: (addr vec3) {
+18   var self/esi: (addr ray) <- copy _self
+19   var src/eax: (addr vec3) <- get self, dir
+20   copy-object src, out
+21   vec3-scale-up out, t
+22   src <- get self, orig
+23   vec3-add-to out, src
+24 }
+
+ + + diff --git a/html/linux/apps/raytracing/vec.mu.html b/html/linux/apps/raytracing/vec.mu.html new file mode 100644 index 00000000..9fe5b990 --- /dev/null +++ b/html/linux/apps/raytracing/vec.mu.html @@ -0,0 +1,201 @@ + + + + +Mu - linux/apps/raytracing/vec.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/vec.mu +
+  1 type vec3 {
+  2   x: float
+  3   y: float
+  4   z: float
+  5 }
+  6 
+  7 fn print-vec3 screen: (addr screen), _v: (addr vec3) {
+  8   var v/esi: (addr vec3) <- copy _v
+  9   print-string screen, "("
+ 10   var tmp/eax: (addr float) <- get v, x
+ 11   print-float-hex screen, *tmp
+ 12   print-string screen, ", "
+ 13   tmp <- get v, y
+ 14   print-float-hex screen, *tmp
+ 15   print-string screen, ", "
+ 16   tmp <- get v, z
+ 17   print-float-hex screen, *tmp
+ 18   print-string screen, ")"
+ 19 }
+ 20 
+ 21 fn vec3-add-to _v1: (addr vec3), _v2: (addr vec3) {
+ 22   var v1/edi: (addr vec3) <- copy _v1
+ 23   var v2/esi: (addr vec3) <- copy _v2
+ 24   # v1.x += v2.x
+ 25   var arg1/eax: (addr float) <- get v1, x
+ 26   var arg2/ecx: (addr float) <- get v2, x
+ 27   var result/xmm0: float <- copy *arg1
+ 28   result <- add *arg2
+ 29   copy-to *arg1, result
+ 30   # v1.y += v2.y
+ 31   arg1 <- get v1, y
+ 32   arg2 <- get v2, y
+ 33   result <- copy *arg1
+ 34   result <- add *arg2
+ 35   copy-to *arg1, result
+ 36   # v1.z += v2.z
+ 37   arg1 <- get v1, z
+ 38   arg2 <- get v2, z
+ 39   result <- copy *arg1
+ 40   result <- add *arg2
+ 41   copy-to *arg1, result
+ 42 }
+ 43 
+ 44 fn vec3-subtract-from v1: (addr vec3), v2: (addr vec3) {
+ 45   var tmp-storage: vec3
+ 46   var tmp/eax: (addr vec3) <- address tmp-storage
+ 47   copy-object v2, tmp
+ 48   vec3-negate tmp
+ 49   vec3-add-to v1, tmp
+ 50 }
+ 51 
+ 52 fn vec3-negate v: (addr vec3) {
+ 53   var negative-one/eax: int <- copy -1
+ 54   var negative-one-f/xmm0: float <- convert negative-one
+ 55   vec3-scale-up v, negative-one-f
+ 56 }
+ 57 
+ 58 fn vec3-scale-up _v: (addr vec3), f: float {
+ 59   var v/edi: (addr vec3) <- copy _v
+ 60   # v.x *= f
+ 61   var dest/eax: (addr float) <- get v, x
+ 62   var result/xmm0: float <- copy *dest
+ 63   result <- multiply f
+ 64   copy-to *dest, result
+ 65   # v.y *= f
+ 66   dest <- get v, y
+ 67   result <- copy *dest
+ 68   result <- multiply f
+ 69   copy-to *dest, result
+ 70   # v.z *= f
+ 71   dest <- get v, z
+ 72   result <- copy *dest
+ 73   result <- multiply f
+ 74   copy-to *dest, result
+ 75 }
+ 76 
+ 77 fn vec3-scale-down _v: (addr vec3), f: float {
+ 78   var v/edi: (addr vec3) <- copy _v
+ 79   # v.x /= f
+ 80   var dest/eax: (addr float) <- get v, x
+ 81   var result/xmm0: float <- copy *dest
+ 82   result <- divide f
+ 83   copy-to *dest, result
+ 84   # v.y /= f
+ 85   dest <- get v, y
+ 86   result <- copy *dest
+ 87   result <- divide f
+ 88   copy-to *dest, result
+ 89   # v.z /= f
+ 90   dest <- get v, z
+ 91   result <- copy *dest
+ 92   result <- divide f
+ 93   copy-to *dest, result
+ 94 }
+ 95 
+ 96 fn vec3-unit in: (addr vec3), out: (addr vec3) {
+ 97   var len/xmm0: float <- vec3-length in
+ 98 #?   print-string 0, "len: "
+ 99 #?   print-float-hex 0, len
+100 #?   print-string 0, "\n"
+101   copy-object in, out
+102   vec3-scale-down out, len
+103 }
+104 
+105 fn vec3-length v: (addr vec3) -> _/xmm0: float {
+106   var result/xmm0: float <- vec3-length-squared v
+107   result <- square-root result
+108   return result
+109 }
+110 
+111 fn vec3-length-squared _v: (addr vec3) -> _/xmm0: float {
+112   var v/esi: (addr vec3) <- copy _v
+113   # result = v.x * v.x
+114   var src/eax: (addr float) <- get v, x
+115   var tmp/xmm1: float <- copy *src
+116   tmp <- multiply tmp
+117   var result/xmm0: float <- copy tmp
+118   # result += v.y * v.y
+119   src <- get v, y
+120   tmp <- copy *src
+121   tmp <- multiply tmp
+122   result <- add tmp
+123   # result += v.z * v.z
+124   src <- get v, z
+125   tmp <- copy *src
+126   tmp <- multiply tmp
+127   result <- add tmp
+128   return result
+129 }
+130 
+131 fn vec3-dot _v1: (addr vec3), _v2: (addr vec3) -> _/xmm0: float {
+132 }
+133 
+134 fn vec3-cross _v1: (addr vec3), _v2: (addr vec3), out: (addr vec3) {
+135 }
+
+ + + diff --git a/html/linux/apps/rpn.mu.html b/html/linux/apps/rpn.mu.html new file mode 100644 index 00000000..b5aba508 --- /dev/null +++ b/html/linux/apps/rpn.mu.html @@ -0,0 +1,215 @@ + + + + +Mu - linux/apps/rpn.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/rpn.mu +
+  1 # Integer arithmetic using postfix notation
+  2 #
+  3 # Limitations:
+  4 #   No division yet.
+  5 #
+  6 # To build:
+  7 #   $ ./translate apps/rpn.mu
+  8 #
+  9 # Example session:
+ 10 #   $ ./a.elf
+ 11 #   press ctrl-c or ctrl-d to exit
+ 12 #   > 1
+ 13 #   1
+ 14 #   > 1 1 +
+ 15 #   2
+ 16 #   > 1 2 3 + +
+ 17 #   6
+ 18 #   > 1 2 3 * +
+ 19 #   7
+ 20 #   > 1 2 + 3 *
+ 21 #   9
+ 22 #   > 1 3 4 * +
+ 23 #   13
+ 24 #   > ^D
+ 25 #   $
+ 26 #
+ 27 # Error handling is non-existent. This is just a prototype.
+ 28 
+ 29 fn main -> _/ebx: int {
+ 30   var in-storage: (stream byte 0x100)
+ 31   var in/esi: (addr stream byte) <- address in-storage
+ 32   print-string 0/screen, "press ctrl-c or ctrl-d to exit\n"
+ 33   # read-eval-print loop
+ 34   {
+ 35     # print prompt
+ 36     print-string 0/screen, "> "
+ 37     # read line
+ 38     clear-stream in
+ 39     read-line-from-real-keyboard in
+ 40     var done?/eax: boolean <- stream-empty? in
+ 41     compare done?, 0
+ 42     break-if-!=
+ 43     # parse and eval
+ 44     var out/eax: int <- simplify in
+ 45     # print
+ 46     print-int32-decimal 0/screen, out
+ 47     print-string 0/screen, "\n"
+ 48     #
+ 49     loop
+ 50   }
+ 51   return 0
+ 52 }
+ 53 
+ 54 type int-stack {
+ 55   data: (handle array int)
+ 56   top: int
+ 57 }
+ 58 
+ 59 fn simplify in: (addr stream byte) -> _/eax: int {
+ 60   var word-storage: slice
+ 61   var word/ecx: (addr slice) <- address word-storage
+ 62   var stack-storage: int-stack
+ 63   var stack/esi: (addr int-stack) <- address stack-storage
+ 64   initialize-int-stack stack, 0x10
+ 65   $simplify:word-loop: {
+ 66     next-word in, word
+ 67     var done?/eax: boolean <- slice-empty? word
+ 68     compare done?, 0
+ 69     break-if-!=
+ 70     # if word is an operator, perform it
+ 71     {
+ 72       var add?/eax: boolean <- slice-equal? word, "+"
+ 73       compare add?, 0
+ 74       break-if-=
+ 75       var _b/eax: int <- pop-int-stack stack
+ 76       var b/edx: int <- copy _b
+ 77       var a/eax: int <- pop-int-stack stack
+ 78       a <- add b
+ 79       push-int-stack stack, a
+ 80       loop $simplify:word-loop
+ 81     }
+ 82     {
+ 83       var sub?/eax: boolean <- slice-equal? word, "-"
+ 84       compare sub?, 0
+ 85       break-if-=
+ 86       var _b/eax: int <- pop-int-stack stack
+ 87       var b/edx: int <- copy _b
+ 88       var a/eax: int <- pop-int-stack stack
+ 89       a <- subtract b
+ 90       push-int-stack stack, a
+ 91       loop $simplify:word-loop
+ 92     }
+ 93     {
+ 94       var mul?/eax: boolean <- slice-equal? word, "*"
+ 95       compare mul?, 0
+ 96       break-if-=
+ 97       var _b/eax: int <- pop-int-stack stack
+ 98       var b/edx: int <- copy _b
+ 99       var a/eax: int <- pop-int-stack stack
+100       a <- multiply b
+101       push-int-stack stack, a
+102       loop $simplify:word-loop
+103     }
+104     # otherwise it's an int
+105     var n/eax: int <- parse-decimal-int-from-slice word
+106     push-int-stack stack, n
+107     loop
+108   }
+109   var result/eax: int <- pop-int-stack stack
+110   return result
+111 }
+112 
+113 fn initialize-int-stack _self: (addr int-stack), n: int {
+114   var self/esi: (addr int-stack) <- copy _self
+115   var d/edi: (addr handle array int) <- get self, data
+116   populate d, n
+117   var top/eax: (addr int) <- get self, top
+118   copy-to *top, 0
+119 }
+120 
+121 fn push-int-stack _self: (addr int-stack), _val: int {
+122   var self/esi: (addr int-stack) <- copy _self
+123   var top-addr/ecx: (addr int) <- get self, top
+124   var data-ah/edx: (addr handle array int) <- get self, data
+125   var data/eax: (addr array int) <- lookup *data-ah
+126   var top/edx: int <- copy *top-addr
+127   var dest-addr/edx: (addr int) <- index data, top
+128   var val/eax: int <- copy _val
+129   copy-to *dest-addr, val
+130   add-to *top-addr, 1
+131 }
+132 
+133 fn pop-int-stack _self: (addr int-stack) -> _/eax: int {
+134   var self/esi: (addr int-stack) <- copy _self
+135   var top-addr/ecx: (addr int) <- get self, top
+136   {
+137     compare *top-addr, 0
+138     break-if->
+139     return 0
+140   }
+141   subtract-from *top-addr, 1
+142   var data-ah/edx: (addr handle array int) <- get self, data
+143   var data/eax: (addr array int) <- lookup *data-ah
+144   var top/edx: int <- copy *top-addr
+145   var result-addr/eax: (addr int) <- index data, top
+146   var val/eax: int <- copy *result-addr
+147   return val
+148 }
+
+ + + diff --git a/html/linux/apps/texture.mu.html b/html/linux/apps/texture.mu.html new file mode 100644 index 00000000..c3f44607 --- /dev/null +++ b/html/linux/apps/texture.mu.html @@ -0,0 +1,126 @@ + + + + +Mu - linux/apps/texture.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/texture.mu +
+ 1 # Playing with emitting cool textures.
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/texture.mu
+ 7 #   $ ./a.elf > a.ppm
+ 8 
+ 9 fn main -> _/ebx: int {
+10 #?   var width/esi: int <- copy 0x190  # 400
+11 #?   var height/edi: int <- copy 0xe1  # 225; aspect ratio 16:9
+12   var width/esi: int <- copy 0xff
+13   var height/edi: int <- copy 0xff
+14   print-string 0/screen, "P3\n"
+15   print-int32-decimal 0/screen, width
+16   print-string 0/screen, " "
+17   print-int32-decimal 0/screen, height
+18   print-string 0/screen, "\n"
+19   print-string 0/screen, "255\n"  # color depth
+20   var row/ecx: int <- copy 0
+21   {
+22     compare row, height
+23     break-if->=
+24     var col/edx: int <- copy 0
+25     {
+26       compare col, width
+27       break-if->=
+28       # r
+29       var tmp/eax: int <- copy col
+30       tmp <- multiply row
+31       tmp <- and 0x7f
+32       tmp <- add 0x80
+33       tmp <- copy 0xff
+34       print-int32-decimal 0/screen, tmp
+35       print-string 0/screen, " "
+36       # g
+37       tmp <- copy row
+38       tmp <- multiply col
+39       tmp <- and 0x7f
+40       tmp <- add 0x80
+41 #?       tmp <- copy 0xcf
+42       print-int32-decimal 0/screen, tmp
+43       print-string 0/screen, " "
+44       # b
+45       tmp <- copy row
+46       tmp <- multiply col
+47       tmp <- and 0x7f
+48       tmp <- add 0x80
+49       print-int32-decimal 0/screen, tmp
+50       print-string 0/screen, "\n"
+51       col <- increment
+52       loop
+53     }
+54     row <- increment
+55     loop
+56   }
+57   return 0
+58 }
+
+ + + diff --git a/html/linux/apps/tui.mu.html b/html/linux/apps/tui.mu.html new file mode 100644 index 00000000..82681e6a --- /dev/null +++ b/html/linux/apps/tui.mu.html @@ -0,0 +1,98 @@ + + + + +Mu - linux/apps/tui.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/tui.mu +
+ 1 # Test some primitives for text-mode.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/tui.mu
+ 5 #   $ ./a.elf
+ 6 
+ 7 fn main -> _/ebx: int {
+ 8   var nrows/eax: int <- copy 0
+ 9   var ncols/ecx: int <- copy 0
+10   nrows, ncols <- screen-size 0
+11   enable-screen-grid-mode
+12   move-cursor 0/screen, 5/row, 0x22/col
+13   start-color 0/screen, 1/fg, 0x7a/bg
+14   start-blinking 0/screen
+15   print-string 0/screen, "Hello world!"
+16   reset-formatting 0/screen
+17   move-cursor 0/screen, 6/row, 0x22/col
+18   print-string 0/screen, "tty dimensions: "
+19   print-int32-hex 0/screen, nrows
+20   print-string 0/screen, " rows, "
+21   print-int32-hex 0/screen, ncols
+22   print-string 0/screen, " rows\n"
+23 
+24   print-string 0/screen, "press a key to see its code: "
+25   enable-keyboard-immediate-mode
+26   var x/eax: grapheme <- read-key-from-real-keyboard
+27   enable-keyboard-type-mode
+28   enable-screen-type-mode
+29   print-string 0/screen, "You pressed "
+30   var x-int/eax: int <- copy x
+31   print-int32-hex 0/screen, x-int
+32   print-string 0/screen, "\n"
+33   return 0
+34 }
+
+ + + diff --git a/html/linux/arith.mu.html b/html/linux/arith.mu.html deleted file mode 100644 index 7cd2e5c9..00000000 --- a/html/linux/arith.mu.html +++ /dev/null @@ -1,326 +0,0 @@ - - - - -Mu - linux/arith.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/linux/arith.mu -
-  1 # Integer arithmetic using conventional precedence.
-  2 #
-  3 # Follows part 2 of Jack Crenshaw's "Let's build a compiler!"
-  4 #   https://compilers.iecc.com/crenshaw
-  5 #
-  6 # Limitations:
-  7 #   No division yet.
-  8 #
-  9 # To build:
- 10 #   $ ./translate arith.mu
- 11 #
- 12 # Example session:
- 13 #   $ ./a.elf
- 14 #   press ctrl-c or ctrl-d to exit
- 15 #   > 1
- 16 #   1
- 17 #   > 1+1
- 18 #   2
- 19 #   > 1 + 1
- 20 #   2
- 21 #   > 1+2 +3
- 22 #   6
- 23 #   > 1+2 *3
- 24 #   7
- 25 #   > (1+2) *3
- 26 #   9
- 27 #   > 1 + 3*4
- 28 #   13
- 29 #   > ^D
- 30 #   $
- 31 #
- 32 # Error handling is non-existent. This is just a prototype.
- 33 
- 34 fn main -> _/ebx: int {
- 35   enable-keyboard-immediate-mode
- 36   var look/esi: grapheme <- copy 0  # lookahead
- 37   var n/eax: int <- copy 0  # result of each expression
- 38   print-string 0/screen, "press ctrl-c or ctrl-d to exit\n"
- 39   # read-eval-print loop
- 40   {
- 41     # print prompt
- 42     print-string 0/screen, "> "
- 43     # read and eval
- 44     n, look <- simplify  # we explicitly thread 'look' everywhere
- 45     # if (look == 0) break
- 46     compare look, 0
- 47     break-if-=
- 48     # print
- 49     print-int32-decimal 0/screen, n
- 50     print-string 0/screen, "\n"
- 51     #
- 52     loop
- 53   }
- 54   enable-keyboard-type-mode
- 55   return 0
- 56 }
- 57 
- 58 fn simplify -> _/eax: int, _/esi: grapheme {
- 59   # prime the pump
- 60   var look/esi: grapheme <- get-char
- 61   # do it
- 62   var result/eax: int <- copy 0
- 63   result, look <- expression look
- 64   return result, look
- 65 }
- 66 
- 67 fn expression _look: grapheme -> _/eax: int, _/esi: grapheme {
- 68   var look/esi: grapheme <- copy _look
- 69   # read arg
- 70   var result/eax: int <- copy 0
- 71   result, look <- term look
- 72   $expression:loop: {
- 73     # while next non-space char in ['+', '-']
- 74     look <- skip-spaces look
- 75     {
- 76       var continue?/eax: boolean <- add-or-sub? look
- 77       compare continue?, 0/false
- 78       break-if-= $expression:loop
- 79     }
- 80     # read operator
- 81     var op/ecx: grapheme <- copy 0
- 82     op, look <- operator look
- 83     # read next arg
- 84     var second/edx: int <- copy 0
- 85     look <- skip-spaces look
- 86     {
- 87       var tmp/eax: int <- copy 0
- 88       tmp, look <- term look
- 89       second <- copy tmp
- 90     }
- 91     # reduce
- 92     $expression:perform-op: {
- 93       {
- 94         compare op, 0x2b/+
- 95         break-if-!=
- 96         result <- add second
- 97         break $expression:perform-op
- 98       }
- 99       {
-100         compare op, 0x2d/minus
-101         break-if-!=
-102         result <- subtract second
-103         break $expression:perform-op
-104       }
-105     }
-106     loop
-107   }
-108   look <- skip-spaces look
-109   return result, look
-110 }
-111 
-112 fn term _look: grapheme -> _/eax: int, _/esi: grapheme {
-113   var look/esi: grapheme <- copy _look
-114   # read arg
-115   look <- skip-spaces look
-116   var result/eax: int <- copy 0
-117   result, look <- factor look
-118   $term:loop: {
-119     # while next non-space char in ['*', '/']
-120     look <- skip-spaces look
-121     {
-122       var continue?/eax: boolean <- mul-or-div? look
-123       compare continue?, 0/false
-124       break-if-= $term:loop
-125     }
-126     # read operator
-127     var op/ecx: grapheme <- copy 0
-128     op, look <- operator look
-129     # read next arg
-130     var second/edx: int <- copy 0
-131     look <- skip-spaces look
-132     {
-133       var tmp/eax: int <- copy 0
-134       tmp, look <- factor look
-135       second <- copy tmp
-136     }
-137     # reduce
-138     $term:perform-op: {
-139       {
-140         compare op, 0x2a/*
-141         break-if-!=
-142         result <- multiply second
-143         break $term:perform-op
-144       }
-145 #?       {
-146 #?         compare op, 0x2f/slash
-147 #?         break-if-!=
-148 #?         result <- divide second  # not in Mu yet
-149 #?         break $term:perform-op
-150 #?       }
-151     }
-152     loop
-153   }
-154   return result, look
-155 }
-156 
-157 fn factor _look: grapheme -> _/eax: int, _/esi: grapheme {
-158   var look/esi: grapheme <- copy _look  # should be a no-op
-159   look <- skip-spaces look
-160   # if next char is not '(', parse a number
-161   compare look, 0x28/open-paren
-162   {
-163     break-if-=
-164     var result/eax: int <- copy 0
-165     result, look <- num look
-166     return result, look
-167   }
-168   # otherwise recurse
-169   look <- get-char  # '('
-170   var result/eax: int <- copy 0
-171   result, look <- expression look
-172   look <- skip-spaces look
-173   look <- get-char  # ')'
-174   return result, look
-175 }
-176 
-177 fn mul-or-div? c: grapheme -> _/eax: boolean {
-178   compare c, 0x2a/*
-179   {
-180     break-if-!=
-181     return 1/true
-182   }
-183   compare c, 0x2f/slash
-184   {
-185     break-if-!=
-186     return 1/true
-187   }
-188   return 0/false
-189 }
-190 
-191 fn add-or-sub? c: grapheme -> _/eax: boolean {
-192   compare c, 0x2b/+
-193   {
-194     break-if-!=
-195     return 1/true
-196   }
-197   compare c, 0x2d/minus
-198   {
-199     break-if-!=
-200     return 1/true
-201   }
-202   return 0/false
-203 }
-204 
-205 fn operator _look: grapheme -> _/ecx: grapheme, _/esi: grapheme {
-206   var op/ecx: grapheme <- copy _look
-207   var look/esi: grapheme <- get-char
-208   return op, look
-209 }
-210 
-211 fn num _look: grapheme -> _/eax: int, _/esi: grapheme {
-212   var look/esi: grapheme <- copy _look
-213   var result/edi: int <- copy 0
-214   {
-215     var first-digit/eax: int <- to-decimal-digit look
-216     result <- copy first-digit
-217   }
-218   {
-219     look <- get-char
-220     # done?
-221     var digit?/eax: boolean <- decimal-digit? look
-222     compare digit?, 0/false
-223     break-if-=
-224     # result *= 10
-225     {
-226       var ten/eax: int <- copy 0xa
-227       result <- multiply ten
-228     }
-229     # result += digit(look)
-230     var digit/eax: int <- to-decimal-digit look
-231     result <- add digit
-232     loop
-233   }
-234   return result, look
-235 }
-236 
-237 fn skip-spaces _look: grapheme -> _/esi: grapheme {
-238   var look/esi: grapheme <- copy _look  # should be a no-op
-239   {
-240     compare look, 0x20
-241     break-if-!=
-242     look <- get-char
-243     loop
-244   }
-245   return look
-246 }
-247 
-248 fn get-char -> _/esi: grapheme {
-249   var look/eax: grapheme <- read-key-from-real-keyboard
-250   print-grapheme-to-real-screen look
-251   compare look, 4
-252   {
-253     break-if-!=
-254     print-string 0/screen, "^D\n"
-255     syscall_exit
-256   }
-257   return look
-258 }
-
- - - diff --git a/html/linux/assort.subx.html b/html/linux/assort.subx.html index b4061120..b75d2baa 100644 --- a/html/linux/assort.subx.html +++ b/html/linux/assort.subx.html @@ -1,14 +1,14 @@ - + - + Mu - linux/assort.subx - - + + - + - - - - -https://github.com/akkartik/mu/blob/main/linux/ex1.mu -
- 1 # First example: return the answer to the Ultimate Question of Life, the
- 2 # Universe, and Everything.
- 3 #
- 4 # To run:
- 5 #   $ ./translate ex1.mu
- 6 #   $ ./a.elf
- 7 # Expected result:
- 8 #   $ echo $?
- 9 #   42
-10 
-11 fn main -> _/ebx: int {
-12   return 0x2a  # Mu requires hexadecimal
-13 }
-
- - - diff --git a/html/linux/ex2.mu.html b/html/linux/ex2.mu.html deleted file mode 100644 index 5c3da3c3..00000000 --- a/html/linux/ex2.mu.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -Mu - linux/ex2.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/linux/ex2.mu -
- 1 # Add 3 and 4, and return the result in the exit code.
- 2 #
- 3 # To run:
- 4 #   $ ./translate ex2.mu
- 5 #   $ ./a.elf
- 6 # Expected result:
- 7 #   $ echo $?
- 8 #   7
- 9 
-10 fn main -> _/ebx: int {
-11   var result/eax: int <- do-add 3 4
-12   return result
-13 }
-14 
-15 fn do-add a: int, b: int -> _/eax: int {
-16   var result/ecx: int <- copy a
-17   result <- add b
-18   return result
-19 }
-
- - - diff --git a/html/linux/ex3.2.mu.html b/html/linux/ex3.2.mu.html deleted file mode 100644 index b2e48718..00000000 --- a/html/linux/ex3.2.mu.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - -Mu - linux/ex3.2.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/linux/ex3.2.mu -
- 1 # Unnecessarily use an array to sum 1..10
- 2 #
- 3 # To run:
- 4 #   $ ./translate ex3.2.mu
- 5 #   $ ./a.elf
- 6 #   $ echo $?
- 7 #   55
- 8 
- 9 fn main -> _/ebx: int {
-10   # populate a
-11   var a: (array int 0xb)  # 11; we waste index 0
-12   var i/ecx: int <- copy 1
-13   {
-14     compare i, 0xb
-15     break-if->=
-16     var x/eax: (addr int) <- index a, i
-17     copy-to *x, i
-18     i <- increment
-19     loop
-20   }
-21   # sum
-22   var result/edx: int <- copy 0
-23   i <- copy 1
-24   {
-25     compare i, 0xb
-26     break-if->=
-27     var x/eax: (addr int) <- index a, i
-28     result <- add *x
-29     i <- increment
-30     loop
-31   }
-32   return result
-33 }
-
- - - diff --git a/html/linux/ex3.mu.html b/html/linux/ex3.mu.html deleted file mode 100644 index 70288094..00000000 --- a/html/linux/ex3.mu.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - -Mu - linux/ex3.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/linux/ex3.mu -
- 1 # Add the first 10 numbers, and return the result in the exit code.
- 2 #
- 3 # To run:
- 4 #   $ ./translate browse.mu
- 5 #   $ ./a.elf
- 6 # Expected result:
- 7 #   $ echo $?
- 8 #   55
- 9 
-10 fn main -> _/ebx: int {
-11   var result/ebx: int <- copy 0
-12   var i/eax: int <- copy 1
-13   {
-14     compare i, 0xa
-15     break-if->
-16     result <- add i
-17     i <- increment
-18     loop
-19   }
-20   return result
-21 }
-
- - - diff --git a/html/linux/factorial.mu.html b/html/linux/factorial.mu.html deleted file mode 100644 index 242c53b7..00000000 --- a/html/linux/factorial.mu.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - -Mu - linux/factorial.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/linux/factorial.mu -
- 1 # compute the factorial of 5, and return the result in the exit code
- 2 #
- 3 # To run:
- 4 #   $ ./translate factorial.mu
- 5 #   $ ./a.elf
- 6 #   $ echo $?
- 7 #   120
- 8 #
- 9 # You can also run the automated test suite:
-10 #   $ ./a.elf test
-11 # Expected output:
-12 #   ........
-13 # Every '.' indicates a passing test. Failing tests get a 'F'.
-14 # There's only one test in this file, but you'll also see tests running from
-15 # Mu's standard library.
-16 #
-17 # Compare factorial4.subx
-18 
-19 fn factorial n: int -> _/eax: int {
-20   compare n, 1
-21   # if (n <= 1) return 1
-22   {
-23     break-if->
-24     return 1
-25   }
-26   # n > 1; return n * factorial(n-1)
-27   var tmp/ecx: int <- copy n
-28   tmp <- decrement
-29   var result/eax: int <- factorial tmp
-30   result <- multiply n
-31   return result
-32 }
-33 
-34 fn test-factorial {
-35   var result/eax: int <- factorial 5
-36   check-ints-equal result, 0x78, "F - test-factorial"
-37 }
-38 
-39 fn main args-on-stack: (addr array addr array byte) -> _/ebx: int {
-40   var args/eax: (addr array addr array byte) <- copy args-on-stack
-41   # len = length(args)
-42   var len/ecx: int <- length args
-43   # if (len <= 1) return factorial(5)
-44   compare len, 1
-45   {
-46     break-if->
-47     var exit-status/eax: int <- factorial 5
-48     return exit-status
-49   }
-50   # if (args[1] == "test") run-tests()
-51   var tmp2/ecx: (addr addr array byte) <- index args, 1
-52   var tmp3/eax: boolean <- string-equal? *tmp2, "test"
-53   compare tmp3, 0
-54   {
-55     break-if-=
-56     run-tests
-57     # TODO: get at Num-test-failures somehow
-58   }
-59   return 0
-60 }
-
- - - diff --git a/html/linux/hello.mu.html b/html/linux/hello.mu.html deleted file mode 100644 index 9023e29e..00000000 --- a/html/linux/hello.mu.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - -Mu - linux/hello.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/linux/hello.mu -
- 1 # Meaningless conventional example.
- 2 #
- 3 # To run:
- 4 #   $ ./translate hello.mu
- 5 #   $ ./a.elf
- 6 
- 7 fn main -> _/ebx: int {
- 8   print-string 0/screen, "Hello world!\n"
- 9   return 0
-10 }
-
- - - diff --git a/html/linux/hex.subx.html b/html/linux/hex.subx.html index cf871dbf..dc0487af 100644 --- a/html/linux/hex.subx.html +++ b/html/linux/hex.subx.html @@ -1,14 +1,14 @@ - + - + Mu - linux/hex.subx - - + + - + - - - - -https://github.com/akkartik/mu/blob/main/linux/parse-int.mu -
- 1 # parse a decimal int at the commandline
- 2 #
- 3 # To run:
- 4 #   $ ./translate parse-int.mu
- 5 #   $ ./a.elf 123
- 6 #   $ echo $?
- 7 #   123
- 8 
- 9 fn main _args: (addr array addr array byte) -> _/ebx: int {
-10   # if no args, print a message and exit
-11   var args/esi: (addr array addr array byte) <- copy _args
-12   var n/ecx: int <- length args
-13   compare n, 1
-14   {
-15     break-if->
-16     print-string 0/screen, "usage: parse-int <integer>\n"
-17     return 1
-18   }
-19   # otherwise parse the first arg as an integer
-20   var in/ecx: (addr addr array byte) <- index args, 1
-21   var out/eax: int <- parse-int *in
-22   return out
-23 }
-24 
-25 fn parse-int _in: (addr array byte) -> _/eax: int {
-26   var in/esi: (addr array byte) <- copy _in
-27   var len/edx: int <- length in
-28   var i/ecx: int <- copy 0
-29   var result/edi: int <- copy 0
-30   {
-31     compare i, len
-32     break-if->=
-33     # result *= 10
-34     var ten/eax: int <- copy 0xa
-35     result <- multiply ten
-36     # c = in[i]
-37     var tmp/ebx: (addr byte) <- index in, i
-38     var c/eax: byte <- copy-byte *tmp
-39     #
-40     var g/eax: grapheme <- copy c
-41     var digit/eax: int <- to-decimal-digit g
-42     result <- add digit
-43     i <- increment
-44     loop
-45   }
-46   return result
-47 }
-
- - - diff --git a/html/linux/print-file.mu.html b/html/linux/print-file.mu.html deleted file mode 100644 index 5ec1ba21..00000000 --- a/html/linux/print-file.mu.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - -Mu - linux/print-file.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/linux/print-file.mu -
- 1 # accept a filename on the commandline, read it and print it out to screen
- 2 # only ascii right now, just like the rest of Mu
- 3 #
- 4 # To run:
- 5 #   $ ./translate print-file.mu
- 6 #   $ echo abc > x
- 7 #   $ ./a.elf x
- 8 #   abc
- 9 
-10 fn main _args: (addr array addr array byte) -> _/ebx: int {
-11   var args/eax: (addr array addr array byte) <- copy _args
-12   var n/ecx: int <- length args
-13   compare n, 1
-14   {
-15     break-if->
-16     print-string 0/screen, "usage: cat <filename>\n"
-17     return 0
-18   }
-19   {
-20     break-if-<=
-21     var filename/edx: (addr addr array byte) <- index args 1
-22     var in: (handle buffered-file)
-23     {
-24       var addr-in/eax: (addr handle buffered-file) <- address in
-25       open *filename, 0/read-only, addr-in
-26     }
-27     var _in-addr/eax: (addr buffered-file) <- lookup in
-28     var in-addr/ecx: (addr buffered-file) <- copy _in-addr
-29     {
-30       var c/eax: byte <- read-byte-buffered in-addr
-31       compare c, 0xffffffff/end-of-file
-32       break-if-=
-33       var g/eax: grapheme <- copy c
-34       print-grapheme 0/screen, g
-35       loop
-36     }
-37   }
-38   return 0
-39 }
-
- - - diff --git a/html/linux/random.subx.html b/html/linux/random.subx.html index b498736b..db841c4e 100644 --- a/html/linux/random.subx.html +++ b/html/linux/random.subx.html @@ -1,14 +1,14 @@ - + - + Mu - linux/random.subx - - + + - + - - - - -https://github.com/akkartik/mu/blob/main/linux/rpn.mu -
-  1 # Integer arithmetic using postfix notation
-  2 #
-  3 # Limitations:
-  4 #   No division yet.
-  5 #
-  6 # To build:
-  7 #   $ ./translate rpn.mu
-  8 #
-  9 # Example session:
- 10 #   $ ./a.elf
- 11 #   press ctrl-c or ctrl-d to exit
- 12 #   > 1
- 13 #   1
- 14 #   > 1 1 +
- 15 #   2
- 16 #   > 1 2 3 + +
- 17 #   6
- 18 #   > 1 2 3 * +
- 19 #   7
- 20 #   > 1 2 + 3 *
- 21 #   9
- 22 #   > 1 3 4 * +
- 23 #   13
- 24 #   > ^D
- 25 #   $
- 26 #
- 27 # Error handling is non-existent. This is just a prototype.
- 28 
- 29 fn main -> _/ebx: int {
- 30   var in-storage: (stream byte 0x100)
- 31   var in/esi: (addr stream byte) <- address in-storage
- 32   print-string 0/screen, "press ctrl-c or ctrl-d to exit\n"
- 33   # read-eval-print loop
- 34   {
- 35     # print prompt
- 36     print-string 0/screen, "> "
- 37     # read line
- 38     clear-stream in
- 39     read-line-from-real-keyboard in
- 40     var done?/eax: boolean <- stream-empty? in
- 41     compare done?, 0
- 42     break-if-!=
- 43     # parse and eval
- 44     var out/eax: int <- simplify in
- 45     # print
- 46     print-int32-decimal 0/screen, out
- 47     print-string 0/screen, "\n"
- 48     #
- 49     loop
- 50   }
- 51   return 0
- 52 }
- 53 
- 54 type int-stack {
- 55   data: (handle array int)
- 56   top: int
- 57 }
- 58 
- 59 fn simplify in: (addr stream byte) -> _/eax: int {
- 60   var word-storage: slice
- 61   var word/ecx: (addr slice) <- address word-storage
- 62   var stack-storage: int-stack
- 63   var stack/esi: (addr int-stack) <- address stack-storage
- 64   initialize-int-stack stack, 0x10
- 65   $simplify:word-loop: {
- 66     next-word in, word
- 67     var done?/eax: boolean <- slice-empty? word
- 68     compare done?, 0
- 69     break-if-!=
- 70     # if word is an operator, perform it
- 71     {
- 72       var add?/eax: boolean <- slice-equal? word, "+"
- 73       compare add?, 0
- 74       break-if-=
- 75       var _b/eax: int <- pop-int-stack stack
- 76       var b/edx: int <- copy _b
- 77       var a/eax: int <- pop-int-stack stack
- 78       a <- add b
- 79       push-int-stack stack, a
- 80       loop $simplify:word-loop
- 81     }
- 82     {
- 83       var sub?/eax: boolean <- slice-equal? word, "-"
- 84       compare sub?, 0
- 85       break-if-=
- 86       var _b/eax: int <- pop-int-stack stack
- 87       var b/edx: int <- copy _b
- 88       var a/eax: int <- pop-int-stack stack
- 89       a <- subtract b
- 90       push-int-stack stack, a
- 91       loop $simplify:word-loop
- 92     }
- 93     {
- 94       var mul?/eax: boolean <- slice-equal? word, "*"
- 95       compare mul?, 0
- 96       break-if-=
- 97       var _b/eax: int <- pop-int-stack stack
- 98       var b/edx: int <- copy _b
- 99       var a/eax: int <- pop-int-stack stack
-100       a <- multiply b
-101       push-int-stack stack, a
-102       loop $simplify:word-loop
-103     }
-104     # otherwise it's an int
-105     var n/eax: int <- parse-decimal-int-from-slice word
-106     push-int-stack stack, n
-107     loop
-108   }
-109   var result/eax: int <- pop-int-stack stack
-110   return result
-111 }
-112 
-113 fn initialize-int-stack _self: (addr int-stack), n: int {
-114   var self/esi: (addr int-stack) <- copy _self
-115   var d/edi: (addr handle array int) <- get self, data
-116   populate d, n
-117   var top/eax: (addr int) <- get self, top
-118   copy-to *top, 0
-119 }
-120 
-121 fn push-int-stack _self: (addr int-stack), _val: int {
-122   var self/esi: (addr int-stack) <- copy _self
-123   var top-addr/ecx: (addr int) <- get self, top
-124   var data-ah/edx: (addr handle array int) <- get self, data
-125   var data/eax: (addr array int) <- lookup *data-ah
-126   var top/edx: int <- copy *top-addr
-127   var dest-addr/edx: (addr int) <- index data, top
-128   var val/eax: int <- copy _val
-129   copy-to *dest-addr, val
-130   add-to *top-addr, 1
-131 }
-132 
-133 fn pop-int-stack _self: (addr int-stack) -> _/eax: int {
-134   var self/esi: (addr int-stack) <- copy _self
-135   var top-addr/ecx: (addr int) <- get self, top
-136   {
-137     compare *top-addr, 0
-138     break-if->
-139     return 0
-140   }
-141   subtract-from *top-addr, 1
-142   var data-ah/edx: (addr handle array int) <- get self, data
-143   var data/eax: (addr array int) <- lookup *data-ah
-144   var top/edx: int <- copy *top-addr
-145   var result-addr/eax: (addr int) <- index data, top
-146   var val/eax: int <- copy *result-addr
-147   return val
-148 }
-
- - - diff --git a/html/linux/sigils.subx.html b/html/linux/sigils.subx.html index 4cf3df1e..f7a7d6a9 100644 --- a/html/linux/sigils.subx.html +++ b/html/linux/sigils.subx.html @@ -1,14 +1,14 @@ - + - + Mu - linux/sigils.subx - - + + - + - - - - -https://github.com/akkartik/mu/blob/main/linux/texture.mu -
- 1 # Playing with emitting cool textures.
- 2 #
- 3 # To run (on Linux):
- 4 #   $ git clone https://github.com/akkartik/mu
- 5 #   $ cd mu
- 6 #   $ ./translate texture.mu
- 7 #   $ ./a.elf > a.ppm
- 8 
- 9 fn main -> _/ebx: int {
-10 #?   var width/esi: int <- copy 0x190  # 400
-11 #?   var height/edi: int <- copy 0xe1  # 225; aspect ratio 16:9
-12   var width/esi: int <- copy 0xff
-13   var height/edi: int <- copy 0xff
-14   print-string 0/screen, "P3\n"
-15   print-int32-decimal 0/screen, width
-16   print-string 0/screen, " "
-17   print-int32-decimal 0/screen, height
-18   print-string 0/screen, "\n"
-19   print-string 0/screen, "255\n"  # color depth
-20   var row/ecx: int <- copy 0
-21   {
-22     compare row, height
-23     break-if->=
-24     var col/edx: int <- copy 0
-25     {
-26       compare col, width
-27       break-if->=
-28       # r
-29       var tmp/eax: int <- copy col
-30       tmp <- multiply row
-31       tmp <- and 0x7f
-32       tmp <- add 0x80
-33       tmp <- copy 0xff
-34       print-int32-decimal 0/screen, tmp
-35       print-string 0/screen, " "
-36       # g
-37       tmp <- copy row
-38       tmp <- multiply col
-39       tmp <- and 0x7f
-40       tmp <- add 0x80
-41 #?       tmp <- copy 0xcf
-42       print-int32-decimal 0/screen, tmp
-43       print-string 0/screen, " "
-44       # b
-45       tmp <- copy row
-46       tmp <- multiply col
-47       tmp <- and 0x7f
-48       tmp <- add 0x80
-49       print-int32-decimal 0/screen, tmp
-50       print-string 0/screen, "\n"
-51       col <- increment
-52       loop
-53     }
-54     row <- increment
-55     loop
-56   }
-57   return 0
-58 }
-
- - - diff --git a/html/linux/tile/box.mu.html b/html/linux/tile/box.mu.html index 1898f0fc..b70352c6 100644 --- a/html/linux/tile/box.mu.html +++ b/html/linux/tile/box.mu.html @@ -1,32 +1,32 @@ - + - + Mu - linux/tile/box.mu - - + + - + - - - - -https://github.com/akkartik/mu/blob/main/linux/tui.mu -
- 1 # Test some primitives for text-mode.
- 2 #
- 3 # To run:
- 4 #   $ ./translate tui.mu
- 5 #   $ ./a.elf
- 6 
- 7 fn main -> _/ebx: int {
- 8   var nrows/eax: int <- copy 0
- 9   var ncols/ecx: int <- copy 0
-10   nrows, ncols <- screen-size 0
-11   enable-screen-grid-mode
-12   move-cursor 0/screen, 5/row, 0x22/col
-13   start-color 0/screen, 1/fg, 0x7a/bg
-14   start-blinking 0/screen
-15   print-string 0/screen, "Hello world!"
-16   reset-formatting 0/screen
-17   move-cursor 0/screen, 6/row, 0x22/col
-18   print-string 0/screen, "tty dimensions: "
-19   print-int32-hex 0/screen, nrows
-20   print-string 0/screen, " rows, "
-21   print-int32-hex 0/screen, ncols
-22   print-string 0/screen, " rows\n"
-23 
-24   print-string 0/screen, "press a key to see its code: "
-25   enable-keyboard-immediate-mode
-26   var x/eax: grapheme <- read-key-from-real-keyboard
-27   enable-keyboard-type-mode
-28   enable-screen-type-mode
-29   print-string 0/screen, "You pressed "
-30   var x-int/eax: int <- copy x
-31   print-int32-hex 0/screen, x-int
-32   print-string 0/screen, "\n"
-33   return 0
-34 }
-
- - - diff --git a/html/mandelbrot-fixed.mu.html b/html/mandelbrot-fixed.mu.html deleted file mode 100644 index 8810395f..00000000 --- a/html/mandelbrot-fixed.mu.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - -Mu - mandelbrot-fixed.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/mandelbrot-fixed.mu -
-  1 # Mandelbrot set using fixed-point numbers.
-  2 #
-  3 # Install:
-  4 #   $ git clone https://github.com/akkartik/mu
-  5 #   $ cd mu
-  6 # Build on Linux:
-  7 #   $ ./translate mandelbrot-fixed.mu
-  8 # Build on other platforms (slow):
-  9 #   $ ./translate_emulated mandelbrot-fixed.mu
- 10 # Run:
- 11 #   $ qemu-system-i386 code.img
- 12 
- 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
- 14   # Initially the viewport is centered at 0, 0 in the scene.
- 15   var scene-cx-f: int
- 16   var scene-cy-f: int
- 17   # Initially the viewport shows a section of the scene 4 units wide.
- 18   var scene-width-f: int
- 19   copy-to scene-width-f, 0x400/4
- 20   {
- 21     mandelbrot screen scene-cx-f, scene-cy-f, scene-width-f
- 22     # move at an angle slowly towards the edge
- 23     var adj-f/eax: int <- multiply-fixed scene-width-f, 0x12/0.07
- 24     subtract-from scene-cx-f, adj-f
- 25     add-to scene-cy-f, adj-f
- 26     # slowly shrink the scene width to zoom in
- 27     var tmp-f/eax: int <- multiply-fixed scene-width-f, 0x80/0.5
- 28     copy-to scene-width-f, tmp-f
- 29     loop
- 30   }
- 31 }
- 32 
- 33 # Since they still look like int types, we'll append a '-f' suffix to variable
- 34 # names to designate fixed-point numbers.
- 35 
- 36 fn int-to-fixed in: int -> _/eax: int {
- 37   var result-f/eax: int <- copy in
- 38   result-f <- shift-left 8/fixed-precision
- 39   {
- 40     break-if-not-overflow
- 41     abort "int-to-fixed: overflow"
- 42   }
- 43   return result-f
- 44 }
- 45 
- 46 fn fixed-to-int in-f: int -> _/eax: int {
- 47   var result/eax: int <- copy in-f
- 48   result <- shift-right-signed 8/fixed-precision
- 49   return result
- 50 }
- 51 
- 52 # The process of throwing bits away always adjusts a number towards -infinity.
- 53 fn test-fixed-conversion {
- 54   # 0
- 55   var f/eax: int <- int-to-fixed 0
- 56   var result/eax: int <- fixed-to-int f
- 57   check-ints-equal result, 0, "F - test-fixed-conversion - 0"
- 58   # 1
- 59   var f/eax: int <- int-to-fixed 1
- 60   var result/eax: int <- fixed-to-int f
- 61   check-ints-equal result, 1, "F - test-fixed-conversion - 1"
- 62   # -1
- 63   var f/eax: int <- int-to-fixed -1
- 64   var result/eax: int <- fixed-to-int f
- 65   check-ints-equal result, -1, "F - test-fixed-conversion - -1"
- 66   # 0.5 = 1/2
- 67   var f/eax: int <- int-to-fixed 1
- 68   f <- shift-right-signed 1
- 69   var result/eax: int <- fixed-to-int f
- 70   check-ints-equal result, 0, "F - test-fixed-conversion - 0.5"
- 71   # -0.5 = -1/2
- 72   var f/eax: int <- int-to-fixed -1
- 73   f <- shift-right-signed 1
- 74   var result/eax: int <- fixed-to-int f
- 75   check-ints-equal result, -1, "F - test-fixed-conversion - -0.5"
- 76   # 1.5 = 3/2
- 77   var f/eax: int <- int-to-fixed 3
- 78   f <- shift-right-signed 1
- 79   var result/eax: int <- fixed-to-int f
- 80   check-ints-equal result, 1, "F - test-fixed-conversion - 1.5"
- 81   # -1.5 = -3/2
- 82   var f/eax: int <- int-to-fixed -3
- 83   f <- shift-right-signed 1
- 84   var result/eax: int <- fixed-to-int f
- 85   check-ints-equal result, -2, "F - test-fixed-conversion - -1.5"
- 86   # 1.25 = 5/4
- 87   var f/eax: int <- int-to-fixed 5
- 88   f <- shift-right-signed 2
- 89   var result/eax: int <- fixed-to-int f
- 90   check-ints-equal result, 1, "F - test-fixed-conversion - 1.25"
- 91   # -1.25 = -5/4
- 92   var f/eax: int <- int-to-fixed -5
- 93   f <- shift-right-signed 2
- 94   var result/eax: int <- fixed-to-int f
- 95   check-ints-equal result, -2, "F - test-fixed-conversion - -1.25"
- 96 }
- 97 
- 98 # special routines for multiplying and dividing fixed-point numbers
- 99 
-100 fn multiply-fixed a-f: int, b-f: int -> _/eax: int {
-101   var result/eax: int <- copy a-f
-102   result <- multiply b-f
-103   {
-104     break-if-not-overflow
-105     abort "multiply-fixed: overflow"
-106   }
-107   result <- shift-right-signed 8/fixed-precision
-108   return result
-109 }
-110 
-111 fn divide-fixed a-f: int, b-f: int -> _/eax: int {
-112   var result-f/eax: int <- copy a-f
-113   result-f <- shift-left 8/fixed-precision
-114   {
-115     break-if-not-overflow
-116     abort "divide-fixed: overflow"
-117   }
-118   var dummy-remainder/edx: int <- copy 0
-119   result-f, dummy-remainder <- integer-divide result-f, b-f
-120   return result-f
-121 }
-122 
-123 # multiplying or dividing by an integer can use existing instructions.
-124 
-125 # adding and subtracting two fixed-point numbers can use existing instructions.
-126 
-127 fn mandelbrot screen: (addr screen), scene-cx-f: int, scene-cy-f: int, scene-width-f: int {
-128   var a/eax: int <- copy 0
-129   var b/ecx: int <- copy 0
-130   a, b <- screen-size screen
-131   var width/esi: int <- copy a
-132   width <- shift-left 3/log2-font-width
-133   var height/edi: int <- copy b
-134   height <- shift-left 4/log2-font-height
-135   var y/ecx: int <- copy 0
-136   {
-137     compare y, height
-138     break-if->=
-139     var imaginary-f/ebx: int <- viewport-to-imaginary-f y, width, height, scene-cy-f, scene-width-f
-140     var x/eax: int <- copy 0
-141     {
-142       compare x, width
-143       break-if->=
-144       var real-f/edx: int <- viewport-to-real-f x, width, scene-cx-f, scene-width-f
-145       var iterations/esi: int <- mandelbrot-iterations-for-point real-f, imaginary-f, 0x400/max
-146       iterations <- shift-right 3
-147       var color/edx: int <- copy 0
-148       {
-149         var dummy/eax: int <- copy 0
-150         dummy, color <- integer-divide iterations, 0x18/24/size-of-cycle-0
-151         color <- add 0x20/cycle-0
-152       }
-153       pixel screen, x, y, color
-154       x <- increment
-155       loop
-156     }
-157     y <- increment
-158     loop
-159   }
-160 }
-161 
-162 fn mandelbrot-iterations-for-point real-f: int, imaginary-f: int, max: int -> _/esi: int {
-163   var x-f/esi: int <- copy 0
-164   var y-f/edi: int <- copy 0
-165   var iterations/ecx: int <- copy 0
-166   {
-167     var done?/eax: boolean <- mandelbrot-done? x-f, y-f
-168     compare done?, 0/false
-169     break-if-!=
-170     compare iterations, max
-171     break-if->=
-172     var x2-f/edx: int <- mandelbrot-x x-f, y-f, real-f
-173     var y2-f/ebx: int <- mandelbrot-y x-f, y-f, imaginary-f
-174     x-f <- copy x2-f
-175     y-f <- copy y2-f
-176     iterations <- increment
-177     loop
-178   }
-179   return iterations
-180 }
-181 
-182 fn mandelbrot-done? x-f: int, y-f: int -> _/eax: boolean {
-183   # x*x + y*y > 4
-184   var tmp-f/eax: int <- multiply-fixed x-f, x-f
-185   var result-f/ecx: int <- copy tmp-f
-186   tmp-f <- multiply-fixed y-f, y-f
-187   result-f <- add tmp-f
-188   compare result-f, 0x400/4
-189   {
-190     break-if->
-191     return 0/false
-192   }
-193   return 1/true
-194 }
-195 
-196 fn mandelbrot-x x-f: int, y-f: int, real-f: int -> _/edx: int {
-197   # x*x - y*y + real
-198   var tmp-f/eax: int <- multiply-fixed x-f, x-f
-199   var result-f/ecx: int <- copy tmp-f
-200   tmp-f <- multiply-fixed y-f, y-f
-201   result-f <- subtract tmp-f
-202   result-f <- add real-f
-203   return result-f
-204 }
-205 
-206 fn mandelbrot-y x-f: int, y-f: int, imaginary-f: int -> _/ebx: int {
-207   # 2*x*y + imaginary
-208   var result-f/eax: int <- copy x-f
-209   result-f <- shift-left 1/log2
-210   result-f <- multiply-fixed result-f, y-f
-211   result-f <- add imaginary-f
-212   return result-f
-213 }
-214 
-215 # Scale (x, y) pixel coordinates to a complex plane where the viewport width
-216 # ranges from -2 to +2. Viewport height just follows the viewport's aspect
-217 # ratio.
-218 
-219 fn viewport-to-real-f x: int, width: int, scene-cx-f: int, scene-width-f: int -> _/edx: int {
-220   # 0 in the viewport       goes to scene-cx - scene-width/2 
-221   # width in the viewport   goes to scene-cx + scene-width/2
-222   # Therefore:
-223   # x in the viewport       goes to (scene-cx - scene-width/2) + x*scene-width/width
-224   # At most two numbers being multiplied before a divide, so no risk of overflow.
-225   var result-f/eax: int <- int-to-fixed x
-226   result-f <- multiply-fixed result-f, scene-width-f
-227   var width-f/ecx: int <- copy width
-228   width-f <- shift-left 8/fixed-precision
-229   result-f <- divide-fixed result-f, width-f
-230   result-f <- add scene-cx-f
-231   var half-scene-width-f/ecx: int <- copy scene-width-f
-232   half-scene-width-f <- shift-right 1
-233   result-f <- subtract half-scene-width-f
-234   return result-f
-235 }
-236 
-237 fn viewport-to-imaginary-f y: int, width: int, height: int, scene-cy-f: int, scene-width-f: int -> _/ebx: int {
-238   # 0 in the viewport       goes to scene-cy - scene-width/2*height/width
-239   # height in the viewport  goes to scene-cy + scene-width/2*height/width
-240   # Therefore:
-241   # y in the viewport       goes to (scene-cy - scene-width/2*height/width) + y*scene-width/width
-242   #  scene-cy - scene-width/width * (height/2 + y)
-243   # At most two numbers being multiplied before a divide, so no risk of overflow.
-244   var result-f/eax: int <- int-to-fixed y
-245   result-f <- multiply-fixed result-f, scene-width-f
-246   var width-f/ecx: int <- copy width
-247   width-f <- shift-left 8/fixed-precision
-248   result-f <- divide-fixed result-f, width-f
-249   result-f <- add scene-cy-f
-250   var second-term-f/edx: int <- copy 0
-251   {
-252     var _second-term-f/eax: int <- copy scene-width-f
-253     _second-term-f <- shift-right 1
-254     var height-f/ebx: int <- copy height
-255     height-f <- shift-left 8/fixed-precision
-256     _second-term-f <- multiply-fixed _second-term-f, height-f
-257     _second-term-f <- divide-fixed _second-term-f, width-f
-258     second-term-f <- copy _second-term-f
-259   }
-260   result-f <- subtract second-term-f
-261   return result-f
-262 }
-
- - - diff --git a/html/mandelbrot-silhouette.mu.html b/html/mandelbrot-silhouette.mu.html deleted file mode 100644 index ca476867..00000000 --- a/html/mandelbrot-silhouette.mu.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - -Mu - mandelbrot-silhouette.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/mandelbrot-silhouette.mu -
-  1 # Mandelbrot set
-  2 #
-  3 # Install:
-  4 #   $ git clone https://github.com/akkartik/mu
-  5 #   $ cd mu
-  6 # Build on Linux:
-  7 #   $ ./translate mandelbrot.mu
-  8 # Build on other platforms (slow):
-  9 #   $ ./translate_emulated mandelbrot.mu
- 10 # Run:
- 11 #   $ qemu-system-i386 code.img
- 12 
- 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
- 14   mandelbrot screen
- 15 }
- 16 
- 17 fn mandelbrot screen: (addr screen) {
- 18   var a/eax: int <- copy 0
- 19   var b/ecx: int <- copy 0
- 20   a, b <- screen-size screen
- 21   var width/esi: int <- copy a
- 22   width <- shift-left 3/log2-font-width
- 23   var height/edi: int <- copy b
- 24   height <- shift-left 4/log2-font-height
- 25   var y/ecx: int <- copy 0
- 26   {
- 27     compare y, height
- 28     break-if->=
- 29     var imaginary/xmm1: float <- viewport-to-imaginary y, width, height
- 30     var x/edx: int <- copy 0
- 31     {
- 32       compare x, width
- 33       break-if->=
- 34       var real/xmm0: float <- viewport-to-real x, width
- 35       var iterations/eax: int <- mandelbrot-iterations-for-point real, imaginary, 0x400/max
- 36       compare iterations, 0x400/max
- 37       {
- 38         break-if->=
- 39         pixel screen, x, y, 0xf/white
- 40       }
- 41       compare iterations, 0x400/max
- 42       {
- 43         break-if-<
- 44         pixel screen, x, y, 0/black
- 45       }
- 46       x <- increment
- 47       loop
- 48     }
- 49     y <- increment
- 50     loop
- 51   }
- 52 }
- 53 
- 54 fn mandelbrot-iterations-for-point real: float, imaginary: float, max: int -> _/eax: int {
- 55   var zero: float
- 56   var x/xmm0: float <- copy zero
- 57   var y/xmm1: float <- copy zero
- 58   var iterations/ecx: int <- copy 0
- 59   {
- 60     var done?/eax: boolean <- mandelbrot-done? x, y
- 61     compare done?, 0/false
- 62     break-if-!=
- 63     compare iterations, max
- 64     break-if->=
- 65     var newx/xmm2: float <- mandelbrot-x x, y, real
- 66     var newy/xmm3: float <- mandelbrot-y x, y, imaginary
- 67     x <- copy newx
- 68     y <- copy newy
- 69     iterations <- increment
- 70     loop
- 71   }
- 72   return iterations
- 73 }
- 74 
- 75 fn mandelbrot-done? x: float, y: float -> _/eax: boolean {
- 76   # x*x + y*y > 4
- 77   var x2/xmm0: float <- copy x
- 78   x2 <- multiply x
- 79   var y2/xmm1: float <- copy y
- 80   y2 <- multiply y
- 81   var sum/xmm0: float <- copy x2
- 82   sum <- add y2
- 83   var four/eax: int <- copy 4
- 84   var four-f/xmm1: float <- convert four
- 85   compare sum, four-f
- 86   {
- 87     break-if-float>
- 88     return 0/false
- 89   }
- 90   return 1/true
- 91 }
- 92 
- 93 fn mandelbrot-x x: float, y: float, real: float -> _/xmm2: float {
- 94   # x*x - y*y + real
- 95   var x2/xmm0: float <- copy x
- 96   x2 <- multiply x
- 97   var y2/xmm1: float <- copy y
- 98   y2 <- multiply y
- 99   var result/xmm0: float <- copy x2
-100   result <- subtract y2
-101   result <- add real
-102   return result
-103 }
-104 
-105 fn mandelbrot-y x: float, y: float, imaginary: float -> _/xmm3: float {
-106   # 2*x*y + imaginary
-107   var two/eax: int <- copy 2
-108   var result/xmm0: float <- convert two
-109   result <- multiply x
-110   result <- multiply y
-111   result <- add imaginary
-112   return result
-113 }
-114 
-115 # Scale (x, y) pixel coordinates to a complex plane where the viewport width
-116 # ranges from -2 to +2. Viewport height just follows the viewport's aspect
-117 # ratio.
-118 
-119 fn viewport-to-real x: int, width: int -> _/xmm0: float {
-120   # (x - width/2)*4/width
-121   var result/xmm0: float <- convert x
-122   var width-f/xmm1: float <- convert width
-123   var two/eax: int <- copy 2
-124   var two-f/xmm2: float <- convert two
-125   var half-width-f/xmm2: float <- reciprocal two-f
-126   half-width-f <- multiply width-f
-127   result <- subtract half-width-f
-128   var four/eax: int <- copy 4
-129   var four-f/xmm2: float <- convert four
-130   result <- multiply four-f
-131   result <- divide width-f
-132   return result
-133 }
-134 
-135 fn viewport-to-imaginary y: int, width: int, height: int -> _/xmm1: float {
-136   # (y - height/2)*4/width
-137   var result/xmm0: float <- convert y
-138   var height-f/xmm1: float <- convert height
-139   var half-height-f/xmm1: float <- copy height-f
-140   var two/eax: int <- copy 2
-141   var two-f/xmm2: float <- convert two
-142   half-height-f <- divide two-f
-143   result <- subtract half-height-f
-144   var four/eax: int <- copy 4
-145   var four-f/xmm1: float <- convert four
-146   result <- multiply four-f
-147   var width-f/xmm1: float <- convert width
-148   result <- divide width-f
-149   return result
-150 }
-
- - - diff --git a/html/mandelbrot.mu.html b/html/mandelbrot.mu.html deleted file mode 100644 index 013dcab9..00000000 --- a/html/mandelbrot.mu.html +++ /dev/null @@ -1,246 +0,0 @@ - - - - -Mu - mandelbrot.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/mandelbrot.mu -
-  1 # Mandelbrot set
-  2 #
-  3 # Install:
-  4 #   $ git clone https://github.com/akkartik/mu
-  5 #   $ cd mu
-  6 # Build on Linux:
-  7 #   $ ./translate mandelbrot.mu
-  8 # Build on other platforms (slow):
-  9 #   $ ./translate_emulated mandelbrot.mu
- 10 # Run:
- 11 #   $ qemu-system-i386 code.img
- 12 
- 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
- 14   # Initially the viewport is centered at 0, 0 in the scene.
- 15   var zero: float
- 16   var scene-cx/xmm1: float <- copy zero
- 17   var scene-cy/xmm2: float <- copy zero
- 18   # Initially the viewport shows a section of the scene 4 units wide.
- 19   # scene-width-scale = 0.5
- 20   var scene-width-scale: float
- 21   var dest/eax: (addr float) <- address scene-width-scale
- 22   fill-in-rational dest, 1, 2
- 23   # scene-width = 4
- 24   var four: float
- 25   var dest/eax: (addr float) <- address four
- 26   fill-in-rational dest, 4, 1
- 27   var scene-width/xmm3: float <- copy four
- 28   {
- 29     mandelbrot screen scene-cx, scene-cy, scene-width
- 30     # move the center some % of the current screen-width
- 31     var adj/xmm0: float <- rational 2, 0x1c/28
- 32     adj <- multiply scene-width
- 33     scene-cx <- subtract adj
- 34     scene-cy <- add adj
- 35     # slowly shrink the scene width to zoom in
- 36     scene-width <- multiply scene-width-scale
- 37     loop
- 38   }
- 39 }
- 40 
- 41 fn mandelbrot screen: (addr screen), scene-cx: float, scene-cy: float, scene-width: float {
- 42   var a/eax: int <- copy 0
- 43   var b/ecx: int <- copy 0
- 44   a, b <- screen-size screen
- 45   var width/esi: int <- copy a
- 46   width <- shift-left 3/log2-font-width
- 47   var height/edi: int <- copy b
- 48   height <- shift-left 4/log2-font-height
- 49   var y/ecx: int <- copy 0
- 50   {
- 51     compare y, height
- 52     break-if->=
- 53     var imaginary/xmm1: float <- viewport-to-imaginary y, width, height, scene-cy, scene-width
- 54     var x/ebx: int <- copy 0
- 55     {
- 56       compare x, width
- 57       break-if->=
- 58       var real/xmm0: float <- viewport-to-real x, width, scene-cx, scene-width
- 59       var iterations/eax: int <- mandelbrot-iterations-for-point real, imaginary, 0x400/max
- 60       iterations <- shift-right 3
- 61       var color/edx: int <- copy 0
- 62       iterations, color <- integer-divide iterations, 0x18/24/size-of-cycle-0
- 63       color <- add 0x20/cycle-0
- 64       pixel screen, x, y, color
- 65       x <- increment
- 66       loop
- 67     }
- 68     y <- increment
- 69     loop
- 70   }
- 71 }
- 72 
- 73 fn mandelbrot-iterations-for-point real: float, imaginary: float, max: int -> _/eax: int {
- 74   var zero: float
- 75   var x/xmm0: float <- copy zero
- 76   var y/xmm1: float <- copy zero
- 77   var iterations/ecx: int <- copy 0
- 78   {
- 79     var done?/eax: boolean <- mandelbrot-done? x, y
- 80     compare done?, 0/false
- 81     break-if-!=
- 82     compare iterations, max
- 83     break-if->=
- 84     var newx/xmm2: float <- mandelbrot-x x, y, real
- 85     var newy/xmm3: float <- mandelbrot-y x, y, imaginary
- 86     x <- copy newx
- 87     y <- copy newy
- 88     iterations <- increment
- 89     loop
- 90   }
- 91   return iterations
- 92 }
- 93 
- 94 fn mandelbrot-done? x: float, y: float -> _/eax: boolean {
- 95   # x*x + y*y > 4
- 96   var x2/xmm0: float <- copy x
- 97   x2 <- multiply x
- 98   var y2/xmm1: float <- copy y
- 99   y2 <- multiply y
-100   var sum/xmm0: float <- copy x2
-101   sum <- add y2
-102   var four/eax: int <- copy 4
-103   var four-f/xmm1: float <- convert four
-104   compare sum, four-f
-105   {
-106     break-if-float>
-107     return 0/false
-108   }
-109   return 1/true
-110 }
-111 
-112 fn mandelbrot-x x: float, y: float, real: float -> _/xmm2: float {
-113   # x*x - y*y + real
-114   var x2/xmm0: float <- copy x
-115   x2 <- multiply x
-116   var y2/xmm1: float <- copy y
-117   y2 <- multiply y
-118   var result/xmm0: float <- copy x2
-119   result <- subtract y2
-120   result <- add real
-121   return result
-122 }
-123 
-124 fn mandelbrot-y x: float, y: float, imaginary: float -> _/xmm3: float {
-125   # 2*x*y + imaginary
-126   var two/eax: int <- copy 2
-127   var result/xmm0: float <- convert two
-128   result <- multiply x
-129   result <- multiply y
-130   result <- add imaginary
-131   return result
-132 }
-133 
-134 # Scale (x, y) pixel coordinates to a complex plane where the viewport width
-135 # ranges from -2 to +2. Viewport height just follows the viewport's aspect
-136 # ratio.
-137 
-138 fn viewport-to-real x: int, width: int, scene-cx: float, scene-width: float -> _/xmm0: float {
-139   # 0 in the viewport       goes to scene-cx - scene-width/2 
-140   # width in the viewport   goes to scene-cx + scene-width/2
-141   # Therefore:
-142   # x in the viewport       goes to (scene-cx - scene-width/2) + x*scene-width/width
-143   # At most two numbers being multiplied before a divide, so no risk of overflow.
-144   var result/xmm0: float <- convert x
-145   result <- multiply scene-width
-146   var width-f/xmm1: float <- convert width
-147   result <- divide width-f
-148   result <- add scene-cx
-149   var two/eax: int <- copy 2
-150   var two-f/xmm2: float <- convert two
-151   var half-scene-width/xmm1: float <- copy scene-width
-152   half-scene-width <- divide two-f
-153   result <- subtract half-scene-width
-154   return result
-155 }
-156 
-157 fn viewport-to-imaginary y: int, width: int, height: int, scene-cy: float, scene-width: float -> _/xmm1: float {
-158   # 0 in the viewport       goes to scene-cy - scene-width/2*height/width
-159   # height in the viewport  goes to scene-cy + scene-width/2*height/width
-160   # Therefore:
-161   # y in the viewport       goes to (scene-cy - scene-width/2*height/width) + y*scene-width/width
-162   #  scene-cy - scene-width/width * (height/2 + y)
-163   # At most two numbers being multiplied before a divide, so no risk of overflow.
-164   var result/xmm0: float <- convert y
-165   result <- multiply scene-width
-166   var width-f/xmm1: float <- convert width
-167   result <- divide width-f
-168   result <- add scene-cy
-169   var two/eax: int <- copy 2
-170   var two-f/xmm2: float <- convert two
-171   var second-term/xmm1: float <- copy scene-width
-172   second-term <- divide two-f
-173   var height-f/xmm2: float <- convert height
-174   second-term <- multiply height-f
-175   var width-f/xmm2: float <- convert width
-176   second-term <- divide width-f
-177   result <- subtract second-term
-178   return result
-179 }
-
- - - diff --git a/html/mu-init.subx.html b/html/mu-init.subx.html index 4af3f5c0..c2a74514 100644 --- a/html/mu-init.subx.html +++ b/html/mu-init.subx.html @@ -1,14 +1,14 @@ - + - + Mu - mu-init.subx - - + + - + - - - - -https://github.com/akkartik/mu/blob/main/rpn.mu -
-  1 # Integer arithmetic using postfix notation
-  2 #
-  3 # Limitations:
-  4 #   Division not implemented yet.
-  5 #
-  6 # To build:
-  7 #   $ ./translate rpn.mu
-  8 #
-  9 # Example session:
- 10 #   $ qemu-system-i386 code.img
- 11 #   > 4
- 12 #   4
- 13 #   > 5 3 -
- 14 #   2
- 15 #
- 16 # Error handling is non-existent. This is just a prototype.
- 17 
- 18 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
- 19   var in-storage: (stream byte 0x80)
- 20   var in/esi: (addr stream byte) <- address in-storage
- 21   var y/ecx: int <- copy 0
- 22   var space/edx: grapheme <- copy 0x20
- 23   # read-eval-print loop
- 24   {
- 25     # print prompt
- 26     var x/eax: int <- draw-text-rightward screen, "> ", 0/x, 0x80/xmax, y, 3/fg/cyan, 0/bg
- 27     # read line from keyboard
- 28     clear-stream in
- 29     {
- 30       draw-cursor screen, space
- 31       var key/eax: byte <- read-key keyboard
- 32       compare key, 0xa/newline
- 33       break-if-=
- 34       compare key, 0
- 35       loop-if-=
- 36       var key2/eax: int <- copy key
- 37       append-byte in, key2
- 38       var g/eax: grapheme <- copy key2
- 39       draw-grapheme-at-cursor screen, g, 0xf/fg, 0/bg
- 40       move-cursor-right 0
- 41       loop
- 42     }
- 43     # clear cursor
- 44     draw-grapheme-at-cursor screen, space, 3/fg/never-used, 0/bg
- 45     # parse and eval
- 46     var out/eax: int <- simplify in
- 47     # print
- 48     y <- increment
- 49     out, y <- draw-int32-decimal-wrapping-right-then-down screen, out, 0/xmin, y, 0x80/xmax, 0x30/ymax, 0/x, y, 7/fg, 0/bg
- 50     # newline
- 51     y <- increment
- 52     #
- 53     loop
- 54   }
- 55 }
- 56 
- 57 type int-stack {
- 58   data: (handle array int)
- 59   top: int
- 60 }
- 61 
- 62 fn simplify in: (addr stream byte) -> _/eax: int {
- 63   var word-storage: slice
- 64   var word/ecx: (addr slice) <- address word-storage
- 65   var stack-storage: int-stack
- 66   var stack/esi: (addr int-stack) <- address stack-storage
- 67   initialize-int-stack stack, 0x10
- 68   $simplify:word-loop: {
- 69     next-word in, word
- 70     var done?/eax: boolean <- slice-empty? word
- 71     compare done?, 0
- 72     break-if-!=
- 73     # if word is an operator, perform it
- 74     {
- 75       var is-add?/eax: boolean <- slice-equal? word, "+"
- 76       compare is-add?, 0
- 77       break-if-=
- 78       var _b/eax: int <- pop-int-stack stack
- 79       var b/edx: int <- copy _b
- 80       var a/eax: int <- pop-int-stack stack
- 81       a <- add b
- 82       push-int-stack stack, a
- 83       loop $simplify:word-loop
- 84     }
- 85     {
- 86       var is-sub?/eax: boolean <- slice-equal? word, "-"
- 87       compare is-sub?, 0
- 88       break-if-=
- 89       var _b/eax: int <- pop-int-stack stack
- 90       var b/edx: int <- copy _b
- 91       var a/eax: int <- pop-int-stack stack
- 92       a <- subtract b
- 93       push-int-stack stack, a
- 94       loop $simplify:word-loop
- 95     }
- 96     {
- 97       var is-mul?/eax: boolean <- slice-equal? word, "*"
- 98       compare is-mul?, 0
- 99       break-if-=
-100       var _b/eax: int <- pop-int-stack stack
-101       var b/edx: int <- copy _b
-102       var a/eax: int <- pop-int-stack stack
-103       a <- multiply b
-104       push-int-stack stack, a
-105       loop $simplify:word-loop
-106     }
-107     # otherwise it's an int
-108     var n/eax: int <- parse-decimal-int-from-slice word
-109     push-int-stack stack, n
-110     loop
-111   }
-112   var result/eax: int <- pop-int-stack stack
-113   return result
-114 }
-115 
-116 fn initialize-int-stack _self: (addr int-stack), n: int {
-117   var self/esi: (addr int-stack) <- copy _self
-118   var d/edi: (addr handle array int) <- get self, data
-119   populate d, n
-120   var top/eax: (addr int) <- get self, top
-121   copy-to *top, 0
-122 }
-123 
-124 fn push-int-stack _self: (addr int-stack), _val: int {
-125   var self/esi: (addr int-stack) <- copy _self
-126   var top-addr/ecx: (addr int) <- get self, top
-127   var data-ah/edx: (addr handle array int) <- get self, data
-128   var data/eax: (addr array int) <- lookup *data-ah
-129   var top/edx: int <- copy *top-addr
-130   var dest-addr/edx: (addr int) <- index data, top
-131   var val/eax: int <- copy _val
-132   copy-to *dest-addr, val
-133   add-to *top-addr, 1
-134 }
-135 
-136 fn pop-int-stack _self: (addr int-stack) -> _/eax: int {
-137   var self/esi: (addr int-stack) <- copy _self
-138   var top-addr/ecx: (addr int) <- get self, top
-139   {
-140     compare *top-addr, 0
-141     break-if->
-142     return 0
-143   }
-144   subtract-from *top-addr, 1
-145   var data-ah/edx: (addr handle array int) <- get self, data
-146   var data/eax: (addr array int) <- lookup *data-ah
-147   var top/edx: int <- copy *top-addr
-148   var result-addr/eax: (addr int) <- index data, top
-149   var val/eax: int <- copy *result-addr
-150   return val
-151 }
-
- - - diff --git a/html/shell/cell.mu.html b/html/shell/cell.mu.html index e1d417c7..62ecb6ba 100644 --- a/html/shell/cell.mu.html +++ b/html/shell/cell.mu.html @@ -1,32 +1,32 @@ - + - + Mu - shell/cell.mu - - + + - + - -