Many, many, untested opcodes added.
This commit is contained in:
parent
af33bd6865
commit
389592fc12
25 changed files with 676 additions and 65 deletions
|
@ -41,7 +41,7 @@
|
|||
#define MSG_INT_V12_SHIFT "Add V1/V2 shifting."
|
||||
#define MSG_INT_V12_SHIFT_LOCK "Add V1/V2 shift locking."
|
||||
#define MSG_MEM_BUFFER "Unable to allocate memory buffer."
|
||||
#define MSG_OP_VAR_MISSING_PROPERTY "Missing object property."
|
||||
#define MSG_OP_OBJ_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 // DEBUGGING
|
||||
|
|
|
@ -29,7 +29,11 @@
|
|||
|
||||
|
||||
uint32_t objectPointerGet(uint16_t objectId);
|
||||
uint32_t objectPointerParentGet(uint32_t objectPointer);
|
||||
uint16_t objectPropertyDefaultGet(uint32_t propertyId);
|
||||
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size);
|
||||
uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship);
|
||||
void objectUnparent(uint16_t objectId);
|
||||
|
||||
|
||||
#endif // OBJECT_H
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
|
||||
void opcodes_call(void);
|
||||
void opcodes_ret(void);
|
||||
void opcodes_rfalse(void);
|
||||
void opcodes_rtrue(void);
|
||||
void opcodes_ret_popped(void);
|
||||
|
||||
|
||||
#endif // OC_CALL_H
|
||||
|
|
|
@ -28,9 +28,15 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_dec_chk(void);
|
||||
void opcodes_inc_chk(void);
|
||||
void opcodes_je(void);
|
||||
void opcodes_jg(void);
|
||||
void opcodes_jin(void);
|
||||
void opcodes_jl(void);
|
||||
void opcodes_jump(void);
|
||||
void opcodes_jz(void);
|
||||
void opcodes_test(void);
|
||||
|
||||
|
||||
#endif // OC_COMPARE_H
|
||||
|
|
|
@ -28,4 +28,7 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_read(void);
|
||||
|
||||
|
||||
#endif // OC_INPUT_H
|
||||
|
|
|
@ -29,6 +29,13 @@
|
|||
|
||||
|
||||
void opcodes_add(void);
|
||||
void opcodes_and(void);
|
||||
void opcodes_dec(void);
|
||||
void opcodes_div(void);
|
||||
void opcodes_inc(void);
|
||||
void opcodes_mod(void);
|
||||
void opcodes_mul(void);
|
||||
void opcodes_or(void);
|
||||
void opcodes_sub(void);
|
||||
|
||||
|
||||
|
|
|
@ -28,8 +28,11 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_load(void);
|
||||
void opcodes_loadb(void);
|
||||
void opcodes_loadw(void);
|
||||
void opcodes_store(void);
|
||||
void opcodes_storeb(void);
|
||||
void opcodes_storew(void);
|
||||
|
||||
|
||||
|
|
|
@ -28,4 +28,9 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_nop(void);
|
||||
void opcodes_quit(void);
|
||||
void opcodes_random(void);
|
||||
|
||||
|
||||
#endif // OC_MISC_H
|
||||
|
|
|
@ -28,7 +28,18 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_clear_attr(void);
|
||||
void opcodes_get_child(void);
|
||||
void opcodes_get_next_prop(void);
|
||||
void opcodes_get_parent(void);
|
||||
void opcodes_get_prop(void);
|
||||
void opcodes_get_prop_addr(void);
|
||||
void opcodes_get_prop_len(void);
|
||||
void opcodes_get_sibling(void);
|
||||
void opcodes_insert_obj(void);
|
||||
void opcodes_put_prop(void);
|
||||
void opcodes_remove_obj(void);
|
||||
void opcodes_set_attr(void);
|
||||
void opcodes_test_attr(void);
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
|
||||
void opcodes_new_line(void);
|
||||
void opcodes_print(void);
|
||||
void opcodes_print_addr(void);
|
||||
void opcodes_print_char(void);
|
||||
void opcodes_print_num(void);
|
||||
void opcodes_print_obj(void);
|
||||
void opcodes_print_paddr(void);
|
||||
void opcodes_print_ret(void);
|
||||
|
||||
|
||||
#endif // OC_OUTPUT_H
|
||||
|
|
|
@ -28,4 +28,9 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
void opcodes_save(void);
|
||||
void opcodes_restart(void);
|
||||
void opcodes_restore(void);
|
||||
|
||||
|
||||
#endif // OC_SAVE_H
|
||||
|
|
|
@ -28,13 +28,19 @@
|
|||
#include "common.h"
|
||||
|
||||
|
||||
uint8_t portByteGet(uint16_t address);
|
||||
void portByteSet(uint16_t address, uint8_t value);
|
||||
void portDie(char *fmt, ...);
|
||||
void portPrintChars(char *chars, uint16_t len);
|
||||
void portStoryLoad(void);
|
||||
uint16_t portWordGet(uint16_t address);
|
||||
void portWordSet(uint16_t address, uint16_t value);
|
||||
uint8_t portByteGet(uint16_t address);
|
||||
void portByteSet(uint16_t address, uint8_t value);
|
||||
void portCharsPrint(char *chars, uint16_t len);
|
||||
void portDie(char *fmt, ...);
|
||||
void portFileClose(uint32_t *handle);
|
||||
byte portFileByteRead(uint32_t *handle);
|
||||
bool portFileByteWrite(uint32_t *handle, byte value);
|
||||
bool portFileReadOpen(uint32_t *handle, char *name);
|
||||
bool portFileWriteOpen(uint32_t *handle, char *name);
|
||||
uint16_t portRandomGet(int16_t range);
|
||||
void portStoryLoad(void);
|
||||
uint16_t portWordGet(uint16_t address);
|
||||
void portWordSet(uint16_t address, uint16_t value);
|
||||
|
||||
|
||||
#endif // PORTME_H
|
||||
|
|
61
src/object.c
61
src/object.c
|
@ -42,6 +42,35 @@ uint32_t objectPointerGet(uint16_t objectId) {
|
|||
}
|
||||
|
||||
|
||||
uint32_t objectPointerParentGet(uint32_t objectPointer) {
|
||||
uint32_t result = 0;
|
||||
uint32_t parent;
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
parent = ZPEEK(objectPointer + 4);
|
||||
result = parent ? objectPointerGet(parent) : 0;
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint16_t objectPropertyDefaultGet(uint32_t propertyId) {
|
||||
uint32_t values;
|
||||
|
||||
if (((storyVersion() <= 3) && (propertyId > 31)) || ((storyVersion() >= 4) && (propertyId > 63))) {
|
||||
//***TODO*** Should we die here? This seems to work.
|
||||
return 0;
|
||||
}
|
||||
|
||||
values = storyObjectTableAddress() + ((propertyId - 1) * 2);
|
||||
|
||||
return ZPEEKW(values);
|
||||
}
|
||||
|
||||
|
||||
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size) {
|
||||
uint32_t ptr = objectPointerGet(objectId);
|
||||
uint16_t addr;
|
||||
|
@ -78,3 +107,35 @@ uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size)
|
|||
}
|
||||
|
||||
|
||||
uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship) {
|
||||
uint32_t objPtr = objectPointerGet(objectId);
|
||||
uint16_t result = 0;
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
result = ZPEEKW(objPtr + relationship);
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void objectUnparent(uint16_t objectId) {
|
||||
uint32_t objPtr = objectPointerGet(objectId);
|
||||
uint32_t parentPtr = objectPointerParentGet(objPtr);
|
||||
uint32_t ptr;
|
||||
|
||||
if (parentPtr != 0) {
|
||||
if (storyVersion() <= 3) {
|
||||
ptr = parentPtr + 6; // 4 to skip attrs, 2 to skip to child.
|
||||
while (ZPEEK(ptr) != objectId) { // If not direct child, look through sibling list..
|
||||
ptr = objectPointerGet(ZPEEK(ptr)) + 5;
|
||||
}
|
||||
ZPOKE(ptr, ZPEEK(objPtr + 5)); // obj sibling takes obj's place.
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,3 +93,18 @@ void opcodes_call(void) {
|
|||
void opcodes_ret(void) {
|
||||
interpreterDoReturn(__state.operands[0]);
|
||||
}
|
||||
|
||||
void opcodes_rfalse(void) {
|
||||
interpreterDoReturn(0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_rtrue(void) {
|
||||
interpreterDoReturn(1);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_ret_popped(void) {
|
||||
// Top of stack.
|
||||
interpreterDoReturn(variableLoad(0));
|
||||
}
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
#include "oc_compare.h"
|
||||
#include "state.h"
|
||||
#include "interpreter.h"
|
||||
#include "variable.h"
|
||||
#include "object.h"
|
||||
#include "story.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
void opcodes_je(void) {
|
||||
|
@ -41,6 +47,48 @@ void opcodes_je(void) {
|
|||
}
|
||||
|
||||
|
||||
void opcodes_dec_chk(void) {
|
||||
int16_t val = variableLoad(__state.operands[0]);
|
||||
val--;
|
||||
variableStore(__state.operands[0], val);
|
||||
interpreterDoBranch(((int16_t)val < (int16_t)__state.operands[1]) ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_inc_chk(void) {
|
||||
int16_t val = variableLoad(__state.operands[0]);
|
||||
val++;
|
||||
variableStore(__state.operands[0], val);
|
||||
interpreterDoBranch(((int16_t)val > (int16_t)__state.operands[1]) ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_jg(void) {
|
||||
interpreterDoBranch(((int16_t)__state.operands[0] > (int16_t)__state.operands[1]) ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_jin(void) {
|
||||
uint16_t objId = __state.operands[0];
|
||||
uint16_t parentId = __state.operands[1];
|
||||
uint32_t objPtr = objectPointerGet(objId);
|
||||
|
||||
// Zork 1 will trigger this on "go X" where "x" isn't a direction.
|
||||
if (objPtr == 0) return;
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
interpreterDoBranch((ZPEEKW(objPtr + 4) == parentId) ? 1 : 0);
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void opcodes_jl(void) {
|
||||
interpreterDoBranch(((int16_t)__state.operands[0] < (int16_t)__state.operands[1]) ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_jump(void) {
|
||||
__state.pc = __state.pc + ((int16_t)__state.operands[0]) - 2;
|
||||
}
|
||||
|
@ -51,3 +99,7 @@ void opcodes_jz(void) {
|
|||
}
|
||||
|
||||
|
||||
void opcodes_test(void) {
|
||||
interpreterDoBranch(((__state.operands[0] & __state.operands[1]) == __state.operands[0]) ? 1 : 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,3 +22,11 @@
|
|||
|
||||
|
||||
#include "oc_input.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
|
||||
|
||||
void opcodes_read(void) {
|
||||
//***TODO***
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
|
|
|
@ -28,11 +28,45 @@
|
|||
|
||||
|
||||
void opcodes_add(void) {
|
||||
variableStore(ZPEEK(__state.pc++), __state.operands[0] + __state.operands[1]);
|
||||
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] + (int16_t)__state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_and(void) {
|
||||
variableStore(ZPEEK(__state.pc++), __state.operands[0] & __state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_dec(void) {
|
||||
variableStore(__state.operands[0], variableLoad(__state.operands[0]) - 1);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_div(void) {
|
||||
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] / (int16_t)__state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_inc(void) {
|
||||
variableStore(__state.operands[0], variableLoad(__state.operands[0]) + 1);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_mod(void) {
|
||||
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] % (int16_t)__state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_mul(void) {
|
||||
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] * (int16_t)__state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_or(void) {
|
||||
variableStore(ZPEEK(__state.pc++), __state.operands[0] | __state.operands[1]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_sub(void) {
|
||||
variableStore(ZPEEK(__state.pc++), __state.operands[0] - __state.operands[1]);
|
||||
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] - (int16_t)__state.operands[1]);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,17 @@
|
|||
#include "memory.h"
|
||||
|
||||
|
||||
void opcodes_load(void) {
|
||||
variableStore(ZPEEK(__state.pc++), ZPEEK((__state.operands[0] & 0xFF)));
|
||||
}
|
||||
|
||||
|
||||
void opcodes_loadb(void) {
|
||||
uint16_t offset = __state.operands[0] + __state.operands[1];
|
||||
variableStore(ZPEEK(__state.pc++), ZPEEK(offset));
|
||||
}
|
||||
|
||||
|
||||
void opcodes_loadw(void) {
|
||||
uint16_t offset = __state.operands[0] + (__state.operands[1] * 2);
|
||||
variableStore(ZPEEK(__state.pc++), ZPEEKW(offset));
|
||||
|
@ -38,6 +49,11 @@ void opcodes_store(void) {
|
|||
}
|
||||
|
||||
|
||||
void opcodes_storeb(void) {
|
||||
ZPOKE(__state.operands[0] + __state.operands[1], __state.operands[2]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_storew(void) {
|
||||
ZPOKEW(__state.operands[0] + (__state.operands[1] * 2), __state.operands[2]);
|
||||
}
|
||||
|
|
|
@ -22,3 +22,21 @@
|
|||
|
||||
|
||||
#include "oc_misc.h"
|
||||
#include "state.h"
|
||||
#include "variable.h"
|
||||
#include "portme.h"
|
||||
|
||||
|
||||
void opcodes_nop(void) {
|
||||
// Well this one is easy.
|
||||
}
|
||||
|
||||
|
||||
void opcodes_quit(void) {
|
||||
__state.quit = true;
|
||||
}
|
||||
|
||||
|
||||
void opcodes_random(void) {
|
||||
variableStore((__state.pc++), portRandomGet((int16_t)__state.operands[0]));
|
||||
}
|
||||
|
|
151
src/oc_object.c
151
src/oc_object.c
|
@ -29,13 +29,133 @@
|
|||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
#include "object.h"
|
||||
#include "variable.h"
|
||||
|
||||
|
||||
void opcodes_clear_attr(void) {
|
||||
uint32_t ptr = objectPointerGet(__state.operands[0]);
|
||||
uint16_t attrId = __state.operands[1];
|
||||
|
||||
// Zork 1 will trigger this on "go X" where "x" isn't a direction, so ignore it.
|
||||
if (ptr == 0) return;
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
ptr += (attrId / 8);
|
||||
ZPOKE(ptr, ZPEEK(ptr) & ~(0x80 >> (attrId & 7)));
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void opcodes_get_child(void) {
|
||||
uint16_t result = objectRelationGet(__state.operands[0], 6);
|
||||
variableStore(ZPEEK(__state.pc++), result);
|
||||
interpreterDoBranch(result != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_get_next_prop(void) {
|
||||
uint16_t objId = __state.operands[0];
|
||||
bool firstProp = (__state.operands[1] == 0);
|
||||
uint16_t result = 0;
|
||||
uint8_t size = 0;
|
||||
uint32_t ptr = objectPropertyGet(objId, firstProp ? 0xFFFFFFFF : __state.operands[1], &size);
|
||||
|
||||
if (ptr == 0) {
|
||||
portDie(MSG_OP_OBJ_MISSING_PROPERTY);
|
||||
}
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
// 5 bits for the prop id.
|
||||
result = ZPEEK(ptr + (firstProp ? -1 : (int8_t)size)) & 0x1f;
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
|
||||
variableStore(ZPEEK(__state.pc++), result);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_get_parent(void) {
|
||||
uint16_t result = objectRelationGet(__state.operands[0], 4);
|
||||
variableStore(ZPEEK(__state.pc++), result);
|
||||
interpreterDoBranch(result != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_get_prop(void) {
|
||||
uint16_t objId = __state.operands[0];
|
||||
uint16_t propId = __state.operands[1];
|
||||
uint16_t result = 0;
|
||||
uint8_t size = 0;
|
||||
uint32_t ptr = objectPropertyGet(objId, propId, &size);
|
||||
|
||||
if (ptr == 0) {
|
||||
result = objectPropertyDefaultGet(propId);
|
||||
} else {
|
||||
result = ZPEEK(ptr);
|
||||
}
|
||||
|
||||
variableStore(ZPEEK(__state.pc++), result);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_get_prop_addr(void) {
|
||||
uint16_t objId = __state.operands[0];
|
||||
uint16_t propId = __state.operands[1];
|
||||
|
||||
variableStore(ZPEEK(__state.pc++), objectPropertyGet(objId, propId, NULL));
|
||||
}
|
||||
|
||||
|
||||
void opcodes_get_prop_len(void) {
|
||||
uint16_t result = 0;
|
||||
uint8_t info;
|
||||
|
||||
// This must return 0 if OP0 is zero, to avoid a bug in older Infocom games.
|
||||
if (__state.operands[0] != 0) {
|
||||
if (storyVersion() <= 3) {
|
||||
info = ZPEEK(__state.operands[0] - 1);
|
||||
result = ((info >> 5) & 0x7) + 1; // 3 bits for property size.
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
variableStore(ZPEEK(__state.pc++), result);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_get_sibling(void) {
|
||||
uint16_t result = objectRelationGet(__state.operands[0], 5);
|
||||
variableStore(ZPEEK(__state.pc++), result);
|
||||
interpreterDoBranch(result != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_insert_obj(void) {
|
||||
uint32_t objPtr = objectPointerGet(__state.operands[0]);
|
||||
uint32_t dstPtr = objectPointerGet(__state.operands[1]);
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
// Take object out of tree.
|
||||
objectUnparent(__state.operands[0]);
|
||||
// Reinsert in right spot.
|
||||
ZPOKE(objPtr + 4, __state.operands[1]);
|
||||
ZPOKE(objPtr + 5, ZPEEK(dstPtr + 6));
|
||||
ZPOKE(dstPtr + 6, __state.operands[0]);
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void opcodes_put_prop(void) {
|
||||
uint8_t size = 0;
|
||||
uint8_t ptr = objectPropertyGet(__state.operands[0], __state.operands[1], &size);
|
||||
|
||||
if (ptr == 0) portDie(MSG_OP_VAR_MISSING_PROPERTY);
|
||||
if (ptr == 0) portDie(MSG_OP_OBJ_MISSING_PROPERTY);
|
||||
|
||||
if (size == 1) {
|
||||
ZPOKE(ptr, (__state.operands[2] & 0xff));
|
||||
|
@ -45,6 +165,35 @@ void opcodes_put_prop(void) {
|
|||
}
|
||||
|
||||
|
||||
void opcodes_remove_obj(void) {
|
||||
uint16_t objId = __state.operands[0];
|
||||
uint32_t objPtr = objectPointerGet(objId);
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
// Remove object from tree.
|
||||
objectUnparent(objId);
|
||||
// Clear out object's relationships.
|
||||
ZPOKE(objPtr + 4, 0); // Parent.
|
||||
ZPOKE(objPtr + 5, 0); // Sibling.
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void opcodes_set_attr(void) {
|
||||
uint32_t ptr = objectPointerGet(__state.operands[0]);
|
||||
uint16_t attrId = __state.operands[1];
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
ptr += (attrId / 8);
|
||||
ZPOKE(ptr, ZPEEK(ptr) | 0x80 >> (attrId & 7));
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void opcodes_test_attr(void) {
|
||||
uint32_t ptr = objectPointerGet(__state.operands[0]);
|
||||
uint16_t attrId = __state.operands[1];
|
||||
|
|
|
@ -25,13 +25,81 @@
|
|||
#include "state.h"
|
||||
#include "portme.h"
|
||||
#include "zscii.h"
|
||||
#include "memory.h"
|
||||
#include "story.h"
|
||||
#include "object.h"
|
||||
#include "messages.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
|
||||
void opcodes_new_line(void) {
|
||||
portPrintChars("\n", 1);
|
||||
portCharsPrint("\n", 1);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print(void) {
|
||||
__state.pc += zsciiPrint(__state.pc, 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print_addr(void) {
|
||||
zsciiPrint(__state.operands[0], 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print_char(void) {
|
||||
static char c[2] = { 0, 0 };
|
||||
|
||||
c[0] = zsciiDecodeChar(__state.operands[0]);
|
||||
if (c[0]) portCharsPrint(c, 1);
|
||||
}
|
||||
|
||||
|
||||
static void opcodes_print_num_helper(int16_t val) {
|
||||
static char c[2] = { 0, 0 };
|
||||
|
||||
if (val < 0) {
|
||||
portCharsPrint("-", 1);
|
||||
val = -val;
|
||||
}
|
||||
|
||||
if (val > 9) {
|
||||
opcodes_print_num_helper(val / 10);
|
||||
}
|
||||
|
||||
c[0] = '0' + (val % 10);
|
||||
portCharsPrint(c, 1);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print_num(void) {
|
||||
opcodes_print_num_helper(__state.operands[0]);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print_obj(void) {
|
||||
uint32_t ptr = objectPointerGet(__state.operands[0]);
|
||||
uint32_t addr;
|
||||
|
||||
if (storyVersion() <= 3) {
|
||||
// Skip to properties field.
|
||||
ptr += 7;
|
||||
// Dereference to get to property table.
|
||||
addr = ZPEEKW(ptr);
|
||||
zsciiPrint(addr + 1, 0);
|
||||
} else {
|
||||
portDie(MSG_UNIMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print_paddr(void) {
|
||||
zsciiPrint(memoryUnpackAddress(__state.operands[0], MEMORY_PRINT), 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_print_ret(void) {
|
||||
__state.pc += zsciiPrint(__state.pc, 0);
|
||||
portCharsPrint("\n", 1);
|
||||
interpreterDoReturn(1);
|
||||
}
|
||||
|
|
|
@ -22,3 +22,101 @@
|
|||
|
||||
|
||||
#include "oc_save.h"
|
||||
#include "interpreter.h"
|
||||
#include "state.h"
|
||||
#include "portme.h"
|
||||
#include "story.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
void opcodes_save(void) {
|
||||
uint32_t f;
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
uint8_t *b;
|
||||
|
||||
ok = portFileWriteOpen(&f, "save.dat");
|
||||
|
||||
// Write out PC.
|
||||
b = (uint8_t *)&__state.pc;
|
||||
ok &= portFileByteWrite(&f, b[0]);
|
||||
ok &= portFileByteWrite(&f, b[1]);
|
||||
ok &= portFileByteWrite(&f, b[2]);
|
||||
ok &= portFileByteWrite(&f, b[3]);
|
||||
|
||||
// Write out SP.
|
||||
b = (uint8_t *)&__state.sp;
|
||||
ok &= portFileByteWrite(&f, b[0]);
|
||||
ok &= portFileByteWrite(&f, b[1]);
|
||||
|
||||
// Write out BP.
|
||||
b = (uint8_t *)&__state.sp;
|
||||
ok &= portFileByteWrite(&f, b[0]);
|
||||
ok &= portFileByteWrite(&f, b[1]);
|
||||
|
||||
// Write out dynamic memory.
|
||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||
ok &= portFileByteWrite(&f, ZPEEK(i));
|
||||
}
|
||||
|
||||
// Write out stack.
|
||||
for (i=0; i<__state.sp; i++) {
|
||||
b = (uint8_t *)&__state.stack[i];
|
||||
ok &= portFileByteWrite(&f, b[0]);
|
||||
ok &= portFileByteWrite(&f, b[1]);
|
||||
}
|
||||
|
||||
portFileClose(&f);
|
||||
|
||||
interpreterDoBranch(ok ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_restart(void) {
|
||||
stateReset();
|
||||
portStoryLoad();
|
||||
storySetup();
|
||||
}
|
||||
|
||||
|
||||
void opcodes_restore(void) {
|
||||
uint32_t f;
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
uint8_t *b;
|
||||
|
||||
ok = portFileReadOpen(&f, "save.dat");
|
||||
|
||||
// Read PC.
|
||||
b = (uint8_t *)&__state.pc;
|
||||
b[0] = portFileByteRead(&f);
|
||||
b[1] = portFileByteRead(&f);
|
||||
b[2] = portFileByteRead(&f);
|
||||
b[3] = portFileByteRead(&f);
|
||||
|
||||
// Read SP.
|
||||
b = (uint8_t *)&__state.sp;
|
||||
b[0] = portFileByteRead(&f);
|
||||
b[1] = portFileByteRead(&f);
|
||||
|
||||
// Read BP.
|
||||
b = (uint8_t *)&__state.bp;
|
||||
b[0] = portFileByteRead(&f);
|
||||
b[1] = portFileByteRead(&f);
|
||||
|
||||
// Read dynamic memory.
|
||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||
ZPOKE(i, portFileByteRead(&f));
|
||||
}
|
||||
|
||||
// Read stack.
|
||||
for (i=0; i<__state.sp; i++) {
|
||||
b = (uint8_t *)&__state.stack[i];
|
||||
b[0] = portFileByteRead(&f);
|
||||
b[1] = portFileByteRead(&f);
|
||||
}
|
||||
|
||||
portFileClose(&f);
|
||||
|
||||
interpreterDoBranch(ok ? 1 : 0);
|
||||
}
|
||||
|
|
|
@ -54,78 +54,78 @@
|
|||
void opcodesBuiltInitialTable(void) {
|
||||
// 2-operand instructions...
|
||||
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(2, jl);
|
||||
OP(3, jg);
|
||||
OP(4, dec_chk);
|
||||
OP(5, inc_chk);
|
||||
OP(6, jin);
|
||||
OP(7, test);
|
||||
OP(8, or);
|
||||
OP(9, and);
|
||||
OP(10, test_attr);
|
||||
mOP(11, set_attr);
|
||||
mOP(12, clear_attr);
|
||||
OP(11, set_attr);
|
||||
OP(12, clear_attr);
|
||||
OP(13, store);
|
||||
mOP(14, insert_obj);
|
||||
OP(14, insert_obj);
|
||||
OP(15, loadw);
|
||||
mOP(16, loadb);
|
||||
mOP(17, get_prop);
|
||||
mOP(18, get_prop_addr);
|
||||
mOP(19, get_next_prop);
|
||||
OP(16, loadb);
|
||||
OP(17, get_prop);
|
||||
OP(18, get_prop_addr);
|
||||
OP(19, get_next_prop);
|
||||
OP(20, add);
|
||||
OP(21, sub);
|
||||
mOP(22, mul);
|
||||
mOP(23, div);
|
||||
mOP(24, mod);
|
||||
OP(22, mul);
|
||||
OP(23, div);
|
||||
OP(24, mod);
|
||||
|
||||
// 1-operand instructions...
|
||||
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);
|
||||
OP(129, get_sibling);
|
||||
OP(130, get_child);
|
||||
OP(131, get_parent);
|
||||
OP(132, get_prop_len);
|
||||
OP(133, inc);
|
||||
OP(134, dec);
|
||||
OP(135, print_addr);
|
||||
|
||||
mOP(137, remove_obj);
|
||||
mOP(138, print_obj);
|
||||
OP(137, remove_obj);
|
||||
OP(138, print_obj);
|
||||
OP(139, ret);
|
||||
OP(140, jump);
|
||||
mOP(141, print_paddr);
|
||||
mOP(142, load);
|
||||
OP(141, print_paddr);
|
||||
OP(142, load);
|
||||
mOP(143, not);
|
||||
|
||||
// 0-operand instructions...
|
||||
mOP(176, rtrue);
|
||||
mOP(177, rfalse);
|
||||
OP(176, rtrue);
|
||||
OP(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);
|
||||
OP(179, print_ret);
|
||||
OP(180, nop);
|
||||
OP(181, save);
|
||||
OP(182, restore);
|
||||
OP(183, restart);
|
||||
OP(184, ret_popped);
|
||||
mOP(185, pop);
|
||||
mOP(186, quit);
|
||||
OP(186, quit);
|
||||
OP(187, new_line);
|
||||
|
||||
// variable operand instructions...
|
||||
OP(224, call);
|
||||
OP(225, storew);
|
||||
mOP(226, storeb);
|
||||
OP(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);
|
||||
OP(228, read);
|
||||
OP(229, print_char);
|
||||
OP(230, print_num);
|
||||
OP(231, random);
|
||||
OP(232, push);
|
||||
OP(233, pull);
|
||||
|
||||
if (storyVersion() < 3) return;
|
||||
|
||||
mOP(188, show_status);
|
||||
mOP(189, verify);
|
||||
OP(189, verify);
|
||||
|
||||
mOP(234, split_window);
|
||||
mOP(235, set_window);
|
||||
|
|
43
src/portme.c
43
src/portme.c
|
@ -46,6 +46,14 @@ void portByteSet(uint16_t address, uint8_t value) {
|
|||
}
|
||||
|
||||
|
||||
void portCharsPrint(char *chars, uint16_t len) {
|
||||
uint16_t x;
|
||||
for (x=0; x<len; x++) {
|
||||
printf("%c", chars[x]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void portDie(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
|
@ -59,11 +67,36 @@ void portDie(char *fmt, ...) {
|
|||
}
|
||||
|
||||
|
||||
void portPrintChars(char *chars, uint16_t len) {
|
||||
uint16_t x;
|
||||
for (x=0; x<len; x++) {
|
||||
printf("%c", chars[x]);
|
||||
}
|
||||
void portFileClose(uint32_t *handle) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
byte portFileByteRead(uint32_t *handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool portFileByteWrite(uint32_t *handle, byte value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool portFileReadOpen(uint32_t *handle, char *name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool portFileWriteOpen(uint32_t *handle, char *name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint16_t portRandomGet(int16_t range) {
|
||||
// If range is zero, randomize with "best" random seed.
|
||||
// If range is negative, use the positive value to seed.
|
||||
|
||||
return 42;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ uint32_t zsciiPrint(uint32_t pc, bool abbr) {
|
|||
ret = zsciiDecode(pc, abbr, __memoryBuffer, &decodedChars);
|
||||
}
|
||||
|
||||
portPrintChars(__memoryBuffer, decodedChars);
|
||||
portCharsPrint(__memoryBuffer, decodedChars);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue