LocalVirtualMachine.cpp
Go to the documentation of this file.
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


aseba
Author(s): Stéphane Magnenat
autogenerated on Thu Jan 2 2014 11:17:16