updated spec
This commit is contained in:
parent
813cc5910c
commit
496b55b45b
246
console.txt
246
console.txt
|
@ -1,78 +1,212 @@
|
|||
CONSOLE DEVICE
|
||||
|
||||
0x10 vector* 0x18 out*
|
||||
0x11 (vector) 0x19 err*
|
||||
0x12 read 0x1a --
|
||||
0x13 exec arguments 0x1b --
|
||||
0x14 (exec arguments) 0x1c --
|
||||
0x15 exec mode 0x1d --
|
||||
0x16 exec action* 0x1e --
|
||||
0x17 input type 0x1f --
|
||||
0x10 vector 0x18 stdout+
|
||||
0x11 (vector) 0x19 stderr+
|
||||
0x12 stdin 0x1a send+
|
||||
0x13 0x1b
|
||||
0x14 proc-get 0x1c param
|
||||
0x15 host-get 0x1d (param)
|
||||
0x16 0x1e opts
|
||||
0x17 type 0x1f action+
|
||||
|
||||
(* denotes a register that causes an immediate effect)
|
||||
(+ denotes a register that causes an immediate effect)
|
||||
|
||||
vector (0x10) contains an address to jump to when input is available.
|
||||
when the vector fires one byte can be read from the read port (0x12),
|
||||
and its meaning is defined by the input type (0x17).
|
||||
vector ports (0x10-0x11) contain an address to jump to when input is
|
||||
available. when the vector fires one byte can be read from the read
|
||||
port (0x12), and its meaning is defined by the type (0x17).
|
||||
|
||||
the read port (0x12) contains one byte of data to be read. it usually
|
||||
occurs as the result of data being available on stdin, but may have
|
||||
other meanings (such as an exit code from a finished process).
|
||||
the stdin port (0x12) contains one byte of data to be read. the byte
|
||||
represents input read from the emulator's stdin.
|
||||
|
||||
the meaning of exec args (0x13) depends on which action it is used with:
|
||||
- 0x00 - unused
|
||||
- 0x01 - address of a command string (e.g. "gcc -o demo demo.c")
|
||||
- 0x02 - address of an env. variable name (e.g. "TERM")
|
||||
- 0x03 - address of an env. variable name=value pair (e.g. "TERM=vt100")
|
||||
- 0x04 - unsigned 16-bit integer (pty height, e.g. 0x0018)
|
||||
- 0x05 - unsigned 16-bit integer (pty width, e.g. 0x0050)
|
||||
- (all strings must be null-terminated)
|
||||
the proc-get port (0x14) contains one byte of data to be read. the byte
|
||||
represents input read from one of the emulator's subprocesses.
|
||||
|
||||
exec mode (0x15) provides context for exec actions (0x16):
|
||||
- lower 2 bits control which child process to use:
|
||||
the host-get port (0x15) contains one byte of data to be read. the byte
|
||||
represents part of a response to a system action.
|
||||
|
||||
the type (0x17) field explains how to interpret calls to the console
|
||||
vector (0x10) and where data can be read from:
|
||||
- 0x00 - no input (n/a)
|
||||
- 0x01 - stdin (stdin)
|
||||
- 0x02 - argument (stdin)
|
||||
- 0x03 - argument spacer (stdin)
|
||||
- 0x04 - argument end (stdin)
|
||||
- 0x05 - host response (host-get)
|
||||
- 0x06 - host response end (host-get)
|
||||
- 0x40 - child 0 exited (host-get contains exit code)
|
||||
- 0x41 - child 1 exited (host-get contains exit code)
|
||||
- 0x42 - child 2 exited (host-get contains exit code)
|
||||
- 0x43 - child 3 exited (host-get contains exit code)
|
||||
- 0x80 - child 0 sent data (proc-get)
|
||||
- 0x81 - child 1 sent data (proc-get)
|
||||
- 0x82 - child 2 sent data (proc-get)
|
||||
- 0x83 - child 3 sent data (proc-get)
|
||||
|
||||
writing a byte to the stdout port (0x18) will send one byte of data to
|
||||
the emulator's stdout.
|
||||
|
||||
writing a byte to the stderr port (0x19) will send one byte of data to
|
||||
the emulator's stderr.
|
||||
|
||||
writing a byte to the send port (0x1a) will send one byte of data to
|
||||
one of the emulator's child processes. the lower 2 bits of the opts
|
||||
port (0x1e) determine which one:
|
||||
- 0x00: child 0
|
||||
- 0x01: child 1
|
||||
- 0x02: child 2
|
||||
- 0x03: child 3
|
||||
|
||||
the param ports (0x1c-0x1d) specify the a value to use as a parameter
|
||||
for a system action (0x1f). the meaning values by action value:
|
||||
- 0x00 - (nop) unused
|
||||
- 0x01 - (execute) command string (e.g. 'gcc -o "demo" demo.c')
|
||||
- 0x02 - (pid) unused
|
||||
- 0x03 - (kill) unused
|
||||
- 0x08 - (pty-set-height) height as u16 integer
|
||||
- 0x09 - (pty-set-width) width as u16 integer
|
||||
- 0x10 - (getenv) name string (e.g. "TERM")
|
||||
- 0x11 - (setenv) assignment string (e.g. "TERM=vt100")
|
||||
- 0x20 - (tty-set-raw) unused
|
||||
- 0x21 - (tty-unset-raw) unused
|
||||
strings must be null-terminated. commands are parsed by /bin/sh -c.
|
||||
|
||||
the opts port (0x1e) specifies options that affect system actions run
|
||||
using the action port (0x1f):
|
||||
- lower 2 bits control which child process to use (when applicable)
|
||||
+ 0x00 - child 0
|
||||
+ 0x01 - child 1
|
||||
+ 0x02 - child 2
|
||||
+ 0x03 - child 3
|
||||
- (next 2 bits unused)
|
||||
- upper 4 bits control which pipes to use with execute:
|
||||
+ 0x80 - use child's pty (implies 0x70)
|
||||
+ 0x40 - read from child's stderr
|
||||
+ 0x20 - read from child's stdout
|
||||
+ 0x10 - write to child's stdin
|
||||
|
||||
exec action (0x16) acts on the exec args address (0x13):
|
||||
the action port (0x1f) specifies which system action to take:
|
||||
- 0x00 - nop: does nothing
|
||||
- 0x01 - execute: reads command string, starts a subprocess
|
||||
- 0x02 - getenv: reads string (NAME) from exec args
|
||||
- 0x03 - setenv: reads string (NAME=value) and updates environment
|
||||
- 0x04 - set-pty-height: reads u16 from exec args, updates winsize
|
||||
- 0x05 - set-pty-width: reads u16 from exec args, updates winsize
|
||||
(getenv data returned using console vector with input type 0x05, 0x06)
|
||||
- 0x02 - pid: responds with child process pid (if any)
|
||||
- 0x03 - kill: shuts down child process
|
||||
- 0x08 - pty-set-height: set a child's pty height
|
||||
- 0x09 - pty-set-width: set a child's pty width
|
||||
- 0x10 - getenv: looks up a name (e.g. TERM) in env, responds with value
|
||||
- 0x11 - setenv: reads an assignment (e.g. TERM=vt100), updates env
|
||||
- 0x20 - tty-set-raw: enable raw mode in emulator's terminal
|
||||
- 0x21 - tty-unset-raw: disable raw mode in emulator's terminal
|
||||
|
||||
the input type (0x17) field explains how to interpret the read port
|
||||
(0x12) when executing the console vector (0x10). these are the input
|
||||
types that are expected:
|
||||
- 0x00 - no input (read port is unused)
|
||||
- 0x01 - stdin
|
||||
- 0x02 - argument
|
||||
- 0x03 - argument spacer (read port is \n)
|
||||
- 0x04 - argument end (read port is \n)
|
||||
- 0x05 - action output
|
||||
- 0x06 - action output end (read port is \n)
|
||||
- 0x40 - child 0 exited (read port is exit code)
|
||||
- 0x41 - child 1 exited (read port is exit code)
|
||||
- 0x42 - child 2 exited (read port is exit code)
|
||||
- 0x43 - child 3 exited (read port is exit code)
|
||||
- 0x81 - child 1
|
||||
- 0x82 - child 2
|
||||
- 0x83 - child 3
|
||||
- (child 0 uses 0x01, i.e. "stdin", instead of 0x80)
|
||||
EXAMPLE PROGRAM FRAGMENTS
|
||||
|
||||
writing a byte to the out port (0x18) will send one byte of data to
|
||||
the standard output. if exec mode (0x15) is non-zero the lower 2 bits
|
||||
will determine which child process to send the output to.
|
||||
( ----------------------------------- )
|
||||
|
||||
writing a byte to the err port (0x19) will send one byte of data to
|
||||
stderr. unlike with the out port (0x18), stderr is never redirected to
|
||||
child processes.
|
||||
1. The following fragment runs `make` and acts based on its exit code:
|
||||
|
||||
|0100 ( -- BRK )
|
||||
;on-console .Console/vector DEO2 ( ; set up console vector callback )
|
||||
... BRK ( ; do other initialization )
|
||||
|
||||
@on-console ( -- BRK )
|
||||
.Console/type DEI #41 ?on-child-exit ( ; 0x41 signals child 1's exit )
|
||||
... BRK ( ; handle other console input )
|
||||
|
||||
@on-child-exit ( -- BRK )
|
||||
.Console/host-get DEI ( ; read child 1's exit code )
|
||||
?{ display-success-msg BRK } ( ; zero exit code means success )
|
||||
display-failure-msg BRK ( ; non-zero exit code means failure )
|
||||
|
||||
@run-make ( -- )
|
||||
;make-cmd .Console/param DEO2 ( ; set up make to run )
|
||||
#01 .Console/opts DEO ( ; use child without pipelines )
|
||||
#01 .Console/action DEO JMP2r ( ; run the command now and return )
|
||||
|
||||
@make-cmd "make $3c ( ; buffer containing cmd to run )
|
||||
|
||||
( ----------------------------------- )
|
||||
|
||||
2. The `mpg123 <path>` commands plays an mp3 from the given path. The
|
||||
following fragment demonstrates part of an mp3 jukebox:
|
||||
|
||||
|0000
|
||||
@running $1
|
||||
|
||||
|0100
|
||||
#01 .running STZ ( ; start running )
|
||||
;on-console .Console/vector DEO2 ( ; set up console vector callback )
|
||||
... BRK ( ; do other initialization and exit )
|
||||
|
||||
@on-console ( -- BRK )
|
||||
.Console/type DEI #04 ?play-jukebox ( ; start jukebox after parsing cmd line )
|
||||
.Console/type DEI #42 ?on-child-exit ( ; 0x42 signals child 2's exit )
|
||||
... BRK ( ; handle other console input )
|
||||
|
||||
@on-child-exit ( -- BRK )
|
||||
.running LDZ ?{ exit } ( ; if we are done, exit )
|
||||
( ; else fall-through to play-jukebox )
|
||||
@play-jukebox ( -- BRK )
|
||||
next-song-path run-mpg123 BRK ( ; play the next song )
|
||||
|
||||
@exit ( -- BRK )
|
||||
#80 .System/halt DEO BRK ( ; exit immediately with code 0 )
|
||||
|
||||
@run-mpg123 ( path* -- )
|
||||
;mpg123-cmd/buf scpy ( ; copy path into cmd buffer )
|
||||
;mpg123-cmd .Console/param DEO2 ( ; set up `mpg123 <path>` cmd to run )
|
||||
#02 .Console/opts DEO ( ; use child 2 without pipelines )
|
||||
#01 .Console/action DEO JMP2r ( ; start playing mp3 now and return )
|
||||
|
||||
@mpg123-cmd "mpg123 20 &buf $100
|
||||
|
||||
@next-song-path ( -- path* ) ... JMP2r ( ; load the next song's path )
|
||||
|
||||
@scpy ( s* dest* -- ) ... JMP2r ( ; copy string, including null, to dest )
|
||||
|
||||
( ----------------------------------- )
|
||||
|
||||
3. The `ispell -a` command accepts a line. It prints "*\n\n" if the input
|
||||
is a correctly-spelled word; otherwise it prints "<some other text>\n\n".
|
||||
|
||||
The following fragment uses `ispell -a` to implement a basic spell checker:
|
||||
|
||||
|0000
|
||||
@spelled-ok? $1
|
||||
@resume $2 ( when set should have signature: -- BRK )
|
||||
|
||||
|0100 ( -- BRK )
|
||||
init-ispell ( ; set up ispell child process )
|
||||
;on-ispell-init .Console/vector DEO2 ( ; set up console vector callback )
|
||||
... BRK ( ; do other initialization )
|
||||
|
||||
@init-ispell ( -- )
|
||||
;ispell-cmd .Console/param DEO2 ( ; set up `ispell -a` to run )
|
||||
#61 .Console/opts DEO ( ; child 1: write to stdin, read from stdout )
|
||||
#01 .Console/action DEO JMP2r ( ; run the command now and return )
|
||||
|
||||
@ispell-cmd "ispell 20 "-a 00 ( ; "ispell -a" )
|
||||
|
||||
@on-ispell-init ( -- BRK )
|
||||
.Console/type DEI #81 EQU ?{ BRK } ( ; 0x81 signals input from child 1 )
|
||||
.Console/proc-get #0a EQU ?{ BRK } ( ; skip ispell's one line banner )
|
||||
;on-ispell-ready .Console/vector DEO2 ( ; finished banner, checker is ready )
|
||||
|
||||
@on-ispell-ready ( -- BRK )
|
||||
.Console/type DEI #81 EQU ?{ BRK } ( ; 0x81 signals input from child 1 )
|
||||
.Console/proc-get LIT "* EQU ( ; line starting with "*" means ok )
|
||||
.spelled-ok STZ ( ; store spelling result )
|
||||
#00 ,on-spell-drain/done STR ( ; drain two lines )
|
||||
;on-ispell-drain .Console/vector DEO2 ( ; ignore rest of line )
|
||||
BRK
|
||||
|
||||
@on-spell-drain ( -- BRK )
|
||||
.Console/type DEI #81 EQU ?{ BRK } ( ; 0x81 signals input from child 1 )
|
||||
.Console/proc-get #0a EQU ?{ BRK } ( ; skip ispell's outupt )
|
||||
LIT [ &done $1 ] ?{ ( ; is this the second newline? )
|
||||
#01 ,on-spell-drain/done STR BRK ( ; no, but next one will be. )
|
||||
}
|
||||
;on-ispell-ready .Console/vector DEO2 ( ; drain finished, checker is ready )
|
||||
!resume ( ; resume whatever we wanted to do after checking )
|
||||
|
||||
@check-spelling ( word* continuation* -- )
|
||||
#01 .Console/opts DEO ( ; act on child 1 )
|
||||
.resume STZ2 ( ; write continuation to resume )
|
||||
&loop LDAk ?{ POP2 JMP2r } ( ; when we read \0 we are done )
|
||||
LDAk .Console/send DEO INC2 !&loop ( ; send byte to child 1 )
|
||||
|
|
Loading…
Reference in New Issue