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

Committer:
earlz
Date:
Fri Apr 12 04:12:59 2013 +0000
Revision:
0:dac6a7d43ed2
Initial import. Upstream changeset 29:8dd470477c0b / tip

Who changed what in which revision?

UserRevisionLine numberNew contents of line
earlz 0:dac6a7d43ed2 1 /**
earlz 0:dac6a7d43ed2 2 <Copyright Header>
earlz 0:dac6a7d43ed2 3 Copyright (c) 2013 Jordan "Earlz" Earls <http://Earlz.net>
earlz 0:dac6a7d43ed2 4 All rights reserved.
earlz 0:dac6a7d43ed2 5
earlz 0:dac6a7d43ed2 6 Redistribution and use in source and binary forms, with or without
earlz 0:dac6a7d43ed2 7 modification, are permitted provided that the following conditions
earlz 0:dac6a7d43ed2 8 are met:
earlz 0:dac6a7d43ed2 9
earlz 0:dac6a7d43ed2 10 1. Redistributions of source code must retain the above copyright
earlz 0:dac6a7d43ed2 11 notice, this list of conditions and the following disclaimer.
earlz 0:dac6a7d43ed2 12 2. Redistributions in binary form must reproduce the above copyright
earlz 0:dac6a7d43ed2 13 notice, this list of conditions and the following disclaimer in the
earlz 0:dac6a7d43ed2 14 documentation and/or other materials provided with the distribution.
earlz 0:dac6a7d43ed2 15 3. The name of the author may not be used to endorse or promote products
earlz 0:dac6a7d43ed2 16 derived from this software without specific prior written permission.
earlz 0:dac6a7d43ed2 17
earlz 0:dac6a7d43ed2 18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
earlz 0:dac6a7d43ed2 19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
earlz 0:dac6a7d43ed2 20 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
earlz 0:dac6a7d43ed2 21 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
earlz 0:dac6a7d43ed2 22 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
earlz 0:dac6a7d43ed2 23 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
earlz 0:dac6a7d43ed2 24 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
earlz 0:dac6a7d43ed2 25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
earlz 0:dac6a7d43ed2 26 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
earlz 0:dac6a7d43ed2 27 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
earlz 0:dac6a7d43ed2 28 </Copyright Header>
earlz 0:dac6a7d43ed2 29 **/
earlz 0:dac6a7d43ed2 30
earlz 0:dac6a7d43ed2 31 #include "lightvm.h"
earlz 0:dac6a7d43ed2 32 #include "stdio.h"
earlz 0:dac6a7d43ed2 33
earlz 0:dac6a7d43ed2 34 int lightvm_init(lightvm_state* state)
earlz 0:dac6a7d43ed2 35 {
earlz 0:dac6a7d43ed2 36 if(state->memory==NULL || state->memorysize<64)
earlz 0:dac6a7d43ed2 37 {
earlz 0:dac6a7d43ed2 38 return -1;
earlz 0:dac6a7d43ed2 39 }
earlz 0:dac6a7d43ed2 40 for(int i=0;i<15;i++)
earlz 0:dac6a7d43ed2 41 {
earlz 0:dac6a7d43ed2 42 *lightvm_register(state, i)=0;
earlz 0:dac6a7d43ed2 43 }
earlz 0:dac6a7d43ed2 44 state->ip=lightvm_register(state, REGISTER_IP);
earlz 0:dac6a7d43ed2 45 state->sp=lightvm_register(state, REGISTER_SP);
earlz 0:dac6a7d43ed2 46 state->tr=lightvm_register(state, REGISTER_TR);
earlz 0:dac6a7d43ed2 47 state->cr=lightvm_register(state, REGISTER_CR);
earlz 0:dac6a7d43ed2 48 *state->ip=64; //set to end of register block
earlz 0:dac6a7d43ed2 49 *state->sp=state->memorysize; //set to end of memory(stack grows downwards)
earlz 0:dac6a7d43ed2 50 // state->opcache=malloc(sizeof(uint_opcache_t));
earlz 0:dac6a7d43ed2 51 // state->cachesize=sizeof(uint_fast16_t);
earlz 0:dac6a7d43ed2 52
earlz 0:dac6a7d43ed2 53 return 0;
earlz 0:dac6a7d43ed2 54 }
earlz 0:dac6a7d43ed2 55
earlz 0:dac6a7d43ed2 56 int lightvm_destroy(lightvm_state* state)
earlz 0:dac6a7d43ed2 57 {
earlz 0:dac6a7d43ed2 58 //free(state->opcache);
earlz 0:dac6a7d43ed2 59 return 0;
earlz 0:dac6a7d43ed2 60 }
earlz 0:dac6a7d43ed2 61
earlz 0:dac6a7d43ed2 62 uint16_t* memory_word(lightvm_state* s, reg16_t address)
earlz 0:dac6a7d43ed2 63 {
earlz 0:dac6a7d43ed2 64 return (uint16_t*)&s->memory[address];
earlz 0:dac6a7d43ed2 65 }
earlz 0:dac6a7d43ed2 66 uint8_t* memory_byte(lightvm_state* s, reg16_t address)
earlz 0:dac6a7d43ed2 67 {
earlz 0:dac6a7d43ed2 68 return (uint8_t*)&s->memory[address];
earlz 0:dac6a7d43ed2 69 }
earlz 0:dac6a7d43ed2 70
earlz 0:dac6a7d43ed2 71 reg16_t *lightvm_register(lightvm_state* state, unsigned int reg)
earlz 0:dac6a7d43ed2 72 {
earlz 0:dac6a7d43ed2 73 if(reg>15)
earlz 0:dac6a7d43ed2 74 {
earlz 0:dac6a7d43ed2 75 return NULL;
earlz 0:dac6a7d43ed2 76 }
earlz 0:dac6a7d43ed2 77 return (reg16_t*) memory_word(state, reg<<2); //shortcut for reg*4
earlz 0:dac6a7d43ed2 78 }
earlz 0:dac6a7d43ed2 79
earlz 0:dac6a7d43ed2 80 uint8_t lightvm_next_op_byte(lightvm_state* s)
earlz 0:dac6a7d43ed2 81 {
earlz 0:dac6a7d43ed2 82 uint8_t tmp=*memory_byte(s, *s->ip);
earlz 0:dac6a7d43ed2 83 (*s->ip)++;
earlz 0:dac6a7d43ed2 84 return tmp;
earlz 0:dac6a7d43ed2 85 }
earlz 0:dac6a7d43ed2 86 uint16_t lightvm_next_op_word(lightvm_state* s)
earlz 0:dac6a7d43ed2 87 {
earlz 0:dac6a7d43ed2 88 uint16_t tmp=*memory_word(s, *s->ip);
earlz 0:dac6a7d43ed2 89 (*s->ip)+=2;
earlz 0:dac6a7d43ed2 90 return tmp;
earlz 0:dac6a7d43ed2 91 }
earlz 0:dac6a7d43ed2 92
earlz 0:dac6a7d43ed2 93 void lightvm_set_error(lightvm_state* s, lightvm_error_t err)
earlz 0:dac6a7d43ed2 94 {
earlz 0:dac6a7d43ed2 95 s->errorcode=err;
earlz 0:dac6a7d43ed2 96 #ifdef INCLUDE_ERROR_MESSAGES
earlz 0:dac6a7d43ed2 97 switch(err)
earlz 0:dac6a7d43ed2 98 {
earlz 0:dac6a7d43ed2 99 case None:
earlz 0:dac6a7d43ed2 100 s->error="No error has occured!?";
earlz 0:dac6a7d43ed2 101 break;
earlz 0:dac6a7d43ed2 102 case InvalidOpcode:
earlz 0:dac6a7d43ed2 103 s->error="Invalid Opcode";
earlz 0:dac6a7d43ed2 104 break;
earlz 0:dac6a7d43ed2 105 default:
earlz 0:dac6a7d43ed2 106 s->error="Unknown error";
earlz 0:dac6a7d43ed2 107 break;
earlz 0:dac6a7d43ed2 108 }
earlz 0:dac6a7d43ed2 109 #endif
earlz 0:dac6a7d43ed2 110 }
earlz 0:dac6a7d43ed2 111
earlz 0:dac6a7d43ed2 112 int lightvm_step(lightvm_state* s)
earlz 0:dac6a7d43ed2 113 {
earlz 0:dac6a7d43ed2 114 uint16_t op=lightvm_next_op_word(s);
earlz 0:dac6a7d43ed2 115 unsigned int primary = (op&0x00FF) >> 8;
earlz 0:dac6a7d43ed2 116 //bitfields sound nice, but not the most portable things to keep exact to a bit.
earlz 0:dac6a7d43ed2 117 unsigned int _8bit=(primary&0x80) > 0;
earlz 0:dac6a7d43ed2 118 // unsigned int arg1_ptr = op&0x4000 > 0;
earlz 0:dac6a7d43ed2 119 // unsigned int arg2_ptr = op&0x2000 > 0;
earlz 0:dac6a7d43ed2 120 // unsigned int immediate = op&0x1000 > 0;
earlz 0:dac6a7d43ed2 121 unsigned int second = op &0x00FF;
earlz 0:dac6a7d43ed2 122
earlz 0:dac6a7d43ed2 123 //gather args
earlz 0:dac6a7d43ed2 124
earlz 0:dac6a7d43ed2 125
earlz 0:dac6a7d43ed2 126 if(_8bit && primary>=12 && primary<=15)
earlz 0:dac6a7d43ed2 127 {
earlz 0:dac6a7d43ed2 128 //is branch.short
earlz 0:dac6a7d43ed2 129 return branch_short(s, primary, second);
earlz 0:dac6a7d43ed2 130 }
earlz 0:dac6a7d43ed2 131 if(_8bit)
earlz 0:dac6a7d43ed2 132 {
earlz 0:dac6a7d43ed2 133
earlz 0:dac6a7d43ed2 134 }
earlz 0:dac6a7d43ed2 135 else
earlz 0:dac6a7d43ed2 136 {
earlz 0:dac6a7d43ed2 137 uint16_t *arg1=parse_16bit_arg1(s, op);
earlz 0:dac6a7d43ed2 138 uint16_t *arg2=parse_16bit_arg2(s, op);
earlz 0:dac6a7d43ed2 139 lightvm_step_16bit(s, op, arg1, arg2);
earlz 0:dac6a7d43ed2 140 }
earlz 0:dac6a7d43ed2 141 return 0;
earlz 0:dac6a7d43ed2 142 }
earlz 0:dac6a7d43ed2 143
earlz 0:dac6a7d43ed2 144 uint16_t *parse_16bit_arg1(lightvm_state* s, uint16_t op)
earlz 0:dac6a7d43ed2 145 {
earlz 0:dac6a7d43ed2 146 unsigned int arg1_ptr = (op&0x0040) > 0;
earlz 0:dac6a7d43ed2 147 unsigned int reg=(op & 0xF000) >> 12;
earlz 0:dac6a7d43ed2 148 if(arg1_ptr)
earlz 0:dac6a7d43ed2 149 {
earlz 0:dac6a7d43ed2 150 return memory_word(s, *lightvm_register(s, reg));
earlz 0:dac6a7d43ed2 151 }
earlz 0:dac6a7d43ed2 152 return (uint16_t*)lightvm_register(s, reg);
earlz 0:dac6a7d43ed2 153 }
earlz 0:dac6a7d43ed2 154 uint16_t *parse_16bit_arg2(lightvm_state* s, uint16_t op)
earlz 0:dac6a7d43ed2 155 {
earlz 0:dac6a7d43ed2 156 unsigned int arg2_ptr = (op&0x0020) > 0;
earlz 0:dac6a7d43ed2 157 unsigned int isimmediate = (op&0x0010) > 0;
earlz 0:dac6a7d43ed2 158 unsigned int reg=(op& 0x0F00) >> 8;
earlz 0:dac6a7d43ed2 159 uint16_t* tmp;
earlz 0:dac6a7d43ed2 160 if(isimmediate)
earlz 0:dac6a7d43ed2 161 {
earlz 0:dac6a7d43ed2 162 uint16_t immd=lightvm_next_op_word(s);
earlz 0:dac6a7d43ed2 163 s->immdreg=immd;
earlz 0:dac6a7d43ed2 164 tmp=(uint16_t*)&s->immdreg;
earlz 0:dac6a7d43ed2 165 }
earlz 0:dac6a7d43ed2 166 else
earlz 0:dac6a7d43ed2 167 {
earlz 0:dac6a7d43ed2 168 tmp=(uint16_t*)lightvm_register(s, reg);
earlz 0:dac6a7d43ed2 169 }
earlz 0:dac6a7d43ed2 170
earlz 0:dac6a7d43ed2 171 if(arg2_ptr)
earlz 0:dac6a7d43ed2 172 {
earlz 0:dac6a7d43ed2 173 return memory_word(s, *tmp);
earlz 0:dac6a7d43ed2 174 }
earlz 0:dac6a7d43ed2 175 return tmp;
earlz 0:dac6a7d43ed2 176 }
earlz 0:dac6a7d43ed2 177
earlz 0:dac6a7d43ed2 178 void lightvm_push(lightvm_state* s, uint16_t value)
earlz 0:dac6a7d43ed2 179 {
earlz 0:dac6a7d43ed2 180 (*s->sp)-=2;
earlz 0:dac6a7d43ed2 181 *memory_word(s, *s->sp) = value;
earlz 0:dac6a7d43ed2 182 }
earlz 0:dac6a7d43ed2 183 uint16_t lightvm_pop(lightvm_state* s)
earlz 0:dac6a7d43ed2 184 {
earlz 0:dac6a7d43ed2 185 uint16_t tmp = *memory_word(s, *s->sp);
earlz 0:dac6a7d43ed2 186 (*s->sp)+=2;
earlz 0:dac6a7d43ed2 187 return tmp;
earlz 0:dac6a7d43ed2 188 }
earlz 0:dac6a7d43ed2 189
earlz 0:dac6a7d43ed2 190 uint16_t lightvm_peek(lightvm_state *s)
earlz 0:dac6a7d43ed2 191 {
earlz 0:dac6a7d43ed2 192 uint16_t tmp = *memory_word(s, *s->sp);
earlz 0:dac6a7d43ed2 193 return tmp;
earlz 0:dac6a7d43ed2 194 }
earlz 0:dac6a7d43ed2 195
earlz 0:dac6a7d43ed2 196 int lightvm_step_8bit(lightvm_state* s, uint8_t* arg1, uint8_t* arg2)
earlz 0:dac6a7d43ed2 197 {
earlz 0:dac6a7d43ed2 198 return 0;
earlz 0:dac6a7d43ed2 199 }
earlz 0:dac6a7d43ed2 200
earlz 0:dac6a7d43ed2 201 void lightvm_dump(lightvm_state *s) //for when test-wat isn't enough
earlz 0:dac6a7d43ed2 202 {
earlz 0:dac6a7d43ed2 203 for(int i=0;i<16;i++)
earlz 0:dac6a7d43ed2 204 {
earlz 0:dac6a7d43ed2 205 reg16_t tmp=*lightvm_register(s, i);
earlz 0:dac6a7d43ed2 206 printf("r%i = %X\n", i, tmp);
earlz 0:dac6a7d43ed2 207 }
earlz 0:dac6a7d43ed2 208 }
earlz 0:dac6a7d43ed2 209
earlz 0:dac6a7d43ed2 210
earlz 0:dac6a7d43ed2 211 int lightvm_step_16bit(lightvm_state* s, uint16_t op, uint16_t* arg1, uint16_t* arg2)
earlz 0:dac6a7d43ed2 212 {
earlz 0:dac6a7d43ed2 213 unsigned int primary=op & 0x0F00 >> 8;
earlz 0:dac6a7d43ed2 214 switch(primary)
earlz 0:dac6a7d43ed2 215 {
earlz 0:dac6a7d43ed2 216 case 0:
earlz 0:dac6a7d43ed2 217 //1-arg ops
earlz 0:dac6a7d43ed2 218 op16_single_arg(s, op, arg2);
earlz 0:dac6a7d43ed2 219 break;
earlz 0:dac6a7d43ed2 220 case 1:
earlz 0:dac6a7d43ed2 221 //xor
earlz 0:dac6a7d43ed2 222 *arg1=(*arg1) ^ (*arg2);
earlz 0:dac6a7d43ed2 223 break;
earlz 0:dac6a7d43ed2 224 case 2:
earlz 0:dac6a7d43ed2 225 //or
earlz 0:dac6a7d43ed2 226 *arg1=(*arg1) | (*arg2);
earlz 0:dac6a7d43ed2 227 break;
earlz 0:dac6a7d43ed2 228 case 3:
earlz 0:dac6a7d43ed2 229 //and
earlz 0:dac6a7d43ed2 230 *arg1=(*arg1) & (*arg2);
earlz 0:dac6a7d43ed2 231 break;
earlz 0:dac6a7d43ed2 232 case 4:
earlz 0:dac6a7d43ed2 233 //unused
earlz 0:dac6a7d43ed2 234 break;
earlz 0:dac6a7d43ed2 235 case 5:
earlz 0:dac6a7d43ed2 236 //mv
earlz 0:dac6a7d43ed2 237 *arg1=*arg2;
earlz 0:dac6a7d43ed2 238 break;
earlz 0:dac6a7d43ed2 239 case 6:
earlz 0:dac6a7d43ed2 240 //comparison 1-arg
earlz 0:dac6a7d43ed2 241 break;
earlz 0:dac6a7d43ed2 242 case 7:
earlz 0:dac6a7d43ed2 243 //mv.iftrue
earlz 0:dac6a7d43ed2 244 if(*s->tr)
earlz 0:dac6a7d43ed2 245 {
earlz 0:dac6a7d43ed2 246 *arg1=*arg2;
earlz 0:dac6a7d43ed2 247 }
earlz 0:dac6a7d43ed2 248 break;
earlz 0:dac6a7d43ed2 249 case 8:
earlz 0:dac6a7d43ed2 250 //shl
earlz 0:dac6a7d43ed2 251 *arg1 = (*arg1) << (*arg2);
earlz 0:dac6a7d43ed2 252 break;
earlz 0:dac6a7d43ed2 253 case 9:
earlz 0:dac6a7d43ed2 254 //shr
earlz 0:dac6a7d43ed2 255 *arg1 = (*arg1) >> (*arg2);
earlz 0:dac6a7d43ed2 256 break;
earlz 0:dac6a7d43ed2 257 case 10:
earlz 0:dac6a7d43ed2 258 //add
earlz 0:dac6a7d43ed2 259 *arg1 = (*arg1) + (*arg2);
earlz 0:dac6a7d43ed2 260 break;
earlz 0:dac6a7d43ed2 261 case 11:
earlz 0:dac6a7d43ed2 262 //sub
earlz 0:dac6a7d43ed2 263 *arg1 = (*arg1) + (*arg2);
earlz 0:dac6a7d43ed2 264 break;
earlz 0:dac6a7d43ed2 265 case 12:
earlz 0:dac6a7d43ed2 266 //push.mv
earlz 0:dac6a7d43ed2 267 lightvm_push(s, *arg1);
earlz 0:dac6a7d43ed2 268 *arg1 = *arg2;
earlz 0:dac6a7d43ed2 269 break;
earlz 0:dac6a7d43ed2 270 case 13:
earlz 0:dac6a7d43ed2 271 //push.mv.ifture
earlz 0:dac6a7d43ed2 272 if(*s->tr)
earlz 0:dac6a7d43ed2 273 {
earlz 0:dac6a7d43ed2 274 lightvm_push(s, *arg1);
earlz 0:dac6a7d43ed2 275 *arg1 = *arg2;
earlz 0:dac6a7d43ed2 276 }
earlz 0:dac6a7d43ed2 277 break;
earlz 0:dac6a7d43ed2 278 case 14:
earlz 0:dac6a7d43ed2 279 //push.mv.iffalse
earlz 0:dac6a7d43ed2 280 if(!(*s->tr))
earlz 0:dac6a7d43ed2 281 {
earlz 0:dac6a7d43ed2 282 lightvm_push(s, *arg1);
earlz 0:dac6a7d43ed2 283 *arg1 = *arg2;
earlz 0:dac6a7d43ed2 284 }
earlz 0:dac6a7d43ed2 285 case 15:
earlz 0:dac6a7d43ed2 286 //extensions/unused
earlz 0:dac6a7d43ed2 287 if((op & 0x00FF) == 0)
earlz 0:dac6a7d43ed2 288 {
earlz 0:dac6a7d43ed2 289 lightvm_dump(s);
earlz 0:dac6a7d43ed2 290 }
earlz 0:dac6a7d43ed2 291 default:
earlz 0:dac6a7d43ed2 292 return -1; //shouldn't reach here
earlz 0:dac6a7d43ed2 293 }
earlz 0:dac6a7d43ed2 294 return 0;
earlz 0:dac6a7d43ed2 295 }
earlz 0:dac6a7d43ed2 296
earlz 0:dac6a7d43ed2 297 int branch_short(lightvm_state* s, unsigned int primary, uint8_t arg)
earlz 0:dac6a7d43ed2 298 {
earlz 0:dac6a7d43ed2 299 unsigned int op = primary & 0x0F;
earlz 0:dac6a7d43ed2 300 if(op==13 && !*s->tr)
earlz 0:dac6a7d43ed2 301 {
earlz 0:dac6a7d43ed2 302 return 0;
earlz 0:dac6a7d43ed2 303 }
earlz 0:dac6a7d43ed2 304 if(op==14 && *s->tr)
earlz 0:dac6a7d43ed2 305 {
earlz 0:dac6a7d43ed2 306 return 0;
earlz 0:dac6a7d43ed2 307 }
earlz 0:dac6a7d43ed2 308 //you can never be too explicit when mixing signed and unsigned values
earlz 0:dac6a7d43ed2 309 int16_t diff = (int8_t)arg; //make it so it can go +/-256 instead of 128
earlz 0:dac6a7d43ed2 310 diff=diff << 1;
earlz 0:dac6a7d43ed2 311 int16_t ip=*s->ip;
earlz 0:dac6a7d43ed2 312 ip=ip+diff;
earlz 0:dac6a7d43ed2 313 *s->ip=*(uint16_t*)&ip; //make sure not to "cast" the int16 to uint16. Just copy direct. Assume C compiler is 2's complement
earlz 0:dac6a7d43ed2 314 return 0;
earlz 0:dac6a7d43ed2 315 }
earlz 0:dac6a7d43ed2 316
earlz 0:dac6a7d43ed2 317
earlz 0:dac6a7d43ed2 318
earlz 0:dac6a7d43ed2 319
earlz 0:dac6a7d43ed2 320
earlz 0:dac6a7d43ed2 321
earlz 0:dac6a7d43ed2 322
earlz 0:dac6a7d43ed2 323
earlz 0:dac6a7d43ed2 324
earlz 0:dac6a7d43ed2 325
earlz 0:dac6a7d43ed2 326
earlz 0:dac6a7d43ed2 327
earlz 0:dac6a7d43ed2 328
earlz 0:dac6a7d43ed2 329
earlz 0:dac6a7d43ed2 330
earlz 0:dac6a7d43ed2 331