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

Dependents:   MbedConsole

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lightvm.c Source File

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