diff options
author | Scott Percival | 2019-10-27 17:25:50 +0800 |
---|---|---|
committer | Eugene Sandulenko | 2019-11-17 22:31:54 +0100 |
commit | cd619768edc22f1a374cf1857a5eef7e6c384696 (patch) | |
tree | c9933e21ab9f46081201eed56d4681cfc63cf5a8 /engines | |
parent | 186ff9cbce3bb9ffa5dcf7dbee1f30e4437e1080 (diff) | |
download | scummvm-rg350-cd619768edc22f1a374cf1857a5eef7e6c384696.tar.gz scummvm-rg350-cd619768edc22f1a374cf1857a5eef7e6c384696.tar.bz2 scummvm-rg350-cd619768edc22f1a374cf1857a5eef7e6c384696.zip |
DIRECTOR: Flesh out bytecode interpreter
Diffstat (limited to 'engines')
-rw-r--r-- | engines/director/lingo/lingo-bytecode.cpp | 236 | ||||
-rw-r--r-- | engines/director/lingo/lingo-code.cpp | 56 | ||||
-rw-r--r-- | engines/director/lingo/lingo.cpp | 1 | ||||
-rw-r--r-- | engines/director/lingo/lingo.h | 20 |
4 files changed, 280 insertions, 33 deletions
diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp index f19ebb7768..c04515ac07 100644 --- a/engines/director/lingo/lingo-bytecode.cpp +++ b/engines/director/lingo/lingo-bytecode.cpp @@ -25,45 +25,62 @@ namespace Director { static struct LingoV4Bytecode { - const char opcode; + const uint8 opcode; const inst func; + const char *args; } lingoV4[] = { - { 0x03, Lingo::c_voidpush }, - { 0x04, Lingo::c_mul }, - { 0x05, Lingo::c_add }, - { 0x06, Lingo::c_sub }, - { 0x07, Lingo::c_div }, - { 0x08, Lingo::c_mod }, - { 0x09, Lingo::c_negate }, - { 0x0a, Lingo::c_ampersand }, - { 0x0b, Lingo::c_concat }, - { 0x0c, Lingo::c_lt }, - { 0x0d, Lingo::c_le }, - { 0x0e, Lingo::c_neq }, - { 0x0f, Lingo::c_eq }, - { 0x10, Lingo::c_gt }, - { 0x11, Lingo::c_ge }, - { 0x12, Lingo::c_and }, - { 0x13, Lingo::c_or }, - { 0x14, Lingo::c_not }, - { 0x15, Lingo::c_contains }, - { 0x16, Lingo::c_starts }, - { 0x17, Lingo::c_of }, - { 0x18, Lingo::c_hilite }, - { 0x19, Lingo::c_intersects }, - { 0x1a, Lingo::c_within }, - { 0x1b, Lingo::c_field }, - { 0x1c, Lingo::c_tell }, - { 0x1d, Lingo::c_telldone }, + { 0x03, Lingo::c_voidpush, "" }, + { 0x04, Lingo::c_mul, "" }, + { 0x05, Lingo::c_add, "" }, + { 0x06, Lingo::c_sub, "" }, + { 0x07, Lingo::c_div, "" }, + { 0x08, Lingo::c_mod, "" }, + { 0x09, Lingo::c_negate, "" }, + { 0x0a, Lingo::c_ampersand, "" }, + { 0x0b, Lingo::c_concat, "" }, + { 0x0c, Lingo::c_lt, "" }, + { 0x0d, Lingo::c_le, "" }, + { 0x0e, Lingo::c_neq, "" }, + { 0x0f, Lingo::c_eq, "" }, + { 0x10, Lingo::c_gt, "" }, + { 0x11, Lingo::c_ge, "" }, + { 0x12, Lingo::c_and, "" }, + { 0x13, Lingo::c_or, "" }, + { 0x14, Lingo::c_not, "" }, + { 0x15, Lingo::c_contains, "" }, + { 0x16, Lingo::c_starts, "" }, + { 0x17, Lingo::c_of, "" }, + { 0x18, Lingo::c_hilite, "" }, + { 0x19, Lingo::c_intersects, "" }, + { 0x1a, Lingo::c_within, "" }, + { 0x1b, Lingo::c_field, "" }, + { 0x1c, Lingo::c_tell, "" }, + { 0x1d, Lingo::c_telldone, "" }, - { 0x41, Lingo::c_intpush }, - { 0, 0 } + { 0x41, Lingo::c_intpush, "b" }, + { 0, 0, 0 } }; +void Lingo::initBytecode() { + for (LingoV4Bytecode *op = lingoV4; op->opcode; op++) { + _lingoV4[op->opcode] = new Opcode( op->func, op->args ); + } +} + void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType type, uint16 id) { debugC(1, kDebugLingoCompile, "Add V4 bytecode for type %s with id %d", scriptType2str(type), id); + if (_scripts[type].contains(id)) { + delete _scripts[type][id]; + } + + _currentScript = new ScriptData; + _currentScriptType = type; + _scripts[type][id] = _currentScript; + _currentEntityId = id; + + // read the Lscr header! // unk1 for (uint32 i = 0; i < 0x10; i++) { stream.readByte(); @@ -88,9 +105,164 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty uint16 unk6 = stream.readUint16(); stream.readUint16(); uint16 consts_base = stream.readUint16(); - - // preload all the constants + + // preload all the constants! + // these are stored as a reference table of 6 byte entries, followed by a storage area. + + // copy the storage area first. + uint32 consts_store_offset = consts_offset+6*consts_count; + uint32 consts_store_size = stream.size()-consts_store_offset; + stream.seek(consts_store_offset); + byte *const_store = (byte *)malloc(consts_store_size); + stream.read(const_store, consts_store_size); + + Common::Array<Datum> const_data; + + // read each entry in the reference table. stream.seek(consts_offset); + for (uint16 i=0; i<consts_count; i++) { + Datum constant; + uint16 const_type = stream.readUint16(); + uint32 value = stream.readUint32(); + switch (const_type) { + case 1: { // String type + constant.type = STRING; + constant.u.s = new Common::String(); + if (value < consts_store_offset) { + warning("Constant string start offset is out of bounds!"); + break; + } + uint32 pointer = value - consts_store_offset; + while (pointer < consts_store_size) { + if (const_store[pointer] == '\r') { + constant.u.s += '\n'; + } else if (const_store[pointer] == '\0') { + break; + } else { + constant.u.s += const_store[pointer]; + } + pointer += 1; + } + if (pointer == consts_store_size) { + warning("Constant string has no null terminator!"); + break; + } + } + break; + case 4: // Integer type + constant.type = INT; + constant.u.i = (int)value; + break; + case 9: { // Float type + constant.type = FLOAT; + if (value < consts_store_offset) { + warning("Constant float start offset is out of bounds!"); + break; + } else if (value+4 > consts_store_offset + consts_store_size) { + warning("Constant float end offset is out of bounds!"); + break; + } + constant.u.f = *(float *)(const_store+value-consts_store_offset); + } + break; + default: + warning("Unknown constant type %d", type); + break; + } + + const_data.push_back(constant); + } + free(const_store); + + // parse each function! + // these are stored as a code storage area, followed by a reference table of 42 byte entries. + + // copy the storage area first. + uint32 code_store_size = functions_offset - code_store_offset; + stream.seek(code_store_offset); + byte *code_store = (byte *)malloc(code_store_size); + stream.read(code_store, code_store_size); + + // read each entry in the function table. + stream.seek(functions_offset); + for (uint16 i=0; i<functions_count; i++) { + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 arg_count = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 var_count = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 name_index = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 length = stream.readUint16(); + stream.readUint16(); + uint16 start_offset = stream.readUint16(); + stream.readUint16(); + stream.readUint16(); + uint16 end_offset = stream.readUint16(); + + if (start_offset < code_store_offset) { + warning("Function %d start offset is out of bounds!", i); + continue; + } else if (end_offset >= code_store_offset+code_store_size) { + warning("Function %d end offset is out of bounds!", i); + continue; + } + + uint32 pointer = start_offset-code_store_offset; + Common::Array<uint32> offset_list; + while (pointer < end_offset-code_store_offset) { + uint8 opcode = code_store[pointer]; + + pointer += 1; + if (_lingoV4.contains(opcode)) { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(_lingoV4[opcode]->func); + + } else { + // unimplemented instruction + inst op_value = 0; + WRITE_UINT32(&op_value, opcode); + + if (opcode < 0x40) { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(Lingo::c_nop); + _currentScript->push_back(op_value); + } else if (opcode < 0x80) { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(Lingo::c_nop1); + _currentScript->push_back(op_value); + inst arg1 = 0; + WRITE_UINT32(&arg1, code_store[pointer]); + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(arg1); + pointer += 1; + } else { + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(Lingo::c_nop2); + _currentScript->push_back(op_value); + inst arg1 = 0; + WRITE_UINT32(&arg1, code_store[pointer]); + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(arg1); + inst arg2 = 0; + WRITE_UINT32(&arg2, code_store[pointer+1]); + offset_list.push_back(_currentScript->size()); + _currentScript->push_back(arg2); + pointer += 2; + } + } + } + + } + } } diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp index 85b50cd8ea..14f08719a9 100644 --- a/engines/director/lingo/lingo-code.cpp +++ b/engines/director/lingo/lingo-code.cpp @@ -57,7 +57,8 @@ static struct FuncDescr { } funcDescr[] = { { 0, "STOP", "" }, { Lingo::c_xpop, "c_xpop", "" }, - { Lingo::c_arraypush, "c_arraypush", "i" }, + { Lingo::c_argspush, "c_argspush", "i" }, + { Lingo::c_arraypush, "c_arraypush", "i" }, { Lingo::c_printtop, "c_printtop", "" }, { Lingo::c_intpush, "c_intpush", "i" }, { Lingo::c_voidpush, "c_voidpush", "" }, @@ -125,6 +126,11 @@ static struct FuncDescr { { Lingo::c_instance, "c_instance", "s" }, { Lingo::c_open, "c_open", "" }, { Lingo::c_hilite, "c_hilite", "" }, + { Lingo::c_jump, "c_jump", "" }, + { Lingo::c_jumpif, "c_jumpif", "" }, + { Lingo::c_nop, "c_nop", "i" }, + { Lingo::c_nop1, "c_nop1", "ii" }, + { Lingo::c_nop2, "c_nop2", "iii" }, { 0, 0, 0 } }; @@ -244,6 +250,21 @@ void Lingo::c_symbolpush() { g_lingo->push(Datum(new Common::String(s))); } +void Lingo::c_argspush() { + Datum d; + inst v = (*g_lingo->_currentScript)[g_lingo->_pc++]; + int argsSize = READ_UINT32(&v); + + warning("STUB: c_argspush()"); + + for (int i = 0; i < argsSize; i++) + g_lingo->pop(); + + d.u.i = argsSize; + d.type = INT; + g_lingo->push(d); +} + void Lingo::c_arraypush() { Datum d; inst v = (*g_lingo->_currentScript)[g_lingo->_pc++]; @@ -1246,4 +1267,37 @@ void Lingo::c_hilite() { cast_id.u.i); } +void Lingo::c_jump() { + +} + +void Lingo::c_jumpif() { + +} + +void Lingo::c_nop() { + int savepc = g_lingo->_pc; + uint opcode = READ_UINT32(&(*g_lingo->_currentScript)[savepc]); + warning("STUB: c_nop: %d", opcode); + g_lingo->_pc += 1; +} + +void Lingo::c_nop1() { + int savepc = g_lingo->_pc; + uint opcode = READ_UINT32(&(*g_lingo->_currentScript)[savepc]); + uint arg1 = READ_UINT32(&(*g_lingo->_currentScript)[savepc+1]); + warning("STUB: c_nop1: %d %d", opcode, arg1); + g_lingo->_pc += 2; +} + +void Lingo::c_nop2() { + int savepc = g_lingo->_pc; + uint opcode = READ_UINT32(&(*g_lingo->_currentScript)[savepc]); + uint arg1 = READ_UINT32(&(*g_lingo->_currentScript)[savepc+1]); + uint arg2 = READ_UINT32(&(*g_lingo->_currentScript)[savepc+2]); + warning("STUB: c_nop2: %d %d %d", opcode, arg1, arg2); + g_lingo->_pc += 3; +} + + } diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp index 77c0bbcb9d..8be3408ad1 100644 --- a/engines/director/lingo/lingo.cpp +++ b/engines/director/lingo/lingo.cpp @@ -73,6 +73,7 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) { initBuiltIns(); initFuncs(); + initBytecode(); initTheEntities(); warning("Lingo Inited"); diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h index e1a165796e..3227786666 100644 --- a/engines/director/lingo/lingo.h +++ b/engines/director/lingo/lingo.h @@ -89,6 +89,14 @@ struct FuncDesc { typedef Common::HashMap<void *, FuncDesc *> FuncHash; +struct Opcode { + inst func; + const char *proto; + + Opcode(inst f, const char *p) { func = f; proto = p; } +}; +typedef Common::HashMap<int, Opcode *> OpcodeHash; + struct Symbol { /* symbol table entry */ Common::String name; int type; @@ -170,6 +178,7 @@ public: void initBuiltIns(); void initFuncs(); + void initBytecode(); void initTheEntities(); void runTests(); @@ -207,6 +216,7 @@ public: int code1(inst code) { _currentScript->push_back(code); return _currentScript->size() - 1; } int code2(inst code_1, inst code_2) { int o = code1(code_1); code1(code_2); return o; } int code3(inst code_1, inst code_2, inst code_3) { int o = code1(code_1); code1(code_2); code1(code_3); return o; } + int code4(inst code_1, inst code_2, inst code_3, inst code_4) { int o = code1(code_1); code1(code_2); code1(code_3); code1(code_4); return o; } int codeString(const char *s); void codeLabel(int label); int codeInt(int val); @@ -270,6 +280,7 @@ public: static void c_stringpush(); static void c_symbolpush(); static void c_varpush(); + static void c_argspush(); static void c_arraypush(); static void c_assign(); bool verify(Symbol *s); @@ -317,6 +328,13 @@ public: static void c_open(); static void c_hilite(); + static void c_jump(); + static void c_jumpif(); + + static void c_nop(); + static void c_nop1(); + static void c_nop2(); + void printSTUBWithArglist(const char *funcname, int nargs, const char *prefix = "STUB:"); void convertVOIDtoString(int arg, int nargs); void dropStack(int nargs); @@ -563,6 +581,8 @@ private: FuncHash _functions; + OpcodeHash _lingoV4; + uint _pc; StackData _stack; |