$search
00001 #include "LocalVirtualMachine.h" 00002 #include "../common/consts.h" 00003 #include <QMessageBox> 00004 #include <QtDebug> 00005 00006 #include <stdio.h> 00007 #include <stdlib.h> 00008 00009 Aseba::LocalVirtualMachine *target = 0; 00010 00011 void AsebaSendEvent(AsebaVMState *vm, uint16 event, uint16 start, uint16 length) 00012 { 00013 Q_UNUSED(vm); 00014 target->emitEvent(event, start, length); 00015 /*uint16 i; 00016 printf("AsebaIOSendEvent(%d, %d, %d):\n", event, start, length); 00017 for (i = start; i < start + length; i++) 00018 printf(" [0x%4x] %d\n", i, asebaVMState.variables[i]); 00019 printf("\n");*/ 00020 } 00021 00022 void AsebaArrayAccessOutOfBoundsException(AsebaVMState *vm, uint16 index) 00023 { 00024 target->emitArrayAccessOutOfBounds(vm->pc, vm->sp, index); 00025 /*printf("AsebaArrayAccessOutOfBoundsException:\n"); 00026 printf(" trying to acces element %d out of %d\n", index, asebaVMState.variablesSize); 00027 printf(" pc = %d, sp = %d\n\n", pc, sp);*/ 00028 } 00029 00030 void AsebaDivisionByZeroException(AsebaVMState *vm) 00031 { 00032 target->emitDivisionByZero(vm->pc, vm->sp); 00033 } 00034 00035 void AsebaNativeFunction(AsebaVMState *vm, uint16 id) 00036 { 00037 QString message = QObject::tr("Native function %0 (sp = %1)").arg(id).arg(vm->sp); 00038 QMessageBox::information(0, QObject::tr("Native function called"), message); 00039 } 00040 00041 #ifdef ASEBA_ASSERT 00042 00043 void AsebaAssert(AsebaVMState *vm, AsebaAssertReason reason) 00044 { 00045 // set message 00046 uint16 pc = vm->pc; 00047 uint16 sp = vm->sp; 00048 QString message = QObject::tr("Assertion at 0x%0 (sp = %2):\n").arg(pc, 16).arg(sp); 00049 switch (reason) 00050 { 00051 case ASEBA_ASSERT_UNKNOWN: message += QObject::tr("unknown"); break; 00052 case ASEBA_ASSERT_UNKNOWN_BINARY_OPERATOR: message += QObject::tr("unknown arithmetic binary operator"); break; 00053 case ASEBA_ASSERT_UNKNOWN_BYTECODE: message += QObject::tr("unknown bytecode"); break; 00054 case ASEBA_ASSERT_STACK_UNDERFLOW: message += QObject::tr("execution stack underflow"); break; 00055 case ASEBA_ASSERT_STACK_OVERFLOW: message += QObject::tr("stack overflow"); break; 00056 case ASEBA_ASSERT_OUT_OF_VARIABLES_BOUNDS: message += QObject::tr("out of variables bounds"); break; 00057 case ASEBA_ASSERT_OUT_OF_BYTECODE_BOUNDS: message += QObject::tr("out of bytecode bounds"); break; 00058 case ASEBA_ASSERT_STEP_OUT_OF_RUN: message += QObject::tr("step called while not thread running"); break; 00059 case ASEBA_ASSERT_BREAKPOINT_OUT_OF_BYTECODE_BOUNDS: message += QObject::tr("a breakpoint has been set out of bytecode bounds"); break; 00060 case ASEBA_ASSERT_EMIT_BUFFER_TOO_LONG: message += QObject::tr("tried to emit a buffer too long"); break; 00061 default: message = QObject::tr("unknown assert define, your code seems broken"); break; 00062 } 00063 00064 // display message 00065 QMessageBox::critical(0, QObject::tr("VM Assertion Failed"), message); 00066 } 00067 00068 #endif /* ASEBA_ASSERT */ 00069 00070 00071 /*// create a stock target description 00072 Aseba::TargetDescription targetDescription; 00073 targetDescription.variablesSize = 64; 00074 targetDescription.bytecodeSize = 256; 00075 targetDescription.stackSize = 32; 00076 Aseba::TargetDescription::NativeFunction testFunction; 00077 testFunction.name = "fft"; 00078 testFunction.argumentsSize.push_back(32); 00079 testFunction.argumentsSize.push_back(1); 00080 targetDescription.nativeFunctions.push_back(testFunction); 00081 00082 */ 00083 namespace Aseba 00084 { 00085 LocalVirtualMachine::LocalVirtualMachine() 00086 { 00087 AsebaVMInit(&vmState); 00088 vmState.flags = ASEBA_VM_DEBUGGER_ATTACHED_MASK; 00089 00090 target = this; 00091 00092 description.variablesSize = 64; 00093 description.bytecodeSize = 256; 00094 description.stackSize = 32; 00095 00096 sizesChanged(); 00097 runEvent = false; 00098 startTimer(40); 00099 } 00100 00101 void LocalVirtualMachine::sizesChanged() 00102 { 00103 // Make sure we are not executing anything 00104 stop(); 00105 00106 // set VM from description 00107 vmBytecode.resize(description.bytecodeSize); 00108 vmState.bytecodeSize = description.bytecodeSize; 00109 vmState.bytecode = &vmBytecode[0]; 00110 00111 vmVariables.resize(description.variablesSize); 00112 vmState.variablesSize = description.variablesSize; 00113 vmState.variables = &vmVariables[0]; 00114 00115 vmStack.resize(description.stackSize); 00116 vmState.stackSize = description.stackSize; 00117 vmState.stack = &vmStack[0]; 00118 } 00119 00120 void LocalVirtualMachine::uploadBytecode(const BytecodeVector &bytecode) 00121 { 00122 Q_ASSERT(bytecode.size() <= vmBytecode.size()); 00123 00124 for (size_t i = 0; i < bytecode.size(); i++) 00125 vmBytecode[i] = bytecode[i].bytecode; 00126 debugBytecode = bytecode; 00127 } 00128 00129 void LocalVirtualMachine::setupEvent(unsigned id) 00130 { 00131 AsebaVMSetupEvent(&vmState, id); 00132 00133 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK)) 00134 { 00135 Q_ASSERT(vmState.pc < debugBytecode.size()); 00136 if (AsebaMaskIsClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK)) 00137 { 00138 emit executionModeChanged(EXECUTION_STEP_BY_STEP); 00139 emit executionPosChanged(debugBytecode[vmState.pc].line); 00140 } 00141 } 00142 } 00143 00144 void LocalVirtualMachine::next() 00145 { 00146 Q_ASSERT(vmState.pc < debugBytecode.size()); 00147 00148 // run until we have switched line 00149 unsigned short previousPC = vmState.pc; 00150 unsigned previousLine = debugBytecode[previousPC].line; 00151 do 00152 { 00153 // execute 00154 AsebaVMStep(&vmState); 00155 Q_ASSERT(!AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK) || (vmState.pc < debugBytecode.size())); 00156 } 00157 while (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK) && (vmState.pc != previousPC) && (debugBytecode[vmState.pc].line == previousLine)); 00158 00159 // emit states changes 00160 emit variablesMemoryChanged(vmVariables); 00161 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK)) 00162 emit executionPosChanged(debugBytecode[vmState.pc].line); 00163 else 00164 emit executionModeChanged(EXECUTION_INACTIVE); 00165 } 00166 00167 void LocalVirtualMachine::runStepSwitch() 00168 { 00169 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK)) 00170 { 00171 if (runEvent) 00172 emit executionModeChanged(EXECUTION_STEP_BY_STEP); 00173 else 00174 emit executionModeChanged(EXECUTION_RUN_EVENT); 00175 runEvent = !runEvent; 00176 } 00177 } 00178 00179 void LocalVirtualMachine::runBackground() 00180 { 00181 runEvent = false; 00182 AsebaMaskSet(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK); 00183 emit executionModeChanged(EXECUTION_RUN_BACKGROUND); 00184 } 00185 00186 void LocalVirtualMachine::stop() 00187 { 00188 runEvent = false; 00189 AsebaMaskClear(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK | ASEBA_VM_RUN_BACKGROUND_MASK); 00190 emit executionModeChanged(EXECUTION_INACTIVE); 00191 } 00192 00193 bool LocalVirtualMachine::setBreakpoint(unsigned line) 00194 { 00195 for (size_t i = 0; i < debugBytecode.size(); i++) 00196 if (debugBytecode[i].line == line) 00197 return AsebaVMSetBreakpoint(&vmState, i) != 0; 00198 return false; 00199 } 00200 00201 bool LocalVirtualMachine::clearBreakpoint(unsigned line) 00202 { 00203 for (size_t i = 0; i < debugBytecode.size(); i++) 00204 if (debugBytecode[i].line == line) 00205 return AsebaVMClearBreakpoint(&vmState, i) != 0; 00206 return false; 00207 } 00208 00209 void LocalVirtualMachine::clearBreakpoints() 00210 { 00211 AsebaVMClearBreakpoints(&vmState); 00212 } 00213 00214 void LocalVirtualMachine::timerEvent(QTimerEvent *event) 00215 { 00216 Q_UNUSED(event); 00217 00218 // in some case we do not want to execute anything in background 00219 if (AsebaMaskIsClear(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK)) 00220 return; 00221 if (!runEvent && AsebaMaskIsClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK)) 00222 return; 00223 00224 // execute 00225 const unsigned maxStepsPerTimeSlice = 100; 00226 unsigned i = 0; 00227 while (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK) && (i < maxStepsPerTimeSlice)) 00228 { 00229 // execute 00230 if (AsebaVMStepBreakpoint(&vmState)) 00231 { 00232 runEvent = false; 00233 AsebaMaskClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK); 00234 emit executionModeChanged(EXECUTION_STEP_BY_STEP); 00235 break; 00236 } 00237 i++; 00238 } 00239 00240 // emit states changes 00241 if (i != 0) 00242 emit variablesMemoryChanged(vmVariables); 00243 // check if we are still running 00244 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK)) 00245 { 00246 Q_ASSERT(vmState.pc < debugBytecode.size()); 00247 emit executionPosChanged(debugBytecode[vmState.pc].line); 00248 } 00249 else if (AsebaMaskIsClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK)) 00250 stop(); 00251 } 00252 00253 void LocalVirtualMachine::emitEvent(unsigned short id, unsigned short start, unsigned short length) 00254 { 00255 emit variablesMemoryChanged(vmVariables); 00256 emit event(id, start, length); 00257 } 00258 00259 void LocalVirtualMachine::emitArrayAccessOutOfBounds(unsigned short pc, unsigned short sp, unsigned short index) 00260 { 00261 Q_UNUSED(sp); 00262 00263 stop(); 00264 emit variablesMemoryChanged(vmVariables); 00265 00266 Q_ASSERT(pc < debugBytecode.size()); 00267 unsigned line = debugBytecode[pc].line; 00268 emit arrayAccessOutOfBounds(line, index); 00269 } 00270 00271 void LocalVirtualMachine::emitDivisionByZero(unsigned short pc, unsigned short sp) 00272 { 00273 Q_UNUSED(sp); 00274 00275 stop(); 00276 emit variablesMemoryChanged(vmVariables); 00277 00278 Q_ASSERT(pc < debugBytecode.size()); 00279 unsigned line = debugBytecode[pc].line; 00280 emit divisionByZero(line); 00281 } 00282 }; // Aseba