├── .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 | 232 | 233 | 275 | 289 | 290 | 291 | 293 |
276 |
xres 277 | yres 278 |
279 |
280 |
281 |

App name: 282 |
283 | 284 |
285 | 286 |
287 |
288 |
292 |
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 | --------------------------------------------------------------------------------