00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pent_include.h"
00020
00021 #include "UCMachine.h"
00022 #include "UCProcess.h"
00023 #include "Usecode.h"
00024 #include "Kernel.h"
00025 #include "DelayProcess.h"
00026 #include "CoreApp.h"
00027 #include "GameInfo.h"
00028 #include "IDataSource.h"
00029 #include "ODataSource.h"
00030 #include "CurrentMap.h"
00031 #include "World.h"
00032 #include "BitSet.h"
00033 #include "UCList.h"
00034 #include "idMan.h"
00035 #include "ConsoleGump.h"
00036 #include "getObject.h"
00037
00038 #define INCLUDE_CONVERTUSECODEU8_WITHOUT_BRINGING_IN_FOLD
00039 #include "u8/ConvertUsecodeU8.h"
00040
00041 #include "MainActor.h"
00042
00043 #ifdef DEBUG
00044 #define LOGPF(X) do { if (trace_show(trace_pid, trace_objid, trace_classid)) pout.printf X; } while (0)
00045 #else
00046 #define LOGPF(X)
00047 #endif
00048
00049 #ifdef DEBUG
00050 static const char *print_bp(const sint16 offset)
00051 {
00052 static char str[32];
00053 snprintf(str, 32, "[BP%c%02Xh]", offset<0?'-':'+',
00054 offset<0?-offset:offset);
00055 return str;
00056 }
00057
00058 static const char *print_sp(const sint16 offset)
00059 {
00060 static char str[32];
00061 snprintf(str, 32, "[SP%c%02Xh]", offset<0?'-':'+',
00062 offset<0?-offset:offset);
00063 return str;
00064 }
00065 #endif
00066
00067
00068
00069
00070 enum UCSegments {
00071 SEG_STACK = 0x0000,
00072 SEG_STACK_FIRST= 0x0001,
00073 SEG_STACK_LAST = 0x7FFE,
00074 SEG_STRING = 0x8000,
00075 SEG_LIST = 0x8001,
00076 SEG_OBJ = 0x8002,
00077 SEG_GLOBAL = 0x8003
00078 };
00079
00080 UCMachine* UCMachine::ucmachine = 0;
00081
00082 UCMachine::UCMachine(Intrinsic *iset, unsigned int icount)
00083 {
00084 con.Print(MM_INFO, "Creating UCMachine...\n");
00085
00086 assert(ucmachine == 0);
00087 ucmachine = this;
00088
00089
00090 globals = new BitSet(0x1000);
00091
00092 convuse = new ConvertUsecodeU8;
00093 loadIntrinsics(iset, icount);
00094
00095 listIDs = new idMan(1, 65534, 128);
00096 stringIDs = new idMan(1, 65534, 256);
00097
00098 con.AddConsoleCommand("UCMachine::getGlobal", ConCmd_getGlobal);
00099 con.AddConsoleCommand("UCMachine::setGlobal", ConCmd_setGlobal);
00100 #ifdef DEBUG
00101 con.AddConsoleCommand("UCMachine::traceObjID", ConCmd_traceObjID);
00102 con.AddConsoleCommand("UCMachine::tracePID", ConCmd_tracePID);
00103 con.AddConsoleCommand("UCMachine::traceClass", ConCmd_traceClass);
00104 con.AddConsoleCommand("UCMachine::traceEvents", ConCmd_traceEvents);
00105 con.AddConsoleCommand("UCMachine::traceAll", ConCmd_traceAll);
00106 con.AddConsoleCommand("UCMachine::stopTrace", ConCmd_stopTrace);
00107
00108 tracing_enabled = false;
00109 trace_all = false;
00110 #endif
00111 }
00112
00113
00114 UCMachine::~UCMachine()
00115 {
00116 con.Print(MM_INFO, "Destroying UCMachine...\n");
00117
00118 con.RemoveConsoleCommand(UCMachine::ConCmd_getGlobal);
00119 con.RemoveConsoleCommand(UCMachine::ConCmd_setGlobal);
00120 #ifdef DEBUG
00121 con.RemoveConsoleCommand(UCMachine::ConCmd_traceObjID);
00122 con.RemoveConsoleCommand(UCMachine::ConCmd_tracePID);
00123 con.RemoveConsoleCommand(UCMachine::ConCmd_traceClass);
00124 con.RemoveConsoleCommand(UCMachine::ConCmd_traceAll);
00125 con.RemoveConsoleCommand(UCMachine::ConCmd_stopTrace);
00126 #endif
00127
00128 ucmachine = 0;
00129
00130 delete globals; globals = 0;
00131 delete convuse; convuse = 0;
00132 delete listIDs; listIDs = 0;
00133 delete stringIDs; stringIDs = 0;
00134 }
00135
00136 void UCMachine::reset()
00137 {
00138 con.Print(MM_INFO, "Resetting UCMachine\n");
00139
00140
00141 globals->setSize(0x1000);
00142
00143
00144 std::map<uint16, UCList*>::iterator iter;
00145 for (iter = listHeap.begin(); iter != listHeap.end(); ++iter)
00146 delete (iter->second);
00147 listHeap.clear();
00148 stringHeap.clear();
00149 }
00150
00151 void UCMachine::loadIntrinsics(Intrinsic *i, unsigned int icount)
00152 {
00153 intrinsics=i;
00154 intrinsiccount=icount;
00155 }
00156
00157 bool UCMachine::execProcess(UCProcess* p)
00158 {
00159 assert(p);
00160
00161 uint32 base = p->usecode->get_class_base_offset(p->classid);
00162 IBufferDataSource cs(p->usecode->get_class(p->classid) + base,
00163 p->usecode->get_class_size(p->classid) - base);
00164 cs.seek(p->ip);
00165
00166 #ifdef DEBUG
00167 if (trace_show(p->pid, p->item_num, p->classid)) {
00168 pout << std::hex << "running process " << p->pid
00169 << ", item " << p->item_num << ", type " << p->type
00170 << ", class " << p->classid << ", offset " << p->ip
00171 << std::dec << std::endl;
00172 }
00173 #endif
00174
00175 bool cede = false;
00176 bool error = false;
00177
00178 while(!cede && !error && !p->is_terminated())
00179 {
00182
00183 uint8 opcode = cs.read1();
00184
00185 #ifdef DEBUG
00186 uint16 trace_classid = p->classid;
00187 ObjId trace_objid = p->item_num;
00188 ProcId trace_pid = p->pid;
00189 #endif
00190
00191 LOGPF(("sp = %02X; %04X:%04X: %02X\t",
00192 p->stack.stacksize(), p->classid, p->ip, opcode));
00193
00194 sint8 si8a, si8b;
00195 uint8 ui8a;
00196 uint16 ui16a, ui16b;
00197 uint32 ui32a, ui32b;
00198 sint16 si16a, si16b;
00199 sint32 si32a, si32b;
00200
00201 switch(opcode)
00202 {
00203
00204
00205 case 0x00:
00206
00207
00208 si8a = static_cast<sint8>(cs.read1());
00209 ui16a = p->stack.pop2();
00210 p->stack.assign1(p->bp+si8a, static_cast<uint8>(ui16a));
00211 LOGPF(("pop byte\t%s = %02Xh\n", print_bp(si8a), ui16a));
00212 break;
00213
00214 case 0x01:
00215
00216
00217 si8a = static_cast<sint8>(cs.read1());
00218 ui16a = p->stack.pop2();
00219 p->stack.assign2(p->bp+si8a, ui16a);
00220 LOGPF(("pop\t\t%s = %04Xh\n", print_bp(si8a), ui16a));
00221 break;
00222
00223 case 0x02:
00224
00225
00226 si8a = static_cast<sint8>(cs.read1());
00227 ui32a = p->stack.pop4();
00228 p->stack.assign4(p->bp+si8a, ui32a);
00229 LOGPF(("pop dword\t%s = %08Xh\n", print_bp(si8a), ui32a));
00230 break;
00231
00232 case 0x03:
00233
00234
00235 {
00236 si8a = static_cast<sint8>(cs.read1());
00237 uint8 size = cs.read1();
00238 uint8 buf[256];
00239 p->stack.pop(buf, size);
00240 p->stack.assign(p->bp+si8a, buf, size);
00241 LOGPF(("pop huge\t%s %i\n", print_bp(si8a), size));
00242 }
00243 break;
00244
00245 case 0x08:
00246
00247
00251 LOGPF(("pop dword\tprocess result\n"));
00252 p->result = p->stack.pop4();
00253 break;
00254
00255 case 0x09:
00256
00257
00258 {
00259 si8a = static_cast<sint8>(cs.read1());
00260 ui32a = cs.read1();
00261 si8b = static_cast<sint8>(cs.read1());
00262 LOGPF(("assign element\t%s (%02X) (slist==%02X)\n",
00263 print_bp(si8a), ui32a, si8b));
00264 ui16a = p->stack.pop2()-1;
00265 ui16b = p->stack.access2(p->bp+si8a);
00266 UCList* l = getList(ui16b);
00267 if (!l) {
00268 perr << "assign element to an invalid list (" << ui16b << ")"
00269 << std::endl;
00270 error = true;
00271 break;
00272 }
00273 if (si8b) {
00274
00275
00276 if (ui32a != 2) error = true;
00277 l->assign(ui16a, p->stack.access());
00278 p->stack.pop2();
00279 } else {
00280 l->assign(ui16a, p->stack.access());
00281 p->stack.addSP(ui32a);
00282 }
00283 } break;
00284
00285
00286
00287 case 0x0A:
00288
00289
00290 ui16a = static_cast<sint8>(cs.read1());
00291 p->stack.push2(ui16a);
00292 LOGPF(("push byte\t%04Xh\n", ui16a));
00293 break;
00294
00295 case 0x0B:
00296
00297
00298 ui16a = cs.read2();
00299 p->stack.push2(ui16a);
00300 LOGPF(("push\t\t%04Xh\n", ui16a));
00301 break;
00302
00303 case 0x0C:
00304
00305
00306 ui32a = cs.read4();
00307 p->stack.push4(ui32a);
00308 LOGPF(("push dword\t%08Xh\n", ui32a));
00309 break;
00310
00311 case 0x0D:
00312
00313
00314 {
00315 ui16a = cs.read2();
00316 char *str = new char[ui16a+1];
00317 cs.read(str, ui16a);
00318 str[ui16a] = 0;
00319 LOGPF(("push string\t\"%s\"\n", str));
00320 ui16b = cs.read1();
00321 if (ui16b != 0) error = true;
00322 p->stack.push2(assignString(str));
00323 delete[] str;
00324 }
00325 break;
00326
00327 case 0x0E:
00328
00329
00330
00331 {
00332 ui16a = cs.read1();
00333 ui16b = cs.read1();
00334 UCList* l = new UCList(ui16a, ui16b);
00335 p->stack.addSP(ui16a * (ui16b - 1));
00336 for (unsigned int i = 0; i < ui16b; i++) {
00337 l->append(p->stack.access());
00338 p->stack.addSP(-ui16a);
00339 }
00340 p->stack.addSP(ui16a * (ui16b + 1));
00341 p->stack.push2(assignList(l));
00342 LOGPF(("create list\t%02X (%02X)\n", ui16b, ui16a));
00343 }
00344 break;
00345
00346
00347
00348
00349 case 0x0F:
00350
00351
00352
00353
00354 {
00356 uint16 arg_bytes = cs.read1();
00357 uint16 func = cs.read2();
00358 LOGPF(("calli\t\t%04Xh (%02Xh arg bytes) %s \n", func, arg_bytes, convuse->intrinsics()[func]));
00359
00360
00361 if (func >= intrinsiccount || intrinsics[func] == 0) {
00362 p->temp32 = 0;
00363 perr << "Unhandled intrinsic \'" << convuse->intrinsics()[func] << "\' (" << std::hex << func << std::dec << ") called" << std::endl;
00364 } else {
00366 if (intrinsics[func] == UCMachine::I_dummyProcess ||
00367 intrinsics[func] == UCMachine::I_true) {
00368
00369 }
00370 uint8 *argbuf = new uint8[arg_bytes];
00371 p->stack.pop(argbuf, arg_bytes);
00372 p->stack.addSP(-arg_bytes);
00373
00374 p->temp32 = intrinsics[func](argbuf, arg_bytes);
00375
00376 delete[] argbuf;
00377 }
00378
00379
00380
00381
00382
00383
00384 if (GAME_IS_U8 && p->classid == 0x48B && func == 0xD0)
00385 {
00386 globals->setBits(0, 1, 1);
00387 }
00388
00389 }
00390 break;
00391
00392
00393 case 0x11:
00394
00395
00396
00397
00398
00399 {
00400 uint16 new_classid = cs.read2();
00401 uint16 new_offset = cs.read2();
00402 LOGPF(("call\t\t%04X:%04X\n", new_classid, new_offset));
00403 if (GAME_IS_CRUSADER) {
00404 new_offset = p->usecode->get_class_event(new_classid,
00405 new_offset);
00406 }
00407
00408 p->ip = static_cast<uint16>(cs.getPos());
00409 p->call(new_classid, new_offset);
00410
00411
00412 uint32 base = p->usecode->get_class_base_offset(p->classid);
00413 cs.load(p->usecode->get_class(p->classid) + base,
00414 p->usecode->get_class_size(p->classid) - base);
00415 cs.seek(p->ip);
00416
00417
00418 }
00419 break;
00420
00421 case 0x12:
00422
00423
00424 p->temp32 = p->stack.pop2();
00425 LOGPF(("pop\t\ttemp = %04X\n", (p->temp32 & 0xFFFF)));
00426 break;
00427
00428 case 0x13:
00429
00430
00431
00432 p->temp32 = p->stack.pop4();
00433 LOGPF(("pop long\t\ttemp = %08X\n", p->temp32));
00434 break;
00435
00436
00437
00438 case 0x14:
00439
00440
00441 si16a = static_cast<sint16>(p->stack.pop2());
00442 si16b = static_cast<sint16>(p->stack.pop2());
00443 p->stack.push2(static_cast<uint16>(si16a + si16b));
00444 LOGPF(("add\n"));
00445 break;
00446
00447 case 0x15:
00448
00449
00450 si32a = static_cast<sint32>(p->stack.pop4());
00451 si32b = static_cast<sint32>(p->stack.pop4());
00452 p->stack.push4(static_cast<uint32>(si32a + si32b));
00453 LOGPF(("add long\n"));
00454 break;
00455
00456
00457 case 0x16:
00458
00459
00460
00461 ui16a = p->stack.pop2();
00462 ui16b = p->stack.pop2();
00463 if (ui16b == 0) {
00464 perr << "Trying to append to string 0." << std::endl;
00465 error = true;
00466 break;
00467 }
00468 stringHeap[ui16b] += getString(ui16a);
00469 freeString(ui16a);
00470 p->stack.push2(ui16b);
00471 LOGPF(("concat\t\t= %s\n", stringHeap[ui16b].c_str()));
00472 break;
00473
00474 case 0x17:
00475
00476
00477
00478 {
00479 ui16a = p->stack.pop2();
00480 ui16b = p->stack.pop2();
00481 UCList* listA = getList(ui16a);
00482 UCList* listB = getList(ui16b);
00483
00484 if (listB && listA) {
00485 if (listA->getElementSize() != listB->getElementSize()) {
00486 perr << "Trying to append lists with different element "
00487 << "sizes (" << listB->getElementSize() << " != "
00488 << listA->getElementSize() << ")" << std::endl;
00489 error = true;
00490 } else {
00491 listB->appendList(*listA);
00492 }
00493
00494 assert(ui16a != ui16b);
00495 freeList(ui16a);
00496 p->stack.push2(ui16b);
00497 } else {
00498
00499
00500
00501
00502 if (listA) {
00503 p->stack.push2(ui16a);
00504 } else if (listB) {
00505 p->stack.push2(ui16b);
00506 } else {
00507 p->stack.push2(0);
00508 }
00509 }
00510 LOGPF(("append\n"));
00511 } break;
00512
00513 case 0x19:
00514
00515
00516 ui32a = cs.read1();
00517 if (ui32a != 2) error = true;
00518 ui16a = p->stack.pop2();
00519 ui16b = p->stack.pop2();
00520 getList(ui16b)->unionStringList(*getList(ui16a));
00521 freeStringList(ui16a);
00522 p->stack.push2(ui16b);
00523 LOGPF(("union slist\t(%02X)\n", ui32a));
00524 break;
00525
00526 case 0x1A:
00527
00528
00529
00530
00531 ui32a = cs.read1();
00532 ui32a = 2;
00533 ui16a = p->stack.pop2();
00534 ui16b = p->stack.pop2();
00535 getList(ui16b)->substractStringList(*getList(ui16a));
00536 freeStringList(ui16a);
00537 p->stack.push2(ui16b);
00538 LOGPF(("remove slist\t(%02X)\n", ui32a));
00539 break;
00540
00541 case 0x1B:
00542
00543
00544
00545
00546 ui32a = cs.read1();
00547 ui16a = p->stack.pop2();
00548 ui16b = p->stack.pop2();
00549 getList(ui16b)->substractList(*getList(ui16a));
00550 freeList(ui16a);
00551 p->stack.push2(ui16b);
00552 LOGPF(("remove list\t(%02X)\n", ui32a));
00553 break;
00554
00555 case 0x1C:
00556
00557
00558 si16a = static_cast<sint16>(p->stack.pop2());
00559 si16b = static_cast<sint16>(p->stack.pop2());
00560 p->stack.push2(static_cast<uint16>(si16b - si16a));
00561 LOGPF(("sub\n"));
00562 break;
00563
00564 case 0x1D:
00565
00566
00567 si32a = static_cast<sint16>(p->stack.pop4());
00568 si32b = static_cast<sint16>(p->stack.pop4());
00569 p->stack.push4(static_cast<uint32>(si32b - si32a));
00570 LOGPF(("sub long\n"));
00571 break;
00572
00573 case 0x1E:
00574
00575
00576 si16a = static_cast<sint16>(p->stack.pop2());
00577 si16b = static_cast<sint16>(p->stack.pop2());
00578 p->stack.push2(static_cast<uint16>(si16a * si16b));
00579 LOGPF(("mul\n"));
00580 break;
00581
00582 case 0x1F:
00583
00584
00585 si32a = static_cast<sint16>(p->stack.pop4());
00586 si32b = static_cast<sint16>(p->stack.pop4());
00587 p->stack.push4(static_cast<uint32>(si32a * si32b));
00588 LOGPF(("mul long\n"));
00589 break;
00590
00591 case 0x20:
00592
00593
00594 si16a = static_cast<sint16>(p->stack.pop2());
00595 si16b = static_cast<sint16>(p->stack.pop2());
00596 if (si16a != 0) {
00597 p->stack.push2(static_cast<uint16>(si16b / si16a));
00598 } else {
00599 perr.printf("division by zero.\n");
00600 p->stack.push2(0);
00601 }
00602 LOGPF(("div\n"));
00603 break;
00604
00605 case 0x21:
00606
00607
00608 si32a = static_cast<sint16>(p->stack.pop4());
00609 si32b = static_cast<sint16>(p->stack.pop4());
00610 if (si32a != 0) {
00611 p->stack.push4(static_cast<uint32>(si32b / si32a));
00612 } else {
00613 perr.printf("division by zero.\n");
00614 p->stack.push4(0);
00615 }
00616 LOGPF(("div\n"));
00617 break;
00618
00619 case 0x22:
00620
00621
00622
00623
00624 si16a = static_cast<sint16>(p->stack.pop2());
00625 si16b = static_cast<sint16>(p->stack.pop2());
00626 if (si16a != 0) {
00627 p->stack.push2(static_cast<uint16>(si16b % si16a));
00628 } else {
00629 perr.printf("division by zero.\n");
00630 p->stack.push2(0);
00631 }
00632 LOGPF(("mod\n"));
00633 break;
00634
00635 case 0x23:
00636
00637
00638
00639 si32a = static_cast<sint16>(p->stack.pop4());
00640 si32b = static_cast<sint16>(p->stack.pop4());
00641 if (si32a != 0) {
00642 p->stack.push4(static_cast<uint32>(si32b % si32a));
00643 } else {
00644 perr.printf("division by zero.\n");
00645 p->stack.push4(0);
00646 }
00647 LOGPF(("mod long\n"));
00648 break;
00649
00650 case 0x24:
00651
00652
00653 si16a = static_cast<sint16>(p->stack.pop2());
00654 si16b = static_cast<sint16>(p->stack.pop2());
00655 if (si16a == si16b) {
00656 p->stack.push2(1);
00657 } else {
00658 p->stack.push2(0);
00659 }
00660 LOGPF(("cmp\n"));
00661 break;
00662
00663 case 0x25:
00664
00665
00666 si32a = static_cast<sint32>(p->stack.pop4());
00667 si32b = static_cast<sint32>(p->stack.pop4());
00668 if (si32a == si32b) {
00669 p->stack.push2(1);
00670 } else {
00671 p->stack.push2(0);
00672 }
00673 LOGPF(("cmp long\n"));
00674 break;
00675
00676
00677 case 0x26:
00678
00679
00680
00681 ui16a = p->stack.pop2();
00682 ui16b = p->stack.pop2();
00683 if (getString(ui16b) == getString(ui16a))
00684 p->stack.push2(1);
00685 else
00686 p->stack.push2(0);
00687 freeString(ui16a);
00688 freeString(ui16b);
00689 LOGPF(("strcmp\n"));
00690 break;
00691
00692
00693 case 0x28:
00694
00695
00696 si16a = static_cast<sint16>(p->stack.pop2());
00697 si16b = static_cast<sint16>(p->stack.pop2());
00698 if (si16b < si16a) {
00699 p->stack.push2(1);
00700 } else {
00701 p->stack.push2(0);
00702 }
00703 LOGPF(("lt\n"));
00704 break;
00705
00706 case 0x29:
00707
00708
00709 si32a = static_cast<sint32>(p->stack.pop4());
00710 si32b = static_cast<sint32>(p->stack.pop4());
00711 if (si32b < si32a) {
00712 p->stack.push2(1);
00713 } else {
00714 p->stack.push2(0);
00715 }
00716 LOGPF(("lt long\n"));
00717 break;
00718
00719 case 0x2A:
00720
00721
00722 si16a = static_cast<sint16>(p->stack.pop2());
00723 si16b = static_cast<sint16>(p->stack.pop2());
00724 if (si16b <= si16a) {
00725 p->stack.push2(1);
00726 } else {
00727 p->stack.push2(0);
00728 }
00729 LOGPF(("le\n"));
00730 break;
00731
00732 case 0x2B:
00733
00734
00735 si32a = static_cast<sint32>(p->stack.pop4());
00736 si32b = static_cast<sint32>(p->stack.pop4());
00737 if (si32b <= si32a) {
00738 p->stack.push2(1);
00739 } else {
00740 p->stack.push2(0);
00741 }
00742 LOGPF(("le long\n"));
00743 break;
00744
00745 case 0x2C:
00746
00747
00748 si16a = static_cast<sint16>(p->stack.pop2());
00749 si16b = static_cast<sint16>(p->stack.pop2());
00750 if (si16b > si16a) {
00751 p->stack.push2(1);
00752 } else {
00753 p->stack.push2(0);
00754 }
00755 LOGPF(("gt\n"));
00756 break;
00757
00758 case 0x2D:
00759
00760
00761 si32a = static_cast<sint32>(p->stack.pop4());
00762 si32b = static_cast<sint32>(p->stack.pop4());
00763 if (si32b > si32a) {
00764 p->stack.push2(1);
00765 } else {
00766 p->stack.push2(0);
00767 }
00768 LOGPF(("gt long\n"));
00769 break;
00770
00771 case 0x2E:
00772
00773
00774 si16a = static_cast<sint16>(p->stack.pop2());
00775 si16b = static_cast<sint16>(p->stack.pop2());
00776 if (si16b >= si16a) {
00777 p->stack.push2(1);
00778 } else {
00779 p->stack.push2(0);
00780 }
00781 LOGPF(("ge\n"));
00782 break;
00783
00784 case 0x2F:
00785
00786
00787 si32a = static_cast<sint32>(p->stack.pop4());
00788 si32b = static_cast<sint32>(p->stack.pop4());
00789 if (si32b >= si32a) {
00790 p->stack.push2(1);
00791 } else {
00792 p->stack.push2(0);
00793 }
00794 LOGPF(("ge long\n"));
00795 break;
00796
00797 case 0x30:
00798
00799
00800 ui16a = p->stack.pop2();
00801 if (!ui16a) {
00802 p->stack.push2(1);
00803 } else {
00804 p->stack.push2(0);
00805 }
00806 LOGPF(("not\n"));
00807 break;
00808
00809
00810 case 0x31:
00811
00812
00813 ui32a = p->stack.pop4();
00814 if (!ui32a) {
00815 p->stack.push4(1);
00816 } else {
00817 p->stack.push4(0);
00818 }
00819 LOGPF(("not long\n"));
00820 break;
00821
00822 case 0x32:
00823
00824
00825 ui16a = p->stack.pop2();
00826 ui16b = p->stack.pop2();
00827 if (ui16a && ui16b) {
00828 p->stack.push2(1);
00829 } else {
00830 p->stack.push2(0);
00831 }
00832 LOGPF(("and\n"));
00833 break;
00834
00835 case 0x33:
00836
00837
00838 ui32a = p->stack.pop4();
00839 ui32b = p->stack.pop4();
00840 if (ui32a && ui32b) {
00841 p->stack.push4(1);
00842 } else {
00843 p->stack.push4(0);
00844 }
00845 LOGPF(("and long\n"));
00846 break;
00847
00848 case 0x34:
00849
00850
00851 ui16a = p->stack.pop2();
00852 ui16b = p->stack.pop2();
00853 if (ui16a || ui16b) {
00854 p->stack.push2(1);
00855 } else {
00856 p->stack.push2(0);
00857 }
00858 LOGPF(("or\n"));
00859 break;
00860
00861 case 0x35:
00862
00863
00864 ui32a = p->stack.pop4();
00865 ui32b = p->stack.pop4();
00866 if (ui32a || ui32b) {
00867 p->stack.push4(1);
00868 } else {
00869 p->stack.push4(0);
00870 }
00871 LOGPF(("or long\n"));
00872 break;
00873
00874 case 0x36:
00875
00876
00877 si16a = static_cast<sint16>(p->stack.pop2());
00878 si16b = static_cast<sint16>(p->stack.pop2());
00879 if (si16a != si16b) {
00880 p->stack.push2(1);
00881 } else {
00882 p->stack.push2(0);
00883 }
00884 LOGPF(("ne\n"));
00885 break;
00886
00887 case 0x37:
00888
00889
00890 si32a = static_cast<sint16>(p->stack.pop4());
00891 si32b = static_cast<sint16>(p->stack.pop4());
00892 if (si32a != si32b) {
00893 p->stack.push2(1);
00894 } else {
00895 p->stack.push2(0);
00896 }
00897 LOGPF(("ne long\n"));
00898 break;
00899
00900
00901 case 0x38:
00902
00903
00904
00905
00906 ui16a = cs.read1();
00907 ui32a = cs.read1();
00908 ui16b = p->stack.pop2();
00909 if (ui32a) {
00910 if (ui16a != 2) error = true;
00911 if (getList(ui16b)->stringInList(p->stack.pop2()))
00912 p->stack.push2(1);
00913 else
00914 p->stack.push2(0);
00915 freeStringList(ui16b);
00916 } else {
00917 bool found = getList(ui16b)->inList(p->stack.access());
00918 p->stack.addSP(ui16a);
00919 if (found)
00920 p->stack.push2(1);
00921 else
00922 p->stack.push2(0);
00923
00924 freeList(ui16b);
00925 }
00926 LOGPF(("in list\t\t%s slist==%02X\n", print_bp(ui16a), ui32a));
00927 break;
00928
00929 case 0x39:
00930
00931
00932 ui16a = p->stack.pop2();
00933 ui16b = p->stack.pop2();
00934 p->stack.push2(ui16a & ui16b);
00935 LOGPF(("bit_and\n"));
00936 break;
00937
00938 case 0x3A:
00939
00940
00941 ui16a = p->stack.pop2();
00942 ui16b = p->stack.pop2();
00943 p->stack.push2(ui16a | ui16b);
00944 LOGPF(("bit_or\n"));
00945 break;
00946
00947 case 0x3B:
00948
00949
00950 ui16a = p->stack.pop2();
00951 p->stack.push2(~ui16a);
00952 LOGPF(("bit_not\n"));
00953 break;
00954
00955 case 0x3C:
00956
00957
00958
00959 si16a = static_cast<sint16>(p->stack.pop2());
00960 ui16b = static_cast<sint16>(p->stack.pop2());
00961 p->stack.push2(static_cast<uint16>(si16a << ui16b));
00962 LOGPF(("lsh\n"));
00963 break;
00964
00965 case 0x3D:
00966
00967
00968
00969
00970 si16a = static_cast<sint16>(p->stack.pop2());
00971 ui16b = static_cast<sint16>(p->stack.pop2());
00972 p->stack.push2(static_cast<uint16>(si16a >> ui16b));
00973 LOGPF(("rsh\n"));
00974 break;
00975
00976 case 0x3E:
00977
00978
00979 si8a = static_cast<sint8>(cs.read1());
00980 ui16a = p->stack.access1(p->bp+si8a);
00981 p->stack.push2(ui16a);
00982 LOGPF(("push byte\t%s = %02Xh\n", print_bp(si8a), ui16a));
00983 break;
00984
00985 case 0x3F:
00986
00987
00988 si8a = static_cast<sint8>(cs.read1());
00989 ui16a = p->stack.access2(p->bp+si8a);
00990 p->stack.push2(ui16a);
00991 LOGPF(("push\t\t%s = %04Xh\n", print_bp(si8a), ui16a));
00992 break;
00993
00994 case 0x40:
00995
00996
00997 si8a = static_cast<sint8>(cs.read1());
00998 ui32a = p->stack.access4(p->bp+si8a);
00999 p->stack.push4(ui32a);
01000 LOGPF(("push dword\t%s = %08Xh\n", print_bp(si8a), ui32a));
01001 break;
01002
01003 case 0x41:
01004
01005
01006
01007 {
01008 si8a = static_cast<sint8>(cs.read1());
01009 ui16a = p->stack.access2(p->bp+si8a);
01010 p->stack.push2(duplicateString(ui16a));
01011 LOGPF(("push string\t%s\n", print_bp(si8a)));
01012 }
01013 break;
01014
01015 case 0x42:
01016
01017
01018
01019 {
01020 si8a = static_cast<sint8>(cs.read1());
01021 ui16a = cs.read1();
01022 ui16b = p->stack.access2(p->bp+si8a);
01023 UCList* l = new UCList(ui16a);
01024 if (getList(ui16b)) {
01025 l->copyList(*getList(ui16b));
01026 } else {
01027
01028
01029
01030
01031 }
01032 uint16 newlistid = assignList(l);
01033 p->stack.push2(newlistid);
01034 LOGPF(("push list\t%s (%04X, copy %04X, %d elements)\n",
01035 print_bp(si8a), ui16b, newlistid, l->getSize()));
01036 }
01037 break;
01038
01039 case 0x43:
01040
01041
01042
01043 {
01044 si8a = static_cast<sint8>(cs.read1());
01046 ui16a = 2;
01047 ui16b = p->stack.access2(p->bp+si8a);
01048 UCList* l = new UCList(ui16a);
01049 if (getList(ui16b)) {
01050 l->copyStringList(*getList(ui16b));
01051 } else {
01052
01053
01054
01055
01056 }
01057 p->stack.push2(assignList(l));
01058 LOGPF(("push slist\t%s\n", print_bp(si8a)));
01059 }
01060 break;
01061
01062 case 0x44:
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072 {
01073 ui32a = cs.read1();
01074 ui32b = cs.read1();
01075 ui16a = p->stack.pop2()-1;
01076 ui16b = p->stack.pop2();
01077 UCList* l = getList(ui16b);
01078 if (!l) {
01079
01080
01081
01082 p->stack.push0(ui32a);
01083
01084 } else {
01085 if (ui32b) {
01086 uint16 s = getList(ui16b)->getStringIndex(ui16a);
01087 p->stack.push2(duplicateString(s));
01088 } else {
01089 p->stack.push((*getList(ui16b))[ui16a], ui32a);
01090 }
01091 }
01092 LOGPF(("push element\t%02X slist==%02X\n", ui32a, ui32b));
01093 } break;
01094
01095 case 0x45:
01096
01097
01098 si8a = static_cast<sint8>(cs.read1());
01099 ui16b = cs.read1();
01100 p->stack.push(p->stack.access(p->bp+si8a), ui16b);
01101 LOGPF(("push huge\t%s %02X\n", print_bp(si8a), ui16b));
01102 break;
01103
01104 case 0x4B:
01105
01106
01107 si8a = static_cast<sint8>(cs.read1());
01108 p->stack.push4(stackToPtr(p->pid, p->bp+si8a));
01109 LOGPF(("push addr\t%s\n", print_bp(si8a)));
01110 break;
01111
01112 case 0x4C:
01113
01114
01115
01116
01117 {
01118 ui16a = cs.read1();
01119 ui32a = p->stack.pop4();
01120
01121 p->stack.addSP(-ui16a);
01122 if (!dereferencePointer(ui32a,
01123 p->stack.access(),
01124 ui16a))
01125 error = true;
01126
01127 LOGPF(("push indirect\t%02Xh bytes", ui16a));
01128 if (!error && ui16a == 2) {
01129 LOGPF((" = %04Xh\n", p->stack.access2(p->stack.getSP())));
01130 } else {
01131 LOGPF(("\n"));
01132 }
01133 }
01134 break;
01135
01136 case 0x4D:
01137
01138
01139
01140
01141 {
01142 ui16a = cs.read1();
01143 ui32a = p->stack.pop4();
01144
01145 if (assignPointer(ui32a, p->stack.access(), ui16a)) {
01146 p->stack.addSP(ui16a);
01147 } else {
01148 error = true;
01149 }
01150
01151 LOGPF(("pop indirect\t%02Xh bytes\n", ui16a));
01152 }
01153 break;
01154
01155 case 0x4E:
01156
01157
01158 ui16a = cs.read2();
01159 ui16b = cs.read1();
01160
01161
01162 ui32a = globals->getBits(ui16a, ui16b);
01163 p->stack.push2(static_cast<uint16>(ui32a));
01164 LOGPF(("push\t\tglobal [%04X %02X] = %02X\n", ui16a,ui16b,ui32a));
01165 break;
01166
01167 case 0x4F:
01168
01169
01170 ui16a = cs.read2();
01171 ui16b = cs.read1();
01172
01173 ui32a = p->stack.pop2();
01174 globals->setBits(ui16a, ui16b, ui32a);
01175
01176 if (ui32a & ~(((1 << ui16b)-1))) {
01177 perr << "Warning: value popped into a bitflag it doesn't fit in" << std::endl;
01178 }
01179
01180
01181 assert(globals->getBits(ui16a, ui16b)==(ui32a & ((1 << ui16b)-1)));
01182
01183 LOGPF(("pop\t\tglobal [%04X %02X] = %02X\n", ui16a, ui16b, ui32a));
01184 break;
01185
01186 case 0x50:
01187
01188
01189
01190 if (p->ret()) {
01191
01192 LOGPF(("ret\t\tfrom process\n"));
01193 p->terminateDeferred();
01194
01195
01196
01197
01198 } else {
01199 LOGPF(("ret\t\tto %04X:%04X\n", p->classid, p->ip));
01200
01201
01202
01203
01204 uint32 base = p->usecode->get_class_base_offset(p->classid);
01205 cs.load(p->usecode->get_class(p->classid) + base,
01206 p->usecode->get_class_size(p->classid) - base);
01207 cs.seek(p->ip);
01208 }
01209
01210
01211 break;
01212
01213 case 0x51:
01214
01215
01216 si16a = static_cast<sint16>(cs.read2());
01217 ui16b = p->stack.pop2();
01218 if (!ui16b) {
01219 ui16a = cs.getPos() + si16a;
01220 cs.seek(ui16a);
01221 LOGPF(("jne\t\t%04hXh\t(to %04X) (taken)\n", si16a,
01222 cs.getPos()));
01223 } else {
01224 LOGPF(("jne\t\t%04hXh\t(to %04X) (not taken)\n", si16a,
01225 cs.getPos()));
01226 }
01227 break;
01228
01229 case 0x52:
01230
01231
01232 si16a = static_cast<sint16>(cs.read2());
01233 ui16a = cs.getPos() + si16a;
01234 cs.seek(ui16a);
01235 LOGPF(("jmp\t\t%04hXh\t(to %04X)\n", si16a, cs.getPos()));
01236 break;
01237
01238 case 0x53:
01239
01240
01241 LOGPF(("suspend\n"));
01242 cede=true;
01243 break;
01244
01245 case 0x54:
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266 {
01267 cs.read2();
01268 ui16a = p->stack.pop2();
01269 ui16b = p->stack.pop2();
01270 p->stack.push2(ui16a);
01271 LOGPF(("implies\n"));
01272
01273 Process *proc = Kernel::get_instance()->getProcess(ui16b);
01274 Process *proc2 = Kernel::get_instance()->getProcess(ui16a);
01275 if (proc && proc2) {
01276 proc->waitFor(ui16a);
01277 } else {
01278 perr << "Non-existent process PID (";
01279 if (!proc && !proc2) {
01280 perr << ui16a << "," << ui16b;
01281 } else if (!proc) {
01282 perr << ui16b;
01283 } else {
01284 perr << ui16a;
01285 }
01286 perr << ") in implies." << std::endl;
01287
01288
01289
01290
01291
01292
01293 if ((ui16a && !proc2) || (ui16b && !proc))
01294 error = true;
01295 }
01296 }
01297 break;
01298
01299 case 0x57:
01300
01301
01302
01303
01304
01305
01306 {
01307 int arg_bytes = cs.read1();
01308 int this_size = cs.read1();
01309 uint16 classid = cs.read2();
01310 uint16 offset = cs.read2();
01311
01312 uint32 thisptr = p->stack.pop4();
01313
01314 LOGPF(("spawn\t\t%02X %02X %04X:%04X\n",
01315 arg_bytes, this_size, classid, offset));
01316
01317 if (GAME_IS_CRUSADER) {
01318 offset = p->usecode->get_class_event(classid, offset);
01319 }
01320
01321 UCProcess* newproc = new UCProcess(classid, offset,
01322 thisptr,
01323 this_size,
01324 p->stack.access(),
01325 arg_bytes);
01326 p->temp32 = Kernel::get_instance()->addProcessExec(newproc);
01327
01328 #ifdef DEBUG
01329 if (trace_show(p->pid, p->item_num, p->classid)) {
01330 pout << std::hex << "(still) running process " << p->pid
01331 << ", item " << p->item_num << ", type " << p->type
01332 << ", class " << p->classid << ", offset " << p->ip
01333 << std::dec << std::endl;
01334 }
01335 #endif
01336
01337
01338
01339
01340
01341
01342
01343
01344 }
01345 break;
01346
01347
01348 case 0x58:
01349
01350
01351
01352
01353
01354 {
01355 uint16 classid = cs.read2();
01356 uint16 offset = cs.read2();
01357 uint16 delta = cs.read2();
01358 int this_size = cs.read1();
01359 uint32 unknown = cs.read1();
01360
01361 LOGPF(("spawn inline\t%04X:%04X+%04X=%04X %02X %02X\n",
01362 classid,offset,delta,offset+delta,this_size, unknown));
01363
01364 uint32 thisptr = 0;
01365 if (this_size > 0)
01366 thisptr = p->stack.access4(p->bp+6);
01367 UCProcess* newproc = new UCProcess(classid, offset + delta,
01368 thisptr, this_size);
01369
01370 uint16 newpid= Kernel::get_instance()->addProcessExec(newproc);
01371
01372 #ifdef DEBUG
01373 if (trace_show(p->pid, p->item_num, p->classid)) {
01374 pout << std::hex << "(still) running process " << p->pid
01375 << ", item " << p->item_num << ", class " <<p->classid
01376 << ", offset " << p->ip << std::dec << std::endl;
01377 }
01378 #endif
01379
01380
01381
01382
01383 p->stack.push2(newpid);
01384
01385
01386 }
01387 break;
01388
01389 case 0x59:
01390
01391
01392 p->stack.push2(p->pid);
01393 LOGPF(("push\t\tpid = %04Xh\n", p->pid));
01394 break;
01395
01396 case 0x5A:
01397
01398
01399
01400 ui16a = cs.read1();
01401 LOGPF(("init\t\t%02X\n", ui16a));
01402
01403 if (ui16a & 1) ui16a++;
01404 if (ui16a > 0) {
01405 p->stack.push0(ui16a);
01406 }
01407 break;
01408
01409 case 0x5D:
01410
01411
01412
01413 p->stack.push2(static_cast<uint8>(p->temp32 & 0xFF));
01414 LOGPF(("push byte\tretval = %02Xh\n", (p->temp32 & 0xFF)));
01415 break;
01416
01417 case 0x5E:
01418
01419
01420
01421 p->stack.push2(static_cast<uint16>(p->temp32 & 0xFFFF));
01422 LOGPF(("push\t\tretval = %04Xh\n", (p->temp32 & 0xFFFF)));
01423 break;
01424
01425 case 0x5F:
01426
01427
01428
01429 p->stack.push4(p->temp32);
01430 LOGPF(("push long\t\tretval = %08Xh\n", p->temp32));
01431 break;
01432
01433 case 0x60:
01434
01435
01436 si32a = static_cast<sint16>(p->stack.pop2());
01437 p->stack.push4(si32a);
01438 LOGPF(("int to long\n"));
01439 break;
01440
01441 case 0x61:
01442
01443
01444 si16a = static_cast<sint16>(p->stack.pop4());
01445 p->stack.push2(si16a);
01446 LOGPF(("long to int\n"));
01447 break;
01448
01449 case 0x62:
01450
01451
01452 si8a = static_cast<sint8>(cs.read1());
01453 ui16a = p->stack.access2(p->bp+si8a);
01454 freeString(ui16a);
01455 LOGPF(("free string\t%s = %04X\n", print_bp(si8a), ui16a));
01456 break;
01457
01458 case 0x63:
01459
01460
01461 si8a = static_cast<sint8>(cs.read1());
01462 ui16a = p->stack.access2(p->bp+si8a);
01463 freeStringList(ui16a);
01464 LOGPF(("free slist\t%s = %04X\n", print_bp(si8a), ui16a));
01465 break;
01466
01467 case 0x64:
01468
01469
01470 si8a = static_cast<sint8>(cs.read1());
01471 ui16a = p->stack.access2(p->bp+si8a);
01472 freeList(ui16a);
01473 LOGPF(("free list\t%s = %04X\n", print_bp(si8a), ui16a));
01474 break;
01475
01476 case 0x65:
01477
01478
01479
01480
01481 si8a = static_cast<sint8>(cs.read1());
01482 ui16a = p->stack.access2(p->stack.getSP()+si8a);
01483 freeString(ui16a);
01484 LOGPF(("free string\t%s = %04X\n", print_sp(si8a), ui16a));
01485 break;
01486
01487 case 0x66:
01488
01489
01490 si8a = static_cast<sint8>(cs.read1());
01491 ui16a = p->stack.access2(p->stack.getSP()+si8a);
01492 freeList(ui16a);
01493 LOGPF(("free list\t%s = %04X\n", print_sp(si8a), ui16a));
01494 break;
01495
01496 case 0x67:
01497
01498
01499 si8a = static_cast<sint8>(cs.read1());
01500 ui16a = p->stack.access2(p->stack.getSP()+si8a);
01501 freeStringList(ui16a);
01502 LOGPF(("free slist\t%s = %04x\n", print_sp(si8a), ui16a));
01503 break;
01504
01505 case 0x69:
01506
01507
01508 si8a = static_cast<sint8>(cs.read1());
01509 ui16a = p->stack.access2(p->bp+si8a);
01510 p->stack.push4(stringToPtr(ui16a));
01511 LOGPF(("str to ptr\t%s\n", print_bp(si8a)));
01512 break;
01513
01514 case 0x6B:
01515
01516
01517 ui16a = p->stack.pop2();
01518 p->stack.push4(stringToPtr(ui16a));
01519 LOGPF(("str to ptr\n"));
01520 break;
01521
01522 case 0x6C:
01523
01524
01525
01526
01527 si8a = cs.read1();
01528 ui8a = cs.read1();
01529 LOGPF(("param pid chg\t%s, type=%u\n", print_bp(si8a), ui8a));
01530
01531 ui16a = p->stack.access2(p->bp+si8a);
01532 switch (ui8a) {
01533 case 1:
01534
01535 ui16b = duplicateString(ui16a);
01536 break;
01537 case 2: {
01538 UCList* l = new UCList(2);
01539 l->copyStringList(*getList(ui16a));
01540 ui16b = assignList(l);
01541 } break;
01542 case 3: {
01543 UCList* l = getList(ui16a);
01544 int elementsize = l->getElementSize();
01545 UCList* l2 = new UCList(elementsize);
01546 l2->copyList(*l);
01547 ui16b = assignList(l2);
01548 } break;
01549 default:
01550 ui16b = 0;
01551 perr << "Error: invalid param pid change type (" << ui8a
01552 << ")" << std::endl;
01553 error = true;
01554 }
01555 p->stack.assign2(p->bp+si8a, ui16b);
01556 p->freeOnTerminate(ui16b, ui8a);
01557 break;
01558
01559 case 0x6D:
01560
01561
01562
01563
01564 LOGPF(("push dword\tprocess result\n"));
01565 p->stack.push4(p->result);
01566 break;
01567
01568 case 0x6E:
01569
01570
01571
01572 si8a = static_cast<sint8>(cs.read1());
01573 p->stack.addSP(-si8a);
01574 LOGPF(("move sp\t\t%s%02Xh\n", si8a<0?"-":"", si8a<0?-si8a:si8a));
01575 break;
01576
01577
01578 case 0x6F:
01579
01580
01581 si8a = static_cast<sint8>(cs.read1());
01582 p->stack.push4(stackToPtr(p->pid, static_cast<uint16>(p->stack.getSP() - si8a)));
01583 LOGPF(("push addr\t%s\n", print_sp(-si8a)));
01584 break;
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597 case 0x70:
01598
01599
01600
01601
01602 {
01603 si16a = cs.readXS(1);
01604 uint32 scriptsize = cs.read1();
01605 uint32 searchtype = cs.read1();
01606
01607 ui16a = p->stack.pop2();
01608 ui16b = p->stack.pop2();
01609
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622 if (scriptsize > 0x20) {
01623 perr << "Loopscript too long" << std::endl;
01624 error = true;
01625 break;
01626 }
01627
01628 uint8* script = new uint8[scriptsize];
01629 p->stack.pop(script, scriptsize);
01630
01631 uint32 stacksize = 0;
01632 bool recurse = false;
01633
01634
01635 UCList *itemlist = new UCList(2);
01636
01637 World* world = World::get_instance();
01638
01639 switch (searchtype) {
01640 case 2: case 3:
01641 {
01642
01643 stacksize = 0x34;
01644 if (GAME_IS_CRUSADER) stacksize = 0x3A;
01645 if (searchtype == 3) recurse = true;
01646
01647
01648 Item* item = getItem(ui16a);
01649
01650 if (item) {
01651 world->getCurrentMap()->areaSearch(itemlist, script,
01652 scriptsize, item,
01653 ui16b, recurse);
01654 } else {
01655
01656 perr << "Warning: invalid item passed to area search"
01657 << std::endl;
01658 }
01659 break;
01660 }
01661 case 4: case 5:
01662 {
01663
01664 stacksize = 0x28;
01665 if (GAME_IS_CRUSADER) stacksize = 0x2A;
01666 if (searchtype == 5) { stacksize += 2; recurse = true; }
01667
01668
01669 Container* container = getContainer(ui16b);
01670
01671 if (ui16a != 0xFFFF) {
01672 perr << "Warning: non-FFFF value passed to "
01673 << "container search" << std::endl;
01674 }
01675
01676 if (container) {
01677 container->containerSearch(itemlist, script,
01678 scriptsize, recurse);
01679 } else {
01680
01681 perr << "Warning: invalid container passed to "
01682 << "container search" << std::endl;
01683 }
01684 break;
01685 }
01686 case 6:
01687 {
01688
01689 stacksize = 0x3D;
01690 if (GAME_IS_CRUSADER) stacksize = 0x43;
01691
01692 bool above = ui16a != 0xFFFF;
01693 bool below = ui16b != 0xFFFF;
01694 Item* item = getItem( below?ui16b:ui16a );
01695
01696 if (item) {
01697 world->getCurrentMap()->surfaceSearch(itemlist, script,
01698 scriptsize, item,
01699 above, below);
01700 } else {
01701
01702 perr << "Warning: invalid item passed to surface search"
01703 << std::endl;
01704 }
01705 break;
01706 }
01707 default:
01708 perr << "Unhandled search type " << searchtype <<std::endl;
01709 error = true;
01710 delete[] script;
01711 break;
01712 }
01713
01714 p->stack.push0(stacksize - scriptsize - 8);
01715 p->stack.push(script, scriptsize);
01716 p->stack.push2(scriptsize);
01717 p->stack.push2(static_cast<uint16>(si16a));
01718 p->stack.push2(0);
01719 uint16 itemlistID = assignList(itemlist);
01720 p->stack.push2(itemlistID);
01721
01722 delete[] script;
01723
01724 LOGPF(("loop\t\t%s %02X %02X\n", print_bp(si16a),
01725 scriptsize, searchtype));
01726 }
01727
01728 case 0x73:
01729
01730
01731 {
01732 unsigned int sp = p->stack.getSP();
01733 uint16 itemlistID = p->stack.access2(sp);
01734 UCList* itemlist = getList(itemlistID);
01735 uint16 index = p->stack.access2(sp+2);
01736 si16a = static_cast<sint16>(p->stack.access2(sp+4));
01737 #if 0
01738 uint16 scriptsize = p->stack.access2(sp+6);
01739 const uint8* loopscript = p->stack.access(sp+8);
01740 #endif
01741
01742 if (!itemlist) {
01743 perr << "Invalid item list in loopnext!" << std::endl;
01744 error = true;
01745 break;
01746 }
01747
01748
01749 bool valid = false;
01750 do {
01751 if (index >= itemlist->getSize()) {
01752 break;
01753 }
01754
01755 p->stack.assign(p->bp+si16a, (*itemlist)[index], 2);
01756 uint16 objid = p->stack.access2(p->bp+si16a);
01757 Item* item = getItem(objid);
01758 if (item) {
01759 #if 0
01760 valid = item->checkLoopScript(loopscript, scriptsize);
01761 #else
01762 valid = true;
01763 #endif
01764 }
01765
01766 if (!valid) index++;
01767
01768 } while (!valid);
01769
01770 if (!valid) {
01771 p->stack.push2(0);
01772 freeList(itemlistID);
01773 } else {
01774 p->stack.push2(1);
01775
01776 p->stack.assign2(sp+2, index+1);
01777 }
01778
01779 if (opcode == 0x73) {
01780 LOGPF(("loopnext\n"));
01781 }
01782 }
01783 break;
01784
01785 case 0x74:
01786
01787
01788 ui8a = cs.read1();
01789 p->stack.push1(ui8a);
01790 LOGPF(("loopscr\t\t%02X \"%c\"\n", ui8a, static_cast<char>(ui8a)));
01791 break;
01792
01793 case 0x75: case 0x76:
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833 si8a = cs.read1();
01834 ui32a = cs.read1();
01835 si16a = cs.read2();
01836
01837 ui16a = p->stack.access2(p->stack.getSP());
01838 ui16b = p->stack.access2(p->stack.getSP()+2);
01839
01840 if (opcode == 0x76 && ui32a != 2) {
01841 error = true;
01842 }
01843
01844 if (opcode == 0x75) {
01845 LOGPF(("for each\t%s (%02X) %04hX\n",
01846 print_bp(si8a), ui32a, si16a));
01847 } else {
01848 LOGPF(("for each str\t%s (%02X) %04hX\n",
01849 print_bp(si8a), ui32a, si16a));
01850 }
01851
01852
01853 if (ui16a == 0xFFFF) ui16a = 0;
01854 else ui16a++;
01855
01856 if (ui16a >= getList(ui16b)->getSize()) {
01857
01858
01859
01860 if (opcode == 0x75) {
01861 freeList(ui16b);
01862 } else {
01863 freeStringList(ui16b);
01864 }
01865
01866 p->stack.addSP(4);
01867
01868
01869 ui16a = cs.getPos() + si16a;
01870 cs.seek(ui16a);
01871 }
01872 else
01873 {
01874
01875
01876
01877
01878 p->stack.assign2(p->stack.getSP(),ui16a);
01879
01880
01881 p->stack.assign(p->bp+si8a, (*getList(ui16b))[ui16a], ui32a);
01882 }
01883 break;
01884
01885 case 0x77:
01886
01887
01888
01889 p->setItemNum(p->stack.pop2());
01890 p->setType(p->stack.pop2());
01891 LOGPF(("set info\n"));
01892 break;
01893
01894 case 0x78:
01895
01896
01897
01898
01899
01900
01901
01902 LOGPF(("process exclude"));
01903
01904 if (Kernel::get_instance()->
01905 getNumProcesses(p->item_num, p->type) > 1) {
01906
01907 p->terminateDeferred();
01908 LOGPF(("\t(terminating)\n"));
01909 } else {
01910 LOGPF(("\n"));
01911 }
01912
01913
01914 break;
01915
01916
01917 case 0x79: case 0x7A:
01918
01919
01920
01922 LOGPF(("end\n"));
01923 perr.printf("end of function opcode reached!\n");
01924 error = true;
01925 break;
01926
01927 case 0x5B: case 0x5C:
01928 perr.printf("unhandled opcode %02X\n", opcode);
01929 break;
01930
01931 default:
01932 perr.printf("unhandled opcode %02X\n", opcode);
01933
01934 }
01935
01936
01937 p->ip = static_cast<uint16>(cs.getPos());
01938
01939
01940 if((p->flags & Process::PROC_SUSPENDED)!=0)
01941 cede = true;
01942 }
01943
01944 if (error) {
01945 perr << "Process " << p->pid << " caused an error. Killing process."
01946 << std::endl;
01947
01948 p->terminateDeferred();
01949 }
01950
01951
01952 return false;
01953 }
01954
01955
01956 std::string& UCMachine::getString(uint16 str)
01957 {
01958 static std::string emptystring("");
01959
01960 std::map<uint16, std::string>::iterator iter = stringHeap.find(str);
01961
01962 if (iter != stringHeap.end())
01963 return iter->second;
01964
01965 return emptystring;
01966 }
01967
01968 UCList* UCMachine::getList(uint16 l)
01969 {
01970 std::map<uint16, UCList*>::iterator iter = listHeap.find(l);
01971
01972 if (iter != listHeap.end())
01973 return iter->second;
01974
01975 return 0;
01976 }
01977
01978
01979
01980 uint16 UCMachine::assignString(const char* str)
01981 {
01982 uint16 id = stringIDs->getNewID();
01983 if (id == 0) return 0;
01984
01985 stringHeap[id] = str;
01986
01987 return id;
01988 }
01989
01990 uint16 UCMachine::duplicateString(uint16 str)
01991 {
01992 return assignString(stringHeap[str].c_str());
01993 }
01994
01995
01996 uint16 UCMachine::assignList(UCList* l)
01997 {
01998 uint16 id = listIDs->getNewID();
01999 if (id == 0) return 0;
02000 assert(listHeap.find(id) == listHeap.end());
02001
02002 listHeap[id] = l;
02003
02004 return id;
02005 }
02006
02007 void UCMachine::freeString(uint16 s)
02008 {
02013 std::map<uint16, std::string>::iterator iter = stringHeap.find(s);
02014 if (iter != stringHeap.end()) {
02015 stringHeap.erase(iter);
02016 stringIDs->clearID(s);
02017 }
02018 }
02019
02020 void UCMachine::freeList(uint16 l)
02021 {
02022 std::map<uint16, UCList*>::iterator iter = listHeap.find(l);
02023 if (iter != listHeap.end() && iter->second) {
02024 iter->second->free();
02025 delete iter->second;
02026 listHeap.erase(iter);
02027 listIDs->clearID(l);
02028 }
02029 }
02030
02031 void UCMachine::freeStringList(uint16 l)
02032 {
02033 std::map<uint16, UCList*>::iterator iter = listHeap.find(l);
02034 if (iter != listHeap.end() && iter->second) {
02035 iter->second->freeStrings();
02036 delete iter->second;
02037 listHeap.erase(iter);
02038 listIDs->clearID(l);
02039 }
02040 }
02041
02042
02043 uint32 UCMachine::listToPtr(uint16 l)
02044 {
02045 uint32 ptr = SEG_LIST;
02046 ptr <<= 16;
02047 ptr += l;
02048 return ptr;
02049 }
02050
02051
02052 uint32 UCMachine::stringToPtr(uint16 s)
02053 {
02054 uint32 ptr = SEG_STRING;
02055 ptr <<= 16;
02056 ptr += s;
02057 return ptr;
02058 }
02059
02060
02061 uint32 UCMachine::stackToPtr(uint16 pid, uint16 offset)
02062 {
02063 uint32 ptr = SEG_STACK + pid;
02064 ptr <<= 16;
02065 ptr += offset;
02066 return ptr;
02067 }
02068
02069
02070 uint32 UCMachine::globalToPtr(uint16 offset)
02071 {
02072 uint32 ptr = SEG_GLOBAL;
02073 ptr <<= 16;
02074 ptr += offset;
02075 return ptr;
02076 }
02077
02078
02079 uint32 UCMachine::objectToPtr(uint16 objID)
02080 {
02081 uint32 ptr = SEG_OBJ;
02082 ptr <<= 16;
02083 ptr += objID;
02084 return ptr;
02085 }
02086
02087 bool UCMachine::assignPointer(uint32 ptr, const uint8* data, uint32 size)
02088 {
02089
02090
02091
02092
02093
02095
02096 uint16 segment =static_cast<uint16>(ptr >> 16);
02097 uint16 offset = static_cast<uint16>(ptr & 0xFFFF);
02098
02099 if (segment >= SEG_STACK_FIRST && segment <= SEG_STACK_LAST)
02100 {
02101 UCProcess *proc = p_dynamic_cast<UCProcess*>
02102 (Kernel::get_instance()->getProcess(segment));
02103
02104
02105 if (!proc) {
02106
02107 perr << "Trying to access stack of non-existent "
02108 << "process (pid: " << segment << ")" << std::endl;
02109 return false;
02110 } else {
02111 proc->stack.assign(offset, data, size);
02112 }
02113 }
02114 else if (segment == SEG_GLOBAL)
02115 {
02116 CANT_HAPPEN_MSG("pointers to globals not implemented yet");
02117 }
02118 else
02119 {
02120 perr << "Trying to access segment " << std::hex
02121 << segment << std::dec << std::endl;
02122 return false;
02123 }
02124
02125 return true;
02126 }
02127
02128 bool UCMachine::dereferencePointer(uint32 ptr, uint8* data, uint32 size)
02129 {
02130
02131
02132
02133
02134
02135
02136
02138
02139 uint16 segment = static_cast<uint16>(ptr >> 16);
02140 uint16 offset = static_cast<uint16>(ptr & 0xFFFF);
02141
02142 if (segment >= SEG_STACK_FIRST && segment <= SEG_STACK_LAST)
02143 {
02144 UCProcess *proc = p_dynamic_cast<UCProcess*>
02145 (Kernel::get_instance()->getProcess(segment));
02146
02147
02148 if (!proc) {
02149
02150 perr << "Trying to access stack of non-existent "
02151 << "process (pid: " << segment << ")" << std::endl;
02152 return false;
02153 } else {
02154 std::memcpy(data, proc->stack.access(offset), size);
02155 }
02156 }
02157 else if (segment == SEG_OBJ)
02158 {
02159 if (size != 2) {
02160 perr << "Trying to read other than 2 bytes from objptr"
02161 << std::endl;
02162 return false;
02163 } else {
02164
02165 data[0] = static_cast<uint8>(offset);
02166 data[1] = static_cast<uint8>(offset>>8);
02167 }
02168 }
02169 else if (segment == SEG_GLOBAL)
02170 {
02171 CANT_HAPPEN_MSG("pointers to globals not implemented yet");
02172 }
02173 else
02174 {
02175 perr << "Trying to access segment " << std::hex
02176 << segment << std::dec << std::endl;
02177 return false;
02178 }
02179 return true;
02180 }
02181
02182
02183 uint16 UCMachine::ptrToObject(uint32 ptr)
02184 {
02186
02187 uint16 segment = static_cast<uint16>(ptr >> 16);
02188 uint16 offset = static_cast<uint16>(ptr);
02189 if (segment >= SEG_STACK_FIRST && segment <= SEG_STACK_LAST)
02190 {
02191 UCProcess *proc = p_dynamic_cast<UCProcess*>
02192 (Kernel::get_instance()->getProcess(segment));
02193
02194
02195 if (!proc) {
02196
02197 perr << "Trying to access stack of non-existent "
02198 << "process (pid: " << segment << ")" << std::endl;
02199 return 0;
02200 } else {
02201 return proc->stack.access2(offset);
02202 }
02203 }
02204 else if (segment == SEG_OBJ || segment == SEG_STRING)
02205 {
02206 return offset;
02207 }
02208 else if (segment == SEG_GLOBAL)
02209 {
02210 CANT_HAPPEN_MSG("pointers to globals not implemented yet");
02211 return 0;
02212 }
02213 else
02214 {
02215 perr << "Trying to access segment " << std::hex
02216 << segment << std::dec << std::endl;
02217 return 0;
02218 }
02219 }
02220
02221 void UCMachine::usecodeStats()
02222 {
02223 pout << "Usecode Machine memory stats:" << std::endl;
02224 pout << "Strings : " << stringHeap.size() << "/65534" << std::endl;
02225 #ifdef DUMPHEAP
02226 std::map<uint16, std::string>::iterator iter;
02227 for (iter = stringHeap.begin(); iter != stringHeap.end(); ++iter)
02228 pout << iter->first << ":" << iter->second << std::endl;
02229 #endif
02230 pout << "Lists : " << listHeap.size() << "/65534" << std::endl;
02231 #ifdef DUMPHEAP
02232 std::map<uint16, UCList*>::iterator iterl;
02233 for (iterl = listHeap.begin(); iterl != listHeap.end(); ++iterl) {
02234 if (!iterl->second) {
02235 pout << iterl->first << ": <null>" << std::endl;
02236 continue;
02237 }
02238 if (iterl->second->getElementSize() == 2) {
02239 pout << iterl->first << ":";
02240 for (unsigned int i = 0; i < iterl->second->getSize(); ++i) {
02241 if (i > 0) pout << ",";
02242 pout << iterl->second->getuint16(i);
02243 }
02244 pout << std::endl;
02245 } else {
02246 pout << iterl->first << ": " << iterl->second->getSize()
02247 << " elements of size " << iterl->second->getElementSize()
02248 << std::endl;
02249 }
02250 }
02251 #endif
02252 }
02253
02254 void UCMachine::saveGlobals(ODataSource* ods)
02255 {
02256 globals->save(ods);
02257 }
02258
02259 void UCMachine::saveStrings(ODataSource* ods)
02260 {
02261 stringIDs->save(ods);
02262 ods->write4(stringHeap.size());
02263
02264 std::map<uint16, std::string>::iterator iter;
02265 for (iter = stringHeap.begin(); iter != stringHeap.end(); ++iter)
02266 {
02267 ods->write2((*iter).first);
02268 ods->write4((*iter).second.size());
02269 ods->write((*iter).second.c_str(), (*iter).second.size());
02270 }
02271 }
02272
02273 void UCMachine::saveLists(ODataSource* ods)
02274 {
02275 listIDs->save(ods);
02276 ods->write4(listHeap.size());
02277
02278 std::map<uint16, UCList*>::iterator iter;
02279 for (iter = listHeap.begin(); iter != listHeap.end(); ++iter)
02280 {
02281 ods->write2((*iter).first);
02282 (*iter).second->save(ods);
02283 }
02284 }
02285
02286 bool UCMachine::loadGlobals(IDataSource* ids, uint32 version)
02287 {
02288 return globals->load(ids, version);
02289 }
02290
02291 bool UCMachine::loadStrings(IDataSource* ids, uint32 version)
02292 {
02293 if (!stringIDs->load(ids, version)) return false;
02294
02295 uint32 stringcount = ids->read4();
02296 for (unsigned int i = 0; i < stringcount; ++i)
02297 {
02298 uint16 sid = ids->read2();
02299 uint32 len = ids->read4();
02300 if (len) {
02301 char* buf = new char[len+1];
02302 ids->read(buf, len);
02303 buf[len] = 0;
02304 stringHeap[sid] = buf;
02305 delete[] buf;
02306 } else {
02307 stringHeap[sid] = "";
02308 }
02309 }
02310
02311 return true;
02312 }
02313
02314 bool UCMachine::loadLists(IDataSource* ids, uint32 version)
02315 {
02316 if (!listIDs->load(ids, version)) return false;
02317
02318 uint32 listcount = ids->read4();
02319 for (unsigned int i = 0; i < listcount; ++i)
02320 {
02321 uint16 lid = ids->read2();
02322 UCList* l = new UCList(2);
02323 bool ret = l->load(ids, version);
02324 if (!ret) return false;
02325
02326 listHeap[lid] = l;
02327 }
02328
02329 return true;
02330 }
02331
02332
02333 uint32 UCMachine::I_true(const uint8* , unsigned int )
02334 {
02335 return 1;
02336 }
02337
02338 uint32 UCMachine::I_dummyProcess(const uint8* , unsigned int )
02339 {
02340 return Kernel::get_instance()->addProcess(new DelayProcess(4));
02341 }
02342
02343 uint32 UCMachine::I_getName(const uint8* , unsigned int )
02344 {
02345 UCMachine *uc = UCMachine::get_instance();
02346 MainActor* av = getMainActor();
02347 return uc->assignString(av->getName().c_str());
02348 }
02349
02350 uint32 UCMachine::I_numToStr(const uint8* args, unsigned int )
02351 {
02352 ARG_SINT16(num);
02353
02354 char buf[16];
02355 snprintf(buf, 16, "%d", num);
02356
02357 return UCMachine::get_instance()->assignString(buf);
02358 }
02359
02360 uint32 UCMachine::I_urandom(const uint8* args, unsigned int )
02361 {
02362 ARG_UINT16(num);
02363 if (num <= 1) return 0;
02364
02365
02366
02367 return (std::rand() % num);
02368 }
02369
02370 uint32 UCMachine::I_rndRange(const uint8* args, unsigned int )
02371 {
02372 ARG_SINT16(lo);
02373 ARG_SINT16(hi);
02374
02375
02376
02377 if (hi <= lo) return lo;
02378
02379 return (lo + (std::rand() % (hi-lo+1)));
02380 }
02381
02382
02383 void UCMachine::ConCmd_getGlobal(const Console::ArgvType &argv)
02384 {
02385 UCMachine *uc = UCMachine::get_instance();
02386 if (argv.size() != 3) {
02387 pout << "usage: UCMachine::getGlobal offset size" << std::endl;
02388 return;
02389 }
02390
02391 unsigned int offset = strtol(argv[1].c_str(), 0, 0);
02392 unsigned int size = strtol(argv[2].c_str(), 0, 0);
02393
02394 pout.printf("[%04X %02X] = %d\n", offset, size,
02395 uc->globals->getBits(offset, size));
02396 }
02397
02398 void UCMachine::ConCmd_setGlobal(const Console::ArgvType &argv)
02399 {
02400 UCMachine *uc = UCMachine::get_instance();
02401 if (argv.size() != 4) {
02402 pout << "usage: UCMachine::setGlobal offset size value" << std::endl;
02403 return;
02404 }
02405
02406 unsigned int offset = strtol(argv[1].c_str(), 0, 0);
02407 unsigned int size = strtol(argv[2].c_str(), 0, 0);
02408 unsigned int value = strtol(argv[3].c_str(), 0, 0);
02409
02410 uc->globals->setBits(offset, size, value);
02411
02412 pout.printf("[%04X %02X] = %d\n", offset, size,
02413 uc->globals->getBits(offset, size));
02414 }
02415
02416 #ifdef DEBUG
02417
02418 void UCMachine::ConCmd_tracePID(const Console::ArgvType &argv)
02419 {
02420 if (argv.size() != 2) {
02421 pout << "Usage: UCMachine::tracePID pid" << std::endl;
02422 return;
02423 }
02424
02425 uint16 pid = strtol(argv[1].c_str(), 0, 0);
02426
02427 UCMachine *uc = UCMachine::get_instance();
02428 uc->tracing_enabled = true;
02429 uc->trace_PIDs.insert(pid);
02430
02431 pout << "UCMachine: tracing process " << pid << std::endl;
02432 }
02433
02434 void UCMachine::ConCmd_traceObjID(const Console::ArgvType &argv)
02435 {
02436 if (argv.size() != 2) {
02437 pout << "Usage: UCMachine::traceObjID objid" << std::endl;
02438 return;
02439 }
02440
02441 uint16 objid = strtol(argv[1].c_str(), 0, 0);
02442
02443 UCMachine *uc = UCMachine::get_instance();
02444 uc->tracing_enabled = true;
02445 uc->trace_ObjIDs.insert(objid);
02446
02447 pout << "UCMachine: tracing object " << objid << std::endl;
02448 }
02449
02450 void UCMachine::ConCmd_traceClass(const Console::ArgvType &argv)
02451 {
02452 if (argv.size() != 2) {
02453 pout << "Usage: UCMachine::traceClass class" << std::endl;
02454 return;
02455 }
02456
02457 uint16 ucclass = strtol(argv[1].c_str(), 0, 0);
02458
02459 UCMachine *uc = UCMachine::get_instance();
02460 uc->tracing_enabled = true;
02461 uc->trace_classes.insert(ucclass);
02462
02463 pout << "UCMachine: tracing class " << ucclass << std::endl;
02464 }
02465
02466 void UCMachine::ConCmd_traceAll(const Console::ArgvType &argv)
02467 {
02468 UCMachine *uc = UCMachine::get_instance();
02469 uc->tracing_enabled = true;
02470 uc->trace_all = true;
02471
02472 pout << "UCMachine: tracing all usecode" << std::endl;
02473 }
02474
02475 void UCMachine::ConCmd_traceEvents(const Console::ArgvType &argv)
02476 {
02477 UCMachine *uc = UCMachine::get_instance();
02478 uc->tracing_enabled = true;
02479 uc->trace_events = true;
02480
02481 pout << "UCMachine: tracing usecode events" << std::endl;
02482 }
02483
02484
02485
02486 void UCMachine::ConCmd_stopTrace(const Console::ArgvType &)
02487 {
02488 UCMachine *uc = UCMachine::get_instance();
02489 uc->trace_ObjIDs.clear();
02490 uc->trace_PIDs.clear();
02491 uc->trace_classes.clear();
02492 uc->tracing_enabled = false;
02493 uc->trace_all = false;
02494 uc->trace_events = false;
02495 }
02496
02497 #endif