2022-03-18 23:57:35 +00:00
|
|
|
package prog8.vm
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
Virtual machine:
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
|
2022-04-24 22:10:12 +00:00
|
|
|
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
|
2022-03-23 00:52:01 +00:00
|
|
|
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
2022-04-11 20:39:33 +00:00
|
|
|
Value stack, max 128 entries of 1 byte each.
|
2022-04-24 22:10:12 +00:00
|
|
|
Status registers: Carry, Zero, Negative.
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-04-24 22:10:12 +00:00
|
|
|
Most instructions have an associated data type 'b','w','f'. (omitting it means 'b'/byte).
|
|
|
|
Currently NO support for 24 or 32 bits integers.
|
|
|
|
Floating point operations are just 'f' typed regular instructions, and additionally there are
|
|
|
|
a few fp conversion instructions to
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
|
|
|
|
|
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
LOAD/STORE
|
|
|
|
----------
|
2022-04-24 22:10:12 +00:00
|
|
|
All have type b or w or f.
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
load reg1, value - load immediate value into register
|
2022-04-24 22:10:12 +00:00
|
|
|
loadm reg1, address - load reg1 with value at memory address
|
|
|
|
loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
|
|
|
|
loadx reg1, reg2, address - load reg1 with value at memory address, indexed by value in reg2
|
|
|
|
loadr reg1, reg2 - load reg1 with value at register reg2
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-04-24 22:10:12 +00:00
|
|
|
storem reg1, address - store reg1 at memory address
|
|
|
|
storei reg1, reg2 - store reg1 at memory indirect, memory pointed to by reg2
|
|
|
|
storex reg1, reg2, address - store reg1 at memory address, indexed by value in reg2
|
|
|
|
storez address - store zero at memory address
|
|
|
|
storezi reg1 - store zero at memory pointed to by reg1
|
|
|
|
storezx reg1, address - store zero at memory address, indexed by value in reg
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
CONTROL FLOW
|
|
|
|
------------
|
|
|
|
Possible subroutine call convention:
|
|
|
|
Set parameters in Reg 0, 1, 2... before call. Return value set in Reg 0 before return.
|
|
|
|
But you can decide whatever you want because here we just care about jumping and returning the flow of control.
|
|
|
|
Saving/restoring registers is possible with PUSH and POP instructions.
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
jump location - continue running at instruction number given by location
|
2022-03-22 00:41:23 +00:00
|
|
|
jumpi reg1 - continue running at instruction number in reg1
|
2022-03-23 00:52:01 +00:00
|
|
|
call location - save current instruction location+1, continue execution at instruction nr given by location
|
|
|
|
calli reg1 - save current instruction location+1, continue execution at instruction number in reg1
|
2022-03-18 23:57:35 +00:00
|
|
|
syscall value - do a systemcall identified by call number
|
|
|
|
return - restore last saved instruction location and continue at that instruction
|
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
|
|
|
|
BRANCHING
|
|
|
|
---------
|
2022-04-08 22:49:23 +00:00
|
|
|
All have type b or w except the branches that only check status bits.
|
2022-03-23 00:52:01 +00:00
|
|
|
|
2022-04-08 22:49:23 +00:00
|
|
|
bstcc location - branch to location if Status bit Carry is Clear
|
|
|
|
bstcs location - branch to location if Status bit Carry is Set
|
2022-04-18 17:59:48 +00:00
|
|
|
bsteq location - branch to location if Status bit Zero is set
|
|
|
|
bstne location - branch to location if Status bit Zero is not set
|
|
|
|
bstneg location - branch to location if Status bit Negative is not set
|
|
|
|
bstpos location - branch to location if Status bit Negative is not set
|
2022-03-30 21:40:39 +00:00
|
|
|
bz reg1, location - branch to location if reg1 is zero
|
|
|
|
bnz reg1, location - branch to location if reg1 is not zero
|
|
|
|
beq reg1, reg2, location - jump to location in program given by location, if reg1 == reg2
|
|
|
|
bne reg1, reg2, location - jump to location in program given by location, if reg1 != reg2
|
|
|
|
blt reg1, reg2, location - jump to location in program given by location, if reg1 < reg2 (unsigned)
|
|
|
|
blts reg1, reg2, location - jump to location in program given by location, if reg1 < reg2 (signed)
|
|
|
|
ble reg1, reg2, location - jump to location in program given by location, if reg1 <= reg2 (unsigned)
|
|
|
|
bles reg1, reg2, location - jump to location in program given by location, if reg1 <= reg2 (signed)
|
|
|
|
bgt reg1, reg2, location - jump to location in program given by location, if reg1 > reg2 (unsigned)
|
|
|
|
bgts reg1, reg2, location - jump to location in program given by location, if reg1 > reg2 (signed)
|
|
|
|
bge reg1, reg2, location - jump to location in program given by location, if reg1 >= reg2 (unsigned)
|
|
|
|
bges reg1, reg2, location - jump to location in program given by location, if reg1 >= reg2 (signed)
|
|
|
|
seq reg1, reg2, reg3 - set reg=1 if reg2 == reg3, otherwise set reg1=0
|
|
|
|
sne reg1, reg2, reg3 - set reg=1 if reg2 != reg3, otherwise set reg1=0
|
|
|
|
slt reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (unsigned), otherwise set reg1=0
|
|
|
|
slts reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (signed), otherwise set reg1=0
|
|
|
|
sle reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (unsigned), otherwise set reg1=0
|
|
|
|
sles reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (signed), otherwise set reg1=0
|
|
|
|
sgt reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (unsigned), otherwise set reg1=0
|
|
|
|
sgts reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (signed), otherwise set reg1=0
|
|
|
|
sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0
|
|
|
|
sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
|
2022-04-24 22:10:12 +00:00
|
|
|
ARITHMETIC
|
|
|
|
----------
|
|
|
|
All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte.
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (latter not yet implemented as we don't have longs yet)
|
|
|
|
exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: latter ext.w, not yet implemented as we don't have longs yet)
|
|
|
|
inc reg1 - reg1 = reg1+1
|
2022-03-30 21:40:39 +00:00
|
|
|
incm address - memory at address += 1
|
2022-03-23 00:52:01 +00:00
|
|
|
dec reg1 - reg1 = reg1-1
|
2022-03-30 21:40:39 +00:00
|
|
|
decm address - memory at address -= 1
|
2022-03-23 00:52:01 +00:00
|
|
|
neg reg1 - reg1 = sign negation of reg1
|
2022-03-18 23:57:35 +00:00
|
|
|
add reg1, reg2, reg3 - reg1 = reg2+reg3 (unsigned + signed)
|
|
|
|
sub reg1, reg2, reg3 - reg1 = reg2-reg3 (unsigned + signed)
|
|
|
|
mul reg1, reg2, reg3 - unsigned multiply reg1=reg2*reg3 note: byte*byte->byte, no type extension to word!
|
|
|
|
div reg1, reg2, reg3 - unsigned division reg1=reg2/reg3 note: division by zero yields max signed int $ff/$ffff
|
2022-03-23 00:52:01 +00:00
|
|
|
mod reg1, reg2, reg3 - remainder (modulo) of unsigned division reg1=reg2%reg3 note: division by zero yields max signed int $ff/$ffff
|
2022-04-24 22:10:12 +00:00
|
|
|
sqrt reg1, reg2 - reg1 is the square root of reg2
|
2022-04-11 20:39:33 +00:00
|
|
|
sgn reg1, reg2 - reg1 is the sign of reg2 (0, 1 or -1)
|
2022-04-18 17:59:48 +00:00
|
|
|
cmp reg1, reg2 - set processor status bits C, N, Z according to comparison of reg1 with reg2. (semantics taken from 6502/68000 CMP instruction)
|
2022-04-24 22:10:12 +00:00
|
|
|
rnd reg1 - get a random number (byte, word or float)
|
2022-03-23 00:52:01 +00:00
|
|
|
|
2022-04-08 22:49:23 +00:00
|
|
|
NOTE: because mul/div are constrained (truncated) to remain in 8 or 16 bits, there is NO NEED for separate signed/unsigned mul and div instructions. The result is identical.
|
2022-03-23 00:52:01 +00:00
|
|
|
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
LOGICAL/BITWISE
|
|
|
|
---------------
|
|
|
|
All have type b or w.
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3
|
|
|
|
or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3
|
|
|
|
xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3
|
2022-04-14 20:42:25 +00:00
|
|
|
lsrx reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits + set Carry to shifted bit
|
|
|
|
asrx reg1, reg2, reg3 - reg1 = multi-shift reg2 right by reg3 bits (signed) + set Carry to shifted bit
|
|
|
|
lslx reg1, reg2, reg3 - reg1 = multi-shift reg2 left by reg3 bits + set Carry to shifted bit
|
2022-04-10 22:25:00 +00:00
|
|
|
lsr reg1 - shift reg1 right by 1 bits + set Carry to shifted bit
|
|
|
|
asr reg1 - shift reg1 right by 1 bits (signed) + set Carry to shifted bit
|
|
|
|
lsl reg1 - shift reg1 left by 1 bits + set Carry to shifted bit
|
2022-04-08 22:49:23 +00:00
|
|
|
ror reg1 - rotate reg1 right by 1 bits, not using carry + set Carry to shifted bit
|
|
|
|
roxr reg1 - rotate reg1 right by 1 bits, using carry + set Carry to shifted bit
|
|
|
|
rol reg1 - rotate reg1 left by 1bits, not using carry + set Carry to shifted bit
|
|
|
|
roxl reg1 - rotate reg1 left by 1bits, using carry, + set Carry to shifted bit
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
|
2022-05-02 18:16:45 +00:00
|
|
|
FLOATING POINT CONVERSIONS AND FUNCTIONS
|
|
|
|
----------------------------------------
|
2022-04-24 22:10:12 +00:00
|
|
|
ffromub fpreg1, reg1 - fpreg1 = reg1 from usigned byte
|
|
|
|
ffromsb fpreg1, reg1 - fpreg1 = reg1 from signed byte
|
|
|
|
ffromuw fpreg1, reg1 - fpreg1 = reg1 from unsigned word
|
|
|
|
ffromsw fpreg1, reg1 - fpreg1 = reg1 from signed word
|
|
|
|
ftoub reg1, fpreg1 - reg1 = fpreg1 as unsigned byte
|
|
|
|
ftosb reg1, fpreg1 - reg1 = fpreg1 as signed byte
|
|
|
|
ftouw reg1, fpreg1 - reg1 = fpreg1 as unsigned word
|
|
|
|
ftosw reg1, fpreg1 - reg1 = fpreg1 as signed word
|
2022-05-02 18:16:45 +00:00
|
|
|
fpow fpreg1, fpreg2, fpreg3 - fpreg1 = fpreg2 to the power of fpreg3
|
|
|
|
fabs fpreg1, fpreg2 - fpreg1 = abs(fpreg2)
|
2022-04-24 22:10:12 +00:00
|
|
|
|
|
|
|
|
2022-03-18 23:57:35 +00:00
|
|
|
MISC
|
2022-03-23 00:52:01 +00:00
|
|
|
----
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-04-24 22:10:12 +00:00
|
|
|
clc - clear Carry status bit
|
|
|
|
sec - set Carry status bit
|
|
|
|
nop - do nothing
|
|
|
|
breakpoint - trigger a breakpoint
|
|
|
|
copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes
|
|
|
|
copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte
|
|
|
|
msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs)
|
|
|
|
swapreg reg1, reg2 - swap values in reg1 and reg2
|
|
|
|
concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented; requires 32bits regs)
|
|
|
|
push [b, w] reg1 - push value in reg1 on the stack
|
|
|
|
pop [b, w] reg1 - pop value from stack into reg1
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum class Opcode {
|
|
|
|
NOP,
|
|
|
|
LOAD,
|
|
|
|
LOADM,
|
|
|
|
LOADI,
|
|
|
|
LOADX,
|
|
|
|
LOADR,
|
|
|
|
STOREM,
|
|
|
|
STOREI,
|
|
|
|
STOREX,
|
|
|
|
STOREZ,
|
|
|
|
STOREZI,
|
|
|
|
STOREZX,
|
|
|
|
|
|
|
|
JUMP,
|
|
|
|
JUMPI,
|
2022-03-23 00:52:01 +00:00
|
|
|
CALL,
|
|
|
|
CALLI,
|
2022-03-18 23:57:35 +00:00
|
|
|
SYSCALL,
|
|
|
|
RETURN,
|
2022-04-08 22:49:23 +00:00
|
|
|
|
|
|
|
BSTCC,
|
|
|
|
BSTCS,
|
2022-04-18 17:59:48 +00:00
|
|
|
BSTEQ,
|
|
|
|
BSTNE,
|
|
|
|
BSTNEG,
|
|
|
|
BSTPOS,
|
2022-03-18 23:57:35 +00:00
|
|
|
BZ,
|
|
|
|
BNZ,
|
|
|
|
BEQ,
|
|
|
|
BNE,
|
|
|
|
BLT,
|
|
|
|
BLTS,
|
|
|
|
BGT,
|
|
|
|
BGTS,
|
|
|
|
BLE,
|
|
|
|
BLES,
|
|
|
|
BGE,
|
|
|
|
BGES,
|
2022-03-27 12:23:01 +00:00
|
|
|
SEQ,
|
|
|
|
SNE,
|
|
|
|
SLT,
|
|
|
|
SLTS,
|
|
|
|
SGT,
|
|
|
|
SGTS,
|
|
|
|
SLE,
|
|
|
|
SLES,
|
|
|
|
SGE,
|
|
|
|
SGES,
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
INC,
|
2022-03-30 21:40:39 +00:00
|
|
|
INCM,
|
2022-03-23 00:52:01 +00:00
|
|
|
DEC,
|
2022-03-30 21:40:39 +00:00
|
|
|
DECM,
|
2022-03-18 23:57:35 +00:00
|
|
|
NEG,
|
|
|
|
ADD,
|
|
|
|
SUB,
|
|
|
|
MUL,
|
|
|
|
DIV,
|
2022-03-23 00:52:01 +00:00
|
|
|
MOD,
|
2022-04-11 20:39:33 +00:00
|
|
|
SQRT,
|
|
|
|
SGN,
|
2022-04-18 17:59:48 +00:00
|
|
|
CMP,
|
2022-04-24 22:10:12 +00:00
|
|
|
RND,
|
2022-03-18 23:57:35 +00:00
|
|
|
EXT,
|
|
|
|
EXTS,
|
|
|
|
|
|
|
|
AND,
|
|
|
|
OR,
|
|
|
|
XOR,
|
2022-04-14 20:42:25 +00:00
|
|
|
ASRX,
|
|
|
|
LSRX,
|
|
|
|
LSLX,
|
2022-03-28 21:49:44 +00:00
|
|
|
ASR,
|
2022-03-18 23:57:35 +00:00
|
|
|
LSR,
|
|
|
|
LSL,
|
|
|
|
ROR,
|
2022-04-08 22:49:23 +00:00
|
|
|
ROXR,
|
2022-03-18 23:57:35 +00:00
|
|
|
ROL,
|
2022-04-08 22:49:23 +00:00
|
|
|
ROXL,
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-04-24 22:10:12 +00:00
|
|
|
FFROMUB,
|
|
|
|
FFROMSB,
|
|
|
|
FFROMUW,
|
|
|
|
FFROMSW,
|
|
|
|
FTOUB,
|
|
|
|
FTOSB,
|
|
|
|
FTOUW,
|
|
|
|
FTOSW,
|
2022-05-02 18:16:45 +00:00
|
|
|
FPOW,
|
|
|
|
FABS,
|
|
|
|
FSIN,
|
|
|
|
FCOS,
|
|
|
|
FTAN,
|
|
|
|
FATAN,
|
|
|
|
FLN,
|
|
|
|
FLOG,
|
|
|
|
FSQRT,
|
|
|
|
FROUND,
|
|
|
|
FFLOOR,
|
|
|
|
FCEIL,
|
2022-04-24 22:10:12 +00:00
|
|
|
|
2022-04-08 22:49:23 +00:00
|
|
|
CLC,
|
|
|
|
SEC,
|
2022-03-23 00:52:01 +00:00
|
|
|
PUSH,
|
|
|
|
POP,
|
2022-04-10 22:25:00 +00:00
|
|
|
MSIG,
|
2022-03-28 21:49:44 +00:00
|
|
|
SWAPREG,
|
|
|
|
CONCAT,
|
2022-03-18 23:57:35 +00:00
|
|
|
BREAKPOINT
|
|
|
|
}
|
|
|
|
|
2022-04-05 15:48:49 +00:00
|
|
|
val OpcodesWithAddress = setOf(
|
|
|
|
Opcode.LOADM,
|
|
|
|
Opcode.LOADX,
|
|
|
|
Opcode.STOREM,
|
|
|
|
Opcode.STOREX,
|
|
|
|
Opcode.STOREZ,
|
|
|
|
Opcode.STOREZX
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-03-23 00:52:01 +00:00
|
|
|
enum class VmDataType {
|
2022-03-18 23:57:35 +00:00
|
|
|
BYTE,
|
2022-04-24 22:10:12 +00:00
|
|
|
WORD,
|
|
|
|
FLOAT
|
2022-03-23 00:52:01 +00:00
|
|
|
// TODO add INT (32-bit)? INT24 (24-bit)?
|
2022-03-18 23:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data class Instruction(
|
|
|
|
val opcode: Opcode,
|
2022-03-23 00:52:01 +00:00
|
|
|
val type: VmDataType?=null,
|
2022-03-27 23:49:43 +00:00
|
|
|
val reg1: Int?=null, // 0-$ffff
|
|
|
|
val reg2: Int?=null, // 0-$ffff
|
|
|
|
val reg3: Int?=null, // 0-$ffff
|
2022-04-24 22:10:12 +00:00
|
|
|
val fpReg1: Int?=null, // 0-$ffff
|
|
|
|
val fpReg2: Int?=null, // 0-$ffff
|
|
|
|
val fpReg3: Int?=null, // 0-$ffff
|
2022-03-27 23:49:43 +00:00
|
|
|
val value: Int?=null, // 0-$ffff
|
2022-04-24 22:10:12 +00:00
|
|
|
val fpValue: Float?=null,
|
2022-03-27 23:49:43 +00:00
|
|
|
val symbol: List<String>?=null // alternative to value
|
2022-03-19 00:20:01 +00:00
|
|
|
) {
|
2022-03-30 21:40:39 +00:00
|
|
|
init {
|
2022-04-24 22:10:12 +00:00
|
|
|
val formats = instructionFormats.getValue(opcode)
|
|
|
|
if(type==null && !formats.containsKey(null))
|
2022-03-30 19:44:48 +00:00
|
|
|
throw IllegalArgumentException("missing type")
|
|
|
|
|
2022-04-24 22:10:12 +00:00
|
|
|
val format = formats.getValue(type)
|
2022-03-30 19:44:48 +00:00
|
|
|
if(format.reg1 && reg1==null ||
|
2022-03-30 21:40:39 +00:00
|
|
|
format.reg2 && reg2==null ||
|
|
|
|
format.reg3 && reg3==null)
|
2022-04-28 19:46:24 +00:00
|
|
|
throw IllegalArgumentException("missing a register (int)")
|
|
|
|
|
|
|
|
if(format.fpReg1 && fpReg1==null ||
|
|
|
|
format.fpReg2 && fpReg2==null ||
|
|
|
|
format.fpReg3 && fpReg3==null)
|
|
|
|
throw IllegalArgumentException("missing a register (float)")
|
2022-03-30 19:44:48 +00:00
|
|
|
|
2022-04-08 22:49:23 +00:00
|
|
|
if(!format.reg1 && reg1!=null ||
|
|
|
|
!format.reg2 && reg2!=null ||
|
|
|
|
!format.reg3 && reg3!=null)
|
2022-04-28 19:46:24 +00:00
|
|
|
throw IllegalArgumentException("too many registers (int)")
|
2022-04-08 22:49:23 +00:00
|
|
|
|
2022-04-28 19:46:24 +00:00
|
|
|
if(!format.fpReg1 && fpReg1!=null ||
|
|
|
|
!format.fpReg2 && fpReg2!=null ||
|
|
|
|
!format.fpReg3 && fpReg3!=null)
|
|
|
|
throw IllegalArgumentException("too many registers (float)")
|
2022-04-24 22:10:12 +00:00
|
|
|
|
|
|
|
if (type==VmDataType.FLOAT) {
|
2022-04-28 19:46:24 +00:00
|
|
|
if(format.fpValue && (fpValue==null && symbol==null))
|
2022-04-24 22:10:12 +00:00
|
|
|
throw IllegalArgumentException("$opcode: missing a fp-value or symbol")
|
|
|
|
} else {
|
|
|
|
if(format.value && (value==null && symbol==null))
|
|
|
|
throw IllegalArgumentException("$opcode: missing a value or symbol")
|
|
|
|
if (fpReg1 != null || fpReg2 != null || fpReg3 != null)
|
|
|
|
throw java.lang.IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
|
|
|
|
}
|
2022-03-30 21:40:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun toString(): String {
|
|
|
|
val result = mutableListOf(opcode.name.lowercase())
|
2022-03-23 00:52:01 +00:00
|
|
|
|
2022-03-19 00:20:01 +00:00
|
|
|
when(type) {
|
2022-03-23 00:52:01 +00:00
|
|
|
VmDataType.BYTE -> result.add(".b ")
|
|
|
|
VmDataType.WORD -> result.add(".w ")
|
2022-04-28 19:46:24 +00:00
|
|
|
VmDataType.FLOAT -> result.add(".f ")
|
2022-03-19 00:20:01 +00:00
|
|
|
else -> result.add(" ")
|
|
|
|
}
|
|
|
|
reg1?.let {
|
2022-03-22 00:41:23 +00:00
|
|
|
result.add("r$it")
|
2022-03-19 00:20:01 +00:00
|
|
|
result.add(",")
|
|
|
|
}
|
|
|
|
reg2?.let {
|
2022-03-22 00:41:23 +00:00
|
|
|
result.add("r$it")
|
2022-03-19 00:20:01 +00:00
|
|
|
result.add(",")
|
|
|
|
}
|
|
|
|
reg3?.let {
|
2022-03-22 00:41:23 +00:00
|
|
|
result.add("r$it")
|
2022-03-19 00:20:01 +00:00
|
|
|
result.add(",")
|
|
|
|
}
|
2022-04-24 22:10:12 +00:00
|
|
|
fpReg1?.let {
|
|
|
|
result.add("fr$it")
|
|
|
|
result.add(",")
|
|
|
|
}
|
|
|
|
fpReg2?.let {
|
|
|
|
result.add("fr$it")
|
|
|
|
result.add(",")
|
|
|
|
}
|
|
|
|
fpReg3?.let {
|
|
|
|
result.add("fr$it")
|
|
|
|
result.add(",")
|
|
|
|
}
|
2022-03-19 00:20:01 +00:00
|
|
|
value?.let {
|
|
|
|
result.add(it.toString())
|
2022-03-27 23:49:43 +00:00
|
|
|
result.add(",")
|
|
|
|
}
|
2022-04-24 22:10:12 +00:00
|
|
|
fpValue?.let {
|
|
|
|
result.add(it.toString())
|
|
|
|
result.add(",")
|
|
|
|
}
|
2022-03-27 23:49:43 +00:00
|
|
|
symbol?.let {
|
|
|
|
result.add("_" + it.joinToString("."))
|
2022-03-19 00:20:01 +00:00
|
|
|
}
|
|
|
|
if(result.last() == ",")
|
2022-03-22 00:41:23 +00:00
|
|
|
result.removeLast()
|
2022-03-19 00:20:01 +00:00
|
|
|
return result.joinToString("").trimEnd()
|
|
|
|
}
|
|
|
|
}
|
2022-03-18 23:57:35 +00:00
|
|
|
|
2022-04-24 22:10:12 +00:00
|
|
|
data class InstructionFormat(val datatype: VmDataType?,
|
|
|
|
val reg1: Boolean, val reg2: Boolean, val reg3: Boolean,
|
|
|
|
val fpReg1: Boolean, val fpReg2: Boolean, val fpReg3: Boolean,
|
|
|
|
val value: Boolean,
|
|
|
|
val fpValue: Boolean) {
|
|
|
|
companion object {
|
|
|
|
fun from(spec: String): Map<VmDataType?, InstructionFormat> {
|
|
|
|
val result = mutableMapOf<VmDataType?, InstructionFormat>()
|
|
|
|
for(part in spec.split('|').map{ it.trim() }) {
|
2022-04-28 19:46:24 +00:00
|
|
|
var reg1 = false
|
|
|
|
var reg2 = false
|
|
|
|
var reg3 = false
|
|
|
|
var fpreg1 = false
|
|
|
|
var fpreg2 = false
|
|
|
|
var fpreg3 = false
|
|
|
|
var value = false
|
|
|
|
var fpvalue = false
|
2022-04-24 22:10:12 +00:00
|
|
|
val splits = part.splitToSequence(',').iterator()
|
|
|
|
val typespec = splits.next()
|
|
|
|
while(splits.hasNext()) {
|
|
|
|
when(splits.next()) {
|
|
|
|
"r1" -> reg1=true
|
|
|
|
"r2" -> reg2=true
|
|
|
|
"r3" -> reg3=true
|
|
|
|
"fr1" -> fpreg1=true
|
|
|
|
"fr2" -> fpreg2=true
|
|
|
|
"fr3" -> fpreg3=true
|
|
|
|
"v" -> value = true
|
|
|
|
"fv" -> fpvalue = true
|
|
|
|
else -> throw IllegalArgumentException(spec)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(typespec=="N")
|
|
|
|
result[null] = InstructionFormat(null, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
|
|
|
if('B' in typespec)
|
|
|
|
result[VmDataType.BYTE] = InstructionFormat(VmDataType.BYTE, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
|
|
|
if('W' in typespec)
|
|
|
|
result[VmDataType.WORD] = InstructionFormat(VmDataType.WORD, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
|
|
|
if('F' in typespec)
|
|
|
|
result[VmDataType.FLOAT] = InstructionFormat(VmDataType.FLOAT, reg1=reg1, reg2=reg2, reg3=reg3, fpReg1=fpreg1, fpReg2=fpreg2, fpReg3=fpreg3, value=value, fpValue=fpvalue)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-18 23:57:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
@Suppress("BooleanLiteralArgument")
|
|
|
|
val instructionFormats = mutableMapOf(
|
2022-04-24 22:10:12 +00:00
|
|
|
Opcode.NOP to InstructionFormat.from("N"),
|
|
|
|
Opcode.LOAD to InstructionFormat.from("BW,r1,v | F,fr1,fv"),
|
|
|
|
Opcode.LOADM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
|
|
|
Opcode.LOADI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
|
|
|
Opcode.LOADX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
|
|
|
Opcode.LOADR to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
|
|
|
Opcode.SWAPREG to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
|
|
|
Opcode.STOREM to InstructionFormat.from("BW,r1,v | F,fr1,v"),
|
|
|
|
Opcode.STOREI to InstructionFormat.from("BW,r1,r2 | F,fr1,r1"),
|
|
|
|
Opcode.STOREX to InstructionFormat.from("BW,r1,r2,v | F,fr1,r1,v"),
|
|
|
|
Opcode.STOREZ to InstructionFormat.from("BW,v | F,v"),
|
|
|
|
Opcode.STOREZI to InstructionFormat.from("BW,r1 | F,r1"),
|
|
|
|
Opcode.STOREZX to InstructionFormat.from("BW,r1,v | F,r1,v"),
|
|
|
|
Opcode.JUMP to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.JUMPI to InstructionFormat.from("N,r1"),
|
|
|
|
Opcode.CALL to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.CALLI to InstructionFormat.from("N,r1"),
|
|
|
|
Opcode.SYSCALL to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.RETURN to InstructionFormat.from("N"),
|
|
|
|
Opcode.BSTCC to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.BSTCS to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.BSTEQ to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.BSTNE to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.BSTNEG to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.BSTPOS to InstructionFormat.from("N,v"),
|
|
|
|
Opcode.BZ to InstructionFormat.from("BW,r1,v"),
|
|
|
|
Opcode.BNZ to InstructionFormat.from("BW,r1,v"),
|
|
|
|
Opcode.BEQ to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BNE to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BLT to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BLTS to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BGT to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BGTS to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BLE to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BLES to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BGE to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.BGES to InstructionFormat.from("BW,r1,r2,v"),
|
|
|
|
Opcode.SEQ to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SNE to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SLT to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SLTS to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SGT to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SGTS to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SLE to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SLES to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SGE to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.SGES to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.INC to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.INCM to InstructionFormat.from("BW,v"),
|
|
|
|
Opcode.DEC to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.DECM to InstructionFormat.from("BW,v"),
|
|
|
|
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
|
|
|
|
Opcode.ADD to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
|
|
|
Opcode.SUB to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
|
|
|
Opcode.MUL to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
|
|
|
Opcode.DIV to InstructionFormat.from("BW,r1,r2,r3 | F,fr1,fr2,fr3"),
|
|
|
|
Opcode.SQRT to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
|
|
|
Opcode.SGN to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
|
|
|
Opcode.RND to InstructionFormat.from("BW,r1 | F,fr1"),
|
|
|
|
Opcode.MOD to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.CMP to InstructionFormat.from("BW,r1,r2"),
|
|
|
|
Opcode.EXT to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.EXTS to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.AND to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.OR to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.XOR to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.ASRX to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.LSRX to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.LSLX to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.ASR to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.LSR to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.LSL to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.ROR to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.ROXR to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.ROL to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.ROXL to InstructionFormat.from("BW,r1"),
|
|
|
|
|
|
|
|
Opcode.FFROMUB to InstructionFormat.from("F,fr1,r1"),
|
|
|
|
Opcode.FFROMSB to InstructionFormat.from("F,fr1,r1"),
|
|
|
|
Opcode.FFROMUW to InstructionFormat.from("F,fr1,r1"),
|
|
|
|
Opcode.FFROMSW to InstructionFormat.from("F,fr1,r1"),
|
|
|
|
Opcode.FTOUB to InstructionFormat.from("F,r1,fr1"),
|
|
|
|
Opcode.FTOSB to InstructionFormat.from("F,r1,fr1"),
|
|
|
|
Opcode.FTOUW to InstructionFormat.from("F,r1,fr1"),
|
|
|
|
Opcode.FTOSW to InstructionFormat.from("F,r1,fr1"),
|
2022-05-02 18:16:45 +00:00
|
|
|
Opcode.FPOW to InstructionFormat.from("F,fr1,fr2,fr3"),
|
|
|
|
Opcode.FABS to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FSIN to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FCOS to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FTAN to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FATAN to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FLN to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FLOG to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FSQRT to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FROUND to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FFLOOR to InstructionFormat.from("F,fr1,fr2"),
|
|
|
|
Opcode.FCEIL to InstructionFormat.from("F,fr1,fr2"),
|
2022-04-24 22:10:12 +00:00
|
|
|
|
|
|
|
Opcode.MSIG to InstructionFormat.from("BW,r1,r2"),
|
|
|
|
Opcode.PUSH to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.POP to InstructionFormat.from("BW,r1"),
|
|
|
|
Opcode.CONCAT to InstructionFormat.from("BW,r1,r2,r3"),
|
|
|
|
Opcode.CLC to InstructionFormat.from("N"),
|
|
|
|
Opcode.SEC to InstructionFormat.from("N"),
|
|
|
|
Opcode.BREAKPOINT to InstructionFormat.from("N"),
|
2022-03-18 23:57:35 +00:00
|
|
|
)
|