import { CPU6502, byte } from '@whscullin/cpu6502'; import { debug } from '../util'; // prettier-ignore const rom = [ 0xA9,0xAA,0x20,0xEF,0xFF,0xA9,0x8D,0x20, 0xEF,0xFF,0xA0,0xFF,0xC8,0xAD,0x11,0xD0, 0x10,0xFB,0xAD,0x10,0xD0,0x99,0x00,0x02, 0x20,0xEF,0xFF,0xC9,0x9B,0xF0,0xE1,0xC9, 0x8D,0xD0,0xE9,0xA2,0xFF,0xA9,0x00,0x85, 0x24,0x85,0x25,0x85,0x26,0x85,0x27,0xE8, 0xBD,0x00,0x02,0xC9,0xD2,0xF0,0x56,0xC9, 0xD7,0xF0,0x35,0xC9,0xAE,0xF0,0x27,0xC9, 0x8D,0xF0,0x20,0xC9,0xA0,0xF0,0xE8,0x49, 0xB0,0xC9,0x0A,0x90,0x06,0x69,0x88,0xC9, 0xFA,0x90,0xAD,0x0A,0x0A,0x0A,0x0A,0xA0, 0x04,0x0A,0x26,0x24,0x26,0x25,0x88,0xD0, 0xF8,0xF0,0xCC,0x4C,0x1A,0xFF,0xA5,0x24, 0x85,0x26,0xA5,0x25,0x85,0x27,0xB0,0xBF, 0xA9,0x40,0x20,0xCC,0xC1,0x88,0xA2,0x00, 0xA1,0x26,0xA2,0x10,0x0A,0x20,0xDB,0xC1, 0xD0,0xFA,0x20,0xF1,0xC1,0xA0,0x1E,0x90, 0xEC,0xA6,0x28,0xB0,0x98,0x20,0xBC,0xC1, 0xA9,0x16,0x20,0xCC,0xC1,0x20,0xBC,0xC1, 0xA0,0x1F,0x20,0xBF,0xC1,0xB0,0xF9,0x20, 0xBF,0xC1,0xA0,0x3A,0xA2,0x08,0x48,0x20, 0xBC,0xC1,0x68,0x2A,0xA0,0x39,0xCA,0xD0, 0xF5,0x81,0x26,0x20,0xF1,0xC1,0xA0,0x35, 0x90,0xEA,0xB0,0xCD,0x20,0xBF,0xC1,0x88, 0xAD,0x81,0xC0,0xC5,0x29,0xF0,0xF8,0x85, 0x29,0xC0,0x80,0x60,0x86,0x28,0xA0,0x42, 0x20,0xE0,0xC1,0xD0,0xF9,0x69,0xFE,0xB0, 0xF5,0xA0,0x1E,0x20,0xE0,0xC1,0xA0,0x2C, 0x88,0xD0,0xFD,0x90,0x05,0xA0,0x2F,0x88, 0xD0,0xFD,0xBC,0x00,0xC0,0xA0,0x29,0xCA, 0x60,0xA5,0x26,0xC5,0x24,0xA5,0x27,0xE5, 0x25,0xE6,0x26,0xD0,0x02,0xE6,0x27,0x60 ] as const; export interface ACICallback { progress: (value: number) => void; } export default class ACI { _last: number; _next: number; _recording = false; _readOffset = 0; _flip = false; _beKind = false; _progress = 0; constructor( private cpu: CPU6502, private cb: ACICallback, ) { this._last = cpu.getCycles(); this._next = this._last; } start() { return 0xc0; } end() { return 0xc1; } read(page: byte, off: byte) { const now = this.cpu.getCycles(); let result = rom[off]; if (page === 0xc0) { if (this._recording) { const delta = now - this._last; this.buffer.push(delta); this._last = now; } else { if (this._readOffset < this.buffer.length) { if (now > this._next) { if (this._readOffset % 1000 === 0) { debug('Read ' + this._readOffset / 1000); } this._flip = !this._flip; this._next = now + this.buffer[this._readOffset++]; } } result = this._flip ? rom[off | 0x01] : rom[off & 0xfe]; const progress = Math.round((this._readOffset / this.buffer.length) * 100) / 100; if (this._progress !== progress) { this._progress = progress; this.cb.progress(this._progress); } } } else { if (this.cpu.getSync()) { switch (off) { case 0x00: this._recording = false; this._beKind = true; debug('Entering ACI CLI'); break; case 0x63: if (this._recording) { this.buffer.push(5000000); this._recording = false; } debug('Exiting ACI CLI'); break; case 0x70: // WRITE this._recording = true; if (this._beKind) { this._beKind = false; this.buffer = []; } debug('Start write'); this._last = now; break; //case 0x7c: // WBITLOOP: // _debug = true; // debug("Write bit loop"); // break; case 0x8d: // READ this._recording = false; debug('Start read'); if (this._beKind) { this._readOffset = 0; this._next = now + 5000000; this._beKind = false; this.cb.progress(0); } break; default: break; } } } return result; } write() {} getState() { return {}; } setState() {} setData(data: number[][]) { let seg, idx, jdx, d, b; this.buffer = []; for (seg = 0; seg < data.length; seg++) { for (idx = 0; idx < 16384; idx++) { this.buffer.push(592); } this.buffer.push(180); this.buffer.push(238); d = data[seg]; for (idx = 0; idx < d.length; idx++) { b = d[idx]; for (jdx = 0; jdx < 8; jdx++) { if (b & 0x80) { this.buffer.push(473); this.buffer.push(473); } else { this.buffer.push(238); this.buffer.push(238); } b <<= 1; } } this.buffer.push(5000000); } } buffer: byte[] = []; }