aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorMax Horn2010-02-07 12:13:59 +0000
committerMax Horn2010-02-07 12:13:59 +0000
commit3b4c54f0e5cac47c3f3a402865a800b43fbe4646 (patch)
treead377b42cd037569f4377d0445261c5a6dcaf3ea /engines/sci
parented2a3f1f1604d032ad2d37357ce025b3fcbf088e (diff)
downloadscummvm-rg350-3b4c54f0e5cac47c3f3a402865a800b43fbe4646.tar.gz
scummvm-rg350-3b4c54f0e5cac47c3f3a402865a800b43fbe4646.tar.bz2
scummvm-rg350-3b4c54f0e5cac47c3f3a402865a800b43fbe4646.zip
SCI: Add function readPMachineInstruction()
svn-id: r47956
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/vm.cpp125
-rw-r--r--engines/sci/engine/vm.h18
2 files changed, 91 insertions, 52 deletions
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index a7aeecee05..5a013722e9 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -584,6 +584,75 @@ static void gc_countdown(EngineState *s) {
static const byte _fake_return_buffer[2] = {op_ret << 1, op_ret << 1};
+
+int readPMachineInstruction(const byte *src, byte &extOpcode, int16 opparams[4]) {
+ uint offset = 0;
+ extOpcode = src[offset++]; // Get "extended" opcode (lower bit has special meaning)
+ const byte opnumber = extOpcode >> 1; // get the actual opcode
+
+ memset(opparams, 0, sizeof(opparams));
+
+ for (int i = 0; g_opcode_formats[opnumber][i]; ++i) {
+ //printf("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opnumber, temp);
+ assert(i < 4);
+ switch (g_opcode_formats[opnumber][i]) {
+
+ case Script_Byte:
+ opparams[i] = src[offset++];
+ break;
+ case Script_SByte:
+ opparams[i] = (int8)src[offset++];
+ break;
+
+ case Script_Word:
+ opparams[i] = READ_LE_UINT16(src + offset);
+ offset += 2;
+ break;
+ case Script_SWord:
+ opparams[i] = (int16)READ_LE_UINT16(src + offset);
+ offset += 2;
+ break;
+
+ case Script_Variable:
+ case Script_Property:
+
+ case Script_Local:
+ case Script_Temp:
+ case Script_Global:
+ case Script_Param:
+
+ case Script_Offset:
+ if (extOpcode & 1) {
+ opparams[i] = src[offset++];
+ } else {
+ opparams[i] = READ_LE_UINT16(src + offset);
+ offset += 2;
+ }
+ break;
+
+ case Script_SVariable:
+ case Script_SRelative:
+ if (extOpcode & 1) {
+ opparams[i] = (int8)src[offset++];
+ } else {
+ opparams[i] = (int16)READ_LE_UINT16(src + offset);
+ offset += 2;
+ }
+ break;
+
+ case Script_None:
+ case Script_End:
+ break;
+
+ case Script_Invalid:
+ default:
+ error("opcode %02x: Invalid", extOpcode);
+ }
+ }
+
+ return offset;
+}
+
void run_vm(EngineState *s, bool restoring) {
assert(s);
@@ -635,8 +704,6 @@ void run_vm(EngineState *s, bool restoring) {
s->_executionStackPosChanged = true; // Force initialization
while (1) {
- byte opcode;
- byte opnumber;
int var_type; // See description below
int var_number;
@@ -720,56 +787,10 @@ void run_vm(EngineState *s, bool restoring) {
error("run_vm(): program counter gone astray");
#endif
- opcode = GET_OP_BYTE(); // Get opcode
-
- opnumber = opcode >> 1;
-
- for (temp = 0; g_opcode_formats[opnumber][temp]; temp++) {
- //printf("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opnumber, temp);
- switch (g_opcode_formats[opnumber][temp]) {
-
- case Script_Byte:
- opparams[temp] = GET_OP_BYTE();
- break;
- case Script_SByte:
- opparams[temp] = GET_OP_SIGNED_BYTE();
- break;
-
- case Script_Word:
- opparams[temp] = GET_OP_WORD();
- break;
- case Script_SWord:
- opparams[temp] = GET_OP_SIGNED_WORD();
- break;
-
- case Script_Variable:
- case Script_Property:
-
- case Script_Local:
- case Script_Temp:
- case Script_Global:
- case Script_Param:
- opparams[temp] = GET_OP_FLEX();
- break;
-
- case Script_SVariable:
- case Script_SRelative:
- opparams[temp] = GET_OP_SIGNED_FLEX();
- break;
-
- case Script_Offset:
- opparams[temp] = GET_OP_FLEX();
- break;
-
- case Script_None:
- case Script_End:
- break;
-
- case Script_Invalid:
- default:
- error("opcode %02x: Invalid", opcode);
- }
- }
+ // Get opcode
+ byte opcode;
+ scriptState.xs->addr.pc.offset += readPMachineInstruction(code_buf + scriptState.xs->addr.pc.offset, opcode, opparams);
+ const byte opnumber = opcode >> 1;
switch (opnumber) {
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index f04e06b9ef..da17119507 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -523,6 +523,24 @@ int kfree(SegManager *segMan, reg_t handle);
*/
void shrink_execution_stack(EngineState *s, uint size);
+/**
+ * Read a PMachine instruction from a memory buffer and return its length.
+ *
+ * @param[in] src address from which to start parsing
+ * @param[out] extOpcode "extended" opcode of the parsed instruction
+ * @param[out] opparams parameter for the parsed instruction
+ * @return the length in bytes of the instruction
+ *
+ * @todo How about changing opparams from int16 to int / int32 to preserve
+ * unsigned 16bit words as read for Script_Word? In the past, this
+ * was irrelevant as only a debug opcode used Script_Word. But with
+ * SCI32 we are now using Script_Word for more opcodes. Maybe this is
+ * just a mistake and those opcodes should used Script_SWord -- but if
+ * not then we definitely should change this to int, else we might run
+ * into trouble if we encounter high value words. *If* those exist at all.
+ */
+int readPMachineInstruction(const byte *src, byte &extOpcode, int16 opparams[4]);
+
} // End of namespace Sci
#endif // SCI_ENGINE_VM_H