]> git.karo-electronics.de Git - oswald.git/blob - ui/embedvm.c
Shorten charger plug "tail"
[oswald.git] / ui / embedvm.c
1 /*
2  *  EmbedVM - Embedded Virtual Machine for uC Applications
3  *
4  *  Copyright (C) 2011  Clifford Wolf <clifford@clifford.at>
5  *  
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.
9  *  
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.
17  *
18  */
19
20 #include "embedvm.h"
21
22 static inline int16_t signext(uint16_t val, uint16_t mask)
23 {
24         val = val & mask;
25         if ((val & ~(mask >> 1)) != 0)
26                 val |= ~mask;
27         return val;
28 }
29
30 extern void embedvm_exec(struct embedvm_s *vm)
31 {
32         uint8_t opcode = vm->mem_read(vm->ip, false, vm->user_ctx);
33         uint16_t addr = 0;
34         int16_t a = 0, b = 0;
35         int8_t sfa = 0;
36
37         switch (opcode)
38         {
39         case 0x00 ... 0x3f:
40                 sfa = signext(opcode, 0x3f);
41                 embedvm_push(vm, embedvm_local_read(vm, sfa));
42                 vm->ip++;
43                 break;
44         case 0x40 ... 0x7f:
45                 sfa = signext(opcode, 0x3f);
46                 embedvm_local_write(vm, sfa, embedvm_pop(vm));
47                 vm->ip++;
48                 break;
49         case 0x80+0 ... 0x80+11:
50         case 0xa8+0 ... 0xa8+5:
51                 b = embedvm_pop(vm);
52         case 0x80+12 ... 0x80+14:
53                 a = embedvm_pop(vm);
54                 switch (opcode)
55                 {
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;
77                         
78                 }
79                 vm->ip++;
80                 break;
81         case 0x90 ... 0x97:
82                 a = signext(opcode, 0x07);
83                 if ((a & 0x04) != 0)
84                         a |= ~0x07;
85                 embedvm_push(vm, a);
86                 vm->ip++;
87                 break;
88         case 0x98:
89                 a = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff;
90                 embedvm_push(vm, a);
91                 vm->ip += 2;
92                 break;
93         case 0x99:
94                 a = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff;
95                 embedvm_push(vm, signext(a, 0x00ff));
96                 vm->ip += 2;
97                 break;
98         case 0x9a:
99                 a = vm->mem_read(vm->ip+1, true, vm->user_ctx);
100                 embedvm_push(vm, a);
101                 vm->ip += 3;
102                 break;
103         case 0x9b:
104                 a = embedvm_pop(vm);
105                 if (0) {
106         case 0x9c:
107                         a = 0;
108                 }
109                 vm->sp = vm->sfp;
110                 vm->ip = embedvm_pop(vm);
111                 vm->sfp = embedvm_pop(vm);
112                 if ((vm->sfp & 1) != 0)
113                         vm->sfp &= ~1;
114                 else
115                         embedvm_push(vm, a);
116                 break;
117         case 0x9d:
118                 embedvm_pop(vm);
119                 vm->ip++;
120                 break;
121         case 0x9e:
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);
126                 } else {
127                         embedvm_push(vm, vm->sfp);
128                         embedvm_push(vm, vm->ip + 1);
129                 }
130                 vm->sfp = vm->sp;
131                 vm->ip = addr;
132                 break;
133         case 0x9f:
134                 vm->ip = embedvm_pop(vm);
135                 break;
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);
139                         vm->ip += 2;
140                 } else {
141                         addr = vm->ip + vm->mem_read(vm->ip+1, true, vm->user_ctx);
142                         vm->ip += 3;
143                 }
144                 switch (opcode)
145                 {
146                 case 0xa0:
147                 case 0xa1:
148                         vm->ip = addr;
149                         break;
150                 case 0xa2:
151                 case 0xa3:
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);
155                         } else {
156                                 embedvm_push(vm, vm->sfp);
157                                 embedvm_push(vm, vm->ip);
158                         }
159                         vm->sfp = vm->sp;
160                         vm->ip = addr;
161                         break;
162                 case 0xa4:
163                 case 0xa5:
164                         if (embedvm_pop(vm))
165                                 vm->ip = addr;
166                         break;
167                 case 0xa6:
168                 case 0xa7:
169                         if (!embedvm_pop(vm))
170                                 vm->ip = addr;
171                         break;
172                 }
173                 break;
174         case 0xae:
175                 embedvm_push(vm, vm->sp);
176                 vm->ip++;
177                 break;
178         case 0xaf:
179                 embedvm_push(vm, vm->sfp);
180                 vm->ip++;
181                 break;
182         case 0xb0 ... 0xb0+15:
183                 {
184                         uint8_t argc = embedvm_pop(vm);
185                         int16_t argv[argc];
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);
189                         embedvm_push(vm, a);
190                 }
191                 vm->ip++;
192                 break;
193         case 0xc0 ... 0xef:
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]);
204                         vm->ip++;
205                         break;
206                 }
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]);
216                         vm->ip++;
217                         break;
218                 }
219                 sfa = ((opcode >> 3) & 0x07) == 4 || ((opcode >> 3) & 0x07) == 5 ? 1 : 0;
220                 switch (opcode & 0x07)
221                 {
222                 case 0:
223                         addr = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff;
224                         vm->ip += 2;
225                         break;
226                 case 1:
227                         addr = vm->mem_read(vm->ip+1, true, vm->user_ctx);
228                         vm->ip += 3;
229                         break;
230                 case 2:
231                         addr = embedvm_pop(vm);
232                         vm->ip++;
233                         break;
234                 case 3:
235                         addr = (embedvm_pop(vm) << sfa) + (vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff);
236                         vm->ip += 2;
237                         break;
238                 case 4:
239                         addr = (embedvm_pop(vm) << sfa) + vm->mem_read(vm->ip+1, true, vm->user_ctx);
240                         vm->ip += 3;
241                         break;
242                 }
243                 switch ((opcode >> 3) & 0x07)
244                 {
245                 case 0:
246                         embedvm_push(vm, vm->mem_read(addr, false, vm->user_ctx) & 0x00ff);
247                         break;
248                 case 1:
249                         vm->mem_write(addr, embedvm_pop(vm), false, vm->user_ctx);
250                         break;
251                 case 2:
252                         embedvm_push(vm, signext(vm->mem_read(addr, false, vm->user_ctx), 0x00ff));
253                         break;
254                 case 3:
255                         vm->mem_write(addr, embedvm_pop(vm), false, vm->user_ctx);
256                         break;
257                 case 4:
258                         embedvm_push(vm, vm->mem_read(addr, true, vm->user_ctx));
259                         break;
260                 case 5:
261                         vm->mem_write(addr, embedvm_pop(vm), true, vm->user_ctx);
262                         break;
263                 }
264                 break;
265         case 0xf0 ... 0xf7:
266                 for (sfa = 0; sfa <= (opcode & 0x07); sfa++)
267                         embedvm_push(vm, 0);
268                 vm->ip++;
269                 break;
270         case 0xf8 ... 0xff:
271                 a = embedvm_pop(vm);
272                 vm->sp += 2 + 2*(opcode & 0x07);
273                 embedvm_push(vm, a);
274                 vm->ip++;
275                 break;
276         }
277 }
278
279 void embedvm_interrupt(struct embedvm_s *vm, uint16_t addr)
280 {
281         embedvm_push(vm, vm->sfp | 1);
282         embedvm_push(vm, vm->ip);
283         vm->sfp = vm->sp;
284         vm->ip = addr;
285 }
286
287 int16_t embedvm_pop(struct embedvm_s *vm)
288 {
289         int16_t value = vm->mem_read(vm->sp, true, vm->user_ctx);
290         vm->sp += 2;
291         return value;
292 }
293
294 void embedvm_push(struct embedvm_s *vm, int16_t value)
295 {
296         vm->sp -= 2;
297         vm->mem_write(vm->sp, value, true, vm->user_ctx);
298 }
299
300 int16_t embedvm_local_read(struct embedvm_s *vm, int8_t sfa)
301 {
302         uint16_t addr = vm->sfp - 2*sfa + (sfa < 0 ? +2 : -2);
303         return vm->mem_read(addr, true, vm->user_ctx);
304 }
305
306 void embedvm_local_write(struct embedvm_s *vm, int8_t sfa, int16_t value)
307 {
308         uint16_t addr = vm->sfp - 2*sfa + (sfa < 0 ? +2 : -2);
309         vm->mem_write(addr, value, true, vm->user_ctx);
310 }
311