apple1js/js/cards/aci.ts

163 lines
4.9 KiB
TypeScript

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[] = [];
}