section "evscript Driver", rom0 ; @param de: Variable pool ; @param hl: Script pointer ; @param bank: Script bank ; @return hl: New script pointer. 0 after a return. ; @return bank: New script bank. ; @preserves de ExecuteScript:: ld a, h or a, l ret z .next ld a, [hli] push hl add a, low(EvscriptBytecodeTable >> 1) ld l, a adc a, high(EvscriptBytecodeTable >> 1) sub a, l ld h, a add hl, hl ld a, [hli] ld h, [hl] ld l, a ld b, h ld c, l pop hl push de call .callBC pop de jr ExecuteScript.next .callBC push bc ret section "evscript Bytecode table", rom0, ALIGN[1] EvscriptBytecodeTable: ; Control dw StdReturn dw StdYield ; goto dw StdJump dw StdJumpIfTrue dw StdJumpIfFalse ; Moves dw StdPut dw StdMove ; 8-bit ops dw StdAdd dw StdSub dw StdBinaryAnd dw StdEqu dw StdNotEqu dw StdLessThan dw StdGreaterThan dw StdLessThanEqu dw StdGreaterThanEqu dw StdLogicalAnd dw StdLogicalOr section "evscript Return", rom0 StdReturn: ld hl, 0 StdYield: pop de ; pop return address pop de ; pop pool pointer ret section "evscript Goto", rom0 StdJump: ld a, [hli] ld h, [hl] ld l, a ret StdJumpIfTrue: ld a, [hli] add a, e ld c, a adc a, d sub a, c ld b, a ld a, [bc] and a, a jr nz, StdJump .fail inc hl inc hl ret StdJumpIfFalse: ld a, [hli] add a, e ld c, a adc a, d sub a, c ld b, a ld a, [bc] and a, a jr z, StdJump .fail inc hl inc hl ret section "evscript Put", rom0 StdPut: ld a, [hli] add a, e ld c, a adc a, d sub a, c ld b, a ld a, [hli] ld [bc], a ret section "evscript Mov", rom0 StdMove: ; Load dest ld a, [hli] add a, e ld c, a adc a, d sub a, c ld b, a ; Load source ld a, [hli] add a, e ld e, a adc a, d sub a, e ld d, a ; Move ld a, [de] ld [bc], a ret section "evscript 8-bit Operations", rom0 ; @param de: pool ; @param hl: script pointer ; @return a: lhs ; @return b: rhs OperandPrologue: ld a, [hli] ; lhs offset add a, e ld c, a adc a, d sub a, c ld b, a ; de is preserved & variable is pointed to by bc ld a, [hli] push hl ld l, a ld h, 0 add hl, de ld a, [bc] ld b, [hl] pop hl ret StdAdd: call OperandPrologue add a, b ; Here is the actual operation jr StoreEpilogue StdSub: call OperandPrologue sub a, b ; Here is the actual operation jr StoreEpilogue StdBinaryAnd: call OperandPrologue and a, b jr StoreEpilogue StdEqu: call OperandPrologue cp a, b ld a, 0 jr nz, StoreEpilogue inc a jr StoreEpilogue StdNotEqu: call OperandPrologue cp a, b ld a, 0 jr z, StoreEpilogue inc a jr StoreEpilogue StdLessThan: call OperandPrologue cp a, b ld a, 0 jr nc, StoreEpilogue inc a jr StoreEpilogue StdGreaterThan: call OperandPrologue cp a, b jr z, .zero jr nc, .zero ld a, 1 jr StoreEpilogue .zero xor a, a jr StoreEpilogue StdLessThanEqu: call OperandPrologue cp a, b jr z, .one jr c, .one xor a, a jr StoreEpilogue .one ld a, 1 jr StoreEpilogue StdGreaterThanEqu: call OperandPrologue cp a, b ld a, 0 jr c, StoreEpilogue inc a jr StoreEpilogue StdLogicalAnd: call OperandPrologue and a, a jr z, StoreEpilogue ld a, b and a, a jr z, StoreEpilogue ld a, 1 jr StoreEpilogue StdLogicalOr: call OperandPrologue and a, a jr nz, .true ld a, b and a, a jr z, StoreEpilogue .true ld a, 1 ; fallthrough ; This is stored in the middle so both variable and constant operations can ; reach it. StoreEpilogue: ld b, a ld a, [hli] add a, e ld e, a adc a, d sub a, e ld d, a ld a, b ld [de], a ret