-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathbeebjit.js
111 lines (93 loc) · 3.45 KB
/
beebjit.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
const fs = require('fs');
const MemStart = 0x0000;
const MemLength = 0x8000; // 32K RAM
function exec(cmd) {
const exec = require('child_process').exec;
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.warn(error);
}
resolve(stdout? stdout.trim() : stderr);
});
});
}
async function beebjit(c, jsbeeb){
// Run tweet on emulator
var tokenised;
try {
let basic = c.input;
let tmp = basic.replace(/\#\w+/g, "").trim(); // get rid of tags and white space
if (tmp.match(/^\d/) != null) {
// If there are line numbers remove a trailing explicit "RUN".
basic = basic.replace(/\n\s*RUN[\s\n]*$/, "");
}
console.log(basic)
tokenised = await jsbeeb.tokenise(basic);
await fs.writeFileSync("./tmp/tweet.bas",tokenised,{encoding:"binary"});
await fs.writeFileSync("./tmp/keys.bin","RUN\r",{encoding:"binary"});
let keyboardBuffer = "03e0"; // BBC Micro OS 1.20
let IBP = 0x02E1; // input pointer
let OBP = 0x02D8; // output pointer
let page = ( c.flags.includes("gxr.rom") ) ? "1c00" : "1900";
let end = parseInt(page,16) + tokenised.length;
let endLow = (end & 0xff).toString(16);
let endHigh = ((end >>> 8) & 0xff).toString(16);
// beebjit debug commands
let commands = "'"+
["breakat 725000",
"c",
"loadmem ../tmp/tweet.bas "+page, // paste tokenised program into PAGE
"loadmem ../tmp/keys.bin "+keyboardBuffer, // 0x03E0 OS 1.2
"writem 02e1 e4", // Advance pointer 4 bytes
"writem 0000 "+endLow, // LOWMEM
"writem 0001 "+endHigh,
"writem 0002 "+endLow, // VARTOP
"writem 0003 "+endHigh,
"writem 0012 "+endLow, // TOP
"writem 0013 "+endHigh,
"breakat "+c.cycles, // after emulated cycles
"c",
"r",
"crtc",
"bbc",
`savemem ../tmp/savemem.bin ${MemStart.toString(16)} ${MemLength.toString(16)}`, // BBC Micro memory dump
"c"
].join(";")+"'";
let beebjit_cmd = "cd beebjit && ./beebjit -fast -headless -frames-dir ../tmp/ -cycles "+(c.cycles*2)+" "+c.flags+" -opt video:hack-legacy-shift-mode7 -commands "+commands;
let stdout = await exec(beebjit_cmd );
console.log(beebjit_cmd,stdout);
let state = await parseBeebjitState(stdout);
return state;
} catch (e) {
console.log("Tokenisation FAILED");
console.log(e);
return null;
}
}
// Parse Beebjit state dump
async function parseBeebjitState(stdout){
let regdump = stdout.match(/A=(.+) X=(.+) Y=(.+) S=(.+) F=(.+) PC=(.+) cycles/i);
let crtcregs = stdout.match(/R\d\d \$([0-9A-Fa-f]{2})/mg).map(r => parseInt(r.substring(5,7),16));
let registers = {
A:parseInt(regdump[1],16),
X:parseInt(regdump[2],16),
Y:parseInt(regdump[3],16),
S:parseInt(regdump[4],16),
F:regdump[5],
PC:parseInt(regdump[6],16)
}
let ulaControl = parseInt(stdout.match(/ULA control \$(.+)/i)[1],16);
let ulaPalette = stdout.match(/ULA palette \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+) \$(\S+)/i).slice(1,17).map(a => parseInt(a,16));
let mem = await fs.readFileSync("./tmp/savemem.bin");
let state = {
"RAM": mem.toString('base64'),
"address": MemStart.toString(16),
"CPU6502": registers,
"CRTC": crtcregs,
"ULAcontrol": ulaControl,
"ULApalette": ulaPalette
};
return state; // full BBC Micro state snapshot
}
module.exports = beebjit;