2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module gaem
.runner
.opcodes
is aliced
;
21 // ////////////////////////////////////////////////////////////////////////// //
24 skip
, // skip current instruction; it usually has 3-byte payload
26 copy
, // copy regs; dest: dest reg; op0: first reg to copy; op1: number of regs to copy (0: no copy, lol)
53 plit
, // dest becomes pool slot val (val: 2 bytes) -- load value from pool slot; if val is 0xffff, next instruction is skip
54 ilit
, // dest becomes ilit val (val: short) -- load small integer literal
55 slit
, // dest becomes ilit val (val: short) -- load small integer literal as string index
56 xlit
, // dest becomes integer(!) val (val: short) -- load small integer literal
58 jump
, // addr: 3 bytes
59 xtrue
, // dest is reg to check; skip next instruction if dest is "gml true" (i.e. fabs(v) >= 0.5`)
60 xfalse
, // dest is reg to check; skip next instruction if dest is "gml false" (i.e. fabs(v) >= 0.5`)
62 call, // dest is result; op0: call frame (see below); op1: number of args
65 // int scriptid (after op1+3 slots)
66 // note that there should be no used registers after those (as that will be used as new function frame regs)
68 enter, // dest: number of arguments used; op0: number of stack slots used (including result and args); op1: number of locals
69 // any function will ALWAYS starts with this
71 ret, // dest is retvalue; it is copied to reg0; other stack items are discarded
73 oval
, // load object value to dest; 2byte: object index
74 // this is used for `if (oPlayer1)` and such conditions
75 // "object" is any object here, including sprites, background, sounds...
77 fval
, // load field value; op0: obj id; op1: int! reg (field id)
78 i1fval
, // load indexed value; op0: obj id; op1: xslots (int! field id, first index)
79 i2fval
, // load indexed value; op0: obj id; op1: xslots (int! field id, first index, second index)
81 fstore
, // store value *from* dest into field; op0: obj id; op1: int! reg (field id); can create fields
82 i1fstore
, // store value *from* dest into indexed reference; op0: obj id; op1: xslots (int! field id, first index)
83 i2fstore
, // store value *from* dest into indexed reference; op0: obj id; op1: xslots (int! field id, first index, second index)
85 // `with` is done by copying `self` to another reg, execute the code and restore `self`
86 siter
, // start instance iterator; dest: iterid; op0: objid or instid
87 // this is special: it will skip next instruction if iteration has at least one item
88 // next instruction is always jump, which skips the loop
89 niter
, // dest: is iterreg; next instruction is always jump, which continues the loop
90 kiter
, // kill iterator, should be called to restore `self` and `other`; dest: iterreg
92 // so return from `with` should call kiter for all created iterators first
94 // possible iterator management: preallocate slots for each non-overlapped "with";
95 // let VM to free all iterators from those slots on function exit
97 lirint
, // dest = lrint(op0): do lrint() (or another fast float->int conversion)
101 // ////////////////////////////////////////////////////////////////////////// //
102 ubyte opCode (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return (op
&0xff); }
103 ubyte opDest (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return ((op
>>8)&0xff); }
104 ubyte opOp0 (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return ((op
>>16)&0xff); }
105 ubyte opOp1 (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return ((op
>>24)&0xff); }
106 short opILit (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return cast(short)((op
>>16)&0xffff); }
107 uint op3Byte (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return (op
>>8); }
108 uint op2Byte (uint op
) pure nothrow @safe @nogc { pragma(inline
, true); return (op
>>16); }
110 uint opMakeILit (ubyte op
, byte dest
, short val
) pure nothrow @safe @nogc { pragma(inline
, true); return ((val
<<16)|
((dest
&0xff)<<8)|op
); }
111 uint opMake3Byte (ubyte op
, uint val
) pure nothrow @safe @nogc { pragma(inline
, true); assert(val
<= 0xffffff); return (val
<<8)|op
; }
114 // ////////////////////////////////////////////////////////////////////////// //
115 private import std
.stdio
: File
;
117 // returns instruction size
118 uint dumpInstr (File fo
, uint pc
, const(uint)[] code
) {
119 fo
.writef("%08X: ", pc
);
120 if (pc
== 0 || pc
>= code
.length
) {
121 fo
.writeln("<INVALID>");
124 auto atp
= opargs
[code
[pc
].opCode
];
125 if (atp
== OpArgs
.None
) {
126 fo
.writefln("%s", cast(Op
)code
[pc
].opCode
);
129 fo
.writef("%-9s", cast(Op
)code
[pc
].opCode
);
130 switch (atp
) with (OpArgs
) {
131 case Dest
: fo
.writefln("dest:%s", code
[pc
].opDest
); break;
132 case DestOp0
: fo
.writefln("dest:%s, op0:%s", code
[pc
].opDest
, code
[pc
].opOp0
); break;
133 case DestOp0Op1
: fo
.writefln("dest:%s, op0:%s, op1:%s", code
[pc
].opDest
, code
[pc
].opOp0
, code
[pc
].opOp1
); break;
134 case Dest2Bytes
: fo
.writefln("dest:%s; val:%s", code
[pc
].opDest
, code
[pc
].op2Byte
); break;
135 case Dest3Bytes
: fo
.writefln("dest:%s; val:%s", code
[pc
].opDest
, code
[pc
].op3Byte
); break;
136 case DestInt
: fo
.writefln("dest:%s; val:%s", code
[pc
].opDest
, code
[pc
].opILit
); break;
137 case DestJump
: fo
.writefln("0x%08X", code
[pc
].op3Byte
); break;
138 case DestCall
: fo
.writefln("dest:%s; frame:%s; args:%s", code
[pc
].opDest
, code
[pc
].opOp0
, code
[pc
].opOp1
); break;
139 case Op0Op1
: fo
.writefln("op0:%s, op1:%s", code
[pc
].opOp0
, code
[pc
].opOp1
); break;
140 case Op0
: fo
.writefln("op0:%s", code
[pc
].opOp0
); break;
147 // ////////////////////////////////////////////////////////////////////////// //
164 __gshared
immutable OpArgs
[ubyte] opargs
;
167 shared static this () {
168 with(OpArgs
) opargs
= [
172 Op
.lnot
: DestOp0
, //: lognot
208 Op
.enter: DestOp0Op1
,
215 Op
.i1fval
: DestOp0Op1
,
216 Op
.i2fval
: DestOp0Op1
,
218 Op
.fstore
: DestOp0Op1
,
220 Op
.i1fstore
: DestOp0Op1
,
221 Op
.i2fstore
: DestOp0Op1
,
227 Op
.lirint
: DestOp0
, // dest = lrint(op0): do lrint() (or another fast float->int conversion)