mirror of
https://github.com/whscullin/apple1js.git
synced 2024-12-26 13:31:40 +00:00
Use submodule for cpu6502
This commit is contained in:
parent
6e49066162
commit
b5dd61b88e
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "submodules/cpu6502"]
|
||||||
|
path = submodules/cpu6502
|
||||||
|
url = https://github.com/whscullin/cpu6502
|
@ -9,6 +9,8 @@ Things are still a little rough around the edges right now, hopefully I will hav
|
|||||||
First
|
First
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
import MicroModal from 'micromodal';
|
import MicroModal from 'micromodal';
|
||||||
|
|
||||||
import Apple1IO from './apple1io';
|
import Apple1IO from './apple1io';
|
||||||
import CPU6502 from './cpu6502';
|
import { CPU6502, word, byte } from '@whscullin/cpu6502';
|
||||||
import Prefs from './prefs';
|
import Prefs from './prefs';
|
||||||
import RAM from './ram';
|
import RAM from './ram';
|
||||||
import { TextPage } from './canvas1';
|
import { TextPage } from './canvas1';
|
||||||
@ -25,7 +25,6 @@ import Krusader from './roms/krusader';
|
|||||||
import ACI from './cards/aci';
|
import ACI from './cards/aci';
|
||||||
|
|
||||||
import { mapKeyEvent, KeyBoard } from './ui/keyboard';
|
import { mapKeyEvent, KeyBoard } from './ui/keyboard';
|
||||||
import { address, byte } from './types';
|
|
||||||
|
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
let DEBUG = false;
|
let DEBUG = false;
|
||||||
@ -197,7 +196,7 @@ export function setTurboTape(val: boolean) {
|
|||||||
turbotape = val;
|
turbotape = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
function run(pc?: address) {
|
function run(pc?: word) {
|
||||||
if (runTimer) {
|
if (runTimer) {
|
||||||
clearInterval(runTimer);
|
clearInterval(runTimer);
|
||||||
}
|
}
|
||||||
@ -364,7 +363,7 @@ export function doLoadText() {
|
|||||||
lines.forEach(function (line) {
|
lines.forEach(function (line) {
|
||||||
const parts = line.split(': ');
|
const parts = line.split(': ');
|
||||||
if (parts.length === 2) {
|
if (parts.length === 2) {
|
||||||
let addr: address = 0;
|
let addr: word = 0;
|
||||||
if (parts[0].length > 0) {
|
if (parts[0].length > 0) {
|
||||||
addr = parseInt(parts[0], 16);
|
addr = parseInt(parts[0], 16);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { TextPage } from './canvas1';
|
import { TextPage } from './canvas1';
|
||||||
import type { byte } from './types';
|
import type { byte } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
const LOC = {
|
const LOC = {
|
||||||
KBD: 0x10,
|
KBD: 0x10,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { memory } from './types';
|
import { memory } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { charset } from './roms/apple1char';
|
import { charset } from './roms/apple1char';
|
||||||
import type { byte } from './types';
|
import type { byte } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
0: A9 9 AA 20 EF FF E8 8A 4C 2 0
|
0: A9 9 AA 20 EF FF E8 8A 4C 2 0
|
||||||
|
@ -1,28 +1,40 @@
|
|||||||
import CPU6502 from '../cpu6502';
|
import { CPU6502, byte } from '@whscullin/cpu6502';
|
||||||
import { debug } from '../util';
|
import { debug } from '../util';
|
||||||
import { byte } from '../types';
|
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
const rom = [
|
const rom = [
|
||||||
0xa9, 0xaa, 0x20, 0xef, 0xff, 0xa9, 0x8d, 0x20, 0xef, 0xff, 0xa0, 0xff, 0xc8,
|
0xA9,0xAA,0x20,0xEF,0xFF,0xA9,0x8D,0x20,
|
||||||
0xad, 0x11, 0xd0, 0x10, 0xfb, 0xad, 0x10, 0xd0, 0x99, 0x00, 0x02, 0x20, 0xef,
|
0xEF,0xFF,0xA0,0xFF,0xC8,0xAD,0x11,0xD0,
|
||||||
0xff, 0xc9, 0x9b, 0xf0, 0xe1, 0xc9, 0x8d, 0xd0, 0xe9, 0xa2, 0xff, 0xa9, 0x00,
|
0x10,0xFB,0xAD,0x10,0xD0,0x99,0x00,0x02,
|
||||||
0x85, 0x24, 0x85, 0x25, 0x85, 0x26, 0x85, 0x27, 0xe8, 0xbd, 0x00, 0x02, 0xc9,
|
0x20,0xEF,0xFF,0xC9,0x9B,0xF0,0xE1,0xC9,
|
||||||
0xd2, 0xf0, 0x56, 0xc9, 0xd7, 0xf0, 0x35, 0xc9, 0xae, 0xf0, 0x27, 0xc9, 0x8d,
|
0x8D,0xD0,0xE9,0xA2,0xFF,0xA9,0x00,0x85,
|
||||||
0xf0, 0x20, 0xc9, 0xa0, 0xf0, 0xe8, 0x49, 0xb0, 0xc9, 0x0a, 0x90, 0x06, 0x69,
|
0x24,0x85,0x25,0x85,0x26,0x85,0x27,0xE8,
|
||||||
0x88, 0xc9, 0xfa, 0x90, 0xad, 0x0a, 0x0a, 0x0a, 0x0a, 0xa0, 0x04, 0x0a, 0x26,
|
0xBD,0x00,0x02,0xC9,0xD2,0xF0,0x56,0xC9,
|
||||||
0x24, 0x26, 0x25, 0x88, 0xd0, 0xf8, 0xf0, 0xcc, 0x4c, 0x1a, 0xff, 0xa5, 0x24,
|
0xD7,0xF0,0x35,0xC9,0xAE,0xF0,0x27,0xC9,
|
||||||
0x85, 0x26, 0xa5, 0x25, 0x85, 0x27, 0xb0, 0xbf, 0xa9, 0x40, 0x20, 0xcc, 0xc1,
|
0x8D,0xF0,0x20,0xC9,0xA0,0xF0,0xE8,0x49,
|
||||||
0x88, 0xa2, 0x00, 0xa1, 0x26, 0xa2, 0x10, 0x0a, 0x20, 0xdb, 0xc1, 0xd0, 0xfa,
|
0xB0,0xC9,0x0A,0x90,0x06,0x69,0x88,0xC9,
|
||||||
0x20, 0xf1, 0xc1, 0xa0, 0x1e, 0x90, 0xec, 0xa6, 0x28, 0xb0, 0x98, 0x20, 0xbc,
|
0xFA,0x90,0xAD,0x0A,0x0A,0x0A,0x0A,0xA0,
|
||||||
0xc1, 0xa9, 0x16, 0x20, 0xcc, 0xc1, 0x20, 0xbc, 0xc1, 0xa0, 0x1f, 0x20, 0xbf,
|
0x04,0x0A,0x26,0x24,0x26,0x25,0x88,0xD0,
|
||||||
0xc1, 0xb0, 0xf9, 0x20, 0xbf, 0xc1, 0xa0, 0x3a, 0xa2, 0x08, 0x48, 0x20, 0xbc,
|
0xF8,0xF0,0xCC,0x4C,0x1A,0xFF,0xA5,0x24,
|
||||||
0xc1, 0x68, 0x2a, 0xa0, 0x39, 0xca, 0xd0, 0xf5, 0x81, 0x26, 0x20, 0xf1, 0xc1,
|
0x85,0x26,0xA5,0x25,0x85,0x27,0xB0,0xBF,
|
||||||
0xa0, 0x35, 0x90, 0xea, 0xb0, 0xcd, 0x20, 0xbf, 0xc1, 0x88, 0xad, 0x81, 0xc0,
|
0xA9,0x40,0x20,0xCC,0xC1,0x88,0xA2,0x00,
|
||||||
0xc5, 0x29, 0xf0, 0xf8, 0x85, 0x29, 0xc0, 0x80, 0x60, 0x86, 0x28, 0xa0, 0x42,
|
0xA1,0x26,0xA2,0x10,0x0A,0x20,0xDB,0xC1,
|
||||||
0x20, 0xe0, 0xc1, 0xd0, 0xf9, 0x69, 0xfe, 0xb0, 0xf5, 0xa0, 0x1e, 0x20, 0xe0,
|
0xD0,0xFA,0x20,0xF1,0xC1,0xA0,0x1E,0x90,
|
||||||
0xc1, 0xa0, 0x2c, 0x88, 0xd0, 0xfd, 0x90, 0x05, 0xa0, 0x2f, 0x88, 0xd0, 0xfd,
|
0xEC,0xA6,0x28,0xB0,0x98,0x20,0xBC,0xC1,
|
||||||
0xbc, 0x00, 0xc0, 0xa0, 0x29, 0xca, 0x60, 0xa5, 0x26, 0xc5, 0x24, 0xa5, 0x27,
|
0xA9,0x16,0x20,0xCC,0xC1,0x20,0xBC,0xC1,
|
||||||
0xe5, 0x25, 0xe6, 0x26, 0xd0, 0x02, 0xe6, 0x27, 0x60,
|
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;
|
] as const;
|
||||||
|
|
||||||
export interface ACICallback {
|
export interface ACICallback {
|
||||||
|
3265
js/cpu6502.ts
3265
js/cpu6502.ts
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import { base64_decode, base64_encode } from './base64';
|
import { base64_decode, base64_encode } from './base64';
|
||||||
import { allocMemPages } from './util';
|
import { allocMemPages } from './util';
|
||||||
import type { byte } from './types';
|
import type { byte, memory } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
export interface RAMState {
|
export interface RAMState {
|
||||||
start: byte;
|
start: byte;
|
||||||
@ -20,7 +20,7 @@ export interface RAMState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class RAM {
|
export default class RAM {
|
||||||
mem: Uint8Array | byte[];
|
mem: memory;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private start_page: byte,
|
private start_page: byte,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { byte } from 'js/types';
|
import { byte } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
export default class Basic {
|
export default class Basic {
|
||||||
ram = [
|
ram = [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { byte } from 'js/types';
|
import { byte } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
export default class Bios {
|
export default class Bios {
|
||||||
rom = [
|
rom = [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { byte } from 'js/types';
|
import { byte } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
export default class EnhancedBasic {
|
export default class EnhancedBasic {
|
||||||
rom = [
|
rom = [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { byte } from 'js/types';
|
import { byte } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
export default class Krusader {
|
export default class Krusader {
|
||||||
rom = [
|
rom = [
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
* implied warranty.
|
* implied warranty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { address } from './types';
|
import type { word } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
export const SYMBOLS: Record<address, string> = {
|
export const SYMBOLS: Record<word, string> = {
|
||||||
0xd010: 'KBD',
|
0xd010: 'KBD',
|
||||||
0xd011: 'KBDCR',
|
0xd011: 'KBDCR',
|
||||||
0xd012: 'DSP',
|
0xd012: 'DSP',
|
||||||
|
43
js/types.ts
43
js/types.ts
@ -1,43 +0,0 @@
|
|||||||
/* Copyright 2023 Will Scullin <scullin@scullinsteel.com>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
||||||
* documentation for any purpose is hereby granted without fee, provided that
|
|
||||||
* the above copyright notice appear in all copies and that both that
|
|
||||||
* copyright notice and this permission notice appear in supporting
|
|
||||||
* documentation. No representations are made about the suitability of this
|
|
||||||
* software for any purpose. It is provided "as is" without express or
|
|
||||||
* implied warranty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type byte = number;
|
|
||||||
|
|
||||||
export type word = number;
|
|
||||||
|
|
||||||
export type address = word;
|
|
||||||
|
|
||||||
export type memory = Uint8Array | byte[];
|
|
||||||
|
|
||||||
export interface Memory {
|
|
||||||
/** Read a byte. */
|
|
||||||
read(page: byte, offset: byte): byte;
|
|
||||||
/** Write a byte. */
|
|
||||||
write(page: byte, offset: byte, value: byte): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A mapped region of memory. */
|
|
||||||
export interface MemoryPages extends Memory {
|
|
||||||
/** Start page. */
|
|
||||||
start(): byte;
|
|
||||||
/** End page, inclusive. */
|
|
||||||
end(): byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the members of a constant array as a type. Used as:
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* const SOME_VALUES = ['a', 'b', 1, 2] as const;
|
|
||||||
* type SomeValues = MemberOf<typeof SOME_VALUES>; // 'a' | 'b' | 1 | 2
|
|
||||||
*/
|
|
||||||
export type MemberOf<T extends ReadonlyArray<unknown>> =
|
|
||||||
T extends ReadonlyArray<infer E> ? E : never;
|
|
@ -9,11 +9,10 @@
|
|||||||
* implied warranty.
|
* implied warranty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import CPU6502 from 'js/cpu6502';
|
import { CPU6502, byte } from '@whscullin/cpu6502';
|
||||||
import { debug, toHex } from '../util';
|
import { debug, toHex } from '../util';
|
||||||
import Apple1IO from 'js/apple1io';
|
import Apple1IO from 'js/apple1io';
|
||||||
import { TextPage } from 'js/canvas1';
|
import { TextPage } from 'js/canvas1';
|
||||||
import { byte } from 'js/types';
|
|
||||||
|
|
||||||
// keycode: [plain, cntl, shift]
|
// keycode: [plain, cntl, shift]
|
||||||
|
|
||||||
|
@ -9,12 +9,12 @@
|
|||||||
* implied warranty.
|
* implied warranty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { byte, word } from './types';
|
import { byte, word } from '@whscullin/cpu6502';
|
||||||
|
|
||||||
const hex_digits = '0123456789ABCDEF';
|
const hex_digits = '0123456789ABCDEF';
|
||||||
const bin_digits = '01';
|
const bin_digits = '01';
|
||||||
|
|
||||||
export function allocMem(size: word) {
|
export function allocMem(size: word): Uint8Array | byte[] {
|
||||||
let result;
|
let result;
|
||||||
if (window.Uint8Array) {
|
if (window.Uint8Array) {
|
||||||
result = new Uint8Array(size);
|
result = new Uint8Array(size);
|
||||||
|
1253
package-lock.json
generated
1253
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,7 @@
|
|||||||
"webpack-dev-server": "^4.6.0"
|
"webpack-dev-server": "^4.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@whscullin/cpu6502": "file:submodules/cpu6502",
|
||||||
"micromodal": "^0.4.9"
|
"micromodal": "^0.4.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
submodules/cpu6502
Submodule
1
submodules/cpu6502
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 208e761911a0088a5bafbdbc2c82de8110a92992
|
@ -1,48 +0,0 @@
|
|||||||
import CPU6502, { FLAVOR_ROCKWELL_65C02 } from '../js/cpu6502';
|
|
||||||
// From https://github.com/Klaus2m5/6502_65C02_functional_tests
|
|
||||||
import Test6502 from './roms/6502test';
|
|
||||||
import Test65C02 from './roms/65C02test';
|
|
||||||
|
|
||||||
import { toHex } from '../js/util';
|
|
||||||
|
|
||||||
describe('CPU', function () {
|
|
||||||
let cpu: CPU6502;
|
|
||||||
let lastPC = 0;
|
|
||||||
let done = false;
|
|
||||||
|
|
||||||
function traceCB() {
|
|
||||||
const pc = cpu.getPC();
|
|
||||||
done = lastPC === pc;
|
|
||||||
lastPC = pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('6502', function () {
|
|
||||||
it('completes the test ROM', function () {
|
|
||||||
cpu = new CPU6502();
|
|
||||||
const test = new Test6502();
|
|
||||||
cpu.addPageHandler(test);
|
|
||||||
cpu.setPC(0x400);
|
|
||||||
|
|
||||||
do {
|
|
||||||
cpu.stepCyclesDebug(1000, traceCB);
|
|
||||||
} while (!done);
|
|
||||||
|
|
||||||
expect(toHex(lastPC)).toEqual(toHex(0x3469));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('65C02', function () {
|
|
||||||
it('completes the test ROM', function () {
|
|
||||||
cpu = new CPU6502({ flavor: FLAVOR_ROCKWELL_65C02 });
|
|
||||||
const test = new Test65C02();
|
|
||||||
cpu.addPageHandler(test);
|
|
||||||
cpu.setPC(0x400);
|
|
||||||
|
|
||||||
do {
|
|
||||||
cpu.stepCyclesDebug(1000, traceCB);
|
|
||||||
} while (!done);
|
|
||||||
|
|
||||||
expect(toHex(lastPC)).toEqual(toHex(0x24f1));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
3254
test/cpu6502.spec.ts
3254
test/cpu6502.spec.ts
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,29 +0,0 @@
|
|||||||
// From https://github.com/Klaus2m5/6502_65C02_functional_tests
|
|
||||||
|
|
||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import { MemoryPages, byte } from '../../js/types';
|
|
||||||
|
|
||||||
export default class Test6502 implements MemoryPages {
|
|
||||||
private data: Buffer;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.data = fs.readFileSync(path.join(__dirname, '6502_functional_test.bin'));
|
|
||||||
}
|
|
||||||
|
|
||||||
start = () => {
|
|
||||||
return 0x00;
|
|
||||||
};
|
|
||||||
|
|
||||||
end = () => {
|
|
||||||
return 0xff;
|
|
||||||
};
|
|
||||||
|
|
||||||
read = (page: byte, off: byte) => {
|
|
||||||
return this.data[page << 8 | off];
|
|
||||||
};
|
|
||||||
|
|
||||||
write = (page: byte, off: byte, val: byte) => {
|
|
||||||
this.data[page << 8 | off] = val;
|
|
||||||
};
|
|
||||||
}
|
|
Binary file not shown.
@ -1,29 +0,0 @@
|
|||||||
// From https://github.com/Klaus2m5/6502_65C02_functional_tests
|
|
||||||
|
|
||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import { MemoryPages, byte } from '../../js/types';
|
|
||||||
|
|
||||||
export default class Test65C02 implements MemoryPages {
|
|
||||||
private data: Buffer;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.data = fs.readFileSync(path.join(__dirname, '65C02_extended_opcodes_test.bin'));
|
|
||||||
}
|
|
||||||
|
|
||||||
start = () => {
|
|
||||||
return 0x00;
|
|
||||||
};
|
|
||||||
|
|
||||||
end = () => {
|
|
||||||
return 0xff;
|
|
||||||
};
|
|
||||||
|
|
||||||
read = (page: byte, off: byte) => {
|
|
||||||
return this.data[page << 8 | off];
|
|
||||||
};
|
|
||||||
|
|
||||||
write = (page: byte, off: byte, val: byte) => {
|
|
||||||
this.data[page << 8 | off] = val;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import { byte } from "../../js/types";
|
|
||||||
|
|
||||||
export const assertByte = (b: byte) => {
|
|
||||||
expect(b <= 0xff).toEqual(true);
|
|
||||||
expect(b >= 0x00).toEqual(true);
|
|
||||||
};
|
|
@ -1,56 +0,0 @@
|
|||||||
import { MemoryPages, byte } from "../../js/types";
|
|
||||||
import { assertByte } from "./asserts";
|
|
||||||
|
|
||||||
export class Program implements MemoryPages {
|
|
||||||
private data: Buffer;
|
|
||||||
|
|
||||||
constructor(private page: byte, code: byte[]) {
|
|
||||||
this.data = Buffer.from(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
return this.page;
|
|
||||||
}
|
|
||||||
|
|
||||||
end() {
|
|
||||||
return this.page;
|
|
||||||
}
|
|
||||||
|
|
||||||
read(page: byte, off: byte) {
|
|
||||||
assertByte(page);
|
|
||||||
assertByte(off);
|
|
||||||
return this.data[off];
|
|
||||||
}
|
|
||||||
|
|
||||||
write(_page: byte, _off: byte, _val: byte) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const bios = new Program(
|
|
||||||
0xff,
|
|
||||||
[
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x45, 0x4c, 0x4c,
|
|
||||||
0x4f, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
|
||||||
0x00, 0x04, 0x00, 0xff,
|
|
||||||
]
|
|
||||||
);
|
|
@ -1,34 +0,0 @@
|
|||||||
import { flags, CpuState } from "js/cpu6502";
|
|
||||||
import { byte } from "js/types";
|
|
||||||
import { toHex } from "js/util";
|
|
||||||
|
|
||||||
export const dumpStatusRegister = (sr: byte) =>
|
|
||||||
[
|
|
||||||
sr & flags.N ? "N" : "-",
|
|
||||||
sr & flags.V ? "V" : "-",
|
|
||||||
sr & flags.X ? "X" : "-",
|
|
||||||
sr & flags.B ? "B" : "-",
|
|
||||||
sr & flags.D ? "D" : "-",
|
|
||||||
sr & flags.I ? "I" : "-",
|
|
||||||
sr & flags.Z ? "Z" : "-",
|
|
||||||
sr & flags.C ? "C" : "-",
|
|
||||||
].join("");
|
|
||||||
|
|
||||||
const detail = !!process.env.JEST_DETAIL;
|
|
||||||
|
|
||||||
export function toReadableState(state: CpuState) {
|
|
||||||
if (detail) {
|
|
||||||
const { pc, sp, a, x, y, s } = state;
|
|
||||||
|
|
||||||
return {
|
|
||||||
pc: toHex(pc, 4),
|
|
||||||
sp: toHex(sp),
|
|
||||||
a: toHex(a),
|
|
||||||
x: toHex(x),
|
|
||||||
y: toHex(y),
|
|
||||||
s: dumpStatusRegister(s),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
import { MemoryPages, byte, word } from "js/types";
|
|
||||||
import { assertByte } from "./asserts";
|
|
||||||
|
|
||||||
export type Log = [address: word, value: byte, types: "read" | "write"];
|
|
||||||
export class TestMemory implements MemoryPages {
|
|
||||||
private data: Buffer;
|
|
||||||
private logging: boolean = false;
|
|
||||||
private log: Log[] = [];
|
|
||||||
|
|
||||||
constructor(private size: number) {
|
|
||||||
this.data = Buffer.alloc(size << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
end() {
|
|
||||||
return this.size - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
read(page: byte, off: byte) {
|
|
||||||
assertByte(page);
|
|
||||||
assertByte(off);
|
|
||||||
|
|
||||||
const val = this.data[(page << 8) | off];
|
|
||||||
if (this.logging) {
|
|
||||||
this.log.push([(page << 8) | off, val, "read"]);
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
write(page: byte, off: byte, val: byte) {
|
|
||||||
assertByte(page);
|
|
||||||
assertByte(off);
|
|
||||||
assertByte(val);
|
|
||||||
|
|
||||||
if (this.logging) {
|
|
||||||
this.log.push([(page << 8) | off, val, "write"]);
|
|
||||||
}
|
|
||||||
this.data[(page << 8) | off] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.log = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
logStart() {
|
|
||||||
this.log = [];
|
|
||||||
this.logging = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
logStop() {
|
|
||||||
this.logging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLog() {
|
|
||||||
return this.log;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user