some updates

This commit is contained in:
~d6 2024-08-03 22:31:46 -04:00
parent 28f27e7fcf
commit ebb6889d48
1 changed files with 78 additions and 5 deletions

View File

@ -29,7 +29,7 @@ There are also 256 bytes of device memory, which are used to interact with the v
There are 32 base values for opcodes: There are 32 base values for opcodes:
0x00 \fB***\fP 0x08 \fBEQU\fP 0x10 \fBLDZ\fP 0x18 \fBADD\fP 0x00 \fBBRK*\fP 0x08 \fBEQU\fP 0x10 \fBLDZ\fP 0x18 \fBADD\fP
0x01 \fBINC\fP 0x09 \fBNEQ\fP 0x11 \fBSTZ\fP 0x19 \fBSUB\fP 0x01 \fBINC\fP 0x09 \fBNEQ\fP 0x11 \fBSTZ\fP 0x19 \fBSUB\fP
0x02 \fBPOP\fP 0x0a \fBGTH\fP 0x12 \fBLDR\fP 0x1a \fBMUL\fP 0x02 \fBPOP\fP 0x0a \fBGTH\fP 0x12 \fBLDR\fP 0x1a \fBMUL\fP
0x03 \fBNIP\fP 0x0b \fBLTH\fP 0x13 \fBSTR\fP 0x1b \fBDIV\fP 0x03 \fBNIP\fP 0x0b \fBLTH\fP 0x13 \fBSTR\fP 0x1b \fBDIV\fP
@ -40,9 +40,9 @@ There are 32 base values for opcodes:
The "complete" opcode's value can be derived by combining the base value with its flags. The "complete" opcode's value can be derived by combining the base value with its flags.
For example, \fBADD2k\fP is \fB(0x18 | 0x20 | 0x80)\fP = \fB0xb8\fP. For example, \fBADD2k\fP is \fB(ADD | 2 | k)\fP = \fB(0x18 | 0x20 | 0x80)\fP = \fB0xb8\fP.
Unlike other opcodes, \fB0x00\fP is contextual. Its meaning depends on the \fImode\fP bits provided: Unlike other opcodes, \fB0x00\fP (\fBBRK*\fP) is contextual: its meaning depends on the \fImode\fP bits provided:
0x00 \fBBRK\fP 0x80 \fBLIT\fP 0x00 \fBBRK\fP 0x80 \fBLIT\fP
0x20 \fBJCI\fP 0xa0 \fBLIT2\fP 0x20 \fBJCI\fP 0xa0 \fBLIT2\fP
@ -51,6 +51,23 @@ Unlike other opcodes, \fB0x00\fP is contextual. Its meaning depends on the \fImo
.SH STACK EFFECTS .SH STACK EFFECTS
.BR
.SS NOTATION
Given a stack effect \fB( a^ b^ c^ -- c^ a^ b^ )\fP here is what each symbol means:
\fB(\fP and \fB)\fP are comment delimiters
\fBa^\fP, \fBb^\fP, and \fBc^\fP are values on the stack
\fB^\fP indicates that each value is a \fIbyte\fP (\fB*\fP would indicate \fIshort\fP)
\fB--\fP separates the "before" and "after" of the stack effect
The effect here is to move the top byte of the stack below the next two bytes, which could be achieved with \fBROT ROT\fP.
By default stack effects describe the effect on \fBwst\fP. When \fBrst\fP is involved we use \fB[]\fP to differentiate the stacks. For example \fB( a* [b*] -- a+1* [b+1*] )\fP will increment the top short of both \fBwst\fP and \fBrst\fP.
.SS EFFECTS AND MODES
Regular instructions have a single stack effect which is modified in a predictable way by any additional modes. Regular instructions have a single stack effect which is modified in a predictable way by any additional modes.
For example the generic effect for \fBADD\fP is ( x y -- x+y ). The eight combinations of modes have the following effects: For example the generic effect for \fBADD\fP is ( x y -- x+y ). The eight combinations of modes have the following effects:
@ -70,6 +87,10 @@ In \fIreturn\fP mode the stacks are reversed. Effects on \fBwst\fP will instead
In \fIkeep\fP mode all the values on the left-hand side of the stack effect will also appear on the right-hand side before the outputs. For example, \fBSWP\fP is \fB(x y -- y x)\fP but \fBSWPk\fP is \fB(x y -- x y y x)\fP. In \fIkeep\fP mode all the values on the left-hand side of the stack effect will also appear on the right-hand side before the outputs. For example, \fBSWP\fP is \fB(x y -- y x)\fP but \fBSWPk\fP is \fB(x y -- x y y x)\fP.
.SS TERMINOLOGY
We consider the top of the stack to be the first value of the stack, and count back from there. For example, given the stack effect \fB( a b c -- )\fP we would say that \fBc\fP is the top of the stack, \fBb\fP is the second value (second from the top), and \fBa\fP is the third value (third from the top).
.SH REGULAR INSTRUCTIONS .SH REGULAR INSTRUCTIONS
.BR .BR
@ -77,66 +98,100 @@ In \fIkeep\fP mode all the values on the left-hand side of the stack effect will
.SS INC .SS INC
( x -- x+1 ) ( x -- x+1 )
Increment the top value of the stack by 1.
Overflow will be truncated, so \fB#ff INC\fP will evaluate to \fB0x00\fP. Overflow will be truncated, so \fB#ff INC\fP will evaluate to \fB0x00\fP.
.SS POP .SS POP
( x -- ) ( x -- )
Remove the top value of the stack.
\fBPOPk\fP is guaranteed to have no effect (it will not change the stack). \fBPOPk\fP is guaranteed to have no effect (it will not change the stack).
.SS NIP .SS NIP
( x y -- y ) ( x y -- y )
Remove the second value of the stack.
.SS SWP .SS SWP
( x y -- y x ) ( x y -- y x )
Swap the top two values of the stack.
.SS ROT .SS ROT
( x y z -- y z x ) ( x y z -- y z x )
Rotate the top three values of the stack. The lowest becomes the top and the others are each shifted down one place.
.SS DUP .SS DUP
( x -- x x ) ( x -- x x )
Place a copy of the top value of the stack on top of the stack.
.SS OVR .SS OVR
( x y -- x y x ) ( x y -- x y x )
Place a copy of the second value of the stack on top of the stack.
.SS EQU .SS EQU
( x y -- x==y^ ) ( x y -- x==y^ )
Test whether the top two values of the stack are equal.
Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP). Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
.SS NEQ .SS NEQ
( x y -- x!=y^ ) ( x y -- x!=y^ )
Test whether the top two values of the stack are not equal.
Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP). Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
.SS GTH .SS GTH
( x y -- x>y^ ) ( x y -- x>y^ )
Test whether the second value of the stack is greater than the top.
Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP). Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
.SS LTH .SS LTH
( x y -- x<y^ ) ( x y -- x<y^ )
Test whether the second value of the stack is less than the top.
Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP). Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
.SS JMP .SS JMP
( x -- ; pc <- x ) ( x -- ; pc <- x )
Jump to a location.
The program counter (\fIpc\fP) is unconditionally updated. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP). The program counter (\fIpc\fP) is unconditionally updated. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP).
It is common to \fBJMP\fP with boolean bytes (0-1) to handle simple conditionals. For example:
@max ( x^ y^ -- max^ ) GTHk JMP SWP POP JMP2r
.SS JCN .SS JCN
( x bool^ -- ; pc <- x if bool ) ( x bool^ -- ; pc <- x if bool )
Jump to a location when a condition is true.
The program counter (\fIpc\fP) is updated when \fIbool\fP is non-zero. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP). The program counter (\fIpc\fP) is updated when \fIbool\fP is non-zero. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP).
.SS JSR .SS JSR
( x -- [pc+1*] ) ( x -- [pc+1*] )
Jump to a location, saving a reference to the current program counter.
Store the next address to execute before unconditionally updating the program counter (\fIpc\fP). This instruction is usually used to invoke subroutines, which use the \fBJMP2r\fP to return. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP). Store the next address to execute before unconditionally updating the program counter (\fIpc\fP). This instruction is usually used to invoke subroutines, which use the \fBJMP2r\fP to return. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP).
.SS STH .SS STH
( x -- [x] ) ( x -- [x] )
Move the top value of the stack to the return stack.
.SS LDZ .SS LDZ
( zp^ -- x ) ( zp^ -- x )
@ -188,21 +243,29 @@ Writing to some ports may have an effect on the underlying VM; in other cases it
.SS ADD .SS ADD
( x y -- x+y ) ( x y -- x+y )
Add the top two values of the stack.
Overflow will be truncated, so \fB#ff #03 ADD\fP will evaluate to \fB0x02\fP. Overflow will be truncated, so \fB#ff #03 ADD\fP will evaluate to \fB0x02\fP.
.SS SUB .SS SUB
( x y -- x-y ) ( x y -- x-y )
Subtract the top of the stack from the second value of the stack.
Underflow will be truncated, so \fB#01 #03 SUB\fP will evaluate to \fB0xfe\fP. Underflow will be truncated, so \fB#01 #03 SUB\fP will evaluate to \fB0xfe\fP.
.SS MUL .SS MUL
( x y -- xy ) ( x y -- xy )
Multiply the top two values of the stack.
Overflow will be truncated, so \fB#11 #11 MUL\fP will evaluate to \fB0x21\fP. Overflow will be truncated, so \fB#11 #11 MUL\fP will evaluate to \fB0x21\fP.
.SS DIV .SS DIV
( x y -- x/y ) ( x y -- x/y )
Divide the second value of the stack by the top of the stack.
\fBDIV\fP implements \fIEuclidean division\fP, which is also known as \fIinteger division\fP. It returns whole numbers, so \fB#08 #09 DIV\fP evaluates to \fB0x00\fP. \fBDIV\fP implements \fIEuclidean division\fP, which is also known as \fIinteger division\fP. It returns whole numbers, so \fB#08 #09 DIV\fP evaluates to \fB0x00\fP.
Division by zero will return zero (instead of signaling an error). Division by zero will return zero (instead of signaling an error).
@ -214,15 +277,23 @@ There is no \fIremainder\fP instruction, but the phrase \fBDIVk MUL SUB\fP can b
.SS AND .SS AND
( x y -- x&y ) ( x y -- x&y )
Compute the bitwise union of the top two values of the stack.
.SS ORA .SS ORA
( x y -- x|y ) ( x y -- x|y )
Compute the bitwise intersection of the top two values of the stack.
.SS EOR .SS EOR
( x y -- x^y ) ( x y -- x^y )
Compute the bitwise exclusive-or (\fIxor\fP) of the top two values of the stack.
.SS SFT .SS SFT
( x rl^ -- (x>>l)<<r ) ( x rl^ -- (x>>l)<<r )
Compute a bit shift of the second value of the stack; the directions and distances are determined by the top value of the stack.
Given a byte \fIrl\fP consisting of a low nibble (\fIl\fP) and a high nibble (\fIh\fP), this instruction shifts \fIx\fP left by \fIl\fP and then right by \fIr\fP. Given a byte \fIrl\fP consisting of a low nibble (\fIl\fP) and a high nibble (\fIh\fP), this instruction shifts \fIx\fP left by \fIl\fP and then right by \fIr\fP.
Right shifts are unsigned (they introduce zero bits); there are no signed shifts. Right shifts are unsigned (they introduce zero bits); there are no signed shifts.
@ -259,6 +330,8 @@ These instructions are created by the assembler from special syntax:
.SS LIT, LIT2, LITr, and LIT2r .SS LIT, LIT2, LITr, and LIT2r
Push a literal value on the stack.
The "literal" instructions are used to push new data onto the stacks. They interpret the next 1-2 bytes of the ROM (\fIwx\fP, \fIwxyz\fP) as data and push it onto the corresponding stack: The "literal" instructions are used to push new data onto the stacks. They interpret the next 1-2 bytes of the ROM (\fIwx\fP, \fIwxyz\fP) as data and push it onto the corresponding stack:
\fBLIT\fP ( -- wx^ ) push literal byte \fIwx\fP onto the \fBwst\fP \fBLIT\fP ( -- wx^ ) push literal byte \fIwx\fP onto the \fBwst\fP