summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--interpret.e108
-rw-r--r--linux.e69
2 files changed, 166 insertions, 11 deletions
diff --git a/interpret.e b/interpret.e
index f1efd4d..147eeac 100644
--- a/interpret.e
+++ b/interpret.e
@@ -159,17 +159,99 @@
 : unhide-entry dup entry-flags@ 0x80 invert & entry-flags! ;
 
 
+~ (pointer to buffer metadata -- pointer to buffer "physical-start" field)
+: buffer-physical-start ;
+  ~ The physical-start field happens to be the first thing in the metadata, so
+  ~ this is an nop, but it still exists as a word because having it reduces
+  ~ confusion.
+~ (pointer to buffer metadata -- pointer to buffer "physical-length" field)
+: buffer-physical-start 8 + ;
+~ (pointer to buffer metadata -- pointer to buffer "logical-start" field)
+: buffer-logical-start 2 8 * + ;
+~ (pointer to buffer metadata -- pointer to buffer "logical-length" field)
+: buffer-logical-length 3 8 * + ;
+~ (pointer to input buffer metadata -- pointer to input buffer "refill" field)
+: input-buffer-refill 4 8 * + ;
+~ (pointer to input buffer metadata
+~  -- pointer to input buffer "next-source" field)
+: input-buffer-next-source 5 8 * + ;
+
+~   Given an initialized buffer (input or otherwise), sets its logical-start
+~ and logical-length fields to indicate the buffer is empty. This relies on
+~ the buffer having a backing store attached, but does not alter the backing
+~ store or its contents.
+~
+~ (pointer to buffer metadata --)
+: clear-buffer
+  dup buffer-physical-start @ swap
+  ~ (address of backing store, metadata pointer)
+  dup 3unroll
+  ~ (metadata pointer, address of backing store, metadata pointer)
+  buffer-logical-start !
+  buffer-logical-length 0 swap ! ;
+
+
+~   Sets all fields in an input buffer metadata structure to zero,
+~ effectively detaching and leaking any backing store that had been attached
+~ to it. Suitable for use during initialization.
+~
+~ (pointer to input buffer metadata --)
+: zero-input-buffer-metadata
+  dup buffer-physical-start 0 swap !
+  dup buffer-physical-length 0 swap !
+  dup buffer-logical-start 0 swap !
+  dup buffer-logical-length 0 swap !
+  dup input-buffer-refill 0 swap !
+  ~ Notice the absence of a dup this time.
+  input-buffer-next-source 0 swap ! ;
+
+
+~   Allocates input-buffer metadata, with no backing store attached.
+~ Initializes the metadata to all zeroes.
+~
+~ (-- pointer to input buffer metadata)
+: allocate-input-buffer-metadata
+  6 8 * allocate
+  dup zero-input-buffer-metadata ;
+
+
+~   Allocates input buffer metadata and a backing store, in one operation.
+~ Points the metadata to the backing store.
+~
+~ (buffer capacity in bytes -- pointer to input buffer metadata)
+: allocate-input-buffer
+  dup 6 8 * + allocate
+  dup zero-input-buffer-metadata
+  ~ (capacity in bytes, metadata pointer)
+  dup dup 6 8 * +
+  ~ (capacity in bytes, metadata pointer, metadata pointer, physical start)
+  swap buffer-physical-start !
+  ~ (capacity in bytes, metadata pointer)
+  dup 3unroll buffer-physical-length !
+  ~ (metadata pointer)
+  dup clear-buffer ;
+
+
+~   Sets the backing store of an input buffer to point at a null-teriminated
+~ string and read from it.
+~
+~ TODO are these backwards
+~ (string pointer, pointer to buffer metadata --)
+: attach-string-to-input-buffer
+  swap
+  ~ (string pointer, metadata pointer)
+  2dup buffer-physical-start !
+  ~ (string pointer, metadata pointer)
+  2dup buffer-logical-start !
+  ~ (string pointer, metadata pointer)
+  swap stringlen swap
+  ~ (string length, metadata pointer)
+  2dup buffer-physical-length !
+  ~ (string length, metadata pointer)
+  buffer-logical-length ! ;
+
+
 ~ TODO
-~ buffer-physical-start                                 0000001000018240
-~ buffer-physical-length                                0000001000018270
-~ buffer-logical-start                                  00000010000182c0
-~ buffer-logical-length                                 0000001000018308
-~ input-buffer-refill                                   0000001000018350
-~ clear-buffer                                          0000001000018398
-~ zero-input-buffer-metadata                            0000001000018428
-~ allocate-input-buffer-metadata                        0000001000018548
-~ allocate-input-buffer                                 00000010000185b0
-~ attach-string-to-input-buffer                         0000001000018688
 ~ main-input-buffer-metadata                            0000001000018738 I raw
 ~ main-input-buffer                                     0000001000018788 asm
 ~ consume-from                                          00000010000187c0
@@ -185,7 +267,11 @@
 ~ dropstring-with-result                                0000001000018f80
 ~ accumulate-string                                     0000001000018fc8
 ~ word                                                  00000010000194a0
-~ find                                                  00000010000195f0
+
+
+~ (string pointer -- entry pointer or 0)
+: find latest swap find-in ;
+
 
 ~ (character -- 1 for true or 0 for false)
 : is-alphanumeric
diff --git a/linux.e b/linux.e
new file mode 100644
index 0000000..ce0b9b7
--- /dev/null
+++ b/linux.e
@@ -0,0 +1,69 @@
+~ ~~~~~~~~~~~~~~~~~~
+~ ~~ System calls ~~
+~ ~~~~~~~~~~~~~~~~~~
+~
+~   The kernel preserves every register except rax, rcx, and r11. The system
+~ call number goes in rax, as does the return value. Parameters go in rdi,
+~ rsi, rdx, r10, r8, and r9, in that order. [SysV] A.2.1.
+~
+~   Notice that rsi is our control stack, so we have to save it (for
+~ syscalls with at least two parameters). We can use the value stack to do
+~ that, since rsp is preserved. We don't save other registers because our
+~ caller should do that, if it cares.
+~
+
+~   This does the Linux exit() system call, passing it an exit code taken
+~ from the stack. It does not return.
+~
+~ (exit code -- *)
+: sys-exit
+  [ here @
+    60 :rax mov-reg64-imm64      ~ syscall number
+    :rdi pop-reg64               ~ exit code
+    syscall
+
+    ~ In the event we're still here, let's minimize confusion.
+    hlt
+
+    ~ This one, uniquely, doesn't need to be followed by the "next" macro. It
+    ~ is, though, since ;asm does that anyway.
+    here ! ] ;asm
+
+
+~   This does the Linux write() system call, passing it an address from the
+~ top of the stack and a length from the second position on the stack. It
+~ writes to file descriptor 1, which is stdout.
+~
+~   For our length parameter, we can pop directly from the stack into rdx,
+~ which directly becomes the syscall parameter. For our address parameter,
+~ the syscall wants it in rsi, which we also care about, so we have to do a
+~ little juggling.
+~
+~ (length to write, base address -- *)
+: sys-write
+  [ here @
+    :rcx pop-reg64               ~ address from stack
+    :rdx pop-reg64               ~ length from stack, passed directly
+    :rsi push-reg64              ~ save rsi
+    1 :rax mov-reg64-imm64       ~ syscall number
+    1 :rdi mov-reg64-imm64       ~ file descriptor
+    :rcx :rsi mov-reg64-reg64    ~ pass address
+    syscall
+    :rsi pop-reg64               ~ restore rsi
+    here ! ] ;asm
+
+
+~ (length to read, base address -- *)
+: sys-read
+  [ here @
+    :rcx pop-reg64               ~ address from stack
+    :rdx pop-reg64               ~ length from stack, passed directly
+    :rsi push-reg64              ~ save rsi
+    0 :rax mov-reg64-imm64       ~ syscall number
+    0 :rdi mov-reg64-imm64       ~ file descriptor
+    :rcx :rsi mov-reg64-reg64    ~ pass address
+    syscall
+    :rsi pop-reg64               ~ restore rsi
+    :rax push-reg64              ~ return length
+    here ! ] ;asm
+