mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-24 12:31:25 +00:00
atari8: fixes, faked .xex loading
This commit is contained in:
parent
c572834c8c
commit
33b2e92396
@ -850,7 +850,7 @@ export abstract class BaseMachinePlatform<T extends Machine> extends BaseDebugPl
|
||||
}
|
||||
|
||||
loadROM(title, data) {
|
||||
this.machine.loadROM(data);
|
||||
this.machine.loadROM(data, title);
|
||||
this.reset();
|
||||
}
|
||||
|
||||
|
@ -308,7 +308,7 @@ export abstract class BasicMachine extends BasicHeadlessMachine implements Sampl
|
||||
abstract sampleRate : number;
|
||||
overscan : boolean = false;
|
||||
rotate : number = 0;
|
||||
aspectRatio : number = 1.0;
|
||||
aspectRatio : number;
|
||||
|
||||
pixels : Uint32Array;
|
||||
audio : SampledAudioSink;
|
||||
|
@ -746,8 +746,9 @@ export function gtia_ntsc_to_rgb(val: number) {
|
||||
let cr = (val >> 4) & 15;
|
||||
let lm = val & 15;
|
||||
let crlv = cr ? color : 0;
|
||||
let phase = ((cr - 1) * 25 - 38) * (2 * Math.PI / 360);
|
||||
let y = 256 * bright * Math.pow((lm + 1) / 16, gamma);
|
||||
if (cr) lm += 1;
|
||||
let phase = ((cr - 1) * 25 - 25) * (2 * Math.PI / 360);
|
||||
let y = 256 * bright * Math.pow(lm / 16, gamma);
|
||||
let i = crlv * Math.cos(phase);
|
||||
let q = crlv * Math.sin(phase);
|
||||
var r = y + 0.956 * i + 0.621 * q;
|
||||
|
@ -563,7 +563,15 @@ export class AddressHeatMapView extends ProbeBitmapViewBase implements ProjectVi
|
||||
this.canvas.onclick = (e) => {
|
||||
var pos = getMousePos(this.canvas, e);
|
||||
var opaddr = Math.floor(pos.x) + Math.floor(pos.y) * 256;
|
||||
runToPC(opaddr & 0xffff);
|
||||
var lastpc = -1;
|
||||
var runpc = -1;
|
||||
this.redraw( (op,addr) => {
|
||||
if (runpc < 0 && lastpc >= 0 && addr == opaddr) {
|
||||
runpc = lastpc;
|
||||
}
|
||||
if (op == ProbeFlags.EXECUTE) lastpc = addr;
|
||||
});
|
||||
if (runpc >= 0) runToPC(runpc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { newPOKEYAudio, TssChannelAdapter } from "../common/audio";
|
||||
import { EmuState, Machine } from "../common/baseplatform";
|
||||
import { Machine } from "../common/baseplatform";
|
||||
import { MOS6502 } from "../common/cpu/MOS6502";
|
||||
import { AcceptsKeyInput, AcceptsPaddleInput, AcceptsROM, BasicScanlineMachine, FrameBased, Probeable, RasterFrameBased, TrapCondition, VideoSource } from "../common/devices";
|
||||
import { dumpRAM, EmuHalt, KeyFlags, Keys, makeKeycodeMap, newAddressDecoder, newKeyboardHandler } from "../common/emu";
|
||||
import { hex, lpad, lzgmini, rgb2bgr, safe_extend, stringToByteArray } from "../common/util";
|
||||
import { AcceptsKeyInput, AcceptsPaddleInput, AcceptsROM, BasicScanlineMachine, FrameBased, Probeable, TrapCondition, VideoSource } from "../common/devices";
|
||||
import { KeyFlags, Keys, makeKeycodeMap, newAddressDecoder, newKeyboardHandler } from "../common/emu";
|
||||
import { hex } from "../common/util";
|
||||
import { BaseWASIMachine } from "../common/wasmplatform";
|
||||
import { ANTIC, MODE_SHIFT } from "./chips/antic";
|
||||
import { CONSOL, GTIA, TRIG0 } from "./chips/gtia";
|
||||
@ -46,12 +46,11 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
cpuFrequency = 1789773;
|
||||
numTotalScanlines = 262;
|
||||
cpuCyclesPerLine = 114;
|
||||
canvasWidth = 348; // TODO?
|
||||
canvasWidth = 336;
|
||||
numVisibleScanlines = 224;
|
||||
aspectRatio = 240 / 172;
|
||||
aspectRatio = this.canvasWidth / this.numVisibleScanlines * 0.857;
|
||||
firstVisibleScanline = 16;
|
||||
firstVisibleClock = 44 * 2; // ... to 215 * 2
|
||||
// TODO: for 400/800/5200
|
||||
firstVisibleClock = (44 - 6) * 2; // ... to 215 * 2
|
||||
defaultROMSize = 0x8000;
|
||||
overscan = true;
|
||||
audioOversample = 4;
|
||||
@ -59,7 +58,6 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
|
||||
cpu: MOS6502;
|
||||
ram: Uint8Array;
|
||||
rom: Uint8Array;
|
||||
bios: Uint8Array;
|
||||
bus;
|
||||
audio_pokey;
|
||||
@ -73,6 +71,7 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
keycode = 0;
|
||||
cart_80 = false;
|
||||
cart_a0 = false;
|
||||
xexdata = null;
|
||||
// TODO: save/load vars
|
||||
|
||||
constructor() {
|
||||
@ -106,10 +105,12 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
[0xd800, 0xffff, 0xffff, (a) => { return this.bios[a - 0xd800]; }],
|
||||
]),
|
||||
write: newAddressDecoder([
|
||||
[0x0000, 0xbfff, 0xffff, (a, v) => { this.ram[a] = v; }],
|
||||
[0x0000, 0xbffa, 0xffff, (a, v) => { this.ram[a] = v; }],
|
||||
[0xbffb, 0xbfff, 0xffff, (a, v) => { this.ram[a] = v; this.initCartA(); }],
|
||||
[0xd000, 0xd0ff, 0x1f, (a, v) => { this.gtia.setReg(a, v); }],
|
||||
[0xd200, 0xd2ff, 0xf, (a, v) => { this.writePokey(a, v); }],
|
||||
[0xd400, 0xd4ff, 0xf, (a, v) => { this.antic.setReg(a, v); }],
|
||||
[0xd500, 0xd5ff, 0xff, (a, v) => { this.writeMapper(a, v); }],
|
||||
]),
|
||||
};
|
||||
}
|
||||
@ -119,11 +120,11 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
}
|
||||
|
||||
reset() {
|
||||
console.log(this.saveState());
|
||||
super.reset();
|
||||
this.antic.reset();
|
||||
this.gtia.reset();
|
||||
this.keycode = 0;
|
||||
if (this.xexdata) this.cart_a0 = true; // TODO
|
||||
}
|
||||
|
||||
read(a) {
|
||||
@ -197,8 +198,6 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
// update GTIA
|
||||
// get X coordinate within scanline
|
||||
let xofs = this.antic.h * 4 - this.firstVisibleClock;
|
||||
// correct for HSCROL
|
||||
if (this.antic.dliop & 0x10) xofs += (this.antic.regs[4] & 1) << 1;
|
||||
// GTIA tick functions
|
||||
let gtiatick1 = () => {
|
||||
this.gtia.clockPulse1();
|
||||
@ -209,8 +208,17 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
this.linergb[xofs++] = this.gtia.rgb;
|
||||
}
|
||||
// tick 4 GTIA clocks for each CPU/ANTIC cycle
|
||||
this.gtia.clockPulse4();
|
||||
// correct for HSCROL -- bias antic +2, bias gtia -1
|
||||
if ((this.antic.dliop & 0x10) && (this.antic.regs[4] & 1)) {
|
||||
xofs += 2;
|
||||
this.gtia.setBias(-1);
|
||||
} else {
|
||||
this.gtia.setBias(0);
|
||||
}
|
||||
let bp = MODE_SHIFT[this.antic.mode];
|
||||
if (bp < 8 || (xofs & 4) == 0) { this.gtia.an = this.antic.shiftout(); }
|
||||
let odd = this.antic.h & 1;
|
||||
if (bp < 8 || odd) { this.gtia.an = this.antic.shiftout(); }
|
||||
gtiatick1();
|
||||
if (bp == 1) { this.gtia.an = this.antic.shiftout(); }
|
||||
gtiatick2();
|
||||
@ -222,12 +230,12 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
}
|
||||
|
||||
loadState(state: any) {
|
||||
this.loadControlsState(state);
|
||||
this.cpu.loadState(state.c);
|
||||
this.ram.set(state.ram);
|
||||
this.antic.loadState(state.antic);
|
||||
this.gtia.loadState(state.gtia);
|
||||
this.irq_pokey.loadState(state.pokey);
|
||||
this.loadControlsState(state);
|
||||
this.lastdmabyte = state.lastdmabyte;
|
||||
this.keycode = state.keycode;
|
||||
}
|
||||
@ -240,7 +248,7 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
pokey: this.irq_pokey.saveState(),
|
||||
inputs: this.inputs.slice(0),
|
||||
lastdmabyte: this.lastdmabyte,
|
||||
keycode: this.keycode, // TODO: inputs?
|
||||
keycode: this.keycode,
|
||||
};
|
||||
}
|
||||
loadControlsState(state) {
|
||||
@ -300,9 +308,26 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
this.probe.logInterrupt(1);
|
||||
}
|
||||
|
||||
loadROM(rom: Uint8Array) {
|
||||
if (rom.length != 0x2000 && rom.length != 0x4000 && rom.length != 0x8000)
|
||||
throw new Error("Sorry, this platform can only load 8/16/32 KB cartridges at the moment.");
|
||||
loadROM(rom: Uint8Array, title: string) {
|
||||
// XEX file?
|
||||
if (title && title.toLowerCase().endsWith('.xex') && rom[0] == 0xff && rom[1] == 0xff) {
|
||||
// TODO: we fake a cartridge
|
||||
this.xexdata = rom;
|
||||
let cart = new Uint8Array(0x1000);
|
||||
cart.set([0x00, 0x01, 0x00, 0x04, 0x00, 0x01], 0xffa);
|
||||
this.loadCartridge(cart);
|
||||
} else {
|
||||
this.loadCartridge(rom);
|
||||
}
|
||||
}
|
||||
|
||||
loadCartridge(rom: Uint8Array) {
|
||||
// strip off header
|
||||
if (rom[0] == 0x43 && rom[1] == 0x41 && rom[2] == 0x52 && rom[3] == 0x54) {
|
||||
rom = rom.slice(16);
|
||||
}
|
||||
if (rom.length != 0x1000 && rom.length != 0x2000 && rom.length != 0x4000 && rom.length != 0x8000)
|
||||
throw new Error("Sorry, this platform can only load 4/8/16/32 KB cartridges at the moment.");
|
||||
// TODO: support other than 8 KB carts
|
||||
// support 4/8/16/32 KB carts
|
||||
let rom2 = new Uint8Array(0x8000);
|
||||
@ -310,9 +335,63 @@ export class Atari800 extends BasicScanlineMachine {
|
||||
rom2.set(rom, i);
|
||||
}
|
||||
this.cart_a0 = true; // TODO
|
||||
if (rom.length == 0x4000) { this.cart_80 = true; }
|
||||
this.cart_80 = rom.length == 0x4000;
|
||||
super.loadROM(rom2);
|
||||
}
|
||||
|
||||
writeMapper(addr:number, value:number) {
|
||||
if (addr == 0xff) {
|
||||
if (value == 0x80) this.cart_80 = false;
|
||||
if (value == 0xa0) this.cart_a0 = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
loadXEX(rom: Uint8Array) {
|
||||
let ofs = 2;
|
||||
let cart = this.ram;
|
||||
let cartofs = 0x100; // stub routine in stack page
|
||||
while (ofs < rom.length) {
|
||||
let start = rom[ofs+0] + rom[ofs+1] * 256;
|
||||
let end = rom[ofs+2] + rom[ofs+3] * 256;
|
||||
console.log('XEX', ofs, hex(start), hex(end));
|
||||
ofs += 4;
|
||||
for (let i=start; i<=end; i++) {
|
||||
this.ram[i] = rom[ofs++];
|
||||
}
|
||||
var runaddr = this.ram[0x2e0] + this.ram[0x2e1]*256;
|
||||
var initaddr = this.ram[0x2e2] + this.ram[0x2e3]*256;
|
||||
console.log('XEX run', hex(runaddr), 'init', hex(initaddr));
|
||||
if (initaddr) {
|
||||
cart[cartofs++] = 0x20;
|
||||
cart[cartofs++] = initaddr & 0xff;
|
||||
cart[cartofs++] = initaddr >> 8;
|
||||
}
|
||||
if (ofs > rom.length) throw new Error("Bad .XEX file format");
|
||||
}
|
||||
if (runaddr) {
|
||||
cart[cartofs++] = 0xa9; // lda #$a0
|
||||
cart[cartofs++] = 0xa0;
|
||||
cart[cartofs++] = 0x8d; // sta $d5ff (disable cart)
|
||||
cart[cartofs++] = 0xff;
|
||||
cart[cartofs++] = 0xd5;
|
||||
cart[cartofs++] = 0x4c; // jmp runaddr
|
||||
cart[cartofs++] = runaddr & 0xff;
|
||||
cart[cartofs++] = runaddr >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
initCartA() {
|
||||
//console.log('init', hex(this.cpu.getPC()));
|
||||
// disable cartridges and load XEX
|
||||
if (this.cpu.getPC() == 0xf17f) {
|
||||
if (this.xexdata) {
|
||||
this.loadXEX(this.xexdata);
|
||||
}
|
||||
//this.cart_80 = this.cart_a0 = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class Atari5200 extends Atari800 {
|
||||
|
@ -10,8 +10,8 @@ import { hex, lpad, safe_extend } from "../../common/util";
|
||||
// http://www.atarimuseum.com/videogames/consoles/5200/conv_to_5200.html
|
||||
// https://www.virtualdub.org/downloads/Altirra%20Hardware%20Reference%20Manual.pdf
|
||||
|
||||
const PF_LEFT = [0, 29, 21, 13];
|
||||
const PF_RIGHT = [0, 29 + 64, 21 + 80, 13 + 96];
|
||||
const PF_LEFT = [0, 25, 17, 9];
|
||||
const PF_RIGHT = [0, 25 + 64, 17 + 80, 9 + 96];
|
||||
|
||||
const DMACTL = 0;
|
||||
const CHACTL = 1;
|
||||
@ -38,8 +38,9 @@ const NMIST_CYCLE = 12;
|
||||
const NMI_CYCLE = 24;
|
||||
const WSYNC_CYCLE = 212;
|
||||
|
||||
const ANTIC_LEFT = 17; // gtia 34
|
||||
const ANTIC_RIGHT = 110; // gtia 221
|
||||
const ANTIC_LEFT = 17 - 4; // gtia 34, 4 cycle delay
|
||||
const ANTIC_RIGHT = 110 - 4; // gtia 221, 4 cycle delay
|
||||
const LAST_DMA_H = 105; // last DMA cycle
|
||||
|
||||
const MODE_LINES = [0, 0, 8, 10, 8, 16, 8, 16, 8, 4, 4, 2, 1, 2, 1, 1];
|
||||
// how many bits before DMA clock repeats?
|
||||
@ -203,9 +204,12 @@ export class ANTIC {
|
||||
|
||||
nextScreen(): number {
|
||||
let b = this.read(this.scanaddr);
|
||||
this.scanaddr = ((this.scanaddr + 1) & 0xfff) | (this.scanaddr & ~0xfff);
|
||||
this.incScanAddr();
|
||||
return b;
|
||||
}
|
||||
incScanAddr() {
|
||||
this.scanaddr = ((this.scanaddr + 1) & 0xfff) | (this.scanaddr & ~0xfff);
|
||||
}
|
||||
|
||||
dlDMAEnabled() { return this.regs[DMACTL] & 0b100000; }
|
||||
|
||||
@ -216,10 +220,10 @@ export class ANTIC {
|
||||
return this.dma_enabled && !this.linesleft;
|
||||
}
|
||||
isPlayerDMAEnabled() {
|
||||
return this.dma_enabled && this.regs[DMACTL] & 0b1000;
|
||||
return this.regs[DMACTL] & 0b1000;
|
||||
}
|
||||
isMissileDMAEnabled() {
|
||||
return this.dma_enabled && this.regs[DMACTL] & 0b1100;
|
||||
return this.regs[DMACTL] & 0b1100;
|
||||
}
|
||||
|
||||
clockPulse(): boolean {
|
||||
@ -280,7 +284,7 @@ export class ANTIC {
|
||||
}
|
||||
this.output = 0; // background color (TODO: only for blank lines)
|
||||
if (this.mode >= 2 && this.period) {
|
||||
let candma = this.h < 106;
|
||||
let candma = this.h <= LAST_DMA_H;
|
||||
this.dmaclock <<= 1;
|
||||
if (this.dmaclock & (1 << this.period)) {
|
||||
this.dmaclock |= 1;
|
||||
@ -289,13 +293,21 @@ export class ANTIC {
|
||||
if (this.h == this.right) { this.dmaclock &= ~1; this.dmaidx++; }
|
||||
if (this.dmaclock & 1) {
|
||||
if (this.mode < 8 && this.yofs == 0) { // only read chars on 1st line
|
||||
this.linebuf[this.dmaidx] = this.nextScreen(); // read char name
|
||||
if (candma) {
|
||||
this.linebuf[this.dmaidx] = this.nextScreen(); // read char name
|
||||
} else {
|
||||
this.incScanAddr();
|
||||
}
|
||||
did_dma = candma;
|
||||
}
|
||||
this.dmaidx++;
|
||||
} else if (this.dmaclock & 8) {
|
||||
this.ch = this.linebuf[this.dmaidx - 4 / this.period]; // latch char
|
||||
this.readBitmapData(); // read bitmap
|
||||
if (candma) {
|
||||
this.readBitmapData(); // read bitmap
|
||||
} else {
|
||||
if (this.mode >= 8) this.incScanAddr();
|
||||
}
|
||||
did_dma = candma;
|
||||
}
|
||||
this.output = this.h >= this.left + 3 && this.h <= this.right + 2 ? 4 : 0;
|
||||
|
@ -33,6 +33,8 @@ const P0PL = 0xc;
|
||||
export const TRIG0 = 0x10;
|
||||
export const CONSOL = 0x1f;
|
||||
|
||||
const HOFFSET = -9; // bias to account for antic->gtia delay
|
||||
|
||||
const PRIOR_TABLE : number[] = [
|
||||
0,1,2,3, 7,7,7,7, 8,8,8,8, 4,5,6,7, // 0001 - 0
|
||||
0,1,2,3, 7,7,7,7, 8,8,8,8, 4,5,6,7, // 0001
|
||||
@ -52,6 +54,13 @@ const PRIOR_TABLE : number[] = [
|
||||
2,3,4,5, 7,7,7,7, 8,8,8,8, 0,1,6,7, // 1000
|
||||
];
|
||||
|
||||
const MODE_9_LOOKUP = [
|
||||
COLPM0+0, COLPM0+1, COLPM0+2, COLPM0+3,
|
||||
COLPF0+0, COLPF0+1, COLPF0+2, COLPF0+3,
|
||||
COLBK, COLBK, COLBK, COLBK,
|
||||
COLPF0+0, COLPF0+1, COLPF0+2, COLPF0+3,
|
||||
]
|
||||
|
||||
export class GTIA {
|
||||
regs = new Uint8Array(0x20);
|
||||
readregs = new Uint8Array(0x20);
|
||||
@ -62,6 +71,9 @@ export class GTIA {
|
||||
an = 0;
|
||||
rgb = 0;
|
||||
pmcol = 0;
|
||||
gtiacol = 0;
|
||||
gtiacol2 = 0;
|
||||
hbias = HOFFSET;
|
||||
|
||||
reset() {
|
||||
this.regs.fill(0);
|
||||
@ -77,6 +89,11 @@ export class GTIA {
|
||||
}
|
||||
setReg(a: number, v: number) {
|
||||
switch (a) {
|
||||
case COLPM0: case COLPM0+1: case COLPM0+2: case COLPM0+3:
|
||||
case COLPF0: case COLPF0+1: case COLPF0+2: case COLPF0+3:
|
||||
case COLBK:
|
||||
v &= 0xfe; // bit 0 unused in color regs
|
||||
break;
|
||||
case HITCLR:
|
||||
this.readregs.fill(0, 0, 16);
|
||||
return;
|
||||
@ -93,6 +110,9 @@ export class GTIA {
|
||||
sync() {
|
||||
this.count = 0;
|
||||
}
|
||||
setBias(b: number) {
|
||||
this.hbias = HOFFSET + b;
|
||||
}
|
||||
updateGfx(h: number, data: number) {
|
||||
switch (h) {
|
||||
case 0:
|
||||
@ -104,32 +124,32 @@ export class GTIA {
|
||||
}
|
||||
}
|
||||
getPlayfieldColor(): number {
|
||||
switch (this.an) {
|
||||
// which GTIA mode?
|
||||
switch (this.regs[PRIOR] >> 6) {
|
||||
// normal mode
|
||||
case 0:
|
||||
return COLBK;
|
||||
case 4: case 5: case 6: case 7:
|
||||
return COLPF0 + this.an - 4;
|
||||
case 8:
|
||||
// combine PF2 hue and PF1 luminance
|
||||
return (this.regs[COLPF2] & 0xf0) | (this.regs[COLPF1] & 0x0f) | 0x100;
|
||||
switch (this.an) {
|
||||
case 0:
|
||||
return COLBK;
|
||||
case 4: case 5: case 6: case 7:
|
||||
return COLPF0 + this.an - 4;
|
||||
case 8:
|
||||
// combine PF2 hue and PF1 luminance
|
||||
return (this.regs[COLPF2] & 0xf0) | (this.regs[COLPF1] & 0x0f) | 0x100;
|
||||
}
|
||||
break;
|
||||
// mode 9 -- 16 luminances
|
||||
case 1:
|
||||
return (this.regs[COLBK] & 0xf0) | (this.gtiacol & 0xf) | 0x100;
|
||||
// mode 10 -- 9 colors from registers
|
||||
case 2:
|
||||
return MODE_9_LOOKUP[this.gtiacol];
|
||||
// mode 11 -- 16 hues
|
||||
case 3:
|
||||
return (this.regs[COLBK] & 0xf) | (this.gtiacol << 4) | 0x100;
|
||||
}
|
||||
return 0x100; // black
|
||||
}
|
||||
clockPulse1(): void {
|
||||
this.processPlayerMissile();
|
||||
this.clockPulse2();
|
||||
this.count++;
|
||||
}
|
||||
clockPulse2(): void {
|
||||
var col: number;
|
||||
if (this.pmcol >= 0) {
|
||||
col = this.pmcol;
|
||||
} else {
|
||||
let pf = this.getPlayfieldColor();
|
||||
col = pf & 0x100 ? pf & 0xff : this.regs[pf];
|
||||
}
|
||||
this.rgb = COLORS_RGBA[col];
|
||||
}
|
||||
anySpriteActive() {
|
||||
return this.shiftregs[0] | this.shiftregs[1] | this.shiftregs[2]
|
||||
| this.shiftregs[3] | this.shiftregs[4] | this.shiftregs[5]
|
||||
@ -144,6 +164,8 @@ export class GTIA {
|
||||
this.pmcol = -1;
|
||||
return;
|
||||
}
|
||||
// TODO: multiple color player enable
|
||||
// TODO: gtia, hi-res mode collisions
|
||||
// compute gfx and collisions for players/missiles
|
||||
let priobias = (this.regs[PRIOR] & 15) << 4; // TODO
|
||||
let topprio = PRIOR_TABLE[(this.an & 7) + 8 + priobias];
|
||||
@ -175,7 +197,7 @@ export class GTIA {
|
||||
this.readregs[M0PF + i] |= 1 << pfset;
|
||||
}
|
||||
this.readregs[M0PL + i] |= ppmask;
|
||||
let prio = PRIOR_TABLE[i + 4 + priobias];
|
||||
let prio = PRIOR_TABLE[i + priobias];
|
||||
if (prio < topprio) {
|
||||
topobj = i + 4;
|
||||
topprio = prio;
|
||||
@ -194,7 +216,7 @@ export class GTIA {
|
||||
shiftObject(i: number) {
|
||||
let bit = (this.shiftregs[i] & 0x80000000) != 0;
|
||||
this.shiftregs[i] <<= 1;
|
||||
if (this.regs[HPOSP0 + i] - 1 == this.count) {
|
||||
if (this.regs[HPOSP0 + i] + this.hbias == this.count) {
|
||||
this.triggerObject(i);
|
||||
}
|
||||
return bit;
|
||||
@ -221,6 +243,30 @@ export class GTIA {
|
||||
this.shiftregs[i] = data;
|
||||
}
|
||||
|
||||
clockPulse1(): void {
|
||||
this.processPlayerMissile();
|
||||
this.clockPulse2();
|
||||
this.count++;
|
||||
}
|
||||
|
||||
clockPulse2(): void {
|
||||
var col: number;
|
||||
if (this.pmcol >= 0) {
|
||||
col = this.pmcol;
|
||||
} else {
|
||||
let pf = this.getPlayfieldColor();
|
||||
col = pf & 0x100 ? pf & 0xff : this.regs[pf];
|
||||
}
|
||||
this.rgb = COLORS_RGBA[col];
|
||||
// TODO: hires modes return 8, so other modes wont work
|
||||
this.gtiacol2 = (this.gtiacol2 << 1) | (this.an >> 3);
|
||||
}
|
||||
|
||||
clockPulse4() {
|
||||
// latch GTIA buffer
|
||||
this.gtiacol = this.gtiacol2 & 15;
|
||||
}
|
||||
|
||||
static stateToLongString(state): string {
|
||||
let s = ''
|
||||
s += `X: ${lpad(state.count, 3)} ANTIC: ${hex(state.an, 1)} PM: ${hex(state.pmcol, 3)}\n`;
|
||||
|
@ -195,6 +195,7 @@ class Atari5200Platform extends Atari800Platform {
|
||||
///
|
||||
|
||||
PLATFORMS['atari8-800.xlmame'] = Atari800MAMEPlatform
|
||||
PLATFORMS['atari8-800xl.mame'] = Atari800MAMEPlatform // for dithertron
|
||||
PLATFORMS['atari8-5200.mame'] = Atari5200MAMEPlatform
|
||||
PLATFORMS['atari8-800.xlwasm'] = Atari800WASMPlatform
|
||||
PLATFORMS['atari8-800'] = Atari800Platform
|
||||
|
@ -367,7 +367,7 @@ describe('Platform Replay', () => {
|
||||
});
|
||||
});
|
||||
it('Should run atari5200', async () => {
|
||||
await testPlatform('atari8-5200', 'acid5200.rom', 1000, (platform, frameno) => {
|
||||
await testPlatform('atari8-5200', 'acid5200.rom', 1100, (platform, frameno) => {
|
||||
if (frameno == 999) {
|
||||
let s = '';
|
||||
for (let i=0; i<40; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user