1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-05-28 23:41:32 +00:00
8bitworkshop/gen/machine/c64.js

363 lines
14 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.C64_WASMMachine = void 0;
const emu_1 = require("../common/emu");
const util_1 = require("../common/util");
const wasmplatform_1 = require("../common/wasmplatform");
class C64_WASMMachine extends wasmplatform_1.BaseWASMMachine {
constructor() {
super(...arguments);
this.numTotalScanlines = 312;
this.cpuCyclesPerLine = 63;
this.joymask0 = 0;
this.joymask1 = 0;
this.lightpen_x = 0;
this.lightpen_y = 0;
}
loadBIOS(srcArray) {
var patch1ofs = 0xea24 - 0xe000 + 0x3000;
if (srcArray[patch1ofs] == 0xc4)
srcArray[patch1ofs] = 0x60; // cursor move, KIL -> RTS
super.loadBIOS(srcArray);
}
reset() {
super.reset();
// clear keyboard
for (var ch = 0; ch < 128; ch++) {
this.exports.machine_key_up(this.sys, ch);
}
// load rom
if (this.romptr && this.romlen) {
this.exports.machine_load_rom(this.sys, this.romptr, this.romlen);
this.prgstart = this.romarr[0] + (this.romarr[1] << 8); // get load address
// look for BASIC program start
if (this.prgstart == 0x801) {
// decode SYS address from decimal?
if (this.romarr[6] == 0x9e) {
var addr = 0;
for (var i = 0; i < 5; i++) {
var ch = this.romarr[7 + i];
if (ch == 0x9b || ch == 0)
break;
addr = addr * 10 + (ch & 0xf);
}
this.prgstart = addr;
console.log("SYS", addr, (0, util_1.hex)(addr));
}
else {
this.prgstart = this.romarr[2] + (this.romarr[3] << 8) + 2; // point to after BASIC program
console.log("RUN", this.prgstart, (0, util_1.hex)(this.prgstart));
}
}
// is program loaded into RAM?
if (this.prgstart < 0x8000) {
// advance BIOS a few frames
this.exports.machine_exec(this.sys, 250000);
// type in command (SYS 2061)
var cmd = "\rSYS " + this.prgstart;
for (var i = 0; i < cmd.length; i++) {
var key = cmd.charCodeAt(i);
this.exports.machine_exec(this.sys, 30000);
this.exports.machine_key_down(this.sys, key);
this.exports.machine_exec(this.sys, 30000);
this.exports.machine_key_up(this.sys, key);
this.exports.machine_exec(this.sys, 1); // chips/kbd.c has a "sticky counter"
}
// advance clock until program starts
this.exports.machine_key_down(this.sys, 13);
this.exports.machine_exec(this.sys, 1); // chips/kbd.c has a "sticky counter"
for (var i = 0; i < 100000 && this.getPC() != this.prgstart; i++) {
this.exports.machine_tick(this.sys);
}
}
else {
// get out of reset
this.exports.machine_exec(this.sys, 100);
// wait until cartridge start
// TODO: detect ROM cartridge
var warmstart = this.romarr[0x4] + this.romarr[0x5] * 256;
for (var i = 0; i < 150000 && this.getPC() != warmstart; i++) {
this.exports.machine_tick(this.sys);
}
}
// TODO: shouldn't we return here @ start of frame?
// and stop probing
}
}
advanceFrame(trap) {
// TODO: does this sync with VSYNC?
// TODO: ticks, not msec (machine_tick() has different rate then machine_exec())
var scanline = this.getRasterY();
var clocks = Math.floor((this.numTotalScanlines - scanline) * 19656 / this.numTotalScanlines);
var probing = this.probe != null;
if (probing)
this.exports.machine_reset_probe_buffer();
clocks = super.advanceFrameClock(trap, clocks);
if (probing)
this.copyProbeData();
//console.log(clocks, this.getRasterY());
return clocks;
}
getCPUState() {
this.exports.machine_save_cpu_state(this.sys, this.cpustateptr);
var s = this.cpustatearr;
var pc = s[2] + (s[3] << 8);
return {
PC: pc,
SP: s[9],
A: s[6],
X: s[7],
Y: s[8],
C: s[10] & 1,
Z: s[10] & 2,
I: s[10] & 4,
D: s[10] & 8,
V: s[10] & 64,
N: s[10] & 128,
o: this.readConst(pc),
R: s[19] != 0x37, // bit 28 of PINS
};
}
saveState() {
this.exports.machine_save_state(this.sys, this.stateptr);
let cia1 = this.getDebugStateOffset(1);
let cia2 = this.getDebugStateOffset(2);
let vic = this.getDebugStateOffset(3);
let sid = this.getDebugStateOffset(4);
let ramofs = this.getDebugStateOffset(5);
let pla = this.getDebugStateOffset(9);
return {
c: this.getCPUState(),
state: this.statearr.slice(0),
ram: this.statearr.slice(ramofs, ramofs + 0x10000),
cia1: this.statearr.slice(cia1, cia1 + 64),
cia2: this.statearr.slice(cia2, cia2 + 64),
vic: this.statearr.slice(vic + 1, vic + 1 + 64),
sid: this.statearr.slice(sid, sid + 32),
pla: this.statearr.slice(pla, pla + 16)
};
}
loadState(state) {
this.statearr.set(state.state);
this.exports.machine_load_state(this.sys, this.stateptr);
}
getVideoParams() {
return { width: 392, height: 272, overscan: true, videoFrequency: 50, aspect: 392 / 272 * 0.9365 };
}
setKeyInput(key, code, flags) {
// TODO: handle shifted keys
if (key == 16 || key == 17 || key == 18 || key == 224)
return; // meta keys
//console.log(key, code, flags);
//if (flags & KeyFlags.Shift) { key += 64; }
// convert to c64
var mask = 0;
var mask2 = 0;
switch (key) {
case 32:
mask = 0x10;
break;
case 37:
key = 0x8;
mask = 0x4;
break; // LEFT
case 38:
key = 0xb;
mask = 0x1;
break; // UP
case 39:
key = 0x9;
mask = 0x8;
break; // RIGHT
case 40:
key = 0xa;
mask = 0x2;
break; // DOWN
case 113:
key = 0xf1;
break; // F2
case 115:
key = 0xf3;
break; // F4
case 119:
key = 0xf5;
break; // F8
case 121:
key = 0xf7;
break; // F10
case 188:
key = flags & emu_1.KeyFlags.Shift ? 0x3c : 0x2e;
break; // < .
case 190:
key = flags & emu_1.KeyFlags.Shift ? 0x3e : 0x2c;
break; // > ,
case 191:
key = flags & emu_1.KeyFlags.Shift ? 0x3f : 0x2f;
break; // ? /
case 222:
key = flags & emu_1.KeyFlags.Shift ? 0x22 : 0x27;
break; // " '
case 219:
key = flags & emu_1.KeyFlags.Shift ? 0x7b : 0x5b;
break; // [
case 221:
key = flags & emu_1.KeyFlags.Shift ? 0x7d : 0x5d;
break; // ]
case 48:
if (flags & emu_1.KeyFlags.Shift)
key = 0x29;
break; // )
case 49:
if (flags & emu_1.KeyFlags.Shift)
key = 0x21;
break; // !
case 50:
if (flags & emu_1.KeyFlags.Shift)
key = 0x40;
break; // @
case 51:
if (flags & emu_1.KeyFlags.Shift)
key = 0x23;
break; // #
case 52:
if (flags & emu_1.KeyFlags.Shift)
key = 0x24;
break; // $
case 53:
if (flags & emu_1.KeyFlags.Shift)
key = 0x25;
break; // %
case 54:
if (flags & emu_1.KeyFlags.Shift)
key = 0x5e;
break; // ^
case 55:
if (flags & emu_1.KeyFlags.Shift)
key = 0x26;
break; // &
case 56:
if (flags & emu_1.KeyFlags.Shift)
key = 0x2a;
break; // *
case 57:
if (flags & emu_1.KeyFlags.Shift)
key = 0x28;
break; // (
case 59:
if (flags & emu_1.KeyFlags.Shift)
key = 0x3a;
break; // ;
case 61:
if (flags & emu_1.KeyFlags.Shift)
key = 0x2b;
break; // +
case 173:
key = flags & emu_1.KeyFlags.Shift ? 0x5f : 0x2d;
break; // _ -
}
if (flags & emu_1.KeyFlags.KeyDown) {
this.exports.machine_key_down(this.sys, key);
this.joymask0 |= mask;
this.joymask1 |= mask2;
}
else if (flags & emu_1.KeyFlags.KeyUp) {
this.exports.machine_key_up(this.sys, key);
this.joymask0 &= ~mask;
this.joymask1 &= ~mask2;
}
this.exports.c64_joystick(this.sys, this.joymask0, this.joymask1);
}
getRasterY() {
return this.exports.machine_get_raster_line(this.sys);
}
getDebugStateOffset(index) {
var p = this.exports.machine_get_debug_pointer(this.sys, index);
return p - this.sys;
}
getDebugCategories() {
return ['CPU', 'ZPRAM', 'Stack', 'PLA', 'CIA', 'VIC', 'SID'];
}
getDebugInfo(category, state) {
switch (category) {
case 'PLA': {
let s = "";
let iomapped = state.pla[0];
let port = state.pla[3];
s += `$0000 - $9FFF RAM\n`;
s += `$A000 - $BFFF ${(port & 3) == 3 ? 'BASIC ROM' : 'RAM'}\n`;
s += `$C000 - $CFFF RAM\n`;
s += `$D000 - $DFFF ${iomapped ? 'I/O' : (port & 3) != 0 ? 'CHAR ROM' : 'RAM'}\n`;
s += `$E000 - $FFFF ${(port & 2) == 2 ? 'KERNAL ROM' : 'RAM'}\n`;
return s;
}
case 'CIA': {
let s = "";
for (let i = 0; i < 2; i++) {
let m = i ? state.cia2 : state.cia1;
s += `CIA ${i + 1}\n`;
s += ` A: Data ${(0, util_1.hex)(m[0])} DDR ${(0, util_1.hex)(m[1])} Input ${(0, util_1.hex)(m[2])}`;
s += ` Timer ${(0, util_1.hex)(m[10] + m[11] * 256, 4)}\n`;
s += ` B: Data ${(0, util_1.hex)(m[4])} DDR ${(0, util_1.hex)(m[5])} Input ${(0, util_1.hex)(m[6])}`;
s += ` Timer ${(0, util_1.hex)(m[10 + 10] + m[11 + 10] * 256, 4)}\n`;
//s += ` IMR ${hex(m[48])} ICR ${hex(m[50])}\n`
}
return s;
}
case 'VIC': {
let m = state.vic;
let s = '';
let vicbank = ((state.cia2[0] & 3) ^ 3) * 0x4000;
let charmem = vicbank + (state.vic[0x18] & 14) * 0x400;
let screen = vicbank + (state.vic[0x18] >> 4) * 0x400;
let isbitmap = state.vic[0x11] & 0x20;
let ischar = (state.cia2[0] & 1) == 1 && (state.vic[0x18] & 12) == 4;
let rasterX = state.state[0xf4];
let rasterY = this.getRasterY();
s += 'Mode:';
if (state.vic[0x11] & 0x20)
s += ' BITMAP';
else
s += ' CHAR';
if (state.vic[0x16] & 0x10)
s += ' MULTICOLOR';
if (state.vic[0x11] & 0x40)
s += ' EXTENDED';
s += "\n";
s += `Raster: (${(0, util_1.lpad)(rasterX, 3)}, ${(0, util_1.lpad)(rasterY, 3)}) `;
s += `Scroll: (${state.vic[0x16] & 7}, ${state.vic[0x11] & 7})`;
s += "\n";
s += `VIC Bank: $${(0, util_1.hex)(vicbank, 4)} Scrn: $${(0, util_1.hex)(screen, 4)} `;
if (isbitmap)
s += `Bitmap: $${(0, util_1.hex)(charmem & 0xe000, 4)}`;
else if (ischar)
s += `Char: ROM $${(0, util_1.hex)(charmem, 4)}`;
else
s += `Char: $${(0, util_1.hex)(charmem, 4)}`;
s += "\n";
s += (0, emu_1.dumpRAM)(m, 0xd000, 64);
return s;
}
case 'SID': {
let m = state.sid;
let s = '';
s += (0, emu_1.dumpRAM)(m, 0xd400, 32);
return s;
}
}
}
setPaddleInput(controller, value) {
if (controller == 0)
this.lightpen_x = value;
if (controller == 1)
this.lightpen_y = value;
const x1 = 22;
const y1 = 36;
const x2 = 228;
const y2 = 220;
let x = (0, util_1.clamp)(0, 255, (this.lightpen_x - x1) / (x2 - x1) * 160 + 24);
let y = (0, util_1.clamp)(0, 255, (this.lightpen_y - y1) / (y2 - y1) * 200 + 50);
this.exports.machine_set_mouse(this.sys, x, y);
}
}
exports.C64_WASMMachine = C64_WASMMachine;
//# sourceMappingURL=c64.js.map