update vocabulary documentation
Top-level and linux/ now have separate vocabulary.md files.
This commit is contained in:
parent
6508ab51cc
commit
cec5ef31b3
|
@ -125,13 +125,13 @@ $set-cursor-position-on-real-screen:end:
|
||||||
5d/pop-to-ebp
|
5d/pop-to-ebp
|
||||||
c3/return
|
c3/return
|
||||||
|
|
||||||
# Draw cursor at current location. But this is rickety:
|
# Not a real `show-cursor` primitive:
|
||||||
# - does not clear previous location cursor was shown at.
|
# - does not clear previous location cursor was shown at.
|
||||||
# - does not preserve what was at the cursor. Caller is responsible for
|
# - does not preserve what was at the cursor. Caller is responsible for
|
||||||
# tracking what was on the screen at this position before and passing it
|
# tracking what was on the screen at this position before and passing it
|
||||||
# in again.
|
# in again.
|
||||||
# - does not stop showing the cursor at this location when the cursor moves
|
# - does not stop showing the cursor at this location when the cursor moves
|
||||||
show-cursor-on-real-screen: # g: grapheme
|
draw-cursor-on-real-screen: # g: grapheme
|
||||||
# . prologue
|
# . prologue
|
||||||
55/push-ebp
|
55/push-ebp
|
||||||
89/<- %ebp 4/r32/esp
|
89/<- %ebp 4/r32/esp
|
||||||
|
@ -141,7 +141,7 @@ show-cursor-on-real-screen: # g: grapheme
|
||||||
#
|
#
|
||||||
(cursor-position-on-real-screen) # => eax, ecx
|
(cursor-position-on-real-screen) # => eax, ecx
|
||||||
(draw-grapheme-on-real-screen *(ebp+8) %eax %ecx 0 7)
|
(draw-grapheme-on-real-screen *(ebp+8) %eax %ecx 0 7)
|
||||||
$show-cursor-on-real-screen:end:
|
$draw-cursor-on-real-screen:end:
|
||||||
# . restore registers
|
# . restore registers
|
||||||
59/pop-to-ecx
|
59/pop-to-ecx
|
||||||
58/pop-to-eax
|
58/pop-to-eax
|
||||||
|
@ -156,7 +156,7 @@ $show-cursor-on-real-screen:end:
|
||||||
# 'draw*cursor*') print to by default.
|
# 'draw*cursor*') print to by default.
|
||||||
#
|
#
|
||||||
# We don't bother displaying the cursor when drawing. It only becomes visible
|
# We don't bother displaying the cursor when drawing. It only becomes visible
|
||||||
# on show-cursor, which is quite rickety (see above)
|
# on draw-cursor, which is quite rickety (see above)
|
||||||
#
|
#
|
||||||
# It's up to applications to manage cursor display:
|
# It's up to applications to manage cursor display:
|
||||||
# - clean up where it used to be
|
# - clean up where it used to be
|
||||||
|
|
6
400.mu
6
400.mu
|
@ -3,7 +3,7 @@ sig pixel-on-real-screen x: int, y: int, color: int
|
||||||
sig draw-grapheme-on-real-screen g: grapheme, x: int, y: int, color: int, background-color: int
|
sig draw-grapheme-on-real-screen g: grapheme, x: int, y: int, color: int, background-color: int
|
||||||
sig cursor-position-on-real-screen -> _/eax: int, _/ecx: int
|
sig cursor-position-on-real-screen -> _/eax: int, _/ecx: int
|
||||||
sig set-cursor-position-on-real-screen x: int, y: int
|
sig set-cursor-position-on-real-screen x: int, y: int
|
||||||
sig show-cursor-on-real-screen g: grapheme
|
sig draw-cursor-on-real-screen g: grapheme
|
||||||
|
|
||||||
# keyboard
|
# keyboard
|
||||||
sig read-key kbd: (addr keyboard) -> _/eax: byte
|
sig read-key kbd: (addr keyboard) -> _/eax: byte
|
||||||
|
@ -26,9 +26,9 @@ sig check-next-stream-line-equal f: (addr stream byte), s: (addr array byte), ms
|
||||||
sig write f: (addr stream byte), s: (addr array byte)
|
sig write f: (addr stream byte), s: (addr array byte)
|
||||||
sig write-stream f: (addr stream byte), s: (addr stream byte)
|
sig write-stream f: (addr stream byte), s: (addr stream byte)
|
||||||
sig read-byte s: (addr stream byte) -> _/eax: byte
|
sig read-byte s: (addr stream byte) -> _/eax: byte
|
||||||
sig append-byte f: (addr stream byte), n: int
|
sig append-byte f: (addr stream byte), n: int # really just a byte, but I want to pass in literal numbers
|
||||||
#sig to-hex-char in/eax: int -> out/eax: int
|
#sig to-hex-char in/eax: int -> out/eax: int
|
||||||
sig append-byte-hex f: (addr stream byte), n: int
|
sig append-byte-hex f: (addr stream byte), n: int # really just a byte, but I want to pass in literal numbers
|
||||||
sig write-int32-hex f: (addr stream byte), n: int
|
sig write-int32-hex f: (addr stream byte), n: int
|
||||||
sig write-int32-hex-bits f: (addr stream byte), n: int, bits: int
|
sig write-int32-hex-bits f: (addr stream byte), n: int, bits: int
|
||||||
sig hex-int? in: (addr slice) -> _/eax: boolean
|
sig hex-int? in: (addr slice) -> _/eax: boolean
|
||||||
|
|
|
@ -177,11 +177,11 @@ fn set-cursor-position screen: (addr screen), x: int, y: int {
|
||||||
copy-to *dest, src
|
copy-to *dest, src
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show-cursor screen: (addr screen), g: grapheme {
|
fn draw-cursor screen: (addr screen), g: grapheme {
|
||||||
{
|
{
|
||||||
compare screen, 0
|
compare screen, 0
|
||||||
break-if-!=
|
break-if-!=
|
||||||
show-cursor-on-real-screen g
|
draw-cursor-on-real-screen g
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
# fake screen
|
# fake screen
|
||||||
|
|
|
@ -62,7 +62,7 @@ fn move-cursor-down screen: (addr screen) {
|
||||||
set-cursor-position screen, cursor-x, cursor-y
|
set-cursor-position screen, cursor-x, cursor-y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move-cursor-to-start-of-next-line screen: (addr screen) {
|
fn move-cursor-to-left-margin-of-next-line screen: (addr screen) {
|
||||||
var dummy/eax: int <- copy 0
|
var dummy/eax: int <- copy 0
|
||||||
var _height/ecx: int <- copy 0
|
var _height/ecx: int <- copy 0
|
||||||
dummy, _height <- screen-size screen
|
dummy, _height <- screen-size screen
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn check-ints-equal _a: int, b: int, msg: (addr array byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
count-test-failure
|
count-test-failure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ fn check _a: boolean, msg: (addr array byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
count-test-failure
|
count-test-failure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,6 @@ fn check-not _a: boolean, msg: (addr array byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
count-test-failure
|
count-test-failure
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ fn check-screen-row-from screen-on-stack: (addr screen), x: int, y: int, expecte
|
||||||
draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
|
draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
|
||||||
move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
|
move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
}
|
}
|
||||||
idx <- increment
|
idx <- increment
|
||||||
increment x
|
increment x
|
||||||
|
@ -120,7 +120,7 @@ fn check-screen-row-in-color-from screen-on-stack: (addr screen), fg: int, y: in
|
||||||
draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
|
draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
|
||||||
move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
|
move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
}
|
}
|
||||||
$check-screen-row-in-color-from:compare-colors: {
|
$check-screen-row-in-color-from:compare-colors: {
|
||||||
var color/eax: int <- screen-color-at-idx screen, idx
|
var color/eax: int <- screen-color-at-idx screen, idx
|
||||||
|
@ -144,7 +144,7 @@ fn check-screen-row-in-color-from screen-on-stack: (addr screen), fg: int, y: in
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, fg, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, fg, 3/fg/cyan, 0/bg
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed color ", 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed color ", 3/fg/cyan, 0/bg
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, color, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, color, 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
idx <- increment
|
idx <- increment
|
||||||
|
@ -211,7 +211,7 @@ fn check-screen-row-in-background-color-from screen-on-stack: (addr screen), bg:
|
||||||
draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
|
draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
|
||||||
move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
|
move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
break $check-screen-row-in-background-color-from:compare-graphemes
|
break $check-screen-row-in-background-color-from:compare-graphemes
|
||||||
}
|
}
|
||||||
$check-screen-row-in-background-color-from:compare-background-colors: {
|
$check-screen-row-in-background-color-from:compare-background-colors: {
|
||||||
|
@ -236,7 +236,7 @@ fn check-screen-row-in-background-color-from screen-on-stack: (addr screen), bg:
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
idx <- increment
|
idx <- increment
|
||||||
|
@ -281,7 +281,7 @@ fn check-background-color-in-screen-row-from screen-on-stack: (addr screen), bg:
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") to not be in background-color ", 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") to not be in background-color ", 3/fg/cyan, 0/bg
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
break $check-background-color-in-screen-row-from:compare-cells
|
break $check-background-color-in-screen-row-from:compare-cells
|
||||||
}
|
}
|
||||||
# otherwise assert that background IS bg
|
# otherwise assert that background IS bg
|
||||||
|
@ -297,7 +297,7 @@ fn check-background-color-in-screen-row-from screen-on-stack: (addr screen), bg:
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
|
||||||
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg
|
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg
|
||||||
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg
|
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg
|
||||||
move-cursor-to-start-of-next-line 0/screen
|
move-cursor-to-left-margin-of-next-line 0/screen
|
||||||
}
|
}
|
||||||
idx <- increment
|
idx <- increment
|
||||||
increment x
|
increment x
|
||||||
|
|
2
ex7.mu
2
ex7.mu
|
@ -14,7 +14,7 @@ fn main {
|
||||||
var space/eax: grapheme <- copy 0x20
|
var space/eax: grapheme <- copy 0x20
|
||||||
set-cursor-position 0/screen, 0, 0
|
set-cursor-position 0/screen, 0, 0
|
||||||
{
|
{
|
||||||
show-cursor 0/screen, space
|
draw-cursor 0/screen, space
|
||||||
var key/eax: byte <- read-key 0/keyboard
|
var key/eax: byte <- read-key 0/keyboard
|
||||||
{
|
{
|
||||||
compare key, 0x68/h
|
compare key, 0x68/h
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# Some helpers for Mu tests.
|
# Some helpers for Mu tests.
|
||||||
|
|
||||||
fn check-true val: boolean, msg: (addr array byte) {
|
fn check val: boolean, msg: (addr array byte) {
|
||||||
var tmp/eax: int <- copy val
|
var tmp/eax: int <- copy val
|
||||||
check-ints-equal tmp, 1, msg
|
check-ints-equal tmp, 1, msg
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check-false val: boolean, msg: (addr array byte) {
|
fn check-not val: boolean, msg: (addr array byte) {
|
||||||
var tmp/eax: int <- copy val
|
var tmp/eax: int <- copy val
|
||||||
check-ints-equal tmp, 0, msg
|
check-ints-equal tmp, 0, msg
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,18 +6,18 @@ fn test-stream {
|
||||||
var s: (stream int 4)
|
var s: (stream int 4)
|
||||||
var s2/ecx: (addr stream int) <- address s
|
var s2/ecx: (addr stream int) <- address s
|
||||||
var tmp/eax: boolean <- stream-empty? s2
|
var tmp/eax: boolean <- stream-empty? s2
|
||||||
check-true tmp, "F - test-stream/empty?/0"
|
check tmp, "F - test-stream/empty?/0"
|
||||||
tmp <- stream-full? s2
|
tmp <- stream-full? s2
|
||||||
check-false tmp, "F - test-stream/full?/0"
|
check-not tmp, "F - test-stream/full?/0"
|
||||||
# step 2: write to stream
|
# step 2: write to stream
|
||||||
var x: int
|
var x: int
|
||||||
copy-to x, 0x34
|
copy-to x, 0x34
|
||||||
var x2/edx: (addr int) <- address x
|
var x2/edx: (addr int) <- address x
|
||||||
write-to-stream s2, x2
|
write-to-stream s2, x2
|
||||||
tmp <- stream-empty? s2
|
tmp <- stream-empty? s2
|
||||||
check-false tmp, "F - test-stream/empty?/1"
|
check-not tmp, "F - test-stream/empty?/1"
|
||||||
tmp <- stream-full? s2
|
tmp <- stream-full? s2
|
||||||
check-false tmp, "F - test-stream/full?/1"
|
check-not tmp, "F - test-stream/full?/1"
|
||||||
# step 3: modify the value written (should make no difference)
|
# step 3: modify the value written (should make no difference)
|
||||||
copy-to x, 0
|
copy-to x, 0
|
||||||
# step 4: read back
|
# step 4: read back
|
||||||
|
@ -25,9 +25,9 @@ fn test-stream {
|
||||||
var y2/ebx: (addr int) <- address y
|
var y2/ebx: (addr int) <- address y
|
||||||
read-from-stream s2, y2
|
read-from-stream s2, y2
|
||||||
tmp <- stream-empty? s2
|
tmp <- stream-empty? s2
|
||||||
check-true tmp, "F - test-stream/empty?/2"
|
check tmp, "F - test-stream/empty?/2"
|
||||||
tmp <- stream-full? s2
|
tmp <- stream-full? s2
|
||||||
check-false tmp, "F - test-stream/full?/2"
|
check-not tmp, "F - test-stream/full?/2"
|
||||||
# we read back what was written
|
# we read back what was written
|
||||||
check-ints-equal y, 0x34, "F - test-stream"
|
check-ints-equal y, 0x34, "F - test-stream"
|
||||||
}
|
}
|
||||||
|
@ -37,12 +37,12 @@ fn test-stream-full {
|
||||||
var s: (stream int 1)
|
var s: (stream int 1)
|
||||||
var s2/ecx: (addr stream int) <- address s
|
var s2/ecx: (addr stream int) <- address s
|
||||||
var tmp/eax: boolean <- stream-full? s2
|
var tmp/eax: boolean <- stream-full? s2
|
||||||
check-false tmp, "F - test-stream-full?/pre"
|
check-not tmp, "F - test-stream-full?/pre"
|
||||||
var x: int
|
var x: int
|
||||||
var x2/edx: (addr int) <- address x
|
var x2/edx: (addr int) <- address x
|
||||||
write-to-stream s2, x2
|
write-to-stream s2, x2
|
||||||
tmp <- stream-full? s2
|
tmp <- stream-full? s2
|
||||||
check-true tmp, "F - test-stream-full?"
|
check tmp, "F - test-stream-full?"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test-fake-input-buffered-file {
|
fn test-fake-input-buffered-file {
|
||||||
|
|
|
@ -620,7 +620,7 @@ fn check-buffer-contains _buf: (addr array byte), _contents: (addr array byte),
|
||||||
var buf/esi: (addr array byte) <- copy _buf
|
var buf/esi: (addr array byte) <- copy _buf
|
||||||
var contents/edi: (addr array byte) <- copy _contents
|
var contents/edi: (addr array byte) <- copy _contents
|
||||||
var a/eax: boolean <- string-starts-with? buf, contents
|
var a/eax: boolean <- string-starts-with? buf, contents
|
||||||
check-true a, msg
|
check a, msg
|
||||||
var len/ecx: int <- length contents
|
var len/ecx: int <- length contents
|
||||||
var len2/eax: int <- length buf
|
var len2/eax: int <- length buf
|
||||||
compare len, len2
|
compare len, len2
|
||||||
|
|
|
@ -8,6 +8,10 @@ kernel. To run programs under this directory, you must first `cd` into it.
|
||||||
Hello world!
|
Hello world!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See the [shared vocabulary](vocabulary.md) of data types and functions shared
|
||||||
|
by Mu programs running on Linux. Mu programs can transparently call low-level
|
||||||
|
functions written in SubX.
|
||||||
|
|
||||||
Some programs to try out:
|
Some programs to try out:
|
||||||
|
|
||||||
* `tile`: [An experimental live-updating postfix shell environment](https://mastodon.social/@akkartik/105108305362341204)
|
* `tile`: [An experimental live-updating postfix shell environment](https://mastodon.social/@akkartik/105108305362341204)
|
||||||
|
|
|
@ -0,0 +1,368 @@
|
||||||
|
## Reference documentation on available primitives
|
||||||
|
|
||||||
|
### Data Structures
|
||||||
|
|
||||||
|
- Handles: addresses to objects allocated on the heap. They're augmented with
|
||||||
|
book-keeping to guarantee memory-safety, and so cannot be stored in registers.
|
||||||
|
See [mu.md](mu.md) for details, but in brief:
|
||||||
|
- You need `addr` values to access data they point to.
|
||||||
|
- You can't store `addr` values in other types. They're temporary.
|
||||||
|
- You can store `handle` values in other types.
|
||||||
|
- To convert `handle` to `addr`, use `lookup`.
|
||||||
|
- Reclaiming memory (currently unimplemented) invalidates all `addr`
|
||||||
|
values.
|
||||||
|
|
||||||
|
- Kernel strings: null-terminated regions of memory. Unsafe and to be avoided,
|
||||||
|
but needed for interacting with the kernel.
|
||||||
|
|
||||||
|
- Arrays: size-prefixed regions of memory containing multiple elements of a
|
||||||
|
single type. Contents are preceded by 4 bytes (32 bits) containing the
|
||||||
|
`size` of the array in bytes.
|
||||||
|
|
||||||
|
- Slices: a pair of 32-bit addresses denoting a [half-open](https://en.wikipedia.org/wiki/Interval_(mathematics))
|
||||||
|
\[`start`, `end`) interval to live memory with a consistent lifetime.
|
||||||
|
|
||||||
|
Invariant: `start` <= `end`
|
||||||
|
|
||||||
|
- Streams: strings prefixed by 32-bit `write` and `read` indexes that the next
|
||||||
|
write or read goes to, respectively.
|
||||||
|
|
||||||
|
- offset 0: write index
|
||||||
|
- offset 4: read index
|
||||||
|
- offset 8: size of array (in bytes)
|
||||||
|
- offset 12: start of array data
|
||||||
|
|
||||||
|
Invariant: 0 <= `read` <= `write` <= `size`
|
||||||
|
|
||||||
|
- File descriptors (fd): Low-level 32-bit integers that the kernel uses to
|
||||||
|
track files opened by the program.
|
||||||
|
|
||||||
|
- File: 32-bit value containing either a fd or an address to a stream (fake
|
||||||
|
file).
|
||||||
|
|
||||||
|
- Buffered files (buffered-file): Contain a file descriptor and a stream for
|
||||||
|
buffering reads/writes. Each `buffered-file` must exclusively perform either
|
||||||
|
reads or writes.
|
||||||
|
|
||||||
|
- Graphemes: 32-bit fragments of utf-8 that encode a single Unicode code-point.
|
||||||
|
- Code-points: 32-bit integers representing a Unicode character.
|
||||||
|
|
||||||
|
### 'system calls'
|
||||||
|
|
||||||
|
As I said at the top, a primary design goal of SubX (and Mu more broadly) is
|
||||||
|
to explore ways to turn arbitrary manual tests into reproducible automated
|
||||||
|
tests. SubX aims for this goal by baking testable interfaces deep into the
|
||||||
|
stack, at the OS syscall level. The idea is that every syscall that interacts
|
||||||
|
with hardware (and so the environment) should be *dependency injected* so that
|
||||||
|
it's possible to insert fake hardware in tests.
|
||||||
|
|
||||||
|
But those are big goals. Here are the syscalls I have so far:
|
||||||
|
|
||||||
|
- `write`: takes two arguments, a file `f` and an address to array `s`.
|
||||||
|
|
||||||
|
Comparing this interface with the Unix `write()` syscall shows two benefits:
|
||||||
|
|
||||||
|
1. SubX can handle 'fake' file descriptors in tests.
|
||||||
|
|
||||||
|
1. `write()` accepts buffer and its size in separate arguments, which
|
||||||
|
requires callers to manage the two separately and so can be error-prone.
|
||||||
|
SubX's wrapper keeps the two together to increase the chances that we
|
||||||
|
never accidentally go out of array bounds.
|
||||||
|
|
||||||
|
- `read`: takes two arguments, a file `f` and an address to stream `s`. Reads
|
||||||
|
as much data from `f` as can fit in (the free space of) `s`.
|
||||||
|
|
||||||
|
Like with `write()`, this wrapper around the Unix `read()` syscall adds the
|
||||||
|
ability to handle 'fake' file descriptors in tests, and reduces the chances
|
||||||
|
of clobbering outside array bounds.
|
||||||
|
|
||||||
|
One bit of weirdness here: in tests we do a redundant copy from one stream
|
||||||
|
to another. See [the comments before the implementation](http://akkartik.github.io/mu/html/060read.subx.html)
|
||||||
|
for a discussion of alternative interfaces.
|
||||||
|
|
||||||
|
- `stop`: takes two arguments:
|
||||||
|
- `ed` is an address to an _exit descriptor_. Exit descriptors allow us to
|
||||||
|
`exit()` the program in production, but return to the test harness within
|
||||||
|
tests. That allows tests to make assertions about when `exit()` is called.
|
||||||
|
- `value` is the status code to `exit()` with.
|
||||||
|
|
||||||
|
For more details on exit descriptors and how to create one, see [the
|
||||||
|
comments before the implementation](http://akkartik.github.io/mu/html/059stop.subx.html).
|
||||||
|
|
||||||
|
- `new-segment`
|
||||||
|
|
||||||
|
Allocates a whole new segment of memory for the program, discontiguous with
|
||||||
|
both existing code and data (heap) segments. Just a more opinionated form of
|
||||||
|
[`mmap`](http://man7.org/linux/man-pages/man2/mmap.2.html).
|
||||||
|
|
||||||
|
- `allocate`: takes two arguments, an address to allocation-descriptor `ad`
|
||||||
|
and an integer `n`
|
||||||
|
|
||||||
|
Allocates a contiguous range of memory that is guaranteed to be exclusively
|
||||||
|
available to the caller. Returns the starting address to the range in `eax`.
|
||||||
|
|
||||||
|
An allocation descriptor tracks allocated vs available addresses in some
|
||||||
|
contiguous range of memory. The int specifies the number of bytes to allocate.
|
||||||
|
|
||||||
|
Explicitly passing in an allocation descriptor allows for nested memory
|
||||||
|
management, where a sub-system gets a chunk of memory and further parcels it
|
||||||
|
out to individual allocations. Particularly helpful for (surprise) tests.
|
||||||
|
|
||||||
|
- `time`: returns the time in seconds since the epoch.
|
||||||
|
|
||||||
|
- `ntime`: returns the number of nanoseconds since some arbitrary point.
|
||||||
|
Saturates at 32 bits. Useful for fine-grained measurements over relatively
|
||||||
|
short durations.
|
||||||
|
|
||||||
|
- `sleep`: sleep for some number of whole seconds and some fraction of a
|
||||||
|
second expressed in nanoseconds. Not having decimal literals can be awkward
|
||||||
|
here.
|
||||||
|
|
||||||
|
- ... _(to be continued)_
|
||||||
|
|
||||||
|
I will continue to import syscalls over time from [the old Mu VM in the parent
|
||||||
|
directory](https://github.com/akkartik/mu), which has experimented with
|
||||||
|
interfaces for the screen, keyboard, mouse, disk and network.
|
||||||
|
|
||||||
|
### Functions
|
||||||
|
|
||||||
|
The most useful functions from 400.mu and later .mu files. Look for definitions
|
||||||
|
(using `ctags`) to see type signatures.
|
||||||
|
|
||||||
|
_(Compound arguments are usually passed in by reference. Where the results are
|
||||||
|
compound objects that don't fit in a register, the caller usually passes in
|
||||||
|
allocated memory for it.)_
|
||||||
|
|
||||||
|
#### assertions for tests
|
||||||
|
|
||||||
|
- `check`: fails current test if given boolean is false (`= 0`).
|
||||||
|
- `check-not`: fails current test if given boolean isn't false (`!= 0`).
|
||||||
|
- `check-ints-equal`: fails current test if given ints aren't equal
|
||||||
|
- `check-array-equal`: only arrays of ints, passes in a literal array in a
|
||||||
|
whitespace-separated string.
|
||||||
|
- `check-stream-equal`: fails current test if stream doesn't match string
|
||||||
|
- `check-next-stream-line-equal`: fails current test if next line of stream
|
||||||
|
until newline doesn't match string
|
||||||
|
|
||||||
|
Every Mu computer has a global trace that programs can write to, and that
|
||||||
|
tests can make assertions on.
|
||||||
|
|
||||||
|
- `clear-trace-stream`
|
||||||
|
- `check-trace-contains`
|
||||||
|
- `check-trace-scans-to`: like `check-trace-contains` but with an implicit,
|
||||||
|
stateful start index
|
||||||
|
|
||||||
|
#### error handling
|
||||||
|
|
||||||
|
- `error`: takes three arguments, an exit-descriptor, a file and a string (message)
|
||||||
|
|
||||||
|
Prints out the message to the file and then exits using the provided
|
||||||
|
exit-descriptor.
|
||||||
|
|
||||||
|
- `error-byte`: like `error` but takes an extra byte value that it prints out
|
||||||
|
at the end of the message.
|
||||||
|
|
||||||
|
#### numbers
|
||||||
|
|
||||||
|
- `abs`
|
||||||
|
- `repeated-shift-left`, since x86 only supports bit-shifts by constant values
|
||||||
|
- `repeated-shift-right`
|
||||||
|
- `shift-left-bytes`: shift left by `n*8` bits
|
||||||
|
- `integer-divide`
|
||||||
|
|
||||||
|
Floating point constructors, since x86 doesn't support immediate floats and Mu
|
||||||
|
doesn't yet parse floating-point literals:
|
||||||
|
|
||||||
|
- `rational`: int, int -> float
|
||||||
|
- `fill-in-rational`: int, int, (addr float)
|
||||||
|
- `fill-in-sqrt`: int, (addr float)
|
||||||
|
|
||||||
|
#### arrays and strings
|
||||||
|
|
||||||
|
- `populate`: allocates space for `n` objects of the appropriate type.
|
||||||
|
- `copy-array`: allocates enough space and writes out a copy of an array of
|
||||||
|
some type.
|
||||||
|
- `slice-to-string`: allocates space for an array of bytes and copies the
|
||||||
|
slice into it.
|
||||||
|
|
||||||
|
- `array-equal?`
|
||||||
|
- `substring`: string, start, length -> string
|
||||||
|
- `split-string`: string, delimiter -> array of strings
|
||||||
|
|
||||||
|
- `copy-array-object`
|
||||||
|
|
||||||
|
#### predicates
|
||||||
|
|
||||||
|
- `kernel-string-equal?`: compares a kernel string with a string
|
||||||
|
- `string-equal?`: compares two strings
|
||||||
|
- `stream-data-equal?`: compares a stream with a string
|
||||||
|
- `next-stream-line-equal?`: compares with string the next line in a stream, from
|
||||||
|
`read` index to newline
|
||||||
|
|
||||||
|
- `slice-empty?`: checks if the `start` and `end` of a slice are equal
|
||||||
|
- `slice-equal?`: compares a slice with a string
|
||||||
|
- `slice-starts-with?`: compares the start of a slice with a string
|
||||||
|
- `slice-ends-with?`: compares the end of a slice with a string
|
||||||
|
|
||||||
|
#### writing to disk
|
||||||
|
|
||||||
|
- `write`: string -> file
|
||||||
|
- Can also be used to cat a string into a stream.
|
||||||
|
- `write-stream`: stream -> file
|
||||||
|
- Can also be used to cat one stream into another.
|
||||||
|
- `write-stream-data`: stream -> file
|
||||||
|
- Like `write-stream` but ignores read index.
|
||||||
|
- `write-slice`: slice -> stream
|
||||||
|
- `append-byte`: int -> stream
|
||||||
|
- `append-byte-hex`: int -> stream
|
||||||
|
- textual representation in hex, no '0x' prefix
|
||||||
|
|
||||||
|
- `write-int`: int -> stream
|
||||||
|
- write number to stream
|
||||||
|
- `write-int32-hex`: int -> stream
|
||||||
|
- textual representation in hex, including '0x' prefix
|
||||||
|
- `write-int32-hex-buffered`: int -> buffered-file
|
||||||
|
- `write-int32-decimal`
|
||||||
|
- `write-int32-decimal-buffered`
|
||||||
|
- `write-buffered`: string -> buffered-file
|
||||||
|
- `write-slice-buffered`: slice -> buffered-file
|
||||||
|
- `flush`: buffered-file
|
||||||
|
- `write-byte-buffered`: int -> buffered-file
|
||||||
|
- `write-byte-buffered`: int -> buffered-file
|
||||||
|
- textual representation in hex, no '0x' prefix
|
||||||
|
- `print-int32-buffered`: int -> buffered-file
|
||||||
|
- textual representation in hex, including '0x' prefix
|
||||||
|
|
||||||
|
- `write-grapheme`: grapheme -> stream
|
||||||
|
- `to-grapheme`: code-point -> grapheme
|
||||||
|
|
||||||
|
- `write-float-decimal-approximate`: float, precision: int -> stream
|
||||||
|
|
||||||
|
- `new-buffered-file`
|
||||||
|
- `populate-buffered-file-containing`: string -> buffered-file
|
||||||
|
|
||||||
|
Unless otherwise states, writes to a stream will abort the entire program if
|
||||||
|
there isn't enough room in the destination stream.
|
||||||
|
|
||||||
|
#### reading from disk
|
||||||
|
|
||||||
|
- `read`: file -> stream
|
||||||
|
- Can also be used to cat one stream into another.
|
||||||
|
- Will silently stop reading when destination runs out of space.
|
||||||
|
- `read-byte-buffered`: buffered-file -> byte
|
||||||
|
- `read-line-buffered`: buffered-file -> stream
|
||||||
|
- Will abort the entire program if there isn't enough room.
|
||||||
|
|
||||||
|
- `read-grapheme`: stream -> grapheme
|
||||||
|
- `read-grapheme-buffered`: buffered-file -> grapheme
|
||||||
|
|
||||||
|
- `read-lines`: buffered-file -> array of strings
|
||||||
|
|
||||||
|
#### non-IO operations on streams
|
||||||
|
|
||||||
|
- `populate-stream`: allocates space in a stream for `n` objects of the
|
||||||
|
appropriate type.
|
||||||
|
- Will abort the entire program if `n*b` requires more than 32 bits.
|
||||||
|
- `clear-stream`: resets everything in the stream to `0` (except its `size`).
|
||||||
|
- `rewind-stream`: resets the read index of the stream to `0` without modifying
|
||||||
|
its contents.
|
||||||
|
|
||||||
|
#### reading/writing hex representations of integers
|
||||||
|
|
||||||
|
- `is-hex-int?`: slice -> boolean
|
||||||
|
- `parse-hex-int`: string -> int
|
||||||
|
- `parse-hex-int-from-slice`: slice -> int
|
||||||
|
- `is-hex-digit?`: byte -> boolean
|
||||||
|
|
||||||
|
- `parse-array-of-ints`
|
||||||
|
- `parse-array-of-decimal-ints`
|
||||||
|
|
||||||
|
#### printing to screen
|
||||||
|
|
||||||
|
All screen primitives require a screen object, which can be either the real
|
||||||
|
screen on the computer or a fake screen for tests. Mu supports a subset of
|
||||||
|
Unix terminal properties supported by almost all modern terminal emulators.
|
||||||
|
|
||||||
|
- `enable-screen-type-mode` (default)
|
||||||
|
- `enable-screen-grid-mode`
|
||||||
|
|
||||||
|
- `clear-screen`
|
||||||
|
- `screen-size`
|
||||||
|
|
||||||
|
- `move-cursor`
|
||||||
|
- `hide-cursor`
|
||||||
|
- `show-cursor`
|
||||||
|
|
||||||
|
- `print-string`: string -> screen
|
||||||
|
- `print-stream`
|
||||||
|
- `print-grapheme`
|
||||||
|
- `print-code-point`
|
||||||
|
- `print-int32-hex`
|
||||||
|
- `print-int32-decimal`
|
||||||
|
- `print-int32-decimal-right-justified`
|
||||||
|
- `print-array-of-ints-in-decimal`
|
||||||
|
|
||||||
|
- `print-float-hex`
|
||||||
|
- `print-float-decimal-approximate`: up to some precision
|
||||||
|
|
||||||
|
Printing to screen is stateful, and preserves formatting unless explicitly
|
||||||
|
manipulated.
|
||||||
|
|
||||||
|
- `reset-formatting`
|
||||||
|
- `start-color`: adjusts foreground and background
|
||||||
|
- `start-bold`
|
||||||
|
- `start-underline`
|
||||||
|
- `start-reverse-video`
|
||||||
|
- `start-blinking`
|
||||||
|
|
||||||
|
Assertions for tests:
|
||||||
|
|
||||||
|
- `screen-grapheme-at`
|
||||||
|
- `screen-color-at`
|
||||||
|
- `screen-background-color-at`
|
||||||
|
- `screen-bold-at?`
|
||||||
|
- `screen-underline-at?`
|
||||||
|
- `screen-reverse-at?`
|
||||||
|
- `screen-blink-at?`
|
||||||
|
|
||||||
|
- `check-screen-row`
|
||||||
|
- `check-screen-row-from`
|
||||||
|
- `check-screen-row-in-color`
|
||||||
|
- `check-screen-row-in-color-from`
|
||||||
|
- `check-screen-row-in-background-color`
|
||||||
|
- `check-screen-row-in-background-color-from`
|
||||||
|
- `check-screen-row-in-bold`
|
||||||
|
- `check-screen-row-in-bold-from`
|
||||||
|
- `check-screen-row-in-underline`
|
||||||
|
- `check-screen-row-in-underline-from`
|
||||||
|
- `check-screen-row-in-reverse`
|
||||||
|
- `check-screen-row-in-reverse-from`
|
||||||
|
- `check-screen-row-in-blinking`
|
||||||
|
- `check-screen-row-in-blinking-from`
|
||||||
|
|
||||||
|
#### keyboard
|
||||||
|
|
||||||
|
- `enable-keyboard-type-mode`: process keystrokes on `enter` (default mode)
|
||||||
|
- `read-line-from-real-keyboard`
|
||||||
|
|
||||||
|
- `enable-keyboard-immediate-mode`: process keystrokes as they're typed
|
||||||
|
- `read-key-from-real-keyboard`
|
||||||
|
|
||||||
|
#### tokenization
|
||||||
|
|
||||||
|
from a stream:
|
||||||
|
- `next-token`: stream, delimiter byte -> slice
|
||||||
|
- `skip-chars-matching`: stream, delimiter byte
|
||||||
|
- `skip-chars-not-matching`: stream, delimiter byte
|
||||||
|
|
||||||
|
from a slice:
|
||||||
|
- `next-token-from-slice`: start, end, delimiter byte -> slice
|
||||||
|
- Given a slice and a delimiter byte, returns a new slice inside the input
|
||||||
|
that ends at the delimiter byte.
|
||||||
|
|
||||||
|
- `skip-chars-matching-in-slice`: curr, end, delimiter byte -> new-curr (in `eax`)
|
||||||
|
- `skip-chars-not-matching-in-slice`: curr, end, delimiter byte -> new-curr (in `eax`)
|
||||||
|
|
||||||
|
#### file system
|
||||||
|
|
||||||
|
- `open`: filename, write? -> buffered-file
|
2
rpn.mu
2
rpn.mu
|
@ -28,7 +28,7 @@ fn main {
|
||||||
# read line from keyboard
|
# read line from keyboard
|
||||||
clear-stream in
|
clear-stream in
|
||||||
{
|
{
|
||||||
show-cursor 0/screen, space
|
draw-cursor 0/screen, space
|
||||||
var key/eax: byte <- read-key 0/keyboard
|
var key/eax: byte <- read-key 0/keyboard
|
||||||
compare key, 0xa/newline
|
compare key, 0xa/newline
|
||||||
break-if-=
|
break-if-=
|
||||||
|
|
333
vocabulary.md
333
vocabulary.md
|
@ -2,8 +2,15 @@
|
||||||
|
|
||||||
### Data Structures
|
### Data Structures
|
||||||
|
|
||||||
- Kernel strings: null-terminated regions of memory. Unsafe and to be avoided,
|
- Handles: addresses to objects allocated on the heap. They're augmented with
|
||||||
but needed for interacting with the kernel.
|
book-keeping to guarantee memory-safety, and so cannot be stored in registers.
|
||||||
|
See [mu.md](mu.md) for details, but in brief:
|
||||||
|
- You need `addr` values to access data they point to.
|
||||||
|
- You can't store `addr` values in other types. They're temporary.
|
||||||
|
- You can store `handle` values in other types.
|
||||||
|
- To convert `handle` to `addr`, use `lookup`.
|
||||||
|
- Reclaiming memory (currently unimplemented) invalidates all `addr`
|
||||||
|
values.
|
||||||
|
|
||||||
- Arrays: size-prefixed regions of memory containing multiple elements of a
|
- Arrays: size-prefixed regions of memory containing multiple elements of a
|
||||||
single type. Contents are preceded by 4 bytes (32 bits) containing the
|
single type. Contents are preceded by 4 bytes (32 bits) containing the
|
||||||
|
@ -24,185 +31,189 @@
|
||||||
|
|
||||||
Invariant: 0 <= `read` <= `write` <= `size`
|
Invariant: 0 <= `read` <= `write` <= `size`
|
||||||
|
|
||||||
- File descriptors (fd): Low-level 32-bit integers that the kernel uses to
|
Writes to a stream abort if it's full. Reads to a stream abort if it's
|
||||||
track files opened by the program.
|
empty.
|
||||||
|
|
||||||
- File: 32-bit value containing either a fd or an address to a stream (fake
|
- Graphemes: 32-bit fragments of utf-8 that encode a single Unicode code-point.
|
||||||
file).
|
- Code-points: 32-bit integers representing a Unicode character.
|
||||||
|
|
||||||
- Buffered files (buffered-file): Contain a file descriptor and a stream for
|
### Functions
|
||||||
buffering reads/writes. Each `buffered-file` must exclusively perform either
|
|
||||||
reads or writes.
|
|
||||||
|
|
||||||
### 'system calls'
|
The most useful functions from 400.mu and later .mu files. Look for definitions
|
||||||
|
(using `ctags`) to see type signatures.
|
||||||
|
|
||||||
As I said at the top, a primary design goal of SubX (and Mu more broadly) is
|
- `abort`: print a message in red on the bottom left of the screen and halt
|
||||||
to explore ways to turn arbitrary manual tests into reproducible automated
|
|
||||||
tests. SubX aims for this goal by baking testable interfaces deep into the
|
|
||||||
stack, at the OS syscall level. The idea is that every syscall that interacts
|
|
||||||
with hardware (and so the environment) should be *dependency injected* so that
|
|
||||||
it's possible to insert fake hardware in tests.
|
|
||||||
|
|
||||||
But those are big goals. Here are the syscalls I have so far:
|
|
||||||
|
|
||||||
- `write`: takes two arguments, a file `f` and an address to array `s`.
|
|
||||||
|
|
||||||
Comparing this interface with the Unix `write()` syscall shows two benefits:
|
|
||||||
|
|
||||||
1. SubX can handle 'fake' file descriptors in tests.
|
|
||||||
|
|
||||||
1. `write()` accepts buffer and its size in separate arguments, which
|
|
||||||
requires callers to manage the two separately and so can be error-prone.
|
|
||||||
SubX's wrapper keeps the two together to increase the chances that we
|
|
||||||
never accidentally go out of array bounds.
|
|
||||||
|
|
||||||
- `read`: takes two arguments, a file `f` and an address to stream `s`. Reads
|
|
||||||
as much data from `f` as can fit in (the free space of) `s`.
|
|
||||||
|
|
||||||
Like with `write()`, this wrapper around the Unix `read()` syscall adds the
|
|
||||||
ability to handle 'fake' file descriptors in tests, and reduces the chances
|
|
||||||
of clobbering outside array bounds.
|
|
||||||
|
|
||||||
One bit of weirdness here: in tests we do a redundant copy from one stream
|
|
||||||
to another. See [the comments before the implementation](http://akkartik.github.io/mu/html/060read.subx.html)
|
|
||||||
for a discussion of alternative interfaces.
|
|
||||||
|
|
||||||
- `stop`: takes two arguments:
|
|
||||||
- `ed` is an address to an _exit descriptor_. Exit descriptors allow us to
|
|
||||||
`exit()` the program in production, but return to the test harness within
|
|
||||||
tests. That allows tests to make assertions about when `exit()` is called.
|
|
||||||
- `value` is the status code to `exit()` with.
|
|
||||||
|
|
||||||
For more details on exit descriptors and how to create one, see [the
|
|
||||||
comments before the implementation](http://akkartik.github.io/mu/html/059stop.subx.html).
|
|
||||||
|
|
||||||
- `new-segment`
|
|
||||||
|
|
||||||
Allocates a whole new segment of memory for the program, discontiguous with
|
|
||||||
both existing code and data (heap) segments. Just a more opinionated form of
|
|
||||||
[`mmap`](http://man7.org/linux/man-pages/man2/mmap.2.html).
|
|
||||||
|
|
||||||
- `allocate`: takes two arguments, an address to allocation-descriptor `ad`
|
|
||||||
and an integer `n`
|
|
||||||
|
|
||||||
Allocates a contiguous range of memory that is guaranteed to be exclusively
|
|
||||||
available to the caller. Returns the starting address to the range in `eax`.
|
|
||||||
|
|
||||||
An allocation descriptor tracks allocated vs available addresses in some
|
|
||||||
contiguous range of memory. The int specifies the number of bytes to allocate.
|
|
||||||
|
|
||||||
Explicitly passing in an allocation descriptor allows for nested memory
|
|
||||||
management, where a sub-system gets a chunk of memory and further parcels it
|
|
||||||
out to individual allocations. Particularly helpful for (surprise) tests.
|
|
||||||
|
|
||||||
- ... _(to be continued)_
|
|
||||||
|
|
||||||
I will continue to import syscalls over time from [the old Mu VM in the parent
|
|
||||||
directory](https://github.com/akkartik/mu), which has experimented with
|
|
||||||
interfaces for the screen, keyboard, mouse, disk and network.
|
|
||||||
|
|
||||||
### primitives built atop system calls
|
|
||||||
|
|
||||||
_(Compound arguments are usually passed in by reference. Where the results are
|
|
||||||
compound objects that don't fit in a register, the caller usually passes in
|
|
||||||
allocated memory for it.)_
|
|
||||||
|
|
||||||
#### assertions for tests
|
#### assertions for tests
|
||||||
- `check-ints-equal`: fails current test if given ints aren't equal
|
|
||||||
- `check-stream-equal`: fails current test if stream doesn't match string
|
- `check`: fails current test if given boolean is false (`= 0`).
|
||||||
|
- `check-not`: fails current test if given boolean isn't false (`!= 0`).
|
||||||
|
- `check-ints-equal`: fails current test if given ints aren't equal.
|
||||||
|
- `check-strings-equal`: fails current test if given strings have different bytes.
|
||||||
|
- `check-stream-equal`: fails current test if stream's data doesn't match
|
||||||
|
string in its entirety. Ignores the stream's read index.
|
||||||
|
- `check-array-equal`: fails if an array's elements don't match what's written
|
||||||
|
in a whitespace-separated string.
|
||||||
- `check-next-stream-line-equal`: fails current test if next line of stream
|
- `check-next-stream-line-equal`: fails current test if next line of stream
|
||||||
until newline doesn't match string
|
until newline doesn't match string.
|
||||||
|
|
||||||
#### error handling
|
|
||||||
- `error`: takes three arguments, an exit-descriptor, a file and a string (message)
|
|
||||||
|
|
||||||
Prints out the message to the file and then exits using the provided
|
|
||||||
exit-descriptor.
|
|
||||||
|
|
||||||
- `error-byte`: like `error` but takes an extra byte value that it prints out
|
|
||||||
at the end of the message.
|
|
||||||
|
|
||||||
#### predicates
|
#### predicates
|
||||||
- `kernel-string-equal?`: compares a kernel string with a string
|
|
||||||
- `string-equal?`: compares two strings
|
- `handle-equal?`: checks if two handles point at the identical address. Does
|
||||||
- `stream-data-equal?`: compares a stream with a string
|
not compare payloads at their respective addresses.
|
||||||
|
|
||||||
|
- `array-equal?`: checks if two arrays (of ints only for now) have identical
|
||||||
|
elements.
|
||||||
|
|
||||||
|
- `string-equal?`: compares two strings.
|
||||||
|
- `stream-data-equal?`: compares a stream with a string.
|
||||||
- `next-stream-line-equal?`: compares with string the next line in a stream, from
|
- `next-stream-line-equal?`: compares with string the next line in a stream, from
|
||||||
`read` index to newline
|
`read` index to newline.
|
||||||
|
|
||||||
- `slice-empty?`: checks if the `start` and `end` of a slice are equal
|
- `slice-empty?`: checks if the `start` and `end` of a slice are equal.
|
||||||
- `slice-equal?`: compares a slice with a string
|
- `slice-equal?`: compares a slice with a string.
|
||||||
- `slice-starts-with?`: compares the start of a slice with a string
|
- `slice-starts-with?`: compares the start of a slice with a string.
|
||||||
- `slice-ends-with?`: compares the end of a slice with a string
|
|
||||||
|
|
||||||
#### writing to disk
|
- `stream-full?`: checks if a write to a stream would abort.
|
||||||
- `write`: string -> file
|
- `stream-empty?`: checks if a read from a stream would abort.
|
||||||
- Can also be used to cat a string into a stream.
|
|
||||||
- Will abort the entire program if destination is a stream and doesn't have
|
|
||||||
enough room.
|
|
||||||
- `write-stream`: stream -> file
|
|
||||||
- Can also be used to cat one stream into another.
|
|
||||||
- Will abort the entire program if destination is a stream and doesn't have
|
|
||||||
enough room.
|
|
||||||
- `write-slice`: slice -> stream
|
|
||||||
- Will abort the entire program if there isn't enough room in the
|
|
||||||
destination stream.
|
|
||||||
- `append-byte`: int -> stream
|
|
||||||
- Will abort the entire program if there isn't enough room in the
|
|
||||||
destination stream.
|
|
||||||
- `append-byte-hex`: int -> stream
|
|
||||||
- textual representation in hex, no '0x' prefix
|
|
||||||
- Will abort the entire program if there isn't enough room in the
|
|
||||||
destination stream.
|
|
||||||
- `print-int32`: int -> stream
|
|
||||||
- textual representation in hex, including '0x' prefix
|
|
||||||
- Will abort the entire program if there isn't enough room in the
|
|
||||||
destination stream.
|
|
||||||
- `write-buffered`: string -> buffered-file
|
|
||||||
- `write-slice-buffered`: slice -> buffered-file
|
|
||||||
- `flush`: buffered-file
|
|
||||||
- `write-byte-buffered`: int -> buffered-file
|
|
||||||
- `print-byte-buffered`: int -> buffered-file
|
|
||||||
- textual representation in hex, no '0x' prefix
|
|
||||||
- `print-int32-buffered`: int -> buffered-file
|
|
||||||
- textual representation in hex, including '0x' prefix
|
|
||||||
|
|
||||||
#### reading from disk
|
#### arrays
|
||||||
- `read`: file -> stream
|
|
||||||
- Can also be used to cat one stream into another.
|
- `populate`: allocates space for `n` objects of the appropriate type.
|
||||||
- Will silently stop reading when destination runs out of space.
|
- `copy-array`: allocates enough space and writes out a copy of an array of
|
||||||
- `read-byte-buffered`: buffered-file -> byte
|
some type.
|
||||||
- `read-line-buffered`: buffered-file -> stream
|
- `slice-to-string`: allocates space for an array of bytes and copies the
|
||||||
- Will abort the entire program if there isn't enough room.
|
slice into it.
|
||||||
|
|
||||||
|
#### streams
|
||||||
|
|
||||||
|
- `populate-stream`: allocates space in a stream for `n` objects of the
|
||||||
|
appropriate type.
|
||||||
|
- `write-to-stream`: writes arbitrary objects to a stream of the appropriate
|
||||||
|
type.
|
||||||
|
- `read-from-stream`: reads arbitrary objects from a stream of the appropriate
|
||||||
|
type.
|
||||||
|
- `stream-to-array`: allocates just enough space and writes out a stream's
|
||||||
|
data between its read index (inclusive) and write index (exclusive).
|
||||||
|
|
||||||
#### non-IO operations on streams
|
|
||||||
- `new-stream`: allocates space for a stream of `n` elements, each occupying
|
|
||||||
`b` bytes.
|
|
||||||
- Will abort the entire program if `n*b` requires more than 32 bits.
|
|
||||||
- `clear-stream`: resets everything in the stream to `0` (except its `size`).
|
- `clear-stream`: resets everything in the stream to `0` (except its `size`).
|
||||||
- `rewind-stream`: resets the read index of the stream to `0` without modifying
|
- `rewind-stream`: resets the read index of the stream to `0` without modifying
|
||||||
its contents.
|
its contents.
|
||||||
|
|
||||||
|
- `write`: writes a string into a stream of bytes. Doesn't support streams of
|
||||||
|
other types.
|
||||||
|
- `write-stream`: concatenates one stream into another.
|
||||||
|
- `write-slice`: writes a slice into a stream of bytes.
|
||||||
|
- `append-byte`: writes a single byte into a stream of bytes.
|
||||||
|
- `append-byte-hex`: writes textual representation of lowest byte in hex to
|
||||||
|
a stream of bytes. Does not write a '0x' prefix.
|
||||||
|
- `read-byte`: reads a single byte from a stream of bytes.
|
||||||
|
|
||||||
#### reading/writing hex representations of integers
|
#### reading/writing hex representations of integers
|
||||||
- `is-hex-int?`: takes a slice argument, returns boolean result in `eax`
|
|
||||||
- `parse-hex-int`: takes a slice argument, returns int result in `eax`
|
|
||||||
- `is-hex-digit?`: takes a 32-bit word containing a single byte, returns
|
|
||||||
boolean result in `eax`.
|
|
||||||
- `from-hex-char`: takes a hexadecimal digit character in `eax`, returns its
|
|
||||||
numeric value in `eax`
|
|
||||||
- `to-hex-char`: takes a single-digit numeric value in `eax`, returns its
|
|
||||||
corresponding hexadecimal character in `eax`
|
|
||||||
|
|
||||||
#### tokenization
|
- `write-int32-hex`
|
||||||
|
- `hex-int?`: checks if a slice contains an int in hex. Supports '0x' prefix.
|
||||||
|
- `parse-hex-int`: reads int in hex from string
|
||||||
|
- `parse-hex-int-from-slice`: reads int in hex from slice
|
||||||
|
- `parse-array-of-ints`: reads in multiple ints in hex, separated by whitespace.
|
||||||
|
- `hex-digit?`: checks if byte is in [0, 9] or [a, f] (lowercase only)
|
||||||
|
|
||||||
from a stream:
|
- `write-int32-decimal`
|
||||||
- `next-token`: stream, delimiter byte -> slice
|
- `parse-decimal-int`
|
||||||
- `skip-chars-matching`: stream, delimiter byte
|
- `parse-decimal-int-from-slice`
|
||||||
- `skip-chars-not-matching`: stream, delimiter byte
|
- `parse-decimal-int-from-stream`
|
||||||
|
- `parse-array-of-decimal-ints`
|
||||||
|
- `decimal-digit?`: checks if byte is in [0, 9]
|
||||||
|
|
||||||
from a slice:
|
#### printing to screen
|
||||||
- `next-token-from-slice`: start, end, delimiter byte -> slice
|
|
||||||
- Given a slice and a delimiter byte, returns a new slice inside the input
|
|
||||||
that ends at the delimiter byte.
|
|
||||||
|
|
||||||
- `skip-chars-matching-in-slice`: curr, end, delimiter byte -> new-curr (in `eax`)
|
All screen primitives require a screen object, which can be either the real
|
||||||
- `skip-chars-not-matching-in-slice`: curr, end, delimiter byte -> new-curr (in `eax`)
|
screen on the computer or a fake screen for tests.
|
||||||
|
|
||||||
|
The real screen on the Mu computer can currently display only ASCII characters,
|
||||||
|
though it's easy to import more of the font. There is only one font. All
|
||||||
|
graphemes are 8 pixels wide and 16 pixels tall. These constraints only apply
|
||||||
|
to the real screen.
|
||||||
|
|
||||||
|
- `draw-grapheme`: draws a single grapheme at a given coordinate, with given
|
||||||
|
foreground and background colors.
|
||||||
|
- `render-grapheme`: like `draw-grapheme` and can also handle newlines
|
||||||
|
assuming text is printed left-to-right, top-to-bottom.
|
||||||
|
- `draw-code-point`
|
||||||
|
- `clear-screen`
|
||||||
|
|
||||||
|
- `draw-text-rightward`: draws a single line of text, stopping when it reaches
|
||||||
|
either the provided bound or the right screen margin.
|
||||||
|
- `draw-stream-rightward`
|
||||||
|
- `draw-text-rightward-over-full-screen`: does not provide a bound.
|
||||||
|
- `draw-text-wrapping-right-then-down`: draws multiple lines of text on screen
|
||||||
|
with simplistic word-wrap (no hyphenation) within (x, y) bounds.
|
||||||
|
- `draw-stream-wrapping-right-then-down`
|
||||||
|
- `draw-text-wrapping-right-then-down-over-full-screen`
|
||||||
|
- `draw-int32-hex-wrapping-right-then-down`
|
||||||
|
- `draw-int32-hex-wrapping-right-then-down-over-full-screen`
|
||||||
|
- `draw-int32-decimal-wrapping-right-then-down`
|
||||||
|
- `draw-int32-decimal-wrapping-right-then-down-over-full-screen`
|
||||||
|
|
||||||
|
Similar primitives for writing text top-to-bottom, left-to-right.
|
||||||
|
|
||||||
|
- `draw-text-downward`
|
||||||
|
- `draw-stream-downward`
|
||||||
|
- `draw-text-wrapping-down-then-right`
|
||||||
|
- `draw-stream-wrapping-down-then-right`
|
||||||
|
- `draw-text-wrapping-down-then-right-over-full-screen`
|
||||||
|
- `draw-int32-hex-wrapping-down-then-right`
|
||||||
|
- `draw-int32-hex-wrapping-down-then-right-over-full-screen`
|
||||||
|
- `draw-int32-decimal-wrapping-down-then-right`
|
||||||
|
- `draw-int32-decimal-wrapping-down-then-right-over-full-screen`
|
||||||
|
|
||||||
|
Screens remember the current cursor position.
|
||||||
|
|
||||||
|
- `cursor-position`
|
||||||
|
- `set-cursor-position`
|
||||||
|
- `draw-grapheme-at-cursor`
|
||||||
|
- `draw-code-point-at-cursor`
|
||||||
|
- `draw-cursor`: highlights the current position of the cursor. Programs must
|
||||||
|
pass in the grapheme to draw at the cursor position, and are responsible for
|
||||||
|
clearing the highlight when the cursor moves.
|
||||||
|
- `move-cursor-left`, `move-cursor-right`, `move-cursor-up`, `move-cursor-down`.
|
||||||
|
These primitives always silently fail if the desired movement would go out
|
||||||
|
of screen bounds.
|
||||||
|
- `move-cursor-to-left-margin-of-next-line`
|
||||||
|
- `move-cursor-rightward-and-downward`: move cursor one grapheme to the right
|
||||||
|
|
||||||
|
- `draw-text-rightward-from-cursor`
|
||||||
|
- `draw-text-wrapping-right-then-down-from-cursor`
|
||||||
|
- `draw-text-wrapping-right-then-down-from-cursor-over-full-screen`
|
||||||
|
- `draw-int32-hex-wrapping-right-then-down-from-cursor`
|
||||||
|
- `draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen`
|
||||||
|
- `draw-int32-decimal-wrapping-right-then-down-from-cursor`
|
||||||
|
- `draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen`
|
||||||
|
|
||||||
|
- `draw-text-wrapping-down-then-right-from-cursor`
|
||||||
|
- `draw-text-wrapping-down-then-right-from-cursor-over-full-screen`
|
||||||
|
|
||||||
|
Assertions for tests:
|
||||||
|
|
||||||
|
- `check-screen-row`: compare a screen from the left margin of a given row
|
||||||
|
index with a string. The row index counts downward from 0 at the top of the
|
||||||
|
screen. String can be smaller or larger than a single row, and defines the
|
||||||
|
region of interest. Strings longer than a row wrap around to the left margin
|
||||||
|
of the next screen row. Currently assumes text is printed left-to-right on
|
||||||
|
the screen.
|
||||||
|
- `check-screen-row-from`: compare a fragment of a screen (left to write, top
|
||||||
|
to bottom) starting from a given (x, y) coordinate with an expected string.
|
||||||
|
Currently assumes text is printed left-to-right and top-to-bottom on the
|
||||||
|
screen.
|
||||||
|
- `check-screen-row-in-color`: like `check-screen-row` but:
|
||||||
|
- also compares foreground color
|
||||||
|
- ignores screen locations where the expected string contains spaces
|
||||||
|
- `check-screen-row-in-color-from`
|
||||||
|
- `check-screen-row-in-background-color`
|
||||||
|
- `check-screen-row-in-background-color-from`
|
||||||
|
- `check-background-color-in-screen-row`: unlike previous functions, this
|
||||||
|
doesn't check screen contents, only background color. Ignores background
|
||||||
|
color where expected string contains spaces, and compares background color
|
||||||
|
where expected string does not contain spaces. Never compares the character
|
||||||
|
at any screen location.
|
||||||
|
- `check-background-color-in-screen-row-from`
|
||||||
|
|
Loading…
Reference in New Issue