2 * EmbedVM - Embedded Virtual Machine for uC Applications
4 * Copyright (C) 2011 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 static inline int16_t signext(uint16_t val, uint16_t mask)
25 if ((val & ~(mask >> 1)) != 0)
30 extern void embedvm_exec(struct embedvm_s *vm)
32 uint8_t opcode = vm->mem_read(vm->ip, false, vm->user_ctx);
40 sfa = signext(opcode, 0x3f);
41 embedvm_push(vm, embedvm_local_read(vm, sfa));
45 sfa = signext(opcode, 0x3f);
46 embedvm_local_write(vm, sfa, embedvm_pop(vm));
49 case 0x80+0 ... 0x80+11:
50 case 0xa8+0 ... 0xa8+5:
52 case 0x80+12 ... 0x80+14:
56 case 0x80 + 0: embedvm_push(vm, a + b); break;
57 case 0x80 + 1: embedvm_push(vm, a - b); break;
58 case 0x80 + 2: embedvm_push(vm, a * b); break;
59 case 0x80 + 3: embedvm_push(vm, a / b); break;
60 case 0x80 + 4: embedvm_push(vm, a % b); break;
61 case 0x80 + 5: embedvm_push(vm, a << b); break;
62 case 0x80 + 6: embedvm_push(vm, a >> b); break;
63 case 0x80 + 7: embedvm_push(vm, a & b); break;
64 case 0x80 + 8: embedvm_push(vm, a | b); break;
65 case 0x80 + 9: embedvm_push(vm, a ^ b); break;
66 case 0x80 + 10: embedvm_push(vm, a && b); break;
67 case 0x80 + 11: embedvm_push(vm, a || b); break;
68 case 0x80 + 12: embedvm_push(vm, ~a); break;
69 case 0x80 + 13: embedvm_push(vm, -a); break;
70 case 0x80 + 14: embedvm_push(vm, !a); break;
71 case 0xa8 + 0: embedvm_push(vm, a < b); break;
72 case 0xa8 + 1: embedvm_push(vm, a <= b); break;
73 case 0xa8 + 2: embedvm_push(vm, a == b); break;
74 case 0xa8 + 3: embedvm_push(vm, a != b); break;
75 case 0xa8 + 4: embedvm_push(vm, a >= b); break;
76 case 0xa8 + 5: embedvm_push(vm, a > b); break;
82 a = signext(opcode, 0x07);
89 a = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff;
94 a = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff;
95 embedvm_push(vm, signext(a, 0x00ff));
99 a = vm->mem_read(vm->ip+1, true, vm->user_ctx);
110 vm->ip = embedvm_pop(vm);
111 vm->sfp = embedvm_pop(vm);
112 if ((vm->sfp & 1) != 0)
122 addr = embedvm_pop(vm);
123 if (vm->mem_read(vm->ip+1, false, vm->user_ctx) == 0x9d) {
124 embedvm_push(vm, vm->sfp | 1);
125 embedvm_push(vm, vm->ip + 2);
127 embedvm_push(vm, vm->sfp);
128 embedvm_push(vm, vm->ip + 1);
134 vm->ip = embedvm_pop(vm);
136 case 0xa0 ... 0xa0+7:
137 if ((opcode & 1) == 0) {
138 addr = vm->ip + signext(vm->mem_read(vm->ip+1, false, vm->user_ctx), 0x00ff);
141 addr = vm->ip + vm->mem_read(vm->ip+1, true, vm->user_ctx);
152 if (vm->mem_read(vm->ip, false, vm->user_ctx) == 0x9d) {
153 embedvm_push(vm, vm->sfp | 1);
154 embedvm_push(vm, vm->ip + 1);
156 embedvm_push(vm, vm->sfp);
157 embedvm_push(vm, vm->ip);
169 if (!embedvm_pop(vm))
175 embedvm_push(vm, vm->sp);
179 embedvm_push(vm, vm->sfp);
182 case 0xb0 ... 0xb0+15:
184 uint8_t argc = embedvm_pop(vm);
186 for (sfa=0; sfa<argc; sfa++)
187 argv[sfa] = embedvm_pop(vm);
188 a = vm->call_user(opcode - 0xb0, argc, argv, vm->user_ctx);
194 if ((opcode & 0x07) == 5) {
195 /* this is a "bury" instruction */
196 uint8_t depth = (opcode >> 3) & 0x07;
197 int16_t stack[depth+1];
198 for (sfa = 0; sfa <= depth; sfa++)
199 stack[sfa] = embedvm_pop(vm);
200 embedvm_push(vm, stack[0]);
201 for (sfa = depth; sfa > 0; sfa--)
202 embedvm_push(vm, stack[sfa]);
203 embedvm_push(vm, stack[0]);
207 if ((opcode & 0x07) == 6) {
208 /* this is a "dig" instruction */
209 uint8_t depth = (opcode >> 3) & 0x07;
210 int16_t stack[depth+2];
211 for (sfa = 0; sfa < depth+2; sfa++)
212 stack[sfa] = embedvm_pop(vm);
213 for (sfa = depth+1; sfa > 0; sfa--)
214 embedvm_push(vm, stack[sfa-1]);
215 embedvm_push(vm, stack[depth+1]);
219 sfa = ((opcode >> 3) & 0x07) == 4 || ((opcode >> 3) & 0x07) == 5 ? 1 : 0;
220 switch (opcode & 0x07)
223 addr = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff;
227 addr = vm->mem_read(vm->ip+1, true, vm->user_ctx);
231 addr = embedvm_pop(vm);
235 addr = (embedvm_pop(vm) << sfa) + (vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff);
239 addr = (embedvm_pop(vm) << sfa) + vm->mem_read(vm->ip+1, true, vm->user_ctx);
243 switch ((opcode >> 3) & 0x07)
246 embedvm_push(vm, vm->mem_read(addr, false, vm->user_ctx) & 0x00ff);
249 vm->mem_write(addr, embedvm_pop(vm), false, vm->user_ctx);
252 embedvm_push(vm, signext(vm->mem_read(addr, false, vm->user_ctx), 0x00ff));
255 vm->mem_write(addr, embedvm_pop(vm), false, vm->user_ctx);
258 embedvm_push(vm, vm->mem_read(addr, true, vm->user_ctx));
261 vm->mem_write(addr, embedvm_pop(vm), true, vm->user_ctx);
266 for (sfa = 0; sfa <= (opcode & 0x07); sfa++)
272 vm->sp += 2 + 2*(opcode & 0x07);
279 void embedvm_interrupt(struct embedvm_s *vm, uint16_t addr)
281 embedvm_push(vm, vm->sfp | 1);
282 embedvm_push(vm, vm->ip);
287 int16_t embedvm_pop(struct embedvm_s *vm)
289 int16_t value = vm->mem_read(vm->sp, true, vm->user_ctx);
294 void embedvm_push(struct embedvm_s *vm, int16_t value)
297 vm->mem_write(vm->sp, value, true, vm->user_ctx);
300 int16_t embedvm_local_read(struct embedvm_s *vm, int8_t sfa)
302 uint16_t addr = vm->sfp - 2*sfa + (sfa < 0 ? +2 : -2);
303 return vm->mem_read(addr, true, vm->user_ctx);
306 void embedvm_local_write(struct embedvm_s *vm, int8_t sfa, int16_t value)
308 uint16_t addr = vm->sfp - 2*sfa + (sfa < 0 ? +2 : -2);
309 vm->mem_write(addr, value, true, vm->user_ctx);