diff options
author | sanine-a <sanine.not@pm.me> | 2023-05-22 17:24:43 -0500 |
---|---|---|
committer | sanine-a <sanine.not@pm.me> | 2023-05-22 17:24:43 -0500 |
commit | d6e89d16d332954dde3fc4c5ee7549af7c8bb556 (patch) | |
tree | 46ae395bda119c5e59ae40140226c55205bca772 | |
parent | 9fa301a7cf8e8b5883521d1a966ee7b65ecf925e (diff) |
begin writing vm
-rw-r--r-- | src/vm/core.js | 51 | ||||
-rw-r--r-- | src/vm/enum.js | 27 | ||||
-rw-r--r-- | src/vm/instruction.js | 116 |
3 files changed, 194 insertions, 0 deletions
diff --git a/src/vm/core.js b/src/vm/core.js new file mode 100644 index 0000000..292ceb0 --- /dev/null +++ b/src/vm/core.js @@ -0,0 +1,51 @@ +'use strict'; + +const { Op, AddrMode} = require('./enum.js'); + + +class Core { + constructor(size) { + this.data = new Array(size); + + // initialize core to all DAT 0, 0 + for (let i=0; i<size; i++) { + this.data[i] = { + opcode: Op.DAT, + a: { value: 0, mode: AddrMode.Direct }, + b: { value: 0, mode: AddrMode.Direct }, + }; + } + } + + + normalize(pc, value) { + return (pc + value) % this.data.length; + } + + + getLocation(pc, address) { + switch(address.mode) { + case AddrMode.Immediate: + throw "Cannot get location from immediate-mode address"; + case AddrMode.Direct: + return this.normalize(pc, address.value); + case AddrMode.Indirect: { + let loc = this.normalize(pc, address.value); + let b = this.data[loc]; + return this.normalize(loc, b); + } + case AddrMode.Predecrement: { + let loc = this.normalize(pc, address.value); + this.data[loc].b -= 1; + let b = this.data[loc].b; + return this.normalize(loc, b); + } + default: + throw `Invalid addressing mode "${address.mode}"`; + } + } + + getValue(pc, address) { + return this.data[this.getLocation(pc, address)]; + } +} diff --git a/src/vm/enum.js b/src/vm/enum.js new file mode 100644 index 0000000..5271991 --- /dev/null +++ b/src/vm/enum.js @@ -0,0 +1,27 @@ +'use strict'; + +const Op = { + DAT: 'DAT', + MOV: 'MOV', + ADD: 'ADD', + SUB: 'SUB', + JMP: 'JMP', + JMZ: 'JMZ', + JMN: 'JMN', + CMP: 'CMP', + SLT: 'SLT', + DJN: 'DJN', + SPL: 'SPL', +}; + + +const AddrMode = { + Immediate: 'immediate', + Indirect: 'indirect', + Predecrement: 'predecrement', + Direct: 'direct', +}; + + +exports.Op = Op; +exports.AddrMode = AddrMode; diff --git a/src/vm/instruction.js b/src/vm/instruction.js new file mode 100644 index 0000000..0fe922d --- /dev/null +++ b/src/vm/instruction.js @@ -0,0 +1,116 @@ +'use strict'; + +const { AddrMode } = require('./enum.js'); + + +function DoDat(core, pc, ins) { + // do nothing + return []; +} + + +function DoMov(core, pc, ins) { + if (ins.a.mode === AddrMode.Immediate) { + let mem = core.getValue(pc, ins.b); + mem.b.value = ins.a.value; + } else { + const src = core.getValue(pc, ins.a); + const dstLoc = core.getLocation(pc, ins.b); + + // hacky deep copy + core.data[dstLoc] = JSON.parse(JSON.stringify(src)); + } + return [pc + 1]; +} + + +function DoAdd(core, pc, ins) { + if (ins.a.mode === AddrMode.Immediate) { + let dst = core.getValue(pc, ins.b); + dst.b += ins.a.value; + } else { + let src = core.getValue(pc, ins.a); + let dst = core.getValue(pc, ins.b); + dst.a.value += src.a.value; + dst.b.value += src.b.value; + } + return [pc + 1]; +} + + +function DoSub(core, pc, ins) { + if (ins.a.mode === AddrMode.Immediate) { + let dst = core.getValue(pc, ins.b); + dst.b -= ins.a.value; + } else { + let src = core.getValue(pc, ins.a); + let dst = core.getValue(pc, ins.b); + dst.a.value -= src.a.value; + dst.b.value -= src.b.value; + } + return [pc + 1]; +} + + +function DoJmp(core, pc, ins) { + return [core.getLocation(pc, ins.a)]; +} + + +function DoJmz(core, pc, ins) { + let test + if (ins.b.mode === AddrMode.Immediate) { + test = ins; + } else { + test = core.getValue(pc, ins.b); + } + + if (test.b.value === 0) { + return [core.getLocation(pc, ins.a)]; + } else { + return [pc + 1]; + } +} + + +function DoJmn(core, pc, ins) { + let test + if (ins.b.mode === AddrMode.Immediate) { + test = ins; + } else { + test = core.getValue(pc, ins.b); + } + + if (test.b.value !== 0) { + return [core.getLocation(pc, ins.a)]; + } else { + return [pc + 1]; + } +} + + +function DoCmp(core, pc, ins) { + if (ins.a.mode === AddrMode.Immediate) { + const test = core.getValue(pc, ins.b); + if (ins.a.value === test.b.value) { + return [pc + 2]; + } else { + return [pc + 1]; + } + } else { + const a = core.getValue(pc, ins.a); + const b = core.getValue(pc, ins.b); + + if ( + a.opcode === b.opcode && + a.a.value === b.a.value && + a.b.value === b.b.value) + ) { + return [pc + 2]; + } else { + return [pc + 1]; + } + } +} + + |