A lightweight VM which allows for easy custom programs to be made on the device without having to worry about linking and PIC code and all of that. BSD licensed. See https://bitbucket.org/earlz/lightvm/ for the upstream general purpose repository
lightvm.c
00001 /** 00002 <Copyright Header> 00003 Copyright (c) 2013 Jordan "Earlz" Earls <http://Earlz.net> 00004 All rights reserved. 00005 00006 Redistribution and use in source and binary forms, with or without 00007 modification, are permitted provided that the following conditions 00008 are met: 00009 00010 1. Redistributions of source code must retain the above copyright 00011 notice, this list of conditions and the following disclaimer. 00012 2. Redistributions in binary form must reproduce the above copyright 00013 notice, this list of conditions and the following disclaimer in the 00014 documentation and/or other materials provided with the distribution. 00015 3. The name of the author may not be used to endorse or promote products 00016 derived from this software without specific prior written permission. 00017 00018 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 00019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 00020 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 00021 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00022 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00023 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 00024 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00025 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00026 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 00027 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00028 </Copyright Header> 00029 **/ 00030 00031 #include "lightvm.h" 00032 #include "stdio.h" 00033 00034 int lightvm_init(lightvm_state* state) 00035 { 00036 if(state->memory==NULL || state->memorysize<64) 00037 { 00038 return -1; 00039 } 00040 for(int i=0;i<15;i++) 00041 { 00042 *lightvm_register(state, i)=0; 00043 } 00044 state->ip=lightvm_register(state, REGISTER_IP); 00045 state->sp=lightvm_register(state, REGISTER_SP); 00046 state->tr=lightvm_register(state, REGISTER_TR); 00047 state->cr=lightvm_register(state, REGISTER_CR); 00048 *state->ip=64; //set to end of register block 00049 *state->sp=state->memorysize; //set to end of memory(stack grows downwards) 00050 // state->opcache=malloc(sizeof(uint_opcache_t)); 00051 // state->cachesize=sizeof(uint_fast16_t); 00052 00053 return 0; 00054 } 00055 00056 int lightvm_destroy(lightvm_state* state) 00057 { 00058 //free(state->opcache); 00059 return 0; 00060 } 00061 00062 uint16_t* memory_word(lightvm_state* s, reg16_t address) 00063 { 00064 return (uint16_t*)&s->memory[address]; 00065 } 00066 uint8_t* memory_byte(lightvm_state* s, reg16_t address) 00067 { 00068 return (uint8_t*)&s->memory[address]; 00069 } 00070 00071 reg16_t *lightvm_register(lightvm_state* state, unsigned int reg) 00072 { 00073 if(reg>15) 00074 { 00075 return NULL; 00076 } 00077 return (reg16_t*) memory_word(state, reg<<2); //shortcut for reg*4 00078 } 00079 00080 uint8_t lightvm_next_op_byte(lightvm_state* s) 00081 { 00082 uint8_t tmp=*memory_byte(s, *s->ip); 00083 (*s->ip)++; 00084 return tmp; 00085 } 00086 uint16_t lightvm_next_op_word(lightvm_state* s) 00087 { 00088 uint16_t tmp=*memory_word(s, *s->ip); 00089 (*s->ip)+=2; 00090 return tmp; 00091 } 00092 00093 void lightvm_set_error(lightvm_state* s, lightvm_error_t err) 00094 { 00095 s->errorcode=err; 00096 #ifdef INCLUDE_ERROR_MESSAGES 00097 switch(err) 00098 { 00099 case None: 00100 s->error="No error has occured!?"; 00101 break; 00102 case InvalidOpcode: 00103 s->error="Invalid Opcode"; 00104 break; 00105 default: 00106 s->error="Unknown error"; 00107 break; 00108 } 00109 #endif 00110 } 00111 00112 int lightvm_step(lightvm_state* s) 00113 { 00114 uint16_t op=lightvm_next_op_word(s); 00115 unsigned int primary = (op&0x00FF) >> 8; 00116 //bitfields sound nice, but not the most portable things to keep exact to a bit. 00117 unsigned int _8bit=(primary&0x80) > 0; 00118 // unsigned int arg1_ptr = op&0x4000 > 0; 00119 // unsigned int arg2_ptr = op&0x2000 > 0; 00120 // unsigned int immediate = op&0x1000 > 0; 00121 unsigned int second = op &0x00FF; 00122 00123 //gather args 00124 00125 00126 if(_8bit && primary>=12 && primary<=15) 00127 { 00128 //is branch.short 00129 return branch_short(s, primary, second); 00130 } 00131 if(_8bit) 00132 { 00133 00134 } 00135 else 00136 { 00137 uint16_t *arg1=parse_16bit_arg1(s, op); 00138 uint16_t *arg2=parse_16bit_arg2(s, op); 00139 lightvm_step_16bit(s, op, arg1, arg2); 00140 } 00141 return 0; 00142 } 00143 00144 uint16_t *parse_16bit_arg1(lightvm_state* s, uint16_t op) 00145 { 00146 unsigned int arg1_ptr = (op&0x0040) > 0; 00147 unsigned int reg=(op & 0xF000) >> 12; 00148 if(arg1_ptr) 00149 { 00150 return memory_word(s, *lightvm_register(s, reg)); 00151 } 00152 return (uint16_t*)lightvm_register(s, reg); 00153 } 00154 uint16_t *parse_16bit_arg2(lightvm_state* s, uint16_t op) 00155 { 00156 unsigned int arg2_ptr = (op&0x0020) > 0; 00157 unsigned int isimmediate = (op&0x0010) > 0; 00158 unsigned int reg=(op& 0x0F00) >> 8; 00159 uint16_t* tmp; 00160 if(isimmediate) 00161 { 00162 uint16_t immd=lightvm_next_op_word(s); 00163 s->immdreg=immd; 00164 tmp=(uint16_t*)&s->immdreg; 00165 } 00166 else 00167 { 00168 tmp=(uint16_t*)lightvm_register(s, reg); 00169 } 00170 00171 if(arg2_ptr) 00172 { 00173 return memory_word(s, *tmp); 00174 } 00175 return tmp; 00176 } 00177 00178 void lightvm_push(lightvm_state* s, uint16_t value) 00179 { 00180 (*s->sp)-=2; 00181 *memory_word(s, *s->sp) = value; 00182 } 00183 uint16_t lightvm_pop(lightvm_state* s) 00184 { 00185 uint16_t tmp = *memory_word(s, *s->sp); 00186 (*s->sp)+=2; 00187 return tmp; 00188 } 00189 00190 uint16_t lightvm_peek(lightvm_state *s) 00191 { 00192 uint16_t tmp = *memory_word(s, *s->sp); 00193 return tmp; 00194 } 00195 00196 int lightvm_step_8bit(lightvm_state* s, uint8_t* arg1, uint8_t* arg2) 00197 { 00198 return 0; 00199 } 00200 00201 void lightvm_dump(lightvm_state *s) //for when test-wat isn't enough 00202 { 00203 for(int i=0;i<16;i++) 00204 { 00205 reg16_t tmp=*lightvm_register(s, i); 00206 printf("r%i = %X\n", i, tmp); 00207 } 00208 } 00209 00210 00211 int lightvm_step_16bit(lightvm_state* s, uint16_t op, uint16_t* arg1, uint16_t* arg2) 00212 { 00213 unsigned int primary=op & 0x0F00 >> 8; 00214 switch(primary) 00215 { 00216 case 0: 00217 //1-arg ops 00218 op16_single_arg(s, op, arg2); 00219 break; 00220 case 1: 00221 //xor 00222 *arg1=(*arg1) ^ (*arg2); 00223 break; 00224 case 2: 00225 //or 00226 *arg1=(*arg1) | (*arg2); 00227 break; 00228 case 3: 00229 //and 00230 *arg1=(*arg1) & (*arg2); 00231 break; 00232 case 4: 00233 //unused 00234 break; 00235 case 5: 00236 //mv 00237 *arg1=*arg2; 00238 break; 00239 case 6: 00240 //comparison 1-arg 00241 break; 00242 case 7: 00243 //mv.iftrue 00244 if(*s->tr) 00245 { 00246 *arg1=*arg2; 00247 } 00248 break; 00249 case 8: 00250 //shl 00251 *arg1 = (*arg1) << (*arg2); 00252 break; 00253 case 9: 00254 //shr 00255 *arg1 = (*arg1) >> (*arg2); 00256 break; 00257 case 10: 00258 //add 00259 *arg1 = (*arg1) + (*arg2); 00260 break; 00261 case 11: 00262 //sub 00263 *arg1 = (*arg1) + (*arg2); 00264 break; 00265 case 12: 00266 //push.mv 00267 lightvm_push(s, *arg1); 00268 *arg1 = *arg2; 00269 break; 00270 case 13: 00271 //push.mv.ifture 00272 if(*s->tr) 00273 { 00274 lightvm_push(s, *arg1); 00275 *arg1 = *arg2; 00276 } 00277 break; 00278 case 14: 00279 //push.mv.iffalse 00280 if(!(*s->tr)) 00281 { 00282 lightvm_push(s, *arg1); 00283 *arg1 = *arg2; 00284 } 00285 case 15: 00286 //extensions/unused 00287 if((op & 0x00FF) == 0) 00288 { 00289 lightvm_dump(s); 00290 } 00291 default: 00292 return -1; //shouldn't reach here 00293 } 00294 return 0; 00295 } 00296 00297 int branch_short(lightvm_state* s, unsigned int primary, uint8_t arg) 00298 { 00299 unsigned int op = primary & 0x0F; 00300 if(op==13 && !*s->tr) 00301 { 00302 return 0; 00303 } 00304 if(op==14 && *s->tr) 00305 { 00306 return 0; 00307 } 00308 //you can never be too explicit when mixing signed and unsigned values 00309 int16_t diff = (int8_t)arg; //make it so it can go +/-256 instead of 128 00310 diff=diff << 1; 00311 int16_t ip=*s->ip; 00312 ip=ip+diff; 00313 *s->ip=*(uint16_t*)&ip; //make sure not to "cast" the int16 to uint16. Just copy direct. Assume C compiler is 2's complement 00314 return 0; 00315 } 00316 00317 00318 00319 00320 00321 00322 00323 00324 00325 00326 00327 00328 00329 00330 00331
Generated on Mon Jul 18 2022 19:33:40 by 1.7.2