Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

src/interpret.c

Go to the documentation of this file.
00001 /* {{{
00002  * CalcRogue, a roguelike game for PCs, calculators and PDAs
00003  * Copyright (C) 2003 Jim Babcock
00004  * 
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018  * }}} */
00019 // interpret.c
00022 
00023 #include "crogue.h"
00024 #ifdef INTERPRETER_DEBUG
00025     #include <assert.h>
00026 #endif
00027 
00028 #ifdef INTERPRETER_DEBUG
00029     #ifndef INLINE
00030         #define INLINE
00031     #endif
00032 #else
00033     #ifndef INLINE
00034         #define INLINE inline
00035     #endif
00036 #endif
00037 
00038 //{{{
00039 #define OP_NOP     0x00
00040 #define OP_HALT    0x01
00041 #define OP_DISC    0x02
00042 #define OP_DISCN   0x03
00043 #define OP_DUP     0x04
00044 #define OP_ALLOCA  0x05
00045 //}}}
00046 //{{{
00047 #define OP_RET     0x10
00048 #define OP_CALL    0x11
00049 #define OP_STA     0x12
00050 #define OP_MVA     0x13
00051 #define OP_LINK    0x14
00052 #define OP_CCALL   0x15
00053 //}}}
00054 //{{{
00055 #define OP_LDR     0x20
00056 #define OP_LDR2    0x21
00057 #define OP_STR     0x22
00058 #define OP_MOV     0x23
00059 #define OP_LDIB    0x24
00060 #define OP_LDIW    0x25
00061 #define OP_LDIL    0x26
00062 #define OP_LDIZ    0x27
00063 #define OP_LDIO    0x28
00064 //}}}
00065 //{{{
00066 #define OP_ADD     0x30
00067 #define OP_SUB     0x31
00068 #define OP_MUL     0x32
00069 #define OP_DIV     0x33
00070 #define OP_MOD     0x34
00071 #define OP_ASL     0x35
00072 #define OP_ASR     0x36
00073 #define OP_AND     0x37
00074 #define OP_OR      0x38
00075 #define OP_XOR     0x39
00076 #define OP_NEG     0x3A
00077 #define OP_INCR    0x3B
00078 #define OP_DECR    0x3C
00079 //}}}
00080 //{{{
00081 #define OP_BOOL    0x40
00082 #define OP_BOOL2   0x41
00083 #define OP_NOT     0x42
00084 #define OP_TEQ     0x43
00085 #define OP_TLT     0x44
00086 #define OP_TGT     0x45
00087 //}}}
00088 //{{{
00089 #define OP_JMPB    0x50
00090 #define OP_JMPW    0x51
00091 #define OP_JMPL    0x52
00092 #define OP_BRAB    0x53
00093 #define OP_BRAW    0x54
00094 #define OP_BRAL    0x55
00095 //}}}
00096 //{{{
00097 #define OP_DEREFB  0x60
00098 #define OP_DEREFW  0x61
00099 #define OP_DEREFL  0x62
00100 #define OP_POKEB   0x63
00101 #define OP_POKEW   0x64
00102 #define OP_POKEL   0x65
00103 #define OP_LDLBL   0x66
00104 //}}}
00105 
00106 //{{{
00107 typedef union instruction_args
00108 {
00109     signed   char bytes[6];
00110     unsigned char ubytes[4];
00111     signed   short words[2];
00112     signed   long dword;
00113 } instruction_args_t;
00114 //}}}
00115 
00116 static const char *interpreter_call_stack[32];
00117 static int interpreter_call_stack_pos = 0;
00118 
00119 #define pop_stack() (*(--stack_pos))
00120 #define push_stack(n) (*(stack_pos++) = (n))
00121 #define write_arg(v) (*(arg_pos++) = (v))
00122 #define load_register(n) (register_pos[n])
00123 #define save_register(n,v) (register_pos[n] = (v))
00124 #define start_args() (arg_pos = register_pos + register_used + 1)
00125 
00126 //{{{
00127 static const char *interp_func_name(const char *pos)
00128 {
00129     pos--;
00130     do {
00131         pos--;
00132     } while(*pos != '\0');
00133     pos++;
00134     return pos;
00135 }
00136 //}}}
00137 
00138 //{{{
00139 //
00140 // *** This function MUST be reentrant when exiting via OP_CCALL! ***
00141 //
00142 long run_program(const unsigned char *program_data, int num_params, va_list params)
00143 {
00144     int ii;
00145     long new_pc;
00146     long param1, param2;
00147     const unsigned char *execution_pos;
00148     instruction_args_t args;
00149     return_info_t ret;
00150     
00151     long *stack_pos;
00152     long *register_pos;
00153     long *arg_pos;
00154     long pc;
00155     short call_pos;
00156     short register_used;
00157     long active_stack[ACTIVE_STACK_DEPTH];
00158     long register_stack[REGISTER_STACK_DEPTH];
00159     short call_stack[CALL_STACK_DEPTH];
00160     
00161     pc = 0;
00162     register_used = 0;
00163     stack_pos = active_stack;
00164     register_pos = register_stack;
00165     call_pos = 0;
00166     
00167     start_args();
00168     
00169     for(ii=0; ii<num_params; ii++)
00170         write_arg(va_arg(params, long));
00171     va_end(params);
00172     
00173     new_pc = pc;
00174     
00175     while(1)
00176     {
00177         pc = new_pc;
00178         new_pc++;
00179         execution_pos = program_data + pc;
00180         
00181         args.bytes[0] = execution_pos[1];
00182         args.bytes[1] = execution_pos[2];
00183         args.bytes[2] = execution_pos[3];
00184         args.bytes[3] = execution_pos[4];
00185         
00186         switch(*execution_pos)
00187         {
00188 //{{{
00189         case OP_NOP:
00190             break;
00191         case OP_HALT:
00192             return 0;
00193         case OP_DISC:
00194             (void)pop_stack();
00195             break;
00196         case OP_DISCN:
00197             new_pc++;
00198             for(ii=0; ii<args.ubytes[0]; ii++)
00199                 (void)pop_stack();
00200             break;
00201         case OP_DUP:
00202             param1 = pop_stack();
00203             push_stack(param1);
00204             push_stack(param1);
00205             break;
00206         case OP_ALLOCA:
00207             param1 = pop_stack();
00208             push_stack( (long)(register_pos + register_used) );
00209             register_used += ((param1+3) & (~3)) >> 2;
00210                 // use size/4 rounded up registers
00211             start_args();
00212             break;
00213 //}}}
00214 //{{{
00215         case OP_RET:
00216             interpreter_call_stack_pos--;
00217             if(call_pos == 0)
00218             {
00219                 if(stack_pos > active_stack) {
00220                     param1 = pop_stack();
00221                     return param1;
00222                 }
00223                 else {
00224                     return 0;
00225                 }
00226             }
00227             
00228             // Unlink registers
00229             register_pos--;
00230             register_used = *register_pos;
00231             register_pos -= register_used;
00232             
00233             new_pc = call_stack[--call_pos];
00234             start_args();
00235             interpreter_call_stack[interpreter_call_stack_pos] = NULL;
00236             break;
00237         case OP_CALL:
00238             new_pc += 2;
00239             call_stack[call_pos++] = new_pc;
00240             new_pc = pc + args.words[0];
00241             break;
00242         case OP_STA:
00243             write_arg(pop_stack());
00244             break;
00245         case OP_MVA:
00246             new_pc++;
00247             write_arg(load_register(args.ubytes[0]));
00248             break;
00249         case OP_LINK:
00250             new_pc++;
00251             
00252             // Allocate registers
00253             register_pos[register_used] = register_used;
00254             register_pos += register_used + 1;
00255             register_used = args.ubytes[0];
00256             
00257             start_args();
00258             interpreter_call_stack[interpreter_call_stack_pos++] = interp_func_name(execution_pos);
00259             break;
00260         case OP_CCALL:
00261             new_pc += 2;
00262             // Call C interface function by index (see table in interpret_aux.c)
00263             ret = interpret_call(args.words[0],
00264                                 register_pos + register_used + 1);
00265             if(ret.returns)
00266                 push_stack( ret.retval );
00267             start_args();
00268             break;
00269 //}}}
00270 //{{{
00271         case OP_LDR2:
00272             new_pc+=2;
00273             push_stack(load_register(args.ubytes[0]));
00274             push_stack(load_register(args.ubytes[1]));
00275             break;
00276             
00277         case OP_LDR:
00278             new_pc++;
00279             push_stack(load_register(args.ubytes[0]));
00280             break;
00281         case OP_STR:
00282             new_pc++;
00283             save_register(args.ubytes[0], pop_stack());
00284             break;
00285         case OP_MOV:
00286             new_pc += 2;
00287             save_register(args.ubytes[1], load_register(args.ubytes[0]));
00288             break;
00289         case OP_LDIB:
00290             new_pc++;
00291             push_stack((long)(args.bytes[0]));
00292             break;
00293         case OP_LDIW:
00294             new_pc += 2;
00295             push_stack((long)(args.words[0]));
00296             break;
00297         case OP_LDIL:
00298             new_pc += 4;
00299             push_stack( args.dword );
00300             break;
00301         case OP_LDIZ:
00302             push_stack(0);
00303             break;
00304         case OP_LDIO:
00305             push_stack(1);
00306             break;
00307 //}}}
00308 //{{{
00309         case OP_ADD:
00310             param2 = pop_stack();
00311             param1 = pop_stack();
00312             push_stack(param1 + param2);
00313             break;
00314         case OP_SUB:
00315             param2 = pop_stack();
00316             param1 = pop_stack();
00317             push_stack(param1 - param2);
00318             break;
00319         case OP_MUL:
00320             param2 = pop_stack();
00321             param1 = pop_stack();
00322             push_stack(param1 * param2);
00323             break;
00324         case OP_DIV:
00325             param2 = pop_stack();
00326             param1 = pop_stack();
00327             push_stack(param1 / param2);
00328             break;
00329         case OP_MOD:
00330             param2 = pop_stack();
00331             param1 = pop_stack();
00332             push_stack(param1 % param2);
00333             break;
00334         case OP_ASL:
00335             param2 = pop_stack();
00336             param1 = pop_stack();
00337             push_stack(param1 << param2);
00338             break;
00339         case OP_ASR:
00340             param2 = pop_stack();
00341             param1 = pop_stack();
00342             push_stack(param1 >> param2);
00343             break;
00344         case OP_AND:
00345             param2 = pop_stack();
00346             param1 = pop_stack();
00347             push_stack(param1 & param2);
00348             break;
00349         case OP_OR:
00350             param2 = pop_stack();
00351             param1 = pop_stack();
00352             push_stack(param1 | param2);
00353             break;
00354         case OP_XOR:
00355             param2 = pop_stack();
00356             param1 = pop_stack();
00357             push_stack(param1 ^ param2);
00358             break;
00359         case OP_NEG:
00360             param1 = -pop_stack();
00361             push_stack(param1);
00362             break;
00363         case OP_INCR:
00364             new_pc++;
00365             save_register(args.ubytes[0], load_register(args.ubytes[0]) + 1);
00366             break;
00367         case OP_DECR:
00368             new_pc++;
00369             save_register(args.ubytes[0], load_register(args.ubytes[0]) - 1);
00370             break;
00371 //}}}
00372 //{{{
00373         case OP_BOOL:
00374             param1 = !!pop_stack();
00375             push_stack(param1);
00376             break;
00377         case OP_BOOL2:
00378             param1 = pop_stack();
00379             param2 = pop_stack();
00380             push_stack(!!param2);
00381             push_stack(!!param1);
00382             break;
00383         case OP_NOT:
00384             param1 = pop_stack();
00385             push_stack(!param1);
00386             break;
00387         case OP_TEQ:
00388             param2 = pop_stack();
00389             param1 = pop_stack();
00390             push_stack(param1 == param2);
00391             break;
00392         case OP_TLT:
00393             param2 = pop_stack();
00394             param1 = pop_stack();
00395             push_stack(param1 < param2);
00396             break;
00397         case OP_TGT:
00398             param2 = pop_stack();
00399             param1 = pop_stack();
00400             push_stack(param1 > param2);
00401             break;
00402 //}}}
00403 //{{{
00404         case OP_JMPB:
00405             new_pc = pc + args.bytes[0];
00406             break;
00407         case OP_JMPW:
00408             new_pc = pc + args.words[0];
00409             break;
00410         case OP_JMPL:
00411             new_pc = pc + args.dword;
00412             break;
00413         case OP_BRAB:
00414             if(pop_stack())
00415                 new_pc = pc + args.bytes[0];
00416             else
00417                 new_pc++;
00418             break;
00419         case OP_BRAW:
00420             if(pop_stack()) {
00421                 new_pc = pc + args.words[0];
00422             } else {
00423                 new_pc+=2;
00424             }
00425             break;
00426         case OP_BRAL:
00427             if(pop_stack())
00428                 new_pc = pc + args.dword;
00429             else
00430                 new_pc+=4;
00431             break;
00432 //}}}
00433 //{{{
00434         case OP_DEREFB:
00435             param1 = pop_stack();
00436             #ifdef INTERPRETER_DEBUG
00437                 assert(param1 > 1024);
00438             #endif
00439             push_stack( *((char*)param1) );
00440             break;
00441         case OP_DEREFW:
00442             param1 = pop_stack();
00443             #ifdef INTERPRETER_DEBUG
00444                 assert(param1 > 1024);
00445             #endif
00446             push_stack( *((short*)param1) );
00447             break;
00448         case OP_DEREFL:
00449             param1 = pop_stack();
00450             #ifdef INTERPRETER_DEBUG
00451                 assert(param1 > 1024);
00452             #endif
00453             push_stack( *((long*)param1) );
00454             break;
00455         case OP_POKEB:
00456             param1 = pop_stack();
00457             param2 = pop_stack();
00458             #ifdef INTERPRETER_DEBUG
00459                 assert(param2 > 1024);
00460             #endif
00461             *((char*)param2) = param1;
00462             break;
00463         case OP_POKEW:
00464             param1 = pop_stack();
00465             param2 = pop_stack();
00466             #ifdef INTERPRETER_DEBUG
00467                 assert(param2 > 1024);
00468             #endif
00469             *((short*)param2) = param1;
00470             break;
00471         case OP_POKEL:
00472             param1 = pop_stack();
00473             param2 = pop_stack();
00474             #ifdef INTERPRETER_DEBUG
00475                 assert(param2 > 1024);
00476             #endif
00477             *((long*)param2) = param1;
00478             break;
00479         case OP_LDLBL:
00480             push_stack((long)(execution_pos + args.dword));
00481             new_pc += 4;
00482             break;
00483 //}}}
00484 //{{{
00485         default:
00486             break;
00487 //}}}
00488         }
00489     }
00490 }
00491 //}}}
00492 

Generated on Thu May 20 13:12:10 2004 for CalcRogue by doxygen 1.3.6