mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
Increase test coverage, fix docs
This commit is contained in:
parent
547f6df1cd
commit
cbfce46dee
|
@ -161,27 +161,44 @@ type StrictInstruction =
|
|||
|
||||
type Instructions = Record<byte, StrictInstruction>
|
||||
|
||||
type callback = (cpu: CPU6502) => void;
|
||||
type callback = (cpu: CPU6502) => boolean | void;
|
||||
|
||||
export default class CPU6502 {
|
||||
/** 65C02 emulation mode flag */
|
||||
private readonly is65C02: boolean;
|
||||
|
||||
/* Registers */
|
||||
private pc: word = 0; //
|
||||
private sr: byte = flags.X // Process Status Register
|
||||
private ar: byte = 0; // Accumulator
|
||||
private xr: byte = 0; // X Register
|
||||
private yr: byte = 0; // Y Register
|
||||
private sp: byte = 0xff; // Stack Pointer
|
||||
/**
|
||||
* Registers
|
||||
*/
|
||||
|
||||
/** Program counter */
|
||||
private pc: word = 0;
|
||||
/** Status register */
|
||||
private sr: byte = flags.X
|
||||
/** Accumulator */
|
||||
private ar: byte = 0;
|
||||
/** X index */
|
||||
private xr: byte = 0;
|
||||
/** Y index */
|
||||
private yr: byte = 0;
|
||||
/** Stack pointer */
|
||||
private sp: byte = 0xff;
|
||||
|
||||
/** Current instruction */
|
||||
private op: Instruction
|
||||
private addr: word = 0; // address bus
|
||||
/** Last accessed memory address */
|
||||
private addr: word = 0;
|
||||
|
||||
/** Filled array of memory handlers by address page */
|
||||
private memPages: Memory[] = new Array(0x100);
|
||||
/** Callbacks invoked on reset signal */
|
||||
private resetHandlers: ResettablePageHandler[] = [];
|
||||
/** Elapsed cycles */
|
||||
private cycles = 0;
|
||||
/** Command being fetched signal */
|
||||
private sync = false;
|
||||
|
||||
/** Filled array of CPU operations */
|
||||
private readonly opary: Instruction[];
|
||||
|
||||
constructor(options: CpuOptions = {}) {
|
||||
|
@ -391,7 +408,7 @@ export default class CPU6502 {
|
|||
}
|
||||
}
|
||||
|
||||
private writePageCross(pc: word, addr: word, addrIdx: word): void {
|
||||
private workCycleIndexedWrite(pc: word, addr: word, addrIdx: word): void {
|
||||
const oldPage = addr & 0xff00;
|
||||
if (this.is65C02) {
|
||||
this.readByte(pc);
|
||||
|
@ -401,7 +418,7 @@ export default class CPU6502 {
|
|||
}
|
||||
}
|
||||
|
||||
private readPageCross(pc: word, addr: word, addrIdx: word): void {
|
||||
private workCycleIndexedRead(pc: word, addr: word, addrIdx: word): void {
|
||||
const oldPage = addr & 0xff00;
|
||||
const newPage = addrIdx & 0xff00;
|
||||
if (newPage !== oldPage) {
|
||||
|
@ -446,7 +463,7 @@ export default class CPU6502 {
|
|||
const addr = this.readWordPC();
|
||||
const pc = this.addr;
|
||||
const addrIdx = (addr + this.xr) & 0xffff;
|
||||
this.readPageCross(pc, addr, addrIdx);
|
||||
this.workCycleIndexedRead(pc, addr, addrIdx);
|
||||
return this.readByte(addrIdx);
|
||||
}
|
||||
|
||||
|
@ -455,7 +472,7 @@ export default class CPU6502 {
|
|||
const addr = this.readWordPC();
|
||||
const pc = this.addr;
|
||||
const addrIdx = (addr + this.yr) & 0xffff;
|
||||
this.readPageCross(pc, addr, addrIdx);
|
||||
this.workCycleIndexedRead(pc, addr, addrIdx);
|
||||
return this.readByte(addrIdx);
|
||||
}
|
||||
|
||||
|
@ -487,7 +504,7 @@ export default class CPU6502 {
|
|||
const pc = this.addr;
|
||||
const addr = this.readZPWord(zpAddr);
|
||||
const addrIdx = (addr + this.yr) & 0xffff;
|
||||
this.readPageCross(pc, addr, addrIdx);
|
||||
this.workCycleIndexedRead(pc, addr, addrIdx);
|
||||
return this.readByte(addrIdx);
|
||||
}
|
||||
|
||||
|
@ -515,7 +532,7 @@ export default class CPU6502 {
|
|||
const addr = this.readWordPC();
|
||||
const pc = this.addr;
|
||||
const addrIdx = (addr + this.xr) & 0xffff;
|
||||
this.writePageCross(pc, addr, addrIdx);
|
||||
this.workCycleIndexedWrite(pc, addr, addrIdx);
|
||||
this.writeByte(addrIdx, val);
|
||||
}
|
||||
|
||||
|
@ -524,7 +541,7 @@ export default class CPU6502 {
|
|||
const addr = this.readWordPC();
|
||||
const pc = this.addr;
|
||||
const addrIdx = (addr + this.yr) & 0xffff;
|
||||
this.writePageCross(pc, addr, addrIdx);
|
||||
this.workCycleIndexedWrite(pc, addr, addrIdx);
|
||||
this.writeByte(addrIdx, val);
|
||||
}
|
||||
|
||||
|
@ -556,7 +573,7 @@ export default class CPU6502 {
|
|||
const pc = this.addr;
|
||||
const addr = this.readZPWord(zpAddr);
|
||||
const addrIdx = (addr + this.yr) & 0xffff;
|
||||
this.writePageCross(pc, addr, addrIdx);
|
||||
this.workCycleIndexedWrite(pc, addr, addrIdx);
|
||||
this.writeByte(addrIdx, val);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,122 @@ describe('CPU6502', function() {
|
|||
cpu.addPageHandler(bios);
|
||||
});
|
||||
|
||||
describe('#step functions', function() {
|
||||
const code = [0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA];
|
||||
const initialState = {...DEFAULT_STATE};
|
||||
|
||||
it('step', function() {
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.step();
|
||||
expect(cpu.getState()).toEqual(
|
||||
{ ...DEFAULT_STATE, pc: 0x401, cycles: 2 }
|
||||
);
|
||||
expect(cpu.getCycles()).toEqual(2);
|
||||
});
|
||||
|
||||
it('step with callback', function() {
|
||||
const callback = jest.fn();
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.step(callback);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x401, cycles: 2,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(2);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('stepN', function() {
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.stepN(4);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x404, cycles: 8,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(8);
|
||||
});
|
||||
|
||||
it('stepN with callback', function() {
|
||||
const callback = jest.fn();
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.stepN(4, callback);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x404, cycles: 8,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(8);
|
||||
expect(callback).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
it('stepN with breakpoint', function() {
|
||||
const callback = jest.fn().mockReturnValue(true);
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.stepN(4, callback);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x401, cycles: 2,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(2);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('stepCycles', function() {
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.stepCycles(4);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x402, cycles: 4,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(4);
|
||||
});
|
||||
|
||||
it('stepCyclesDebug', function() {
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.stepCyclesDebug(4);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x402, cycles: 4,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(4);
|
||||
});
|
||||
|
||||
it('stepCyclesDebug with callback', function() {
|
||||
const callback = jest.fn();
|
||||
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.stepCyclesDebug(4, callback);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x402, cycles: 4,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(4);
|
||||
expect(callback).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('stepCyclesDebug with breakpoint', function() {
|
||||
const callback = jest.fn().mockReturnValue(true);
|
||||
|
||||
cpu.setState(initialState);
|
||||
program = new Program(0x04, code);
|
||||
cpu.addPageHandler(program);
|
||||
cpu.stepCyclesDebug(4, callback);
|
||||
expect(cpu.getState()).toEqual({
|
||||
...DEFAULT_STATE, pc: 0x401, cycles: 2,
|
||||
});
|
||||
expect(cpu.getCycles()).toEqual(2);
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#signals', function () {
|
||||
it('should reset', function () {
|
||||
cpu.reset();
|
||||
|
@ -161,6 +277,14 @@ describe('CPU6502', function() {
|
|||
pc: 0x1234
|
||||
});
|
||||
});
|
||||
|
||||
it('should log unimplemented opcodes', () => {
|
||||
jest.spyOn(console, 'log').mockImplementation();
|
||||
testCode([0xFF], 1, {}, {
|
||||
cycles: 1
|
||||
});
|
||||
expect(console.log).toHaveBeenLastCalledWith('Unknown OpCode: FF at 0400');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#registers', function() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user