UCMachine.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2002-2006 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 //#define DUMPHEAP
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, // I don't think this is used
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         // zero globals
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         // clear globals
00141         globals->setSize(0x1000);
00142 
00143         // clear strings, lists
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                 // POP opcodes
00205                 case 0x00:
00206                         // 00 xx
00207                         // pop 16 bit int, and assign LS 8 bit int into bp+xx
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                         // 01 xx
00216                         // pop 16 bit int into bp+xx
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                         // 02 xx
00225                         // pop 32 bit int into bp+xx
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                         // 03 xx yy
00234                         // pop yy bytes into bp+xx
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                         // 08
00247                         // pop 32bits into result register
00251                         LOGPF(("pop dword\tprocess result\n"));
00252                         p->result = p->stack.pop4();
00253                         break;
00254 
00255                 case 0x09:
00256                         // 09 xx yy zz
00257                         // pop yy bytes into an element of list bp+xx (or slist if zz set)
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; // index
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) { // slist?
00274                                 // what special behaviour do we need here?
00275                                 // probably just that the overwritten element has to be freed?
00276                                 if (ui32a != 2) error = true; // um?
00277                                 l->assign(ui16a, p->stack.access());
00278                                 p->stack.pop2(); // advance SP
00279                         } else {
00280                                 l->assign(ui16a, p->stack.access());
00281                                 p->stack.addSP(ui32a);
00282                         }
00283                 } break;
00284 
00285                 // PUSH opcodes
00286 
00287                 case 0x0A:
00288                         // 0A xx
00289                         // push sign-extended 8 bit xx onto the stack as 16 bit
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                         // 0B xx xx
00297                         // push 16 bit xxxx onto the stack
00298                         ui16a = cs.read2();
00299                         p->stack.push2(ui16a);
00300                         LOGPF(("push\t\t%04Xh\n", ui16a));
00301                         break;
00302 
00303                 case 0x0C:
00304                         // 0C xx xx xx xx
00305                         // push 32 bit xxxxxxxx onto the stack
00306                         ui32a = cs.read4();
00307                         p->stack.push4(ui32a);
00308                         LOGPF(("push dword\t%08Xh\n", ui32a));
00309                         break;
00310 
00311                 case 0x0D:
00312                         // 0D xx xx yy ... yy 00
00313                         // push string (yy ... yy) of length xx xx onto the stack
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                         // 0E xx yy
00329                         // pop yy values of size xx and push the resulting list
00330                         // (list is created in reverse order)
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                 // Usecode function and intrinsic calls
00347 
00348 
00349                 case 0x0F:
00350                         // 0F xx yyyy
00351                         // intrinsic call. xx is number of argument bytes
00352                         // (includes this pointer, if present)
00353                         // NB: do not actually pop these argument bytes
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                                 // !constants
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 //                                              perr << "Unhandled intrinsic \'" << convuse->intrinsics()[func] << "\' (" << std::hex << func << std::dec << ") called" << std::endl;
00369                                         }
00370                                         uint8 *argbuf = new uint8[arg_bytes];
00371                                         p->stack.pop(argbuf, arg_bytes);
00372                                         p->stack.addSP(-arg_bytes); // don't really pop the args
00373 
00374                                         p->temp32 = intrinsics[func](argbuf, arg_bytes);
00375 
00376                                         delete[] argbuf;
00377                                 }
00378 
00379 
00380 
00381                                 // REALLY MAJOR HACK:
00382                                 // see docs/u8bugs.txt and
00383                                 // https://sourceforge.net/tracker/index.php?func=detail&aid=1018748&group_id=53819&atid=471709
00384                                 if (GAME_IS_U8 && p->classid == 0x48B && func == 0xD0)
00385                                 { // 0xD0 = setAvatarInStasis
00386                                         globals->setBits(0, 1, 1);
00387                                 }
00388 
00389                         }
00390                         break;
00391 
00392 
00393                 case 0x11:
00394                         // 11 xx xx yy yy
00395                         // Ultima 8:
00396                         // call the function at offset yy yy of class xx xx
00397                         // Crusader:
00398                         // call function number yy yy of class xx xx
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());       // Truncates!!
00409                                 p->call(new_classid, new_offset);
00410 
00411                                 // Update the code segment
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                                 // Resume execution
00418                         }
00419                         break;
00420 
00421                 case 0x12:
00422                         // 12
00423                         // pop 16bits into temp register
00424                         p->temp32 = p->stack.pop2();
00425                         LOGPF(("pop\t\ttemp = %04X\n", (p->temp32 & 0xFFFF)));
00426                         break;
00427 
00428                 case 0x13:
00429                         // 13
00430                         // pop 32bits into temp register
00431                         // NB: 0x13 isn't used AFAIK, but this is a 'logical' guess
00432                         p->temp32 = p->stack.pop4();
00433                         LOGPF(("pop long\t\ttemp = %08X\n", p->temp32));
00434                         break;
00435 
00436                 // Arithmetic
00437 
00438                 case 0x14:
00439                         // 14
00440                         // 16 bit add
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                         // 15
00449                         // 32 bit add
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                         // 16
00459                         // pop two strings from the stack and push the concatenation
00460                         // (free the originals? order?)
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                         // 17
00476                         // pop two lists from the stack and push the 'sum' of the lists
00477                         // (freeing the originals)
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                                 // CHECKME: do we allow appending a list to itself?
00494                                 assert(ui16a != ui16b);
00495                                 freeList(ui16a);
00496                                 p->stack.push2(ui16b);
00497                         } else {
00498                                 // at least one of the lists didn't exist. Error or not?
00499                                 // for now: if one exists, push that one.
00500                                 // if neither exists, push 0.
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                         // 19 02
00515                         // add two stringlists, removing duplicates
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); // contents are actually freed in unionSL
00522                         p->stack.push2(ui16b);
00523                         LOGPF(("union slist\t(%02X)\n", ui32a));
00524                         break;
00525 
00526                 case 0x1A:
00527                         // 1A
00528                         // substract string list
00529                         // NB: this one takes a length parameter in crusader. (not in U8)!!
00530                         // (or rather, it seems it takes one after all? -wjp,20030511)
00531                         ui32a = cs.read1(); // elementsize
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                         // 1B xx
00543                         // pop two lists from the stack and remove the 2nd from the 1st
00544                         // (free the originals? order?)
00545                         // only occurs in crusader.
00546                         ui32a = cs.read1(); // elementsize
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                         // 1C
00557                         // subtract two 16 bit integers
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)); // !! order?
00561                         LOGPF(("sub\n"));
00562                         break;
00563 
00564                 case 0x1D:
00565                         // 1D
00566                         // subtract two 32 bit integers
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)); // !! order?
00570                         LOGPF(("sub long\n"));
00571                         break;
00572 
00573                 case 0x1E:
00574                         // 1E
00575                         // multiply two 16 bit integers
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                         // 1F
00584                         // multiply two 32 bit integers
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                         // 20
00593                         // divide two 16 bit integers    (order?)
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                         // 21
00607                         // divide two 32 bit integers    (order?)
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                         // 22
00621                         // 16 bit mod    (order?)
00622                         // is this a C-style %?
00623                         // or return values between 0 and si16a-1 ?
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                         // 23
00637                         // 32 bit mod   (order)?
00638                         // also see 0x22
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                         // 24
00652                         // 16 bit cmp
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                         // 25
00665                         // 32 bit cmp
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                         // 26
00679                         // compare two strings
00680                         // (delete strings)
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                         // 28
00695                         // 16 bit less-than
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                         // 29
00708                         // 32 bit less-than
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                         // 2A
00721                         // 16 bit less-or-equal
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                         // 2B
00734                         // 32 bit less-or-equal
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                         // 2C
00747                         // 16 bit greater-than
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                         // 2D
00760                         // 32 bit greater-than
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                         // 2E
00773                         // 16 bit greater-or-equal
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                         // 2F
00786                         // 32 bit greater-or-equal
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                         // 30
00799                         // 16 bit boolean not
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                         // 31
00812                         // 32 bit boolean not (both input and output 32 bit?)
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                         // 32
00824                         // 16 bit boolean and
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                         // 33
00837                         // 32 bit boolean and
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                         // 34
00850                         // 16 bit boolean or
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                         // 35
00863                         // 32 bit boolean or
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                         // 36
00876                         // 16 bit not-equal
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                         // 37
00889                         // 32 bit not-equal
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                         // 38 xx yy
00903                         // is element (size xx) in list? (or slist if yy is true)
00904                         // free list/slist afterwards
00905 
00906                         ui16a = cs.read1();
00907                         ui32a = cs.read1();
00908                         ui16b = p->stack.pop2();
00909                         if (ui32a) { // stringlist
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                         // 39
00931                         // 16 bit bitwise and
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                         // 3A
00940                         // 16 bit bitwise or
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                         // 3B
00949                         // 16 bit bitwise not
00950                         ui16a = p->stack.pop2();
00951                         p->stack.push2(~ui16a);
00952                         LOGPF(("bit_not\n"));
00953                         break;
00954 
00955                 case 0x3C:
00956                         // 3C
00957                         // 16 bit left shift
00958                         // operand order?
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                         // 3D
00967                         // 16 bit right shift
00968                         // !! sign-extend or not?
00969                         // operand order?
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                         // 3E xx
00978                         // push the value of the unsigned 8 bit local var xx as 16 bit int
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                         // 3F xx
00987                         // push the value of the 16 bit local var xx
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                         // 40 xx
00996                         // push the value of the 32 bit local var xx
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                         // 41 xx
01005                         // push the string local var xx
01006                         // duplicating the string?
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                         // 42 xx yy
01017                         // push the list (with yy size elements) at BP+xx
01018                         // duplicating the list?
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                                         // trying to push non-existent list. Error or not?
01028                                         // Not: for example, function 01E3::0080, offset 0112
01029                                         // perr << "Pushing non-existent list" << std::endl;
01030                                         // error = true;
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                         // 43 xx
01041                         // push the stringlist local var xx
01042                         // duplicating the list, duplicating the strings in the list
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                                         // trying to push non-existent list. Error or not?
01053                                         // (Devon's talk code seems to use it; so no error for now)
01054                                         // perr << "Pushing non-existent slist" << std::endl;
01055                                         // error = true;
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                         // 44 xx yy
01064                         // push element from the second last var pushed onto the stack
01065                         // (a list/slist), indexed by the last element pushed onto the list
01066                         // (a byte/word). XX is the size of the types contained in the list
01067                         // YY is true if it's a slist (for garbage collection)
01068 
01069                         // duplicate string if YY? yy = 1 only occurs
01070                         // in two places in U8: once it pops into temp afterwards,
01071                         // once it is indeed freed. So, guessing we should duplicate.
01072                 {
01073                         ui32a = cs.read1();
01074                         ui32b = cs.read1();
01075                         ui16a = p->stack.pop2()-1; // index
01076                         ui16b = p->stack.pop2(); // list
01077                         UCList* l = getList(ui16b);
01078                         if (!l) {
01079 //                              perr << "push element from invalid list (" << ui16b << ")"
01080 //                                       << std::endl;
01081                                 // This is necessary for closing the backpack to work
01082                                 p->stack.push0(ui32a);
01083 //                              error = true;
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                         // 45 xx yy
01097                         // push huge of size yy from BP+xx
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                         // 4B xx
01106                         // push 32 bit pointer address of BP+XX
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                         // 4C xx
01114                         // indirect push,
01115                         // pops a 32 bit pointer off the stack and pushes xx bytes
01116                         // from the location referenced by the pointer
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                         // 4D xx
01138                         // indirect pop
01139                         // pops a 32 bit pointer off the stack and pushes xx bytes
01140                         // from the location referenced by the pointer
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                         // 4E xx xx yy
01157                         // push global xxxx size yy bits
01158                         ui16a = cs.read2();
01159                         ui16b = cs.read1();
01160                         // TODO: get flagname for output?
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                         // 4F xx xx yy
01169                         // pop value into global xxxx size yy bits
01170                         ui16a = cs.read2();
01171                         ui16b = cs.read1();
01172                         // TODO: get flagname for output?
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                         // paranoid :-)
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                         // 50
01188                         // return from function
01189 
01190                         if (p->ret()) { // returning from process
01191                                 // TODO
01192                                 LOGPF(("ret\t\tfrom process\n"));
01193                                 p->terminateDeferred();
01194 
01195                                 // return value is going to be stored somewhere,
01196                                 // and some other process is probably waiting for it.
01197                                 // So, we can't delete ourselves just yet.
01198                         } else {
01199                                 LOGPF(("ret\t\tto %04X:%04X\n", p->classid, p->ip));
01200 
01201                                 // return value is stored in temp32 register
01202 
01203                                 // Update the code segment
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                         // Resume execution
01211                         break;
01212 
01213                 case 0x51:
01214                         // 51 xx xx
01215                         // relative jump to xxxx if false
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                         // 52 xx xx
01231                         // relative jump to xxxx
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                         // 53
01240                         // suspend
01241                         LOGPF(("suspend\n"));
01242                         cede=true; 
01243                         break;
01244 
01245                 case 0x54:
01246                         // 54 01 01
01247                         // implies
01248                         // this seems to link two processes (two pids are popped)
01249                         // the '01 01' variety most likely causes one process
01250                         // to wait for the other to finish.
01251                         // the first pid pushed is often the current pid in U8
01252 
01253                         // question: can multiple processes be waiting for a single proc?
01254                         // can a process be waiting for multiple processes?
01255 
01256                         // 'implies' seems to push a value too, although it is very
01257                         // often ignored. It looks like it's a pid, but which one?
01258 
01259                         // additionally, it is possible that 'implies' puts the result
01260                         // of a process in the 'process result' variable,
01261                         // or more likely, when a process finishes, it sets the result
01262                         // value of the processes that were waiting for it.
01263                         // 0x6D (push process result) only seems to occur soon after
01264                         // an 'implies'
01265 
01266                         {
01267                                 cs.read2(); // skip the 01 01
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                                         // This condition triggers in 057C:1090 when talking
01288                                         // to a child (class 02C4), directly after the conversation
01289                                         // Specifically, it occurs because there is no
01290                                         // leaveFastArea usecode for class 02C4.
01291                                         // So currently we only regard this as an error when the
01292                                         // missing process wasn't PID 0.
01293                                         if ((ui16a && !proc2) || (ui16b && !proc))
01294                                                 error = true;
01295                                 }
01296                         }
01297                         break;
01298 
01299                 case 0x57:
01300                         // 57 aa tt xx xx yy yy
01301                         // spawn process function yyyy in class xxxx
01302                         // aa = number of arg bytes pushed (not including this pointer which is 4 bytes)
01303                         // tt = sizeof this pointer object
01304                         // only remove the this pointer from stack (4 bytes)
01305                         // put PID of spawned process in temp                   
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                                 // Note: order of execution of this process and the new one is
01339                                 // relevant. Currently, the spawned processes is executed once
01340                                 // immediately, after which the current process resumes
01341 
01342 
01343                                 // cede = true;
01344                         }
01345                         break;
01346 
01347 
01348                 case 0x58:
01349                         // 58 xx xx yy yy zz zz tt uu
01350                         // spawn inline process function yyyy in class xxxx at offset zzzz
01351                         // tt = size of this pointer
01352                         // uu = unknown (occurring values: 00, 02, 05)
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                                 // as with 'spawn', run execute the spawned process once
01381                                 // immediately
01382 
01383                                 p->stack.push2(newpid); 
01384 
01385                                 // cede = true;
01386                         }
01387                         break;
01388         
01389                 case 0x59:
01390                         // 59
01391                         // push process id
01392                         p->stack.push2(p->pid);
01393                         LOGPF(("push\t\tpid = %04Xh\n", p->pid));
01394                         break;
01395 
01396                 case 0x5A:
01397                         // 5A xx
01398                         // init function. xx = local var size
01399                         // sets xx bytes on stack to 0, moving sp
01400                         ui16a = cs.read1();
01401                         LOGPF(("init\t\t%02X\n", ui16a));
01402                         
01403                         if (ui16a & 1) ui16a++; // 16-bit align
01404                         if (ui16a > 0) {
01405                                 p->stack.push0(ui16a);
01406                         }
01407                         break;
01408 
01409                 case 0x5D:
01410                         // 5D
01411                         // push 8 bit value returned from function call
01412                         // (push temp8 as 16 bit value)
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                         // 5E
01419                         // push 16 bit value returned from function call
01420                         // (push temp16)
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                         // 5F
01427                         // push 32 bit value returned from function call
01428                         // (push temp32)
01429                         p->stack.push4(p->temp32);
01430                         LOGPF(("push long\t\tretval = %08Xh\n", p->temp32));
01431                         break;
01432 
01433                 case 0x60:
01434                         // 60
01435                         // convert 16-bit to 32-bit int (sign extend)
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                         // 61
01443                         // convert 32-bit to 16-bit int
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                         // 62 xx
01451                         // free the string in var BP+xx
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                         // 63 xx
01460                         // free the stringlist in var BP+xx
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                         // 64 xx
01469                         // free the list in var BP+xx
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                         // 65 xx
01478                         // free the string at SP+xx
01479                         // NB: sometimes there's a 32-bit string pointer at SP+xx
01480                         //     However, the low word of this is exactly the 16bit ref
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                         // 66 xx
01489                         // free the list at SP+xx
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                         // 67 xx
01498                         // free the string list at SP+xx
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                         // 69 xx
01507                         // push the string in var BP+xx as 32 bit pointer                       
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                         // 6B
01516                         // pop a string and push 32 bit pointer to string
01517                         ui16a = p->stack.pop2();
01518                         p->stack.push4(stringToPtr(ui16a));
01519                         LOGPF(("str to ptr\n"));
01520                         break;
01521 
01522                 case 0x6C:
01523                         // 6C xx yy
01524                         // yy = type (01 = string, 02 = slist, 03 = list)
01525                         // copy the (string/slist/list) in BP+xx to the current process,
01526                         // and add it to the "Free Me" list of the process
01527                         si8a = cs.read1(); // index
01528                         ui8a = cs.read1(); // type
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: // string
01534                                 // copy string
01535                                 ui16b = duplicateString(ui16a);
01536                                 break;
01537                         case 2: { // slist
01538                                 UCList* l = new UCList(2);
01539                                 l->copyStringList(*getList(ui16a));
01540                                 ui16b = assignList(l);
01541                         } break;
01542                         case 3: { // list
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); // assign new index
01556                         p->freeOnTerminate(ui16b, ui8a); // free new var when terminating
01557                         break;
01558 
01559                 case 0x6D:
01560                         // 6D
01561                         // push 32bit result of process
01562                         // (of which process? pop anything?)
01563                         // (also see comment for 0x54 'implies')
01564                         LOGPF(("push dword\tprocess result\n"));
01565                         p->stack.push4(p->result);
01566                         break;
01567 
01568                 case 0x6E:
01569                         // 6E xx
01570                         // substract xx from stack pointer
01571                         // (effect on SP is the same as popping xx bytes)
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                         // 6F xx
01580                         // push 32 pointer address of SP-xx
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                 // loop-related opcodes
01587                 // 0x70 has different types:
01588                 //    02: search the area around an object
01589                 //    03: search the area around an object, recursing into containers
01590                 //    04: search a container
01591                 //    05: search a container, recursing into containers
01592                 //    06: something about looking for items on top of another (??)
01593                 // each of these types allocate a rather large area on the stack
01594                 // we expect SP to be at the end of that area when 0x73 is executed
01595                 // a 'loop script' (created by 0x74) is used to select items
01596 
01597                 case 0x70:
01598                         // 70 xx yy zz
01599                         // loop something. Stores 'current object' in var xx
01600                         // yy == num bytes in string
01601                         // zz == type
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                                 // We'll first create a list of all matching items.
01613                                 // Store the id of this list in the last two bytes
01614                                 // of our stack area.
01615                                 // Behind that we'll store an index into this list.
01616                                 // This is followed by the variable in which to store the item
01617                                 // After that we store the loopscript length followed by
01618                                 // the loopscript itself.
01619                                 //   (Note that this puts a limit on the max. size of the
01620                                 //    loopscript of 0x20 bytes)
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                                 // we'll put everything on the stack after stacksize is set
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                                         // area search (3 = recursive)
01643                                         stacksize = 0x34;
01644                                         if (GAME_IS_CRUSADER) stacksize = 0x3A;
01645                                         if (searchtype == 3) recurse = true;
01646 
01647                                         // ui16a = item, ui16b = range
01648                                         Item* item = getItem(ui16a);
01649 
01650                                         if (item) {
01651                                             world->getCurrentMap()->areaSearch(itemlist, script,
01652                                                                                                                    scriptsize, item,
01653                                                                                                                    ui16b, recurse);
01654                                         } else {
01655                                                 // return error or return empty list?
01656                                                 perr << "Warning: invalid item passed to area search"
01657                                                          << std::endl;
01658                                         }
01659                                         break;
01660                                 }
01661                                 case 4: case 5:
01662                                 {
01663                                         // container search (4 = recursive)
01664                                         stacksize = 0x28;
01665                                         if (GAME_IS_CRUSADER) stacksize = 0x2A;
01666                                         if (searchtype == 5) { stacksize += 2; recurse = true; }
01667 
01668                                         // ui16a = 0xFFFF (?), ui16b = container
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                                                 // return error or return empty list?
01681                                                 perr << "Warning: invalid container passed to "
01682                                                          << "container search" << std::endl;
01683                                         }
01684                                         break;
01685                                 }
01686                                 case 6:
01687                                 {
01688                                         // Surface search
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                                                 // return error or return empty list?
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); // filler
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                         // FALL-THROUGH to handle first item
01728                 case 0x73:
01729                         // 73
01730                         // next loop object. pushes false if end reached
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                                 // see if there are still valid items left
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); // end of loop
01772                                         freeList(itemlistID);
01773                                 } else {
01774                                         p->stack.push2(1);
01775                                         // increment index
01776                                         p->stack.assign2(sp+2, index+1);
01777                                 }
01778 
01779                                 if (opcode == 0x73) { // because of the fall-through
01780                                         LOGPF(("loopnext\n"));
01781                                 }
01782                         }
01783                         break;
01784 
01785                 case 0x74:
01786                         // 74 xx
01787                         // add xx to the current 'loopscript'
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                         // 75 xx yy zz zz
01795                         // 76 xx yy zz zz
01796                         // xx appears to be the location to store 'current' value from the
01797                         //   list (BP+xx)
01798                         // yy is the 'datasize' of the list, identical to the second parameter
01799                         //   of the create list/slist opcodes
01800                         // zzzz appears to be the offset to jump to after it's finished the
01801                         //   iteration, the opcode before is a 'jmp' to the original position
01802                         //   of the opcode.
01803                         // (all guesses from Remorse1.21 usecode, _may_ be different in u8,
01804                         //   unlikely though)
01805                         // the way it appears to operate is it pops a 'word' off the stack
01806                         //   (maximum number of items to iterate through? No idea, I've only
01807                         //   seen 0xFFFF pushed before it (in Remorse1.21)), then pops
01808                         //   the 'list' off to iterate through
01809 
01810                         // it seems as if there's no way provided to store index
01811                         // and list. Assuming there are no nested loops, this isn't
01812                         // a problem. If there -are- nested loops, we could use a stack
01813                         // for these.
01814                         // There may be problems with jumps from inside the loop to outside
01815                         // Either these are forbidden, or we have to detect when jumping
01816                         // to outside a loop? (yuck)
01817                         // (this will be _very_ messy when combined with nested loops,
01818                         //  let's hope it won't be necessary)
01819 
01820                         // random idea: maybe the 0xFFFF on the stack is used to
01821                         // indicate the start of a loop? Would be mildly ugly, but could
01822                         // be useful for nested loops or loop-escaping jumps
01823 
01824                         // other random idea: 0xFFFF could also be the loop index
01825                         // to start with minus 1. (This would clean up the 'loop_index=0'
01826                         // or 'loop_index++' distinction a bit)
01827 
01828                         // 75 is for lists, 76 for slists
01829                         // Only difference should be in the freeing afterwards.
01830                         // Strings are _not_ duplicated when putting them in the loopvar
01831                         // Lists _are_ freed afterwards
01832 
01833                         si8a = cs.read1();      // loop variable
01834                         ui32a = cs.read1(); // list size
01835                         si16a = cs.read2(); // jump offset
01836 
01837                         ui16a = p->stack.access2(p->stack.getSP());             // Loop index
01838                         ui16b = p->stack.access2(p->stack.getSP()+2);   // Loop list
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                         // Increment the counter
01853                         if (ui16a == 0xFFFF) ui16a = 0;
01854                         else ui16a++;
01855                         
01856                         if (ui16a >= getList(ui16b)->getSize()) {
01857                                 // loop done
01858                                 
01859                                 // free loop list
01860                                 if (opcode == 0x75) {
01861                                         freeList(ui16b);
01862                                 } else {
01863                                         freeStringList(ui16b);
01864                                 }
01865                                 
01866                                 p->stack.addSP(4);      // Pop list and counter
01867 
01868                                 // jump out
01869                                 ui16a = cs.getPos() + si16a;
01870                                 cs.seek(ui16a);
01871                         }
01872                         else
01873                         {
01874                                 // loop iteration
01875                                 // (not duplicating any strings)
01876                                 
01877                                 // updated loop index
01878                                 p->stack.assign2(p->stack.getSP(),ui16a);               
01879 
01880                                 // place next element from list in [bp+si8a]
01881                                 p->stack.assign(p->bp+si8a, (*getList(ui16b))[ui16a], ui32a);
01882                         }
01883                         break;
01884 
01885                 case 0x77:
01886                         // 77
01887                         // set info
01888                         // assigns item number and ProcessType 
01889                         p->setItemNum(p->stack.pop2());
01890                         p->setType(p->stack.pop2());
01891                         LOGPF(("set info\n"));
01892                         break;
01893 
01894                 case 0x78:
01895                         // 78
01896                         // process exclude
01897                         // process gets 'exclusive access' to this (object,type)
01898 
01899                         // Educated guess:
01900                         // Check if any other processes have the same (object,type) info
01901                         // set. If so, return from process.
01902                         LOGPF(("process exclude"));
01903 
01904                         if (Kernel::get_instance()->
01905                                 getNumProcesses(p->item_num, p->type) > 1) {
01906                                 // another process with this (object,type) is already running
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                         // 7A
01919                         // end of function
01920                         // shouldn't happen
01922                         LOGPF(("end\n"));
01923                         perr.printf("end of function opcode reached!\n");
01924                         error = true;
01925                         break;
01926 
01927                 case 0x5B: case 0x5C: // debugging
01928                         perr.printf("unhandled opcode %02X\n", opcode);
01929                         break;
01930 
01931                 default:
01932                         perr.printf("unhandled opcode %02X\n", opcode);
01933 
01934                 } // switch(opcode)
01935 
01936                 // write back IP
01937                 p->ip = static_cast<uint16>(cs.getPos());       // TRUNCATES!
01938 
01939                 // check if we suspended ourselves
01940                 if((p->flags & Process::PROC_SUSPENDED)!=0)
01941                         cede = true;
01942         } // while(!cede && !error && !p->terminated && !p->terminate_deferred)
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 //static
02043 uint32 UCMachine::listToPtr(uint16 l)
02044 {
02045         uint32 ptr = SEG_LIST;
02046         ptr <<= 16;
02047         ptr += l;
02048         return ptr;
02049 }
02050 
02051 //static
02052 uint32 UCMachine::stringToPtr(uint16 s)
02053 {
02054         uint32 ptr = SEG_STRING;
02055         ptr <<= 16;
02056         ptr += s;
02057         return ptr;
02058 }
02059 
02060 //static
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 //static
02070 uint32 UCMachine::globalToPtr(uint16 offset)
02071 {
02072         uint32 ptr = SEG_GLOBAL;
02073         ptr <<= 16;
02074         ptr += offset;
02075         return ptr;
02076 }
02077 
02078 //static
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         // Only implemented the following:
02090         // * stack pointers
02091         // * global pointers
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                 // reference to the stack of pid 'segment'
02105                 if (!proc) {
02106                         // segfault :-)
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         // this one is a bit tricky. There's no way we can support
02131         // all possible pointers, so we're just going to do a few:
02132         // * stack pointers
02133         // * object pointers, as long as xx == 02. (i.e., get objref)
02134         // * global pointers
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                 // reference to the stack of pid 'segment'
02148                 if (!proc) {
02149                         // segfault :-)
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                         // push objref
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 //static
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                 // reference to the stack of pid 'segment'
02195                 if (!proc) {
02196                         // segfault :-)
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); // the "2" will be ignored by load()
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* /*args*/, unsigned int /*argsize*/)
02334 {
02335         return 1;
02336 }
02337 
02338 uint32 UCMachine::I_dummyProcess(const uint8* /*args*/, unsigned int /*argsize*/)
02339 {
02340         return Kernel::get_instance()->addProcess(new DelayProcess(4));
02341 }
02342 
02343 uint32 UCMachine::I_getName(const uint8* /*args*/, unsigned int /*argsize*/)
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 /*argsize*/)
02351 {
02352         ARG_SINT16(num);
02353 
02354         char buf[16]; // a 16 bit int should easily fit
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 /*argsize*/)
02361 {
02362         ARG_UINT16(num);
02363         if (num <= 1) return 0;
02364 
02365         // return random integer between 0 (incl.) to num (excl.)
02366 
02367         return (std::rand() % num);
02368 }
02369 
02370 uint32 UCMachine::I_rndRange(const uint8* args, unsigned int /*argsize*/)
02371 {
02372         ARG_SINT16(lo);
02373         ARG_SINT16(hi);
02374 
02375         // return random integer between lo (incl.) to hi (incl.)
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 &/*argv*/)
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

Generated on Fri Jul 27 22:27:50 2007 for pentagram by  doxygen 1.4.7