Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
whscullin committed Jan 4, 2025
1 parent b7a575a commit e72765c
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 75 deletions.
35 changes: 22 additions & 13 deletions js/apple2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class Apple2 implements Restorable<State>, DebuggerContainer {

private io: Apple2IO;
private mmu: MMU | undefined;
private ram: [RAM, RAM, RAM] | undefined;
private ram: RAM[] | undefined;
private characterRom: rom;
private rom: ROM;

Expand Down Expand Up @@ -113,10 +113,26 @@ export class Apple2 implements Restorable<State>, DebuggerContainer {
this.rom = new Apple2ROM();
this.characterRom = characterRom;

this.gr = new LoresPage(this.vm, 1, this.characterRom, options.e);
this.gr2 = new LoresPage(this.vm, 2, this.characterRom, options.e);
this.hgr = new HiresPage(this.vm, 1);
this.hgr2 = new HiresPage(this.vm, 2);
this.ram = [new RAM(0x00, 0xbf)];
if (options.e) {
this.ram.push(new RAM(0x00, 0xbf));
}
this.gr = new LoresPage(
this.vm,
1,
this.ram,
this.characterRom,
options.e
);
this.gr2 = new LoresPage(
this.vm,
2,
this.ram,
this.characterRom,
options.e
);
this.hgr = new HiresPage(this.vm, 1, this.ram);
this.hgr2 = new HiresPage(this.vm, 2, this.ram);
this.io = new Apple2IO(this.cpu, this.vm);
this.tick = options.tick;

Expand All @@ -129,23 +145,16 @@ export class Apple2 implements Restorable<State>, DebuggerContainer {
this.hgr,
this.hgr2,
this.io,
this.ram,
this.rom
);
this.cpu.addPageHandler(this.mmu);
} else {
this.ram = [
new RAM(0x00, 0x03),
new RAM(0x0c, 0x1f),
new RAM(0x60, 0xbf),
];

this.cpu.addPageHandler(this.ram[0]);
this.cpu.addPageHandler(this.gr);
this.cpu.addPageHandler(this.gr2);
this.cpu.addPageHandler(this.ram[1]);
this.cpu.addPageHandler(this.hgr);
this.cpu.addPageHandler(this.hgr2);
this.cpu.addPageHandler(this.ram[2]);
this.cpu.addPageHandler(this.io);
this.cpu.addPageHandler(this.rom);
}
Expand Down
26 changes: 18 additions & 8 deletions js/canvas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { byte, Color, memory, MemoryPages, rom } from './types';
import { allocMemPages } from './util';
import RAM from './ram';
import {
GraphicsState,
HiresPage,
Expand Down Expand Up @@ -106,6 +106,7 @@ export class LoresPage2D implements LoresPage {
private _buffer: memory[] = [];
private _refreshing = false;
private _blink = false;
private _blinkInterval: ReturnType<typeof setInterval> | undefined;

private highColorTextMode = false;

Expand All @@ -115,13 +116,16 @@ export class LoresPage2D implements LoresPage {
constructor(
private vm: VideoModes,
private page: pageNo,
private readonly charset: rom,
private ram: RAM[],
private charset: rom,
private readonly e: boolean
) {
this.imageData = this.vm.context.createImageData(560, 192);
this.imageData.data.fill(0xff);
this._buffer[0] = allocMemPages(0x4);
this._buffer[1] = allocMemPages(0x4);
const start = 0x4 * this.page;
const end = start + 0x4;
this._buffer[0] = this.ram[0].getBuffer(start, end);
this._buffer[1] = this.ram[1]?.getBuffer(start, end);

this.vm.setLoresPage(page, this);
}
Expand Down Expand Up @@ -427,7 +431,9 @@ export class LoresPage2D implements LoresPage {
}

start() {
setInterval(() => this.blink(), 267);
if (!this._blinkInterval) {
this._blinkInterval = setInterval(() => this.blink(), 267);
}
return this._start();
}

Expand Down Expand Up @@ -526,12 +532,16 @@ export class HiresPage2D implements HiresPage {

constructor(
private vm: VideoModes,
private page: pageNo
private page: pageNo,
private ram: RAM[]
) {
this.imageData = this.vm.context.createImageData(560, 192);
this.imageData.data.fill(0xff);
this._buffer[0] = allocMemPages(0x20);
this._buffer[1] = allocMemPages(0x20);

const start = 0x20 * this.page;
const end = start + 0x20;
this._buffer[0] = this.ram[0].getBuffer(start, end);
this._buffer[1] = this.ram[1]?.getBuffer(start, end);

this.vm.setHiresPage(page, this);
}
Expand Down
27 changes: 19 additions & 8 deletions js/gl.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { byte, Color, memory, MemoryPages, rom } from './types';
import { allocMemPages } from './util';

import { screenEmu } from 'apple2shader';

Expand All @@ -13,6 +12,7 @@ import {
bank,
pageNo,
} from './videomodes';
import RAM from './ram';

// Color constants
const whiteCol: Color = [255, 255, 255];
Expand All @@ -39,20 +39,25 @@ export class LoresPageGL implements LoresPage {
private _buffer: memory[] = [];
private _refreshing = false;
private _blink = false;
private _blinkInterval: ReturnType<typeof setInterval> | undefined;

dirty: Region = { ...notDirty };
imageData: ImageData;

constructor(
private vm: VideoModes,
private page: pageNo,
private readonly charset: rom,
private ram: RAM[],
private charset: rom,
private readonly e: boolean
) {
this.imageData = this.vm.context.createImageData(560, 192);
this.imageData.data.fill(0xff);
this._buffer[0] = allocMemPages(0x4);
this._buffer[1] = allocMemPages(0x4);

const start = 0x4 * this.page;
const end = start + 0x4;
this._buffer[0] = this.ram[0].getBuffer(start, end);
this._buffer[1] = this.ram[1]?.getBuffer(start, end);

this.vm.setLoresPage(page, this);
}
Expand Down Expand Up @@ -293,7 +298,9 @@ export class LoresPageGL implements LoresPage {
}

start() {
setInterval(() => this.blink(), 267);
if (!this._blinkInterval) {
this._blinkInterval = setInterval(() => this.blink(), 267);
}
return this._start();
}

Expand Down Expand Up @@ -406,12 +413,16 @@ export class HiresPageGL implements HiresPage {

constructor(
private vm: VideoModes,
private page: pageNo
private page: pageNo,
private ram: RAM[]
) {
this.imageData = this.vm.context.createImageData(560, 192);
this.imageData.data.fill(0xff);
this._buffer[0] = allocMemPages(0x20);
this._buffer[1] = allocMemPages(0x20);

const start = 0x20 * this.page;
const end = start + 0x20;
this._buffer[0] = this.ram[0].getBuffer(start, end);
this._buffer[1] = this.ram[1]?.getBuffer(start, end);

this.vm.setHiresPage(page, this);
}
Expand Down
74 changes: 35 additions & 39 deletions js/mmu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CPU6502 } from '@whscullin/cpu6502';
import { CPU6502, MemoryPages } from '@whscullin/cpu6502';
import RAM, { RAMState } from './ram';
import ROM, { ROMState } from './roms/rom';
import { debug } from './util';
Expand Down Expand Up @@ -140,10 +140,7 @@ export interface MMUState {
page2: boolean;
hires: boolean;

mem00_01: [RAMState, RAMState];
mem02_03: [RAMState, RAMState];
mem0C_1F: [RAMState, RAMState];
mem60_BF: [RAMState, RAMState];
mem00_BF: [RAMState, RAMState];
memD0_DF: [ROMState, RAMState, RAMState, RAMState, RAMState];
memE0_FF: [ROMState, RAMState, RAMState];
}
Expand Down Expand Up @@ -182,14 +179,14 @@ export default class MMU implements Memory, Restorable<MMUState> {
private auxRom = new AuxRom(this, this.rom);

// These fields represent the bank-switched memory ranges.
private mem00_01 = [new RAM(0x0, 0x1), new RAM(0x0, 0x1)];
private mem02_03 = [new RAM(0x2, 0x3), new RAM(0x2, 0x3)];
private mem04_07 = [this.lores1.bank0(), this.lores1.bank1()];
private mem08_0B = [this.lores2.bank0(), this.lores2.bank1()];
private mem0C_1F = [new RAM(0xc, 0x1f), new RAM(0xc, 0x1f)];
private mem20_3F = [this.hires1.bank0(), this.hires1.bank1()];
private mem40_5F = [this.hires2.bank0(), this.hires2.bank1()];
private mem60_BF = [new RAM(0x60, 0xbf), new RAM(0x60, 0xbf)];
private mem00_01: MemoryPages[];
private mem02_03: MemoryPages[];
private mem04_07: MemoryPages[];
private mem08_0B: MemoryPages[];
private mem0C_1F: MemoryPages[];
private mem20_3F: MemoryPages[];
private mem40_5F: MemoryPages[];
private mem60_BF: MemoryPages[];
private memC0_C0 = [this.switches];
private memC1_CF = [this.io, this.auxRom];
private memD0_DF: [ROM, RAM, RAM, RAM, RAM] = [
Expand All @@ -213,8 +210,30 @@ export default class MMU implements Memory, Restorable<MMUState> {
private readonly hires1: HiresPage,
private readonly hires2: HiresPage,
private readonly io: Apple2IO,
private readonly ram: RAM[],
private readonly rom: ROM
) {
this.mem00_01 = [
new RAM(0x0, 0x1, this.ram[0]),
new RAM(0x0, 0x1, this.ram[1]),
];
this.mem02_03 = [
new RAM(0x2, 0x3, this.ram[0]),
new RAM(0x2, 0x3, this.ram[1]),
];
this.mem04_07 = [this.lores1.bank0(), this.lores1.bank1()];
this.mem08_0B = [this.lores2.bank0(), this.lores2.bank1()];
this.mem0C_1F = [
new RAM(0xc, 0x1f, this.ram[0]),
new RAM(0xc, 0x1f, this.ram[1]),
];
this.mem20_3F = [this.hires1.bank0(), this.hires1.bank1()];
this.mem40_5F = [this.hires2.bank0(), this.hires2.bank1()];
this.mem60_BF = [
new RAM(0x60, 0xbf, this.ram[0]),
new RAM(0x60, 0xbf, this.ram[1]),
];

/*
* Initialize read/write banks
*/
Expand Down Expand Up @@ -789,8 +808,6 @@ export default class MMU implements Memory, Restorable<MMUState> {
}

public start() {
this.lores1.start();
this.lores2.start();
return 0x00;
}

Expand Down Expand Up @@ -881,22 +898,7 @@ export default class MMU implements Memory, Restorable<MMUState> {
page2: this._page2,
hires: this._hires,

mem00_01: [
this.mem00_01[0].getState(),
this.mem00_01[1].getState(),
],
mem02_03: [
this.mem02_03[0].getState(),
this.mem02_03[1].getState(),
],
mem0C_1F: [
this.mem0C_1F[0].getState(),
this.mem0C_1F[1].getState(),
],
mem60_BF: [
this.mem60_BF[0].getState(),
this.mem60_BF[1].getState(),
],
mem00_BF: [this.ram[0].getState(), this.ram[1].getState()],
memD0_DF: [
this.memD0_DF[0].getState(),
this.memD0_DF[1].getState(),
Expand Down Expand Up @@ -930,14 +932,8 @@ export default class MMU implements Memory, Restorable<MMUState> {
this._page2 = state.page2;
this._hires = state.hires;

this.mem00_01[0].setState(state.mem00_01[0]);
this.mem00_01[1].setState(state.mem00_01[1]);
this.mem02_03[0].setState(state.mem02_03[0]);
this.mem02_03[1].setState(state.mem02_03[1]);
this.mem0C_1F[0].setState(state.mem0C_1F[0]);
this.mem0C_1F[1].setState(state.mem0C_1F[1]);
this.mem60_BF[0].setState(state.mem60_BF[0]);
this.mem60_BF[1].setState(state.mem60_BF[1]);
this.ram[0].setState(state.mem00_BF[0]);
this.ram[1].setState(state.mem00_BF[1]);
this.memD0_DF[0].setState(state.memD0_DF[0]);
this.memD0_DF[1].setState(state.memD0_DF[1]);
this.memD0_DF[2].setState(state.memD0_DF[2]);
Expand Down
15 changes: 13 additions & 2 deletions js/ram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ export default class RAM implements Memory, Restorable<RAMState> {
private end_page: byte;
private mem: memory;

constructor(sp: byte, ep: byte) {
constructor(sp: byte, ep: byte, base?: RAM) {
this.start_page = sp;
this.end_page = ep;

this.mem = allocMemPages(ep - sp + 1);
if (base) {
this.mem = base.getBuffer(sp, ep);
} else {
this.mem = allocMemPages(ep - sp + 1);
}
}

public start(): byte {
Expand Down Expand Up @@ -47,4 +51,11 @@ export default class RAM implements Memory, Restorable<RAMState> {
public setState(state: RAMState) {
this.mem = new Uint8Array(state.mem);
}

public getBuffer(start: byte, end: byte): memory {
return this.mem.subarray(
start << (8 - this.start_page),
end << (8 - this.start_page)
);
}
}
9 changes: 7 additions & 2 deletions test/js/canvas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { VideoPage } from 'js/videomodes';
import { LoresPage2D, HiresPage2D, VideoModes2D } from 'js/canvas';
import apple2enh_char from 'js/roms/character/apple2enh_char';
import { createImageFromImageData } from 'test/util/image';
import RAM from 'js/ram';

function checkImageData(page: VideoPage) {
page.refresh();
Expand All @@ -17,11 +18,13 @@ describe('canvas', () => {
let canvas: HTMLCanvasElement;
let lores1: LoresPage2D;
let vm: VideoModes2D;
let ram: RAM[];

beforeEach(() => {
canvas = document.createElement('canvas');
vm = new VideoModes2D(canvas, true);
lores1 = new LoresPage2D(vm, 1, apple2enh_char, true);
ram = [new RAM(0x00, 0xbf), new RAM(0x00, 0xbf)];
lores1 = new LoresPage2D(vm, 1, ram, apple2enh_char, true);
vm.reset();
vm.hires(false);
});
Expand Down Expand Up @@ -183,11 +186,13 @@ describe('canvas', () => {
let canvas: HTMLCanvasElement;
let hires1: HiresPage2D;
let vm: VideoModes2D;
let ram: RAM[];

beforeEach(() => {
canvas = document.createElement('canvas');
vm = new VideoModes2D(canvas, true);
hires1 = new HiresPage2D(vm, 1);
ram = [new RAM(0x00, 0xbf), new RAM(0x00, 0xbf)];
hires1 = new HiresPage2D(vm, 1, ram);
vm.reset();
vm.hires(true);
});
Expand Down
Loading

0 comments on commit e72765c

Please sign in to comment.