├── .vscode
└── settings.json
├── IDE.html
├── Interpreter.js
├── cpp
└── Interpreter.h
├── examples
└── GameOfLife.lsm
└── readme.MD
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "liveServer.settings.port": 5502
3 | }
--------------------------------------------------------------------------------
/IDE.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
192 |
229 |
230 |
231 |
294 |
295 |
--------------------------------------------------------------------------------
/Interpreter.js:
--------------------------------------------------------------------------------
1 | const Opcodes = {
2 | 0: "push",
3 | 1: "pop",
4 | 3: "stor",
5 | 2: "load",
6 | 4: "pushb",
7 | 5: "pushw",
8 | 6: "clone",
9 | 7: "loads",
10 | 8: "stors",
11 | 9: "swap",
12 |
13 | 16: "jmp",
14 | 17: "jz",
15 | 18: "jnz",
16 | 19: "jg",
17 | 20: "jge",
18 | 21: "je",
19 | 22: "jne",
20 |
21 | 32: "and",
22 | 33: "or",
23 | 34: "xor",
24 | 35: "not",
25 | 36: "inc",
26 | 37: "dec",
27 | 38: "add",
28 | 39: "sub",
29 |
30 | 40: "shl",
31 | 41: "shr",
32 | 42: "mul",
33 | 43: "div",
34 | 44: "mod",
35 | 45: "neg",
36 | 46: "abs",
37 |
38 | 254: "debug",
39 | 255: "nop"
40 | };
41 |
42 | class Compiler
43 | {
44 | constructor(text)
45 | {
46 | }
47 |
48 | compile(text, console, optimize = true)
49 | {
50 | const code = [];
51 | const lines = text.split("\n");
52 | const labels = {};
53 | const labelInstances = {};
54 | for(let i = 0; i < lines.length; i++)
55 | {
56 | let line = lines[i].trim();
57 | const c1 = line.indexOf(";");
58 | const c2 = line.indexOf("//");
59 | const c = (c1 != -1) && (c1 < c2) ? c1 : c2;
60 | if(c > -1)
61 | line = line.substr(0, c).trim();
62 | let token = line.replace(/[\t| ].*/,'');
63 | if(token[token.length - 1] == ':')
64 | {
65 | const label = token.substr(0, token.length - 1);
66 | if(!isNaN(this.parseInt(label)))
67 | console.error("label can't be a number: " + label + " line " + i);
68 | if(label in labels)
69 | console.error("label already defined: " + token + " line " + i);
70 | labels[label] = code.length;
71 | line = line.substr(token.length).trim();
72 | token = line.replace(/[\t| ].*/,'');
73 | }
74 | if(token.length)
75 | {
76 | let opcode = Object.keys(Opcodes).find(k=>Opcodes[k]===token);
77 | if(opcode !== undefined)
78 | {
79 | if(token.startsWith("push")) //push
80 | {
81 | let bytes = (token == "pushb") ? 1 : token == "pushw" ? 2 : 4;
82 | line = line.substr(token.length).trim();
83 | token = line.replace(/[\t| ].*/,'');
84 | let v = this.parseInt(token);
85 | let isLabel = isNaN(v);
86 | if(isLabel) v = 0;
87 | if(optimize && !isLabel)
88 | {
89 | if(v < 256)
90 | {
91 | opcode = Object.keys(Opcodes).find(k=>Opcodes[k]==="pushb");
92 | bytes = 1;
93 | }
94 | else if(v < 0x10000)
95 | {
96 | opcode = Object.keys(Opcodes).find(k=>Opcodes[k]==="pushw");
97 | bytes = 2;
98 | }
99 | }
100 | this.appendInt(code, opcode, 1);
101 | if(isLabel)
102 | {
103 | if(token in labelInstances)
104 | labelInstances[token].push([code.length, bytes]);
105 | else
106 | labelInstances[token] = [[code.length, bytes]];
107 | }
108 | this.appendInt(code, v, bytes);
109 | }
110 | else
111 | this.appendInt(code, opcode, 1);
112 | line = line.substr(token.length).trim();
113 | if(line.length)
114 | console.error("extra characters: " + line + " in line " + i);
115 | }
116 | else
117 | console.error("unknown opcode: " + token + " in line " + i);
118 | }
119 | lines[i] = token;
120 | }
121 | for(const label in labels)
122 | if(labelInstances[label])
123 | for(let j = 0; j < labelInstances[label].length; j++)
124 | this.writeInt(code, labelInstances[label][j][0], labels[label], labelInstances[label][j][1]);
125 | return new Uint8Array(code);
126 | }
127 |
128 | decompile(code)
129 | {
130 | let i = 0;
131 | let text = "";
132 | while(i < code.length)
133 | {
134 | const o = code[i];
135 | let line = "0x" + ("000" + i.toString(16)).slice(-4) + "\t" + Opcodes[o];
136 | i++;
137 | if(Opcodes[o] == "push")
138 | line += "\t0x" + (code[i++] | (code[i++] << 8) | (code[i++] << 16) | (code[i++] << 24)).toString(16);
139 | else if(Opcodes[o] == "pushb")
140 | line += "\t0x" + (code[i++]).toString(16);
141 | else if(Opcodes[o] == "pushw")
142 | line += "\t0x" + (code[i++] | (code[i++] << 8)).toString(16);
143 | text += line + "\n";
144 | }
145 | return text;
146 | }
147 |
148 | parseInt(t)
149 | {
150 | if(t.startsWith("0x"))
151 | return parseInt(t.substr(2), 16)
152 | else if(t.startsWith("0b"))
153 | return parseInt(t.substr(2), 2)
154 | return parseInt(t);
155 | }
156 |
157 | appendInt(a, v, b = 4)
158 | {
159 | for(let i = 0; i < b; i++)
160 | a.push((v >> (i * 8)) & 255);
161 | }
162 |
163 | writeInt(a, o, v, b = 4)
164 | {
165 | for(let i = 0; i < b; i++)
166 | a[o + i] = (v >> (i * 8)) & 255;
167 | }
168 | };
169 |
170 | class MemoryMap
171 | {
172 | constructor(heap, gfx, io)
173 | {
174 | this.heap = heap || (new Uint8Array(0x1000));
175 | this.gfx = gfx || (new Uint8Array(0x4000));
176 | this.io = io || (new Uint8Array(0x1000));
177 | }
178 |
179 | writeInt(a, o, v, b = 4)
180 | {
181 | for(let i = 0; i < b; i++)
182 | a[o + i] = (v >> (i * 8)) & 255;
183 | }
184 |
185 | readInt(a, o, b)
186 | {
187 | let v = 0;
188 | for(let i = 0; i < b; i++)
189 | v |= a[o + i] << (i * 8);
190 | return v;
191 | }
192 |
193 | store(a, v)
194 | {
195 | switch(a & 0xf000)
196 | {
197 | case 0x0000:
198 | this.writeInt(this.heap, a & 0xfff, v, 4);
199 | break;
200 | case 0xa000:
201 | case 0xb000:
202 | case 0xc000:
203 | case 0xd000:
204 | this.writeInt(this.gfx, (a - 0xa000) & 0x3fff, v, 4);
205 | break;
206 | case 0xe000:
207 | //flash
208 | break;
209 | case 0xf000:
210 | this.writeInt(this.io, a & 0xfff, v, 4);
211 | break;
212 | }
213 | }
214 |
215 | load(a)
216 | {
217 | switch(a & 0xf000)
218 | {
219 | case 0x0000:
220 | return this.readInt(this.heap, a & 0xfff, 4);
221 | case 0xa000:
222 | case 0xb000:
223 | case 0xc000:
224 | case 0xd000:
225 | return this.readInt(this.gfx, (a - 0xa000) & 0x3fff, 4);
226 | case 0xe000:
227 | //flash
228 | return 0;
229 | case 0xf000:
230 | return this.readInt(this.io, a & 0xfff, 4);
231 | }
232 | return 0;
233 | }
234 | };
235 |
236 | class Interpreter
237 | {
238 | constructor(code, memoryMap, debugLevel = 0)
239 | {
240 | this.IP = 0;
241 | this.stack = [];
242 | this.code = code;
243 | this.mem = memoryMap;
244 | this.debugLevel = debugLevel;
245 | }
246 |
247 | execute()
248 | {
249 | if(this.IP >= this.code.length)
250 | {
251 | this.IP = 0;
252 | this.stack = [];
253 | }
254 |
255 | let op = this.code[this.IP++];
256 | if(this.debugLevel == 3)
257 | console.log("0x" + ("000" + (this.IP-1).toString(16)).slice(-4) + "\t" + Opcodes[op] + "\t[" + this.stack.at(-1) + " ," + this.stack.at(-2) + " ," + this.stack.at(-3) + " ,..]");
258 | if (Opcodes[op] == "push")
259 | this.push(this.code[this.IP++] | (this.code[this.IP++] << 8) | (this.code[this.IP++] << 16) | (this.code[this.IP++] << 24));
260 | else if (Opcodes[op] == "pushb")
261 | this.push(this.code[this.IP++]);
262 | else if (Opcodes[op] == "pushw")
263 | this.push(this.code[this.IP++] | (this.code[this.IP++] << 8));
264 | else
265 | this[Opcodes[op]].call(this);
266 | }
267 |
268 | push(v)
269 | {
270 | this.stack.push(v);
271 | }
272 |
273 | pop()
274 | {
275 | if(this.stack.length == 0 && this.debugLevel == 1)
276 | console.log("0x" + ("000" + (this.IP-1).toString(16)).slice(-4) + "\t pop on empty stack");
277 | return this.stack.pop();
278 | }
279 |
280 | clone()
281 | {
282 | this.push(this.stack.at(-1));
283 | }
284 |
285 | stor()
286 | {
287 | let a = this.pop(); //address
288 | let v = this.pop(); //value
289 | this.mem.store(a, v);
290 | }
291 |
292 | loads()
293 | {
294 | this.push(this.stack.at(-this.pop() - 1));
295 | }
296 |
297 | stors()
298 | {
299 | let o = this.pop(); //offset
300 | let v = this.pop(); //value
301 | this.stack[this.stack.length - 1 - o] = v;
302 | }
303 |
304 | load()
305 | {
306 | this.push(this.mem.load(this.pop()));
307 | }
308 |
309 | swap()
310 | {
311 | let a = this.pop();
312 | let b = this.pop();
313 | this.push(a);
314 | this.push(b);
315 | }
316 |
317 | jmp()
318 | {
319 | let a = this.pop();
320 | this.IP = a;
321 | }
322 |
323 | jz()
324 | {
325 | let a = this.pop();
326 | let v = this.pop();
327 | if(v === 0)
328 | this.IP = a;
329 | }
330 |
331 | jnz()
332 | {
333 | let a = this.pop();
334 | let v = this.pop();
335 | if(v !== 0)
336 | this.IP = a;
337 | }
338 |
339 | jg()
340 | {
341 | let a = this.pop();
342 | let v2 = this.pop();
343 | let v1 = this.pop();
344 | if(v1 > v2)
345 | this.IP = a;
346 | }
347 |
348 | jge()
349 | {
350 | let a = this.pop();
351 | let v2 = this.pop();
352 | let v1 = this.pop();
353 | if(v1 >= v2)
354 | this.IP = a;
355 | }
356 |
357 | je()
358 | {
359 | let a = this.pop();
360 | let v2 = this.pop();
361 | let v1 = this.pop();
362 | if(v1 == v2)
363 | this.IP = a;
364 | }
365 |
366 | jne()
367 | {
368 | let a = this.pop();
369 | let v2 = this.pop();
370 | let v1 = this.pop();
371 | if(v1 != v2)
372 | this.IP = a;
373 | }
374 |
375 | //ALU
376 | and()
377 | {
378 | let v2 = this.pop();
379 | let v1 = this.pop();
380 | this.push(v1 & v2);
381 | }
382 |
383 | or()
384 | {
385 | let v2 = this.pop();
386 | let v1 = this.pop();
387 | this.push(v1 | v2);
388 | }
389 |
390 | xor()
391 | {
392 | let b = this.pop();
393 | let a = this.pop();
394 | this.push(a ^ b);
395 | }
396 |
397 | not()
398 | {
399 | let v = this.pop();
400 | this.push(~v);
401 | }
402 |
403 | inc()
404 | {
405 | let v = this.pop();
406 | this.push(v + 1);
407 | }
408 |
409 | dec()
410 | {
411 | let v = this.pop();
412 | this.push(v - 1);
413 | }
414 |
415 | add()
416 | {
417 | let b = this.pop();
418 | let a = this.pop();
419 | this.push(a + b);
420 | }
421 |
422 | sub()
423 | {
424 | let b = this.pop();
425 | let a = this.pop();
426 | this.push(a - b);
427 | }
428 |
429 | shr()
430 | {
431 | let b = this.pop();
432 | let a = this.pop();
433 | this.push(a >> b);
434 | }
435 |
436 | shl()
437 | {
438 | let b = this.pop();
439 | let a = this.pop();
440 | this.push(a << b);
441 | }
442 |
443 | mul()
444 | {
445 | let b = this.pop();
446 | let a = this.pop();
447 | this.push(a * b);
448 | }
449 |
450 | div()
451 | {
452 | let b = this.pop();
453 | let a = this.pop();
454 | this.push(Math.floor(a / b));
455 | }
456 |
457 | mod()
458 | {
459 | let b = this.pop();
460 | let a = this.pop();
461 | this.push(a % b);
462 | }
463 |
464 | neg()
465 | {
466 | let v = this.pop();
467 | this.push(-v);
468 | }
469 |
470 | abs()
471 | {
472 | let v = this.pop();
473 | this.push(v < 0 ? -v : v);
474 | }
475 |
476 | debug()
477 | {
478 | console.log(this.stack.toReversed());
479 | //debugger;
480 | }
481 |
482 | nop()
483 | {
484 | }
485 |
486 | serialize() {
487 | return {
488 | "IP": this.IP,
489 | "stack": this.stack,
490 | "code": this.code,
491 | "mem": {
492 | "heap": Buffer.from(this.mem.heap),
493 | "gfx": Buffer.from(this.mem.gfx),
494 | "io": Buffer.from(this.mem.io),
495 | },
496 | "debugLevel": this.debugLevel
497 | };
498 | }
499 |
500 | deserialize(o) {
501 | this.IP = o.IP;
502 | this.stack = o.stack;
503 | this.code = o.code;
504 | this.mem = new MemoryMap(
505 | new Uint8Array(o.mem.heap), new Uint8Array(o.mem.gfx), new Uint8Array(o.mem.io));
506 | this.debugLevel = o.debugLevel;
507 | }
508 | };
509 |
--------------------------------------------------------------------------------
/cpp/Interpreter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | //bitluni was here
3 | #include
4 |
5 | const int STACK_SIZE = 0x100;
6 | const int HEAP_SIZE = 0x1000;
7 | const int GFX_SIZE = 0x400;
8 |
9 | class MemoryMap
10 | {
11 | public:
12 | uint8_t heap[HEAP_SIZE];
13 | uint8_t gfx[GFX_SIZE];
14 |
15 | MemoryMap()
16 | {
17 | }
18 |
19 | void write32(uint8_t *a, int o, int v)
20 | {
21 | a[o++] = v & 0xff;
22 | a[o++] = (v >> 8) & 0xff;
23 | a[o++] = (v >> 16) & 0xff;
24 | a[o] = (v >> 24) & 0xff;
25 | }
26 |
27 | int read32(uint8_t *a, int o)
28 | {
29 | return (int)a[o++] | ((int)a[o++] << 8) | ((int)a[o++] << 16)| ((int)a[o] << 24);
30 | }
31 |
32 | void store(int a, int v)
33 | {
34 | switch(a & 0xf000)
35 | {
36 | case 0x0000:
37 | write32(heap, a & (HEAP_SIZE - 1), v);
38 | break;
39 | case 0xa000:
40 | write32(gfx, a & (GFX_SIZE - 1), v);
41 | break;
42 | case 0xf000:
43 | break;
44 | }
45 | }
46 |
47 |
48 | int load(int a)
49 | {
50 | switch(a & 0xf000)
51 | {
52 | case 0x0000:
53 | return read32(heap, a & (HEAP_SIZE - 1));
54 | case 0xa000:
55 | return read32(gfx, a & (GFX_SIZE - 1));
56 | case 0xf000:
57 | return 0;//io[a & 0xfff];
58 | }
59 | return 0;
60 | }
61 | };
62 |
63 | class Interpreter
64 | {
65 | public:
66 | const uint8_t *code;
67 | int codeSize;
68 | int SP;
69 | int IP;
70 | int stack[STACK_SIZE];
71 | MemoryMap mem;
72 |
73 | Interpreter()
74 | {
75 | this->code = 0;
76 | codeSize = 0;
77 | SP = STACK_SIZE;
78 | IP = 0;
79 | }
80 |
81 | void init(const uint8_t *code, int size)
82 | {
83 | this->code = code;
84 | codeSize = size;
85 | SP = STACK_SIZE;
86 | IP = 0;
87 | }
88 |
89 | void push(int v)
90 | {
91 | stack[--SP] = v;
92 | }
93 |
94 | int pop()
95 | {
96 | return stack[SP++];
97 | }
98 |
99 | void clone()
100 | {
101 | push(stack[SP]);
102 | }
103 |
104 | void stor()
105 | {
106 | int a = pop(); //address
107 | int v = pop(); //value
108 | mem.store(a, v);
109 | }
110 |
111 | void loads()
112 | {
113 | int o = pop();
114 | push(stack[SP + o]);
115 | }
116 |
117 | void stors()
118 | {
119 | int o = pop(); //offset
120 | int v = pop(); //value
121 | stack[SP + o] = v;
122 | }
123 |
124 | void load()
125 | {
126 | push(mem.load(pop()));
127 | }
128 |
129 | void swap()
130 | {
131 | int a = pop();
132 | int b = pop();
133 | push(a);
134 | push(b);
135 | }
136 |
137 | void jmp()
138 | {
139 | int a = pop();
140 | IP = a;
141 | }
142 |
143 | void jz()
144 | {
145 | int a = pop();
146 | int v = pop();
147 | if(v == 0)
148 | IP = a;
149 | }
150 |
151 | void jnz()
152 | {
153 | int a = pop();
154 | int v = pop();
155 | if(v != 0)
156 | IP = a;
157 | }
158 |
159 | void jg()
160 | {
161 | int a = pop();
162 | int v2 = pop();
163 | int v1 = pop();
164 | if(v1 > v2)
165 | IP = a;
166 | }
167 |
168 | void jge()
169 | {
170 | int a = pop();
171 | int v2 = pop();
172 | int v1 = pop();
173 | if(v1 >= v2)
174 | IP = a;
175 | }
176 |
177 | void je()
178 | {
179 | int a = pop();
180 | int v2 = pop();
181 | int v1 = pop();
182 | if(v1 == v2)
183 | IP = a;
184 | }
185 |
186 | void jne()
187 | {
188 | int a = pop();
189 | int v2 = pop();
190 | int v1 = pop();
191 | if(v1 != v2)
192 | IP = a;
193 | }
194 |
195 | //ALU
196 | void and_()
197 | {
198 | int b = pop();
199 | int a = pop();
200 | push(a & b);
201 | }
202 |
203 | void or_()
204 | {
205 | int b = pop();
206 | int a = pop();
207 | push(a | b);
208 | }
209 |
210 | void xor_()
211 | {
212 | int b = pop();
213 | int a = pop();
214 | push(a ^ b);
215 | }
216 |
217 | void not_()
218 | {
219 | int a = pop();
220 | push(~a);
221 | }
222 |
223 | void inc()
224 | {
225 | int v = pop();
226 | push(v + 1);
227 | }
228 |
229 | void dec()
230 | {
231 | int v = pop();
232 | push(v - 1);
233 | }
234 |
235 | void add()
236 | {
237 | int b = pop();
238 | int a = pop();
239 | push(a + b);
240 | }
241 |
242 | void sub()
243 | {
244 | int b = pop();
245 | int a = pop();
246 | push(a - b);
247 | }
248 |
249 | void shr()
250 | {
251 | int b = pop();
252 | int a = pop();
253 | push(a >> b);
254 | }
255 |
256 | void shl()
257 | {
258 | int b = pop();
259 | int a = pop();
260 | push(a << b);
261 | }
262 |
263 | void mul()
264 | {
265 | int b = pop();
266 | int a = pop();
267 | push(a * b);
268 | }
269 |
270 | void div()
271 | {
272 | int b = pop();
273 | int a = pop();
274 | push(a / b);
275 | }
276 |
277 | void mod()
278 | {
279 | int b = pop();
280 | int a = pop();
281 | push(a % b);
282 | }
283 |
284 | void neg()
285 | {
286 | int v = pop();
287 | push(-v);
288 | }
289 |
290 | void abs()
291 | {
292 | int v = pop();
293 | push(v < 0 ? -v : v);
294 | }
295 |
296 | void debug()
297 | {
298 | }
299 |
300 | void nop()
301 | {
302 | }
303 |
304 | void execute()
305 | {
306 | if(IP >= codeSize)
307 | {
308 | IP = 0;
309 | SP = STACK_SIZE;
310 | }
311 |
312 | switch(code[IP++])
313 | {
314 | case 0:
315 | push((int)code[IP++] | ((int)code[IP++] << 8) | ((int)code[IP++] << 16)| ((int)code[IP++] << 24));
316 | break;
317 | case 1: pop(); break;
318 | case 3: stor(); break;
319 | case 2: load(); break;
320 | case 4:
321 | push((int)code[IP++]);
322 | break;
323 | case 5:
324 | push((int)code[IP++] | ((int)code[IP++] << 8));
325 | break;
326 | case 6: clone(); break;
327 | case 7: loads(); break;
328 | case 8: stors(); break;
329 | case 9: swap(); break;
330 | case 16: jmp(); break;
331 | case 17: jz(); break;
332 | case 18: jnz(); break;
333 | case 19: jg(); break;
334 | case 20: jge(); break;
335 | case 21: je(); break;
336 | case 22: jne(); break;
337 | case 32: and_(); break;
338 | case 33: or_(); break;
339 | case 34: xor_(); break;
340 | case 35: not_(); break;
341 | case 36: inc(); break;
342 | case 37: dec(); break;
343 | case 38: add(); break;
344 | case 39: sub(); break;
345 | case 40: shl(); break;
346 | case 41: shr(); break;
347 | case 42: mul(); break;
348 | case 43: div(); break;
349 | case 44: mod(); break;
350 | case 45: neg(); break;
351 | case 46: abs(); break;
352 | case 254: debug(); break;
353 | case 255: nop(); break;
354 | }
355 | }
356 | };
357 |
358 |
--------------------------------------------------------------------------------
/examples/GameOfLife.lsm:
--------------------------------------------------------------------------------
1 | push main
2 | push initGame
3 | jmp
4 | main:
5 | push 256
6 | pixelLoop:
7 | push 0 //neighbor count
8 |
9 | push 1 //clone loop counter
10 | loads
11 | dec
12 |
13 | push 2
14 | shl //stack[source,neigh,counter,
15 | clone //stack[source,source,neigh,counter,
16 | push 0x400
17 | add //stack[target,source,neigh,counter
18 | swap //stack[source,target,neigh,counter
19 |
20 | //start counting neighbors
21 |
22 | clone //move left down
23 | push 0b1111000000 //y mask
24 | and
25 | swap
26 | push 4
27 | sub
28 | push 0b0000111111 //x wrap
29 | and
30 | or
31 | push 64 //upper left
32 | add
33 | push 0b1111111111 //y wrap
34 | and
35 | push pix0
36 | push incIfSet
37 | jmp
38 | pix0:
39 |
40 | push 64 //move up
41 | sub
42 | push 0b1111111111 //y wrap
43 | and
44 | push pix1
45 | push incIfSet
46 | jmp
47 | pix1:
48 |
49 | push 64 //move up
50 | sub
51 | push 0b1111111111 //y wrap
52 | and
53 | push pix2
54 | push incIfSet
55 | jmp
56 | pix2:
57 |
58 | clone //move right
59 | push 0b1111000000
60 | and
61 | swap
62 | push 4
63 | add
64 | push 0b0000111111
65 | and
66 | or
67 | push pix3
68 | push incIfSet
69 | jmp
70 | pix3:
71 |
72 | clone //move right
73 | push 0b1111000000
74 | and
75 | swap
76 | push 4
77 | add
78 | push 0b0000111111
79 | and
80 | or
81 | push pix4
82 | push incIfSet
83 | jmp
84 | pix4:
85 |
86 | push 64 //move down
87 | add
88 | push 0b1111111111 //y wrap
89 | and
90 | push pix5
91 | push incIfSet
92 | jmp
93 | pix5:
94 |
95 | push 64 //move down
96 | add
97 | push 0b1111111111 //y wrap
98 | and
99 | push pix6
100 | push incIfSet
101 | jmp
102 | pix6:
103 |
104 | clone //move left
105 | push 0b1111000000
106 | and
107 | swap
108 | push 4
109 | sub
110 | push 0b0000111111
111 | and
112 | or
113 |
114 | push pix7
115 | push incIfSet
116 | jmp
117 | pix7:
118 |
119 | push 64 //move up (back to center)
120 | sub
121 | push 0b1111111111 //y wrap
122 | and
123 |
124 | load //stack[center,target,neigh,counter
125 | push 2
126 | loads //stack[neigh,center,target,neigh,counter,
127 |
128 | //game die [0,1,4,5,6,7,8] keep [2] spawn [3]
129 |
130 | push 3 //if 3 neighbors spawn
131 | push spawn
132 | je
133 |
134 | push 2
135 | loads //stack[neigh,target,neigh,counter,
136 | push 2 //if 2 neighbors keep
137 | push keep
138 | je
139 | die:
140 | pop
141 | push 0 //[0,target,neigh,counter
142 | swap //[target,0,neigh,counter
143 | stor //[target,neigh,counter
144 | push caseEnd
145 | jmp
146 | keep:
147 | swap //[target,center,counter
148 | stor //[counter
149 | push caseEnd
150 | jmp
151 | spawn:
152 | pop
153 | push 1
154 | swap //[target,1,counter
155 | stor //[target,counter
156 | caseEnd:
157 |
158 | pop //neighbor count
159 |
160 | dec
161 | clone
162 | push pixelLoop
163 | jnz
164 | pop
165 |
166 | push afterCopy
167 | push copyBuffer
168 | jmp
169 | afterCopy:
170 |
171 | push afterShow
172 | push showBuffer
173 | jmp
174 | afterShow:
175 |
176 | push main
177 | jmp
178 |
179 |
180 | incIfSet: //[ret,source,target,neigh
181 | push 1
182 | loads //[source,ret,source,target,neigh
183 | load //[val,ret,source,target,neigh
184 | push inactiveCell
185 | jz
186 | push 3
187 | loads
188 | inc
189 | push 3
190 | stors
191 | inactiveCell:
192 | jmp
193 |
194 | copyBuffer:
195 | push 256
196 | copyLoop:
197 |
198 | clone //clone loop counter
199 | dec
200 | push 2
201 | shl //stack[targetaddr,counter,
202 | clone
203 | push 0x400
204 | add //stack[sourcearrd,targetaddr,counter,
205 | load //stack[value,targetaddr,counter
206 | swap //stack[targetaddr,value,counter
207 | stor //stack[counter
208 |
209 | dec
210 | clone
211 | push copyLoop
212 | jnz
213 | pop
214 | jmp
215 |
216 |
217 | showBuffer:
218 | push 0xa000 //frame address (used with loads and stors, local var)
219 | push 240
220 | showLoop:
221 | push 0xffffff //color
222 |
223 | push 2 //stackoffset
224 | loads //load address (offset 2)
225 | clone
226 | push 4
227 | add
228 | push 3
229 | stors
230 | clone //clone gfx address
231 | push 0x3ff //change to buffer in 0x0000
232 | and
233 | load
234 | push pixelSet
235 | jnz
236 | push 0
237 | push 1
238 | stors
239 | pixelSet:
240 | stor
241 |
242 | dec
243 | clone
244 | push showLoop
245 | jnz
246 | pop
247 | pop
248 | jmp
249 |
250 | initGame:
251 | push 1
252 | push 0x002c
253 | stor
254 | push 1
255 | push 0x0070
256 | stor
257 | push 1
258 | push 0x00a8
259 | stor
260 | push 1
261 | push 0x00ac
262 | stor
263 | push 1
264 | push 0x00b0
265 | stor
266 | push 1
267 | push 0x0104
268 | stor
269 | push 1
270 | push 0x0148
271 | stor
272 | push 1
273 | push 0x0180
274 | stor
275 | push 1
276 | push 0x0184
277 | stor
278 | push 1
279 | push 0x0188
280 | stor
281 | push 1
282 | push 0x0224
283 | stor
284 | push 1
285 | push 0x0268
286 | stor
287 | push 1
288 | push 0x02a0
289 | stor
290 | push 1
291 | push 0x02a4
292 | stor
293 | push 1
294 | push 0x02a8
295 | stor
296 | jmp
297 |
--------------------------------------------------------------------------------
/readme.MD:
--------------------------------------------------------------------------------
1 | # what?
2 |
3 | open source interpreter for tiny game consoles
4 |
5 | # why ?
6 |
7 | because we can
8 |
9 | # what?
10 |
11 | ## opcodes
12 | ```
13 | push
14 | pushes 1 value or label address to stack. 32 bit
15 | pop
16 | removes 1 value from stack
17 | stor
18 | stores st(1) to mem[st(0)]. removes 2 values from stack
19 |
20 | //write 69 to memory address 0x1000 and clear the stack
21 | push 69
22 | push 0x1000
23 | stor
24 |
25 | load
26 | loads value from memory mem[st(0)] to stack. removes 1 address from stack. pushes 1 value to stack
27 |
28 | //loads value from memory address 0x1000 checks if its 69 if yes jumps to nice.
29 | //stack is clean afterwards
30 | push 0x1000
31 | load
32 | push 69
33 | push nice
34 | je
35 |
36 | pushb
37 | pushes 1 value or label address to stack. 8 bit (size coding)
38 | pushw
39 | pushes 1 value or label address to stack. 16 bit (size coding)
40 | clone
41 | clones the top value on stack.
42 | loads
43 | loads value from stack with offset and pushes it to the top of the stack (extension)
44 |
45 | //copy value from stack index 1 (after removing the 1 from the stack)
46 | push 69
47 | push 42
48 | push 1
49 | loads
50 | pop //69
51 | pop //42
52 | pop //69
53 |
54 | stors
55 | stores a value st(1) to the stack with offset st(st(0)) (extension)
56 |
57 | //overwrite 0 with the value 69 on the stack
58 | push 0
59 | push 42
60 | push 69
61 | push 1
62 | stors
63 | pop //42
64 | pop //69
65 |
66 | swap
67 | swaps the two top stack values
68 |
69 | jmp
70 | jumps to address st(0). address is removed from stack
71 | jz
72 | jumps to address st(0) if s(1) is zero. 2 values are removed from stack
73 |
74 | //jumps to label zero. stack is cleared
75 | push 0
76 | push zero
77 | jz
78 |
79 | jnz
80 | jumps to address st(0) if s(1) is not zero. 2 values are removed from stack
81 | jg
82 | jumps to address st(0) if s(2) > st(1). 3 values are removed from stack
83 |
84 | //copares 2 > 1 and then jumps to label. stack is cleared
85 | push 2
86 | push 1
87 | push yeah2isGreaterThan1
88 | jg
89 |
90 | jge
91 | jumps to address st(0) if s(2) >= st(1). 3 values are removed from stack
92 | je
93 | jumps to address st(0) if s(2) == st(1). 3 values are removed from stack
94 | jne
95 | jumps to address st(0) if s(2) != st(1). 3 values are removed from stack
96 | and
97 | st(1) & st(0). 2 values popped result pushed
98 | or
99 | st(1) & st(0). 2 values popped result pushed
100 | xor
101 | st(1) ^ st(0). 2 values popped result pushed
102 | not
103 | ~st(0). 2 values popped result pushed
104 |
105 | //invert the top of the stack
106 | push 0x00000000
107 | neg
108 | pop //0xffffffff
109 |
110 | inc
111 | st(0)++
112 | dec
113 | st(0)--
114 | add
115 | st(1) + st(0). 2 values popped result pushed
116 |
117 | //adds 2 and 3
118 | push 2
119 | push 3
120 | add
121 | pop //5
122 |
123 | sub
124 | st(1) - st(0). 2 values popped result pushed
125 | shl
126 | st(1) << st(0). 2 values popped result pushed
127 | shr
128 | st(1) >> st(0). 2 values popped result pushed
129 | mul
130 | st(1) * st(0). 2 values popped result pushed
131 | div
132 | st(1) / st(0). 2 values popped result pushed (1 cycle execution might not be possible)
133 | mod
134 | st(1) % st(0). 2 values popped result pushed (1 cycle execution might not be possible)
135 | neg
136 | -st(0)
137 | abs
138 | |st(0)|
139 |
140 | debug
141 | breakpoint
142 | nop
143 | do nothing
144 | ```
145 |
146 | ## hardware addresses
147 |
148 | ```
149 | 0x0000 heap
150 |
151 | 0xa000 gfx frame buffer
152 | 0xe000 flash storage
153 | 0xf000 hardware
154 | 0x000 system
155 | 0x00 clock cycles (one opcode per clock)
156 | 0x04 clocks per second (setting)
157 | 0x10 xres
158 | 0x14 yres
159 | 0x100 io pins
160 | 0x00 up
161 | 0x04 down
162 | 0x08 left
163 | 0x0c right
164 | 0x10 a
165 | 0x14 b
166 | 0x80 LDR range [0..255] (optional)
167 | 0x800 sound
168 | 0x00 square wave hz / 16
169 | 0x04 square wave amplitude (255 max)
170 | 0x10 sine wave hz / 16
171 | 0x14 sine wave amplitude (255 max)
172 | 0x20 triangle wave hz / 16
173 | 0x24 triangle wave amplitude (255 max)
174 | 0x30 reserved
175 | 0x34 noise aplitude (255 max)
176 | ```
177 |
178 | # license
179 |
180 | take it and run 1.0
181 |
182 |
--------------------------------------------------------------------------------