import CPU6502 from '../cpu6502'; import { debug } from '../util'; import { byte } from '../types'; 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[] = []; }