diff options
| author | sanine-a <sanine.not@pm.me> | 2023-05-23 14:53:53 -0500 | 
|---|---|---|
| committer | sanine-a <sanine.not@pm.me> | 2023-05-23 14:53:53 -0500 | 
| commit | 15323007750e0f0f7c36a6a6fa01ad1d303a4a16 (patch) | |
| tree | 70835b4364299274dc0145af5cd41c5af05ae53b | |
| parent | 29ed5eacb80cdfe49bff0d9335241dc3e2188981 (diff) | |
implement basic vm runner
| -rw-r--r-- | src/main.js | 23 | ||||
| -rw-r--r-- | src/red/coreclear.red | 9 | ||||
| -rw-r--r-- | src/red/wait.red | 5 | ||||
| -rw-r--r-- | src/vm/core.js | 15 | ||||
| -rw-r--r-- | src/vm/vm.js | 34 | 
5 files changed, 75 insertions, 11 deletions
diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..ec74ee7 --- /dev/null +++ b/src/main.js @@ -0,0 +1,23 @@ +'use strict'; + +const process = require('node:process'); +const fs      = require('node:fs'); + +const { assemble }  = require('./parser/parser.js'); +const { RedcodeVm } = require('./vm/vm.js'); + + +const files = process.argv.slice(2); +if (files.length === 0) { +	console.log("no input files provided!"); +} + + +const warriors = files.map(fname => { +	const source = fs.readFileSync(fname, 'utf8'); +	return assemble(source); +}); + + +const vm = new RedcodeVm(8000, warriors); +console.log(vm.run(100000)); diff --git a/src/red/coreclear.red b/src/red/coreclear.red new file mode 100644 index 0000000..7b4d8bb --- /dev/null +++ b/src/red/coreclear.red @@ -0,0 +1,9 @@ +; coreclear +; like dwarf but bombs literally everything + + +bomb    dat #0, #2 +start   add #1, bomb +        mov bomb, @bomb +        jmp start +end start diff --git a/src/red/wait.red b/src/red/wait.red new file mode 100644 index 0000000..4c3c2c9 --- /dev/null +++ b/src/red/wait.red @@ -0,0 +1,5 @@ +; wait +; does nothing + +wait    jmp wait +end diff --git a/src/vm/core.js b/src/vm/core.js index a8fbce7..6363a60 100644 --- a/src/vm/core.js +++ b/src/vm/core.js @@ -133,6 +133,21 @@ class Core {  		const index = this.getLocation(pc, address);  		return this.data[index];  	} + + +	pretty(ins) { +		const prettyMode = { +			'immediate':    '#', +			'direct':       ' ', +			'indirect':     '@', +			'predecrement': '<', +		}; + +		return `\ +${ins.opcode} \ +${prettyMode[ins.a.mode]}${ins.a.value}, \ +${prettyMode[ins.b.mode]}${ins.b.value}`; +	}  } diff --git a/src/vm/vm.js b/src/vm/vm.js index 6add546..eea949a 100644 --- a/src/vm/vm.js +++ b/src/vm/vm.js @@ -23,7 +23,12 @@ class Warrior {  	next() {  		const pc = this.queue[0];  		this.queue = this.queue.slice(1); -		return next; +		return pc; +	} + +	peek() { +		const pc = this.queue[0]; +		return pc;  	}  }; @@ -38,7 +43,8 @@ class RedcodeVm {  	step() {  		let running = 0; -		for (let warrior of this.warriors) { +		for (let i=0; i<this.warriors.length; i++) { +			const warrior = this.warriors[i];  			if (warrior.isDead()) {  				continue;  			} else { @@ -48,6 +54,7 @@ class RedcodeVm {  			const pc = warrior.next();  			const ins = this.core.data[pc];  			let next; +			console.log(i, this.core.pretty(ins));  			switch(ins.opcode) {  				case 'DAT':  					next = DAT(this.core, pc, ins); @@ -85,25 +92,30 @@ class RedcodeVm {  				default:  					throw `core corruption: bad instruction ${ins}`  			} + +			warrior.append(next);  		}  		return running;  	} +	warriorsAlive() { +		return this.warriors.reduce( +			(count, warrior) => warrior.isDead() ? count : count+1, +			0 +		); +	} +  	run(maxSteps) {  		let steps = 0; -		let running = this.warriors.length; -		while(running > 0 && steps < maxSteps) { -			running = this.step(); +		while(this.warriorsAlive() > 1 && steps < maxSteps) { +			this.step();  			steps += 1;  		} -		if (running !== 0) { -			console.log("draw, maximum steps exceeded"); -		} -		for (let i=0; i<this.warriors.length; i++) { -			console.log(`${i} running: ${!this.warriors[i].isDead()}`); -		} +		return this.warriors.map( +			(w, i) => ({ warrior: i, alive: !w.isDead() }) +		);  	}  };  | 
