00001 /* 00002 # This file is Copyright 2006, 2007, 2009, 2010 Dean Hall. 00003 # 00004 # This file is part of the PyMite VM. 00005 # The PyMite VM is free software: you can redistribute it and/or modify 00006 # it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2. 00007 # 00008 # The PyMite VM is distributed in the hope that it will be useful, 00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00011 # A copy of the GNU GENERAL PUBLIC LICENSE Version 2 00012 # is seen in the file COPYING in this directory. 00013 */ 00014 00015 00016 #undef __FILE_ID__ 00017 #define __FILE_ID__ 0x15 00018 00019 00028 #include "pm.h" 00029 00030 00032 #define PM_THREAD_TIMESLICE_MS 10 00033 00034 00036 volatile uint32_t pm_timerMsTicks = 0; 00037 00039 volatile uint32_t pm_lastRescheduleTimestamp = 0; 00040 00041 00042 PmReturn_t 00043 pm_init(PmMemSpace_t memspace, uint8_t const * const pusrimg) 00044 { 00045 PmReturn_t retval; 00046 00047 /* Initialize the hardware platform */ 00048 retval = plat_init(); 00049 PM_RETURN_IF_ERROR(retval); 00050 00051 /* Initialize the heap and the globals */ 00052 retval = heap_init(); 00053 PM_RETURN_IF_ERROR(retval); 00054 00055 retval = global_init(); 00056 PM_RETURN_IF_ERROR(retval); 00057 00058 /* Load usr image info if given */ 00059 if (pusrimg != C_NULL) 00060 { 00061 retval = img_appendToPath(memspace, pusrimg); 00062 } 00063 00064 return retval; 00065 } 00066 00067 00068 PmReturn_t 00069 pm_run(uint8_t const *modstr) 00070 { 00071 PmReturn_t retval; 00072 pPmObj_t pmod; 00073 pPmObj_t pstring; 00074 uint8_t const *pmodstr = modstr; 00075 00076 /* Import module from global struct */ 00077 retval = string_new(&pmodstr, &pstring); 00078 PM_RETURN_IF_ERROR(retval); 00079 retval = mod_import(pstring, &pmod); 00080 PM_RETURN_IF_ERROR(retval); 00081 00082 /* Load builtins into thread */ 00083 retval = global_setBuiltins((pPmFunc_t)pmod); 00084 PM_RETURN_IF_ERROR(retval); 00085 00086 /* Interpret the module's bcode */ 00087 retval = interp_addThread((pPmFunc_t)pmod); 00088 PM_RETURN_IF_ERROR(retval); 00089 retval = interpret(INTERP_RETURN_ON_NO_THREADS); 00090 00091 /* 00092 * De-initialize the hardware platform. 00093 * Ignore plat_deinit's retval so interpret's retval returns to caller. 00094 */ 00095 plat_deinit(); 00096 00097 return retval; 00098 } 00099 00100 00101 /* Warning: Can be called in interrupt context! */ 00102 PmReturn_t 00103 pm_vmPeriodic(uint16_t usecsSinceLastCall) 00104 { 00105 /* 00106 * Add the full milliseconds to pm_timerMsTicks and store additional 00107 * microseconds for the next run. Thus, usecsSinceLastCall must be 00108 * less than 2^16-1000 so it will not overflow usecResidual. 00109 */ 00110 static uint16_t usecResidual = 0; 00111 00112 C_ASSERT(usecsSinceLastCall < 64536); 00113 00114 usecResidual += usecsSinceLastCall; 00115 while (usecResidual >= 1000) 00116 { 00117 usecResidual -= 1000; 00118 pm_timerMsTicks++; 00119 } 00120 00121 /* Check if enough time has passed for a scheduler run */ 00122 if ((pm_timerMsTicks - pm_lastRescheduleTimestamp) 00123 >= PM_THREAD_TIMESLICE_MS) 00124 { 00125 interp_setRescheduleFlag((uint8_t)1); 00126 pm_lastRescheduleTimestamp = pm_timerMsTicks; 00127 } 00128 return PM_RET_OK; 00129 }