Code: Select all
code | nickname | args | operation
------+----------------+-------+-------------------------------------
00-0F | LOADL quick | 0 | left = <quick>
10-1F | LOADR quick | 0 | right = <quick>
20-2F | STORE quick | 0 | <quick> = left
30-3F | PUSH quick | 0 | push <quick>
40-4F | LOADL qimm | 0 | left = <qimm>
50-5F | LOADR qimm | 0 | right = <qimm>
60-6F | PUSH qimm | 0 | push <qimm>
70-7F | ADD qimm | 0 | left = left + <qimm>
------+----------------+-------+-------------------------------------
code | nickname | args | operation
------+----------------+-------+-------------------------------------
80 | (illegal) | --- | (illegal)
81 | LOADL near | 1 | left = <near>
82 | LOADL far | 2 | left = <far>
83 | LOADR near | 1 | right = <near>
84 | LOADR far | 2 | right = <far>
85 | STORE near | 1 | <near> = left
86 | STORE far | 2 | <far> = left
87 | PUSH near | 1 | push <near>
88 | PUSH far | 2 | push <far>
89 | BYTE LOADL imm1| 1 | left = (int8)<imm1>
8A | LOADL imm2 | 2 | left = <imm2>
8B | BYTE LOADR imm1| 1 | right = (int8)<imm1>
8C | LOADR imm2 | 2 | right = <imm2>
8D | BYTE PUSH imm1 | 1 | push (int8)<imm1>
8E | PUSH imm2 | 2 | push <imm2>
8F | BYTE ADD imm1 | 1 | left = left + (int8)<imm1>
90 | ADD imm2 | 2 | left = left + <imm2>
91-9F | (illegal) | --- | (illegal)
------+----------------+-------+-------------------------------------
code | nickname | args | operation
------+----------------+-------+-------------------------------------
A0 | BYTE LOADL far | 2 | left = (uint8)<far>
A1 | BYTE LOADR far | 2 | right = (uint8)<far>
A2 | BYTE STORE far | 2 | (uint8)<far> = left
A3 | BYTE PUSH far | 2 | push (uint8)<far>
A4 | LOADL abs | 2 | left = <abs>
A5 | BYTE LOADL abs | 2 | left = (uint8)<abs>
A6 | LOADR abs | 2 | right = <abs>
A7 | BYTE LOADR abs | 2 | right = (uint8)<abs>
A8 | STORE abs | 2 | <abs> = left
A9 | BYTE STORE abs | 2 | (uint8)<abs> = left
AA | PUSH abs | 2 | push <abs>
AB | BYTE PUSH abs | 2 | push (uint8)<abs>
AC | CALL abs | 2 | call <abs>
AD | COPY imm2 | 2 | copy <imm2> bytes from *left to *right
AE | UNSTACK imm1 | 1 | stackptr = stackptr + (uint8)<imm1>
AF | UNSTACK imm2 | 2 | stackptr = stackptr + <imm2>
------+----------------+-------+-------------------------------------
code | nickname | args | operation
------+----------------+-------+-------------------------------------
B0 | DEREF | 0 | left = *left
B1 | POPSTORE | 0 | pop right; *right = left
B2 | NOP | 0 | no operation
B3 | PUSHL | 0 | push left
B4 | POPR | 0 | pop right
B5 | MULT | 0 | left = left * right
B6 | SDIV | 0 | left = (int16)left / (int16)right
B7 | LONG (prefix) | var. | (prefix for 32-bit instructions)
B8 | UDIV | 0 | left = (uint16)left / (uint16)right
B9 | SMOD | 0 | left = (int16)left % (int16)right
BA | UMOD | 0 | left = (uint16)left % (uint16)right
BB | ADD | 0 | left = left + right
BC | SUB | 0 | left = left - right
BD | LSHIFT | 0 | left = left << right
BE | URSHIFT | 0 | left = (uint16)left >> right
BF | SRSHIFT | 0 | left = (int16)left >> right
------+----------------+-------+-------------------------------------
code | nickname | args | operation
------+----------------+-------+-------------------------------------
C0 | CMPEQ | 0 | left = (left == right)
C1 | CMPNE | 0 | left = (left != right)
C2 | SCMPLT | 0 | left = ((int16)left < (int16)right)
C3 | SCMPLE | 0 | left = ((int16)left <= (int16)right)
C4 | SCMPGT | 0 | left = ((int16)left > (int16)right)
C5 | SCMPGE | 0 | left = ((int16)left >= (int16)right)
C6 | UCMPLT | 0 | left = ((uint16)left < (uint16)right)
C7 | UCMPLE | 0 | left = ((uint16)left <= (uint16)right)
C8 | UCMPGT | 0 | left = ((uint16)left > (uint16)right)
C9 | UCMPGE | 0 | left = ((uint16)left >= (uint16)right)
CA | NOT | 0 | left = !left
CB | MINUS | 0 | left = -left
CC | COMPL | 0 | left = ~left
CD | SWAP | 0 | swap left <-> right
CE | (illegal) | --- | (illegal)
CF | RETURN | 0 | return from function
------+----------------+-------+-------------------------------------
code | nickname | args | operation
------+----------------+-------+-------------------------------------
D0 | INC | 0 | ++left
D1 | DEC | 0 | --left
D2 | LSHIFT1 | 0 | left = left << 1
D3 | BYTE DEREF | 0 | left = *(uint8 *)left
D4 | BYTE POPSTORE | 0 | pop right; *(uint8 *)right = left
D5 | SWITCH offs,num|2+2+tbl| contiguous switch (see below)
D6 | JUMP abs | 2 | instrptr = <abs>
D7 | JUMPT abs | 2 | if (left != 0) instrptr = <abs>
D8 | JUMPF abs | 2 | if (left == 0) instrptr = <abs>
D9 | SWITCH num | 2+tbl | noncontiguous switch (see below)
DA | AND | 0 | left = left & right
DB | OR | 0 | left = left | right
DC | XOR | 0 | left = left ^ right
DD | CALLPTR | 0 | call *left
DE | LEAL far | 2 | left = &<far>
DF | LEAR far | 2 | right = &<far>
------+----------------+-------+-------------------------------------
code | nickname | args | operation
------+----------------+-------+-------------------------------------
E0 | SLOADBF sz,pos | 1+1 | signed bitfield extract (see below)
E1 | ULOADBF sz,pos | 1+1 | unsigned bitfield extract (see below)
E2 | STOREBF sz,pos | 1+1 | bitfield insert (see below)
E3 | JUMP back | 1 | instrptr += <back>-256
E4 | JUMPT back | 1 | if (left != 0) instrptr += <back>-256
E5 | JUMPF back | 1 | if (left == 0) instrptr += <back>-256
E6 | JUMP ahead | 1 | instrptr += <ahead>
E7 | JUMPT ahead | 1 | if (left != 0) instrptr += <ahead>
E8 | JUMPF ahead | 1 | if (left == 0) instrptr += <ahead>
E9 | CALL abs,imm1 | 2+1 | call <abs>; stackptr += (uint8)<imm1>
EA | CALLPTR imm1 | 1 | call *left; stackptr += (uint8)<imm1>
EB-FF | (illegal) | --- | (illegal)
There are two switch instructions, one ($D5) for contiguous cases and the other ($D9) for noncontiguous cases. They work exactly like a C switch statement with the left register as the variable to test.
For the contiguous switch, the first 16-bit word after the instruction is the twos-complement negative of the smallest case value. The next 16-bit word is the number of cases. Then comes the default jump target, followed by the target for each in-range value of left. Example:
Code: Select all
.byte $D5 ; contiguous switch instruction
.word -4, 5 ; smallest case 4, 5 cases
.word DefaultTarget ; jumps to this address if left was < 4 or > 8
.word Target4 ; jumps to this address if left was 4
.word Target5 ; jumps to this address if left was 5
.word Target6 ; jumps to this address if left was 6
.word Target7 ; jumps to this address if left was 7
.word Target8 ; jumps to this address if left was 8
Code: Select all
.byte $D9 ; noncontiguous switch instruction
.word 5 ; 5 cases
.word 1, Target1
.word 4, Target4
.word 9, Target9
.word 16, Target16
.word 25, Target25
.word TargetDefault
Instructions $DE and $DF load a register with the value of the argument + the frame pointer, i.e. with the effective (absolute) address of a local variable. They can be used to pass a pointer to a local variable as a function argument, or in conjunction with the bitfield instructions.
Bitfields
There are three bitfield instructions: one to extract (load from) a signed bitfield, one to extract an unsigned bitfield, and one to insert (store to) a bitfield. For all three bitfield instructions, the first byte after the instruction is the size of the bitfield in bits, and the following byte is the bit position counting from the LSB. The entire bitfield must fit into a 16-bit word (i.e. size + pos < 16)
The two extraction instructions work like the dereference instruction: the address of the bitfield is in left, and the bitfield also gets extracted to left. The insertion instruction takes the value to insert in left, and the address to insert to in right (like the pop-store instruction without the pop).