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",