about summary refs log tree commit diff stats
path: root/500text-screen.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-03-03 22:09:50 -0800
committerKartik K. Agaram <vc@akkartik.com>2021-03-03 22:21:03 -0800
commit71e4f3812982dba2efb471283d310224e8db363e (patch)
treeea111a1acb8b8845dbda39c0e1b4bac1d198143b /500text-screen.mu
parentc6b928be29ac8cdb4e4d6e1eaa20420ff03e5a4c (diff)
downloadmu-71e4f3812982dba2efb471283d310224e8db363e.tar.gz
7842 - new directory organization
Baremetal is now the default build target and therefore has its sources
at the top-level. Baremetal programs build using the phase-2 Mu toolchain
that requires a Linux kernel. This phase-2 codebase which used to be at
the top-level is now under the linux/ directory. Finally, the phase-2 toolchain,
while self-hosting, has a way to bootstrap from a C implementation, which
is now stored in linux/bootstrap. The bootstrap C implementation uses some
literate programming tools that are now in linux/bootstrap/tools.

So the whole thing has gotten inverted. Each directory should build one
artifact and include the main sources (along with standard library). Tools
used for building it are relegated to sub-directories, even though those
tools are often useful in their own right, and have had lots of interesting
programs written using them.

A couple of things have gotten dropped in this process:
  - I had old ways to run on just a Linux kernel, or with a Soso kernel.
    No more.
  - I had some old tooling for running a single test at the cursor. I haven't
    used that lately. Maybe I'll bring it back one day.

The reorg isn't done yet. Still to do:
  - redo documentation everywhere. All the README files, all other markdown,
    particularly vocabulary.md.
  - clean up how-to-run comments at the start of programs everywhere
  - rethink what to do with the html/ directory. Do we even want to keep
    supporting it?

In spite of these shortcomings, all the scripts at the top-level, linux/
and linux/bootstrap are working. The names of the scripts also feel reasonable.
This is a good milestone to take stock at.
Diffstat (limited to '500text-screen.mu')
-rw-r--r--500text-screen.mu298
1 files changed, 298 insertions, 0 deletions
diff --git a/500text-screen.mu b/500text-screen.mu
new file mode 100644
index 00000000..a764aa06
--- /dev/null
+++ b/500text-screen.mu
@@ -0,0 +1,298 @@
+# Testable primitives for writing text to screen.
+# (Mu doesn't yet have testable primitives for graphics.)
+#
+# Unlike the top-level, this text mode has no scrolling.
+
+# coordinates here don't match top-level
+# Here we're consistent with graphics mode. Top-level is consistent with
+# terminal emulators.
+type screen {
+  width: int
+  height: int
+  data: (handle array screen-cell)
+  cursor-x: int
+  cursor-y: int
+}
+
+type screen-cell {
+  data: grapheme
+  color: int
+  background-color: int
+}
+
+fn initialize-screen screen: (addr screen), width: int, height: int {
+  var screen-addr/esi: (addr screen) <- copy screen
+  var tmp/eax: int <- copy 0
+  var dest/edi: (addr int) <- copy 0
+  # screen->width = width
+  dest <- get screen-addr, width
+  tmp <- copy width
+  copy-to *dest, tmp
+  # screen->height = height
+  dest <- get screen-addr, height
+  tmp <- copy height
+  copy-to *dest, tmp
+  # screen->data = new screen-cell[width*height]
+  {
+    var data-addr/edi: (addr handle array screen-cell) <- get screen-addr, data
+    tmp <- multiply width
+    populate data-addr, tmp
+  }
+  # screen->cursor-x = 0
+  dest <- get screen-addr, cursor-x
+  copy-to *dest, 0
+  # screen->cursor-y = 0
+  dest <- get screen-addr, cursor-y
+  copy-to *dest, 0
+}
+
+# in graphemes
+fn screen-size screen: (addr screen) -> _/eax: int, _/ecx: int {
+  var width/eax: int <- copy 0
+  var height/ecx: int <- copy 0
+  compare screen, 0
+  {
+    break-if-!=
+    return 0x80/128, 0x30/48
+  }
+  # fake screen
+  var screen-addr/esi: (addr screen) <- copy screen
+  var tmp/edx: (addr int) <- get screen-addr, width
+  width <- copy *tmp
+  tmp <- get screen-addr, height
+  height <- copy *tmp
+  return width, height
+}
+
+# testable screen primitive
+fn draw-grapheme screen: (addr screen), g: grapheme, x: int, y: int, color: int, background-color: int {
+  {
+    compare screen, 0
+    break-if-!=
+    draw-grapheme-on-real-screen g, x, y, color, background-color
+    return
+  }
+  # fake screen
+  var screen-addr/esi: (addr screen) <- copy screen
+  var idx/ecx: int <- screen-cell-index screen-addr, x, y
+  var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
+  var data/eax: (addr array screen-cell) <- lookup *data-ah
+  var offset/ecx: (offset screen-cell) <- compute-offset data, idx
+  var dest-cell/ecx: (addr screen-cell) <- index data, offset
+  var dest-grapheme/eax: (addr grapheme) <- get dest-cell, data
+  var g2/edx: grapheme <- copy g
+  copy-to *dest-grapheme, g2
+  var dest-color/eax: (addr int) <- get dest-cell, color
+  var src-color/edx: int <- copy color
+  copy-to *dest-color, src-color
+  dest-color <- get dest-cell, background-color
+  src-color <- copy background-color
+  copy-to *dest-color, src-color
+}
+
+# we can't really render non-ASCII yet, but when we do we'll be ready
+fn draw-code-point screen: (addr screen), c: code-point, x: int, y: int, color: int, background-color: int {
+  var g/eax: grapheme <- copy c
+  draw-grapheme screen, g, x, y, color, background-color
+}
+
+# not really needed for a real screen, though it shouldn't do any harm
+fn screen-cell-index screen-on-stack: (addr screen), x: int, y: int -> _/ecx: int {
+  var screen/esi: (addr screen) <- copy screen-on-stack
+  # only one bounds check isn't automatically handled
+  {
+    var xmax/eax: (addr int) <- get screen, width
+    var xcurr/ecx: int <- copy x
+    compare xcurr, *xmax
+    break-if-<
+    abort "tried to print out of screen bounds"
+  }
+  var width-addr/eax: (addr int) <- get screen, width
+  var result/ecx: int <- copy y
+  result <- multiply *width-addr
+  result <- add x
+  return result
+}
+
+fn cursor-position screen: (addr screen) -> _/eax: int, _/ecx: int {
+  {
+    compare screen, 0
+    break-if-!=
+    var x/eax: int <- copy 0
+    var y/ecx: int <- copy 0
+    x, y <- cursor-position-on-real-screen
+    return x, y
+  }
+  # fake screen
+  var screen-addr/esi: (addr screen) <- copy screen
+  var cursor-x-addr/eax: (addr int) <- get screen-addr, cursor-x
+  var cursor-y-addr/ecx: (addr int) <- get screen-addr, cursor-y
+  return *cursor-x-addr, *cursor-y-addr
+}
+
+fn set-cursor-position screen: (addr screen), x: int, y: int {
+  {
+    compare screen, 0
+    break-if-!=
+    set-cursor-position-on-real-screen x, y
+    return
+  }
+  # fake screen
+  var screen-addr/esi: (addr screen) <- copy screen
+  # ignore x < 0
+  {
+    compare x, 0
+    break-if->=
+    return
+  }
+  # ignore x >= width
+  {
+    var width-addr/eax: (addr int) <- get screen-addr, width
+    var width/eax: int <- copy *width-addr
+    compare x, width
+    break-if-<=
+    return
+  }
+  # ignore y < 0
+  {
+    compare y, 0
+    break-if->=
+    return
+  }
+  # ignore y >= height
+  {
+    var height-addr/eax: (addr int) <- get screen-addr, height
+    var height/eax: int <- copy *height-addr
+    compare y, height
+    break-if-<
+    return
+  }
+  # screen->cursor-x = x
+  var dest/edi: (addr int) <- get screen-addr, cursor-x
+  var src/eax: int <- copy x
+  copy-to *dest, src
+  # screen->cursor-y = y
+  dest <- get screen-addr, cursor-y
+  src <- copy y
+  copy-to *dest, src
+}
+
+fn show-cursor screen: (addr screen), g: grapheme {
+  {
+    compare screen, 0
+    break-if-!=
+    show-cursor-on-real-screen g
+    return
+  }
+  # fake screen
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  draw-grapheme screen, g, cursor-x, cursor-y, 0/fg, 7/bg
+}
+
+fn clear-screen screen: (addr screen) {
+  {
+    compare screen, 0
+    break-if-!=
+    clear-real-screen
+    return
+  }
+  # fake screen
+  set-cursor-position screen, 0, 0
+  var screen-addr/esi: (addr screen) <- copy screen
+  var y/eax: int <- copy 0
+  var height/ecx: (addr int) <- get screen-addr, height
+  {
+    compare y, *height
+    break-if->=
+    var x/edx: int <- copy 0
+    var width/ebx: (addr int) <- get screen-addr, width
+    {
+      compare x, *width
+      break-if->=
+      draw-code-point screen, 0x20/space, x, y, 0/fg=black, 0/bg=black
+      x <- increment
+      loop
+    }
+    y <- increment
+    loop
+  }
+  set-cursor-position screen, 0, 0
+}
+
+# there's no grapheme that guarantees to cover every pixel, so we'll bump down
+# to pixels for a real screen
+fn clear-real-screen {
+  var y/eax: int <- copy 0
+  {
+    compare y, 0x300/screen-height=768
+    break-if->=
+    var x/edx: int <- copy 0
+    {
+      compare x, 0x400/screen-width=1024
+      break-if->=
+      pixel-on-real-screen x, y, 0/color=black
+      x <- increment
+      loop
+    }
+    y <- increment
+    loop
+  }
+}
+
+fn screen-grapheme-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: grapheme {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var idx/ecx: int <- screen-cell-index screen-addr, x, y
+  var result/eax: grapheme <- screen-grapheme-at-idx screen-addr, idx
+  return result
+}
+
+fn screen-grapheme-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: grapheme {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
+  var data/eax: (addr array screen-cell) <- lookup *data-ah
+  var idx/ecx: int <- copy idx-on-stack
+  var offset/ecx: (offset screen-cell) <- compute-offset data, idx
+  var cell/eax: (addr screen-cell) <- index data, offset
+  var src/eax: (addr grapheme) <- get cell, data
+  return *src
+}
+
+fn screen-color-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: int {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var idx/ecx: int <- screen-cell-index screen-addr, x, y
+  var result/eax: int <- screen-color-at-idx screen-addr, idx
+  return result
+}
+
+fn screen-color-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: int {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
+  var data/eax: (addr array screen-cell) <- lookup *data-ah
+  var idx/ecx: int <- copy idx-on-stack
+  var offset/ecx: (offset screen-cell) <- compute-offset data, idx
+  var cell/eax: (addr screen-cell) <- index data, offset
+  var src/eax: (addr int) <- get cell, color
+  var result/eax: int <- copy *src
+  return result
+}
+
+fn screen-background-color-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: int {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var idx/ecx: int <- screen-cell-index screen-addr, x, y
+  var result/eax: int <- screen-background-color-at-idx screen-addr, idx
+  return result
+}
+
+fn screen-background-color-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: int {
+  var screen-addr/esi: (addr screen) <- copy screen-on-stack
+  var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
+  var data/eax: (addr array screen-cell) <- lookup *data-ah
+  var idx/ecx: int <- copy idx-on-stack
+  var offset/ecx: (offset screen-cell) <- compute-offset data, idx
+  var cell/eax: (addr screen-cell) <- index data, offset
+  var src/eax: (addr int) <- get cell, background-color
+  var result/eax: int <- copy *src
+  return result
+}