diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b9b402..0734a50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.12) project(zip LANGUAGES C) set(HEADERS + common.h interpreter.h memory.h messages.h diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..6b284b8 --- /dev/null +++ b/include/common.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#ifndef COMMON_H +#define COMMON_H + + +#define DEBUGGING + + +#endif // COMMON_H diff --git a/include/interpreter.h b/include/interpreter.h index b6ba6ba..e09742f 100644 --- a/include/interpreter.h +++ b/include/interpreter.h @@ -26,20 +26,23 @@ #include +#include "common.h" #include "memory.h" - -uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLen); +uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP); char interpreterDecodeZSCIIChar(uint16_t z); -void interpreterDoBranch(int32_t b); +void interpreterDoBranch(int32_t truth); void interpreterDoReturn(uint16_t r); -uint8_t interpreterGetObjectPointer(uint16_t objectId); +uint32_t interpreterGetObjectPointer(uint16_t objectId); uint8_t interpreterGetObjectProperty(uint16_t objectId, uint32_t propertyId, uint8_t *size); +uint32_t interpreterGlobalVariableAddress(uint16_t var); +uint16_t interpreterLoadVariable(uint16_t var); bool interpreterParseOperand(uint8_t opType, uint8_t operandId); uint8_t interpreterParseVariableOperands(uint8_t index); void interpreterPrintChars(char *chars, uint16_t len); uint32_t interpreterPrintZSCII(uint32_t pc, bool abbr); void interpreterRun(void); +void interpreterStoreVariable(uint16_t var, uint16_t value); uint8_t interpreterVariableAddress(uint8_t var, bool writing); diff --git a/include/memory.h b/include/memory.h index 0e8aa5e..4e12271 100644 --- a/include/memory.h +++ b/include/memory.h @@ -26,6 +26,7 @@ #include +#include "common.h" #define MEMORY_ROUTINE 0 @@ -40,9 +41,6 @@ #define PEEKW(a) memoryWord(a) #define POKEW(a,v) memorySetWord(a,v) -// Stack access. -#define SPEEKD(a) ((uint32_t)*(uint32_t *)&__state.stack[a]) - typedef unsigned char byte; typedef unsigned char bool; diff --git a/include/messages.h b/include/messages.h index 59c1c26..5791745 100644 --- a/include/messages.h +++ b/include/messages.h @@ -24,10 +24,11 @@ #ifndef MESSAGES_H #define MESSAGES_H -#define MSG_USE_MESSAGES // Undef this to save memory. + +#include "common.h" -#ifdef MSG_USE_MESSAGES +#ifdef DEBUGGING #define MSG_UNIMPLEMENTED "Unimplemented." #define MSG_INT_INVALID_EXT_OPCODE "Invalid extended opcode!" #define MSG_INT_NO_ABBR "No abbreviations in abbreviations!" @@ -43,7 +44,7 @@ #define MSG_OP_VAR_MISSING_PROPERTY "Missing object property." #define MSG_OP_VAR_TOO_MANY_LOCALS "Too many local variables!" #define MSG_OP_VAR_STACK_OVERFLOW "Stack overflow!" -#else // MSG_USE_MESSAGES +#else // DEBUGGING #define MSG_UNIMPLEMENTED "" #define MSG_INT_INVALID_EXT_OPCODE "" #define MSG_INT_NO_ABBR "" @@ -59,7 +60,7 @@ #define MSG_OP_VAR_MISSING_PROPERTY "" #define MSG_OP_VAR_TOO_MANY_LOCALS "" #define MSG_OP_VAR_STACK_OVERFLOW "" -#endif // MSG_USE_MESSAGES +#endif // DEBUGGING #endif // MESSAGES_H diff --git a/include/oc_0op.h b/include/oc_0op.h index fe1be3d..2effa65 100644 --- a/include/oc_0op.h +++ b/include/oc_0op.h @@ -25,6 +25,9 @@ #define OC_0OP_H +#include "common.h" + + void opcodes_new_line(void); void opcodes_print(void); diff --git a/include/oc_1op.h b/include/oc_1op.h index bfe3408..4f9a6ca 100644 --- a/include/oc_1op.h +++ b/include/oc_1op.h @@ -25,6 +25,8 @@ #define OC_1OP_H +#include "common.h" + void opcodes_jump(void); void opcodes_jz(void); diff --git a/include/oc_2op.h b/include/oc_2op.h index 52ba490..0637e1f 100644 --- a/include/oc_2op.h +++ b/include/oc_2op.h @@ -25,6 +25,9 @@ #define OC_2OP_H +#include "common.h" + + void opcodes_add(void); void opcodes_je(void); void opcodes_loadw(void); diff --git a/include/oc_ext.h b/include/oc_ext.h index ca04c0a..c6bd870 100644 --- a/include/oc_ext.h +++ b/include/oc_ext.h @@ -24,4 +24,8 @@ #ifndef OC_EXT_H #define OC_EXT_H + +#include "common.h" + + #endif // OC_EXT_H diff --git a/include/oc_var_op.h b/include/oc_var_op.h index 4733980..d768fec 100644 --- a/include/oc_var_op.h +++ b/include/oc_var_op.h @@ -25,6 +25,8 @@ #define OC_VAR_OP_H +#include "common.h" + void opcodes_call(void); void opcodes_put_prop(void); diff --git a/include/opcodes.h b/include/opcodes.h index 55f2223..c0c479a 100644 --- a/include/opcodes.h +++ b/include/opcodes.h @@ -25,6 +25,9 @@ #define OPCODES_H +#include "common.h" + + typedef void (*opcodeT)(void); diff --git a/include/portme.h b/include/portme.h index d58863a..1ffd63d 100644 --- a/include/portme.h +++ b/include/portme.h @@ -27,6 +27,8 @@ #include +#include "common.h" + void portDie(char *fmt, ...); void portPrintChars(char *chars, uint16_t len); diff --git a/include/state.h b/include/state.h index 642d1af..f53dad4 100644 --- a/include/state.h +++ b/include/state.h @@ -25,13 +25,11 @@ #define STATE_H +#include "common.h" #include "memory.h" #include "opcodes.h" -#define DEBUGGING - - typedef struct stateS { uint16_t stack[2048]; //***TODO*** How big does this really need to be? Old games are 1024, new...? bool quit; diff --git a/include/story.h b/include/story.h index 9c5d2de..316f904 100644 --- a/include/story.h +++ b/include/story.h @@ -25,6 +25,7 @@ #define STORY_H +#include "common.h" #include "memory.h" diff --git a/src/interpreter.c b/src/interpreter.c index 2394d67..89fe27f 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -20,6 +20,7 @@ * SOFTWARE. */ + #include "interpreter.h" #include "portme.h" #include "messages.h" @@ -31,17 +32,16 @@ #endif -uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLen) { +uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *bufLenP) { + uint32_t bufLen = *bufLenP; uint16_t code = 0; uint8_t alphabet = 0; uint8_t useAbbrTable = 0; uint8_t zsciiCollector = 0; uint16_t zsciiCode = 0; uint32_t decodedChars = 0; - uint32_t bufPtr = 0; uint32_t pc = zstr; char printVal = 0; - uint32_t bufLenTemp; uint32_t index; uint32_t ptr; uint16_t abbrAddr; @@ -56,7 +56,10 @@ uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *b // Characters are 5 bits each, packed three to a 16-bit word. for (i=10; i>=0; i-=5) { - ch = ((code >> 1) & 0x1f); + + newShift = 0; + printVal = 0; + ch = ((code >> i) & 0x1f); if (zsciiCollector) { if (zsciiCollector == 2) { @@ -71,8 +74,9 @@ uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *b printVal = interpreterDecodeZSCIIChar(zsciiCode); if (printVal) { decodedChars++; - if (bufPtr < *bufLen) { - buf[bufPtr++] = printVal; + if (bufLen) { + *(buf++) = printVal; + bufLen--; } } alphabet = 0; @@ -89,19 +93,19 @@ uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *b index = ((32 * (((uint32_t)useAbbrTable) - 1)) + (uint32_t)ch); ptr = storyAbbreviationTableAddress() + (index * 2); abbrAddr = PEEKW(ptr); + ptr += 2; - abbrDecodedChars = *bufLen - bufPtr; + abbrDecodedChars = bufLen; interpreterDecodeZSCII(abbrAddr * 2, 1, buf, &abbrDecodedChars); decodedChars += abbrDecodedChars; - - bufLenTemp = *bufLen - bufPtr; - bufPtr += (bufLenTemp < abbrDecodedChars) ? bufLenTemp : abbrDecodedChars; - bufLenTemp = (bufLenTemp < abbrDecodedChars) ? 0 : (bufLenTemp - abbrDecodedChars); - *bufLen = *bufLen - bufLenTemp; + buf += (bufLen < abbrDecodedChars) ? bufLen : abbrDecodedChars; + bufLen = (bufLen < abbrDecodedChars) ? 0 : (bufLen - abbrDecodedChars); useAbbrTable = 0; alphabet = 0; //***FIXME*** Version 3+ has no shift-lock but V1 needs it. + continue; + } // useAbbrTable switch (ch) { @@ -147,8 +151,9 @@ uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *b if (printVal) { decodedChars++; - if (bufPtr < *bufLen) { - buf[bufPtr++] = printVal; + if (bufLen) { + *(buf++) = printVal; + bufLen--; } } @@ -159,9 +164,9 @@ uint32_t interpreterDecodeZSCII(uint32_t zstr, bool abbr, char *buf, uint32_t *b // There is no NULL terminator, you look for a word with the top bit set. } while ((code & (1 << 15)) == 0); - *bufLen = decodedChars; + *bufLenP = decodedChars; - return pc; + return pc - zstr; } @@ -182,14 +187,14 @@ char interpreterDecodeZSCIIChar(uint16_t z) { } -void interpreterDoBranch(int32_t b) { - uint8_t branch = __state.pc++; +void interpreterDoBranch(int32_t truth) { + uint8_t branch = PEEK(__state.pc++); int32_t farJump = (branch & (1 << 6)) == 0; int32_t onTruth = (branch & (1 << 7)) ? 1 : 0; - uint8_t byte2 = farJump ? __state.pc++ : 0; + uint8_t byte2 = farJump ? PEEK(__state.pc++) : 0; int16_t offset; - if (onTruth == b) { + if (onTruth == truth) { offset = (int16_t)(branch & 0x3f); if (farJump) { if (offset & (1 << 5)) offset |= 0xc0; @@ -208,11 +213,15 @@ void interpreterDoBranch(int32_t b) { void interpreterDoReturn(uint16_t r) { uint8_t storeId; - uint8_t store; - // Newer versions start in a real routine, but still aren't allowed to return from it. + //***TODO*** Newer versions start in a real routine, but still aren't allowed to return from it. + if (__state.bp == 0) portDie(MSG_INT_STACK_UNDERFLOW); +#ifdef DEBUGGING + printf("Returning: initial pc=%X, bp=%u, sp=%u\n", __state.pc, __state.bp, __state.sp); +#endif + // Dump all locals and data pushed on stack during the routine. __state.sp = __state.bp; // Dump our copy of numLocals. @@ -226,14 +235,18 @@ void interpreterDoReturn(uint16_t r) { // Pop the result storage location. storeId = (uint8_t)__state.stack[--__state.sp]; + +#ifdef DEBUGGING + printf("Returning: new pc=%X, bp=%u, sp=%u\n", __state.pc, __state.bp, __state.sp); +#endif + // Store the routine result. - store = interpreterVariableAddress(storeId, 1); - POKEW(store, r); + interpreterStoreVariable(storeId, r); } -uint8_t interpreterGetObjectPointer(uint16_t objectId) { - uint8_t ptr; +uint32_t interpreterGetObjectPointer(uint16_t objectId) { + uint32_t ptr; if (objectId == 0) portDie(MSG_INT_OBJECT0_REF); if ((storyVersion() <= 3) && (objectId > 255)) portDie(MSG_INT_OBJECT_BAD_ID); @@ -247,7 +260,7 @@ uint8_t interpreterGetObjectPointer(uint16_t objectId) { uint8_t interpreterGetObjectProperty(uint16_t objectId, uint32_t propertyId, uint8_t *size) { - uint8_t ptr = interpreterGetObjectPointer(objectId); + uint32_t ptr = interpreterGetObjectPointer(objectId); uint16_t addr; uint8_t info; uint16_t num; @@ -282,9 +295,20 @@ uint8_t interpreterGetObjectProperty(uint16_t objectId, uint32_t propertyId, uin } -bool interpreterParseOperand(uint8_t opType, uint8_t operandId) { - uint8_t addr; +uint32_t interpreterGlobalVariableAddress(uint16_t var) { + return storyGlobalVariableTableAddress() + ((var - 0x10) * 2); +} + +uint16_t interpreterLoadVariable(uint16_t var) { + // Is it on the stack? + if (var < 16) return __state.stack[interpreterVariableAddress(var, 0)]; + // Nope, global. + return PEEKW(interpreterGlobalVariableAddress(var)); +} + + +bool interpreterParseOperand(uint8_t opType, uint8_t operandId) { switch(opType) { // Large constant. case 0: @@ -299,8 +323,7 @@ bool interpreterParseOperand(uint8_t opType, uint8_t operandId) { // Variable. case 2: - addr = interpreterVariableAddress(PEEK(__state.pc++), 0); - __state.operands[operandId] = PEEKW(addr); + __state.operands[operandId] = interpreterLoadVariable(PEEK(__state.pc++)); return true; } @@ -350,6 +373,7 @@ void interpreterRun(void) { uint8_t opcode; bool extended; opcodeT op; + bool eight; while (__state.quit == 0) { opcode = PEEK(__state.pc++); @@ -378,7 +402,8 @@ void interpreterRun(void) { __state.operandCount = 0; } else if (opcode > 191) { // Variable Opcodes - if ((opcode == 236) || (opcode == 250)) { + eight = (opcode == 236) || (opcode == 250); + if (!eight) { // call_vs2 and call_vn2 take up to EIGHT arguments! __state.operandCount = interpreterParseVariableOperands(0); } else { @@ -413,17 +438,38 @@ void interpreterRun(void) { } +void interpreterStoreVariable(uint16_t var, uint16_t value) { + uint32_t addr; + + if (var < 16) { + // On stack. + addr = interpreterVariableAddress(var, 1); + __state.stack[addr] = value; + } else { + // Global. + addr = interpreterGlobalVariableAddress(var); + POKEW(addr, value); + } +} + + uint8_t interpreterVariableAddress(uint8_t var, bool writing) { uint16_t numLocals; if (var == 0) { // top of stack if (writing) { if (__state.sp >= sizeof(__state.stack)) portDie(MSG_INT_STACK_OVERFLOW); +#ifdef DEBUGGING + printf("Push stack\n"); +#endif return __state.sp++; } else { if (__state.sp == 0) portDie(MSG_INT_STACK_UNDERFLOW); numLocals = __state.bp ? __state.stack[__state.bp - 1] : 0; if ((__state.bp + numLocals) >= sizeof(__state.stack)) portDie(MSG_INT_STACK_UNDERFLOW); +#ifdef DEBUGGING + printf("Pop stack\n"); +#endif return --__state.sp; } // writing } // var diff --git a/src/memory.c b/src/memory.c index ac096e0..231addd 100644 --- a/src/memory.c +++ b/src/memory.c @@ -87,7 +87,7 @@ void memoryLoadStory(void) { // Alphabet A2 *(p++) = 0; if (storyVersion() != 1) *(p++) = '\n'; - for (i=0; i<10; i++) *(p++) = 'o' + i; + for (i=0; i<10; i++) *(p++) = '0' + i; *(p++) = '.'; *(p++) = ','; *(p++) = '!'; @@ -112,8 +112,8 @@ void memorySetByte(uint16_t address, uint8_t value) { void memorySetWord(uint16_t address, uint16_t value) { - _RAM[address] = (value & 0xff00) >> 8; // MSB first. - _RAM[address + 1] = value & 0x00ff; + _RAM[address] = (value >> 8) & 0xff; // MSB first. + _RAM[address + 1] = value & 0xff; } diff --git a/src/oc_2op.c b/src/oc_2op.c index 3dd774e..71432fc 100644 --- a/src/oc_2op.c +++ b/src/oc_2op.c @@ -31,8 +31,7 @@ void opcodes_add(void) { - uint8_t store = interpreterVariableAddress(PEEK(__state.pc++), 1); - POKEW(store, ((int16_t)__state.operands[0]) + ((int16_t)__state.operands[1])); + interpreterStoreVariable(PEEK(__state.pc++), __state.operands[0] + __state.operands[1]); } @@ -41,8 +40,10 @@ void opcodes_je(void) { int8_t i; for (i=1; i<__state.operandCount; i++) { - if (a == __state.operands[i]) interpreterDoBranch(1); - return; + if (a == __state.operands[i]) { + interpreterDoBranch(1); + return; + } } interpreterDoBranch(0); @@ -50,31 +51,28 @@ void opcodes_je(void) { void opcodes_loadw(void) { - uint16_t store = interpreterVariableAddress(PEEK(__state.pc++), 1); uint16_t offset = __state.operands[0] + (__state.operands[1] * 2); - POKEW(store, PEEKW(offset)); + interpreterStoreVariable(PEEK(__state.pc++), PEEKW(offset)); } void opcodes_store(void) { - uint8_t store = interpreterVariableAddress((uint8_t)(__state.operands[0] & 0xFF), 1); - POKEW(store, __state.operands[1]); + interpreterStoreVariable((__state.operands[0] & 0xFF), __state.operands[1]); } void opcodes_sub(void) { - uint8_t store = interpreterVariableAddress(PEEK(__state.pc++), 1); - POKEW(store, ((int16_t)__state.operands[0]) - ((int16_t)__state.operands[1])); + interpreterStoreVariable(PEEK(__state.pc++), __state.operands[0] - __state.operands[1]); } void opcodes_test_attr(void) { - uint8_t ptr = interpreterGetObjectPointer(__state.operands[0]); + uint32_t ptr = interpreterGetObjectPointer(__state.operands[0]); uint16_t attrId = __state.operands[1]; if (storyVersion() <= 3) { ptr += (attrId / 8); - interpreterDoBranch((ptr & (0x80 >> (attrId & 7))) ? 1 : 0); + interpreterDoBranch((PEEK(ptr) & (0x80 >> (attrId & 7))) ? 1 : 0); } else { portDie(MSG_UNIMPLEMENTED); } diff --git a/src/opcodes.c b/src/opcodes.c index 3c4fff2..2f77ab5 100644 --- a/src/opcodes.c +++ b/src/opcodes.c @@ -34,226 +34,215 @@ // Macros to declare implemented opcodes. #ifdef DEBUGGING -#define OP(name) __state.opcodes[_nextOpcode] = opcodes_##name; __state.opcodesName[_nextOpcode++] = #name -#define OPn(num, name) __state.opcodes[num] = opcodes_##name; __state.opcodesName[num] = #name -#define OPX(name) __state.extOpcodes[_nextOpcode] = opcodes_ext_##name; __state.extOpcodesName[_nextOpcode++] = #name -#define OPXn(num, name) __state.extOpcodes[num] = opcodes_ext_##name; __state.extOpcodes[num] = #name +#define OP(num, name) __state.opcodes[num] = opcodes_##name; __state.opcodesName[num] = #name +#define OPX(num, name) __state.extOpcodes[num] = opcodes_ext_##name; __state.extOpcodes[num] = #name #else -#define OP(name) __state.opcodes[_nextOpcode++] = opcodes_##name -#define OPn(num, name) __state.opcodes[num] = opcodes_##name -#define OPX(name) __state.extOpcodes[_nextOpcode++] = opcodes_ext_##name -#define OPXn(num, name) __state.extOpcodes[num] = opcodes_ext_##name +#define OP(num, name) __state.opcodes[num] = opcodes_##name +#define OPX(num, name) __state.extOpcodes[num] = opcodes_ext_##name #endif // Macros to declare un-implemented opcodes. -#define mOP(name) _nextOpcode++ -#define mOPn(num, name) -#define mOPX(name) _nextOpcode++ -#define mOPXn(num, name) - - -int16_t _nextOpcode; +#define mOP(num, name) +#define mOPX(num, name) void opcodesBuiltInitialTable(void) { // 2-operand instructions... - _nextOpcode = 1; - OP(je); - mOP(jl); - mOP(jg); - mOP(dec_chk); - mOP(inc_chk); - mOP(jin); - mOP(test); - mOP(or); - mOP(and); - OP(test_attr); - mOP(set_attr); - mOP(clear_attr); - OP(store); - mOP(insert_obj); - OP(loadw); - mOP(loadb); - mOP(get_prop); - mOP(get_prop_addr); - mOP(get_next_prop); - OP(add); - OP(sub); - mOP(mul); - mOP(div); - mOP(mod); // oc# 24 + OP(1, je); + mOP(2, jl); + mOP(3, jg); + mOP(4, dec_chk); + mOP(5, inc_chk); + mOP(6, jin); + mOP(7, test); + mOP(8, or); + mOP(9, and); + OP(10, test_attr); + mOP(11, set_attr); + mOP(12, clear_attr); + OP(13, store); + mOP(14, insert_obj); + OP(15, loadw); + mOP(16, loadb); + mOP(17, get_prop); + mOP(18, get_prop_addr); + mOP(19, get_next_prop); + OP(20, add); + OP(21, sub); + mOP(22, mul); + mOP(23, div); + mOP(24, mod); // 1-operand instructions... - _nextOpcode = 128; - OP(jz); - mOP(get_sibling); - mOP(get_child); - mOP(get_parent); - mOP(get_prop_len); - mOP(inc); - mOP(dec); // oc# 135 + OP(128, jz); + mOP(129, get_sibling); + mOP(130, get_child); + mOP(131, get_parent); + mOP(132, get_prop_len); + mOP(133, inc); + mOP(134, dec); + mOP(135, print_addr); - _nextOpcode = 137; - mOP(print_addr); - mOP(remove_obj); - mOP(print_obj); - OP(ret); - OP(jump); - mOP(print_paddr); - mOP(load); - mOP(not); // oc# 143 + mOP(137, remove_obj); + mOP(138, print_obj); + OP(139, ret); + OP(140, jump); + mOP(141, print_paddr); + mOP(142, load); + mOP(143, not); // 0-operand instructions... - _nextOpcode = 176; - mOP(rtrue); - mOP(rfalse); - OP(print); - mOP(print_ret); - mOP(nop); - mOP(save); - mOP(restore); - mOP(restart); - mOP(ret_popped); - mOP(pop); - mOP(quit); - OP(new_line); // oc# 187 + mOP(176, rtrue); + mOP(177, rfalse); + OP(178, print); + mOP(179, print_ret); + mOP(180, nop); + mOP(181, save); + mOP(182, restore); + mOP(183, restart); + mOP(184, ret_popped); + mOP(185, pop); + mOP(186, quit); + OP(187, new_line); // variable operand instructions... - _nextOpcode = 224; - OP(call); - OP(storew); - mOP(storeb); - OP(put_prop); - mOP(read); - mOP(print_char); - mOP(print_num); - mOP(random); - mOP(push); - mOP(pull); // oc# 233 + OP(224, call); + OP(225, storew); + mOP(226, storeb); + OP(227, put_prop); + mOP(228, read); + mOP(229, print_char); + mOP(230, print_num); + mOP(231, random); + mOP(232, push); + mOP(233, pull); if (storyVersion() < 3) return; - _nextOpcode = 188; - mOP(show_status); - mOP(verify); // oc# 189 + mOP(188, show_status); + mOP(189, verify); - _nextOpcode = 234; - mOP(split_window); - mOP(set_window); // oc# 235 + mOP(234, split_window); + mOP(235, set_window); - _nextOpcode = 243; - mOP(output_stream); - mOP(input_stream); - mOP(sound_effect); // oc# 245 + mOP(243, output_stream); + mOP(244, input_stream); + mOP(245, sound_effect); if (storyVersion() < 4) return; // show_status is illegal in ver4+, but a build of Wishbringer // accidentally calls it, so always treat it as NOP instead. - mOPn(188, opcode_nop); - mOPn(25, call_2s); - mOPn(180, save_ver4); - mOPn(224, call_vs); - mOPn(228, sread_ver4); + mOP(188, opcode_nop); - _nextOpcode = 236; - mOP(call_vs2); - mOP(erase_window); - mOP(erase_line); - mOP(set_cursor); - mOP(get_cursor); - mOP(set_text_style); - mOP(buffer_mode); // oc# 242 + mOP(25, call_2s); - _nextOpcode = 246; - mOP(read_char); - mOP(scan_table); // oc# 247 + mOP(180, save_ver4); + + mOP(224, call_vs); + + mOP(228, sread_ver4); + + mOP(236, call_vs2); + mOP(237, erase_window); + mOP(238, erase_line); + mOP(239, set_cursor); + mOP(240, get_cursor); + mOP(241, set_text_style); + mOP(242, buffer_mode); + + mOP(246, read_char); + mOP(247, scan_table); if (storyVersion() < 5) return; - _nextOpcode = 26; - mOP(call_2n); - mOP(set_colour); - mOP(throw); + mOP(26, call_2n); + mOP(27, set_color); + mOP(28, throw); - mOPn(136, call_1s); - mOPn(143, call_1n); - mOPn(185, catch); - mOPn(191, piracy); - mOPn(228, aread); - mOPn(243, output_stream_ver5); - mOPn(245, sound_effect_ver5); + mOP(136, call_1s); - _nextOpcode = 248; - mOP(not_ver5); - mOP(call_vn); - mOP(call_vn2); - mOP(tokenise); - mOP(encode_text); - mOP(copy_table); - mOP(print_table); - mOP(check_arg_count); // oc# 255 + mOP(143, call_1n); + + mOP(185, catch); + + mOP(191, piracy); + + mOP(228, aread); + + mOP(243, output_stream_ver5); + + mOP(245, sound_effect_ver5); + + mOP(248, not_ver5); + mOP(249, call_vn); + mOP(250, call_vn2); + mOP(251, tokenise); + mOP(252, encode_text); + mOP(253, copy_table); + mOP(254, print_table); + mOP(255, check_arg_count); // this is the "save" and "restore" opcodes in ver1-4; illegal in ver5+. // in ver5+, they use extended opcodes 0 and 1 for these. __state.opcodes[180] = 0; __state.opcodes[181] = 0; +#ifdef DEBUGGING + __state.opcodesName[180] = 0; + __state.opcodesName[181] = 0; +#endif // extended opcodes in ver5+ ... - _nextOpcode = 0; - mOPX(save_ext); - mOPX(restore_ext); - mOPX(log_shift); - mOPX(art_shift); - mOPX(set_font); // xop# 4 + mOPX(0, save_ext); + mOPX(1, restore_ext); + mOPX(2, log_shift); + mOPX(3, art_shift); + mOPX(4, set_font); - _nextOpcode = 9; - mOPX(save_undo); - mOPX(restore_undo); - mOPX(print_unicode); - mOPX(check_unicode); - mOPX(set_true_colour); // xop# 13 + mOPX(9, save_undo); + mOPX(10, restore_undo); + mOPX(11, print_unicode); + mOPX(12, check_unicode); + mOPX(13, set_true_color); if (storyVersion() < 6) return; - _nextOpcode = 27; - mOP(set_colour_ver6); - mOP(throw_ver6); // op# 28 + mOP(27, set_color_ver6); + mOP(28, throw_ver6); - mOPn(185, catch_ver6); - mOPn(233, pull_ver6); + mOP(185, catch_ver6); - _nextOpcode = 238; - mOP(erase_line_ver6); - mOP(set_cursor_ver6); // op# 239 + mOP(233, pull_ver6); - mOPn(243, output_stream_ver6); - mOPn(248, not_ver6); + mOP(238, erase_line_ver6); + mOP(239, set_cursor_ver6); - _nextOpcode = 4; - mOPX(set_font_ver6); - mOPX(draw_picture); - mOPX(picture_data); - mOPX(erase_picture); - mOPX(set_margins); // xop# 8 + mOP(243, output_stream_ver6); - mOPXn(13, set_true_colour_ver6); + mOP(248, not_ver6); - _nextOpcode = 16; - mOPX(move_window); - mOPX(window_size); - mOPX(window_style); - mOPX(get_wind_prop); - mOPX(scroll_window); - mOPX(pop_stack); - mOPX(read_mouse); - mOPX(mouse_window); - mOPX(push_stack); - mOPX(put_wind_prop); - mOPX(print_form); - mOPX(make_menu); - mOPX(picture_table); - mOPX(buffer_screen); // xop# 29 + mOPX(4, set_font_ver6); + mOPX(5, draw_picture); + mOPX(6, picture_data); + mOPX(7, erase_picture); + mOPX(8, set_margins); // xop# 8 + + mOPX(13, set_true_color_ver6); + + mOPX(16, move_window); + mOPX(17, window_size); + mOPX(18, window_style); + mOPX(19, get_wind_prop); + mOPX(20, scroll_window); + mOPX(21, pop_stack); + mOPX(22, read_mouse); + mOPX(23, mouse_window); + mOPX(24, push_stack); + mOPX(25, put_wind_prop); + mOPX(26, print_form); + mOPX(27, make_menu); + mOPX(28, picture_table); + mOPX(29, buffer_screen); } @@ -263,14 +252,14 @@ void opcodesSetup(void) { opcodesBuiltInitialTable(); // 2OP opcodes repeating with different operand forms. - for (i=32; i<=127; i++) __state.opcodes[i] = __state.opcodes[i % 32]; + for (i=32; i<=127; i++) __state.opcodes[i] = __state.opcodes[i % 32]; // 1OP opcodes repeating with different operand forms. for (i=144; i<=175; i++) __state.opcodes[i] = __state.opcodes[128 + (i % 16)]; // 2OP opcodes repeating with VAR operand forms. for (i=192; i<=223; i++) __state.opcodes[i] = __state.opcodes[i % 32]; #ifdef DEBUGGING - for (i=32; i<=127; i++) __state.opcodesName[i] = __state.opcodesName[i % 32]; + for (i=32; i<=127; i++) __state.opcodesName[i] = __state.opcodesName[i % 32]; for (i=144; i<=175; i++) __state.opcodesName[i] = __state.opcodesName[128 + (i % 16)]; for (i=192; i<=223; i++) __state.opcodesName[i] = __state.opcodesName[i % 32]; #endif