mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-01-02 23:30:21 +00:00
atari8: fixed VSCROL, pokey freq, performance
This commit is contained in:
parent
9f1c5377b3
commit
30342d2618
@ -202,7 +202,7 @@ export var POKEYDeviceChannel = function() {
|
|||||||
|
|
||||||
this.setSampleRate = function (rate) {
|
this.setSampleRate = function (rate) {
|
||||||
sampleRate = rate;
|
sampleRate = rate;
|
||||||
baseDelta = FREQ_17_EXACT / rate / 1.2; // TODO?
|
baseDelta = FREQ_17_EXACT / rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateValues(addr) {
|
function updateValues(addr) {
|
||||||
|
@ -61,7 +61,7 @@ const linesPerFrame = 262;
|
|||||||
const numVisibleLines = 258-16;
|
const numVisibleLines = 258-16;
|
||||||
const colorClocksPerLine = 454; // 456?
|
const colorClocksPerLine = 454; // 456?
|
||||||
const colorClocksPreDMA = 28;
|
const colorClocksPreDMA = 28;
|
||||||
const audioOversample = 4;
|
const audioOversample = 2;
|
||||||
const audioSampleRate = linesPerFrame*60*audioOversample;
|
const audioSampleRate = linesPerFrame*60*audioOversample;
|
||||||
|
|
||||||
// TIA chip
|
// TIA chip
|
||||||
|
@ -53,7 +53,7 @@ export class Atari800 extends BasicScanlineMachine {
|
|||||||
firstVisibleClock = (44 - 6) * 2; // ... to 215 * 2
|
firstVisibleClock = (44 - 6) * 2; // ... to 215 * 2
|
||||||
defaultROMSize = 0x8000;
|
defaultROMSize = 0x8000;
|
||||||
overscan = true;
|
overscan = true;
|
||||||
audioOversample = 4;
|
audioOversample = 2;
|
||||||
sampleRate = this.numTotalScanlines * 60 * this.audioOversample;
|
sampleRate = this.numTotalScanlines * 60 * this.audioOversample;
|
||||||
run_address = -1;
|
run_address = -1;
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ export class ANTIC {
|
|||||||
ch: number = 0; // char read
|
ch: number = 0; // char read
|
||||||
linesleft: number = 0; // # of lines left in mode
|
linesleft: number = 0; // # of lines left in mode
|
||||||
yofs: number = 0; // yofs fine
|
yofs: number = 0; // yofs fine
|
||||||
|
isfirstline: boolean = false;
|
||||||
v: number = 0; // vertical scanline #
|
v: number = 0; // vertical scanline #
|
||||||
h: number = 0; // horizontal color clock
|
h: number = 0; // horizontal color clock
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ export class ANTIC {
|
|||||||
dmaidx: number = 0;
|
dmaidx: number = 0;
|
||||||
output: number = 0;
|
output: number = 0;
|
||||||
dramrefresh = false;
|
dramrefresh = false;
|
||||||
vscroll = 0;
|
in_vscroll = 0;
|
||||||
|
|
||||||
constructor(readfn, nmifn) {
|
constructor(readfn, nmifn) {
|
||||||
this.read = readfn; // bus read function
|
this.read = readfn; // bus read function
|
||||||
@ -159,23 +160,24 @@ export class ANTIC {
|
|||||||
//console.log('scanaddr', hex(this.scanaddr));
|
//console.log('scanaddr', hex(this.scanaddr));
|
||||||
}
|
}
|
||||||
this.startaddr = this.scanaddr;
|
this.startaddr = this.scanaddr;
|
||||||
}
|
// horiz scroll
|
||||||
// horiz scroll
|
let effwidth = this.regs[DMACTL] & 3;
|
||||||
let effwidth = this.regs[DMACTL] & 3;
|
let hscroll = (this.dliop & 0x10) ? (this.regs[HSCROL] & 15) >> 1 : 0;
|
||||||
let hscroll = (this.dliop & 0x10) ? (this.regs[HSCROL] & 15) >> 1 : 0;
|
if ((this.dliop & 0x10) && effwidth < 3) effwidth++;
|
||||||
if ((this.dliop & 0x10) && effwidth < 3) effwidth++;
|
this.left = PF_LEFT[effwidth] + hscroll;
|
||||||
this.left = PF_LEFT[effwidth] + hscroll;
|
this.right = PF_RIGHT[effwidth] + hscroll;
|
||||||
this.right = PF_RIGHT[effwidth] + hscroll;
|
// vertical scroll
|
||||||
// vertical scroll
|
let vscrol = this.regs[VSCROL] & 0xf;
|
||||||
let vscrol = this.regs[VSCROL] & 0xf;
|
if ((this.dliop & 0x20) ^ this.in_vscroll) {
|
||||||
if ((this.dliop & 0x20) ^ this.vscroll) {
|
if (this.in_vscroll) {
|
||||||
if (this.vscroll) {
|
this.linesleft = vscrol+1; // exiting
|
||||||
this.linesleft -= vscrol;
|
} else {
|
||||||
} else {
|
this.linesleft -= vscrol; // entering
|
||||||
this.linesleft -= vscrol;
|
this.yofs += vscrol;
|
||||||
this.yofs += vscrol;
|
}
|
||||||
|
this.linesleft &= 0xf;
|
||||||
|
this.in_vscroll ^= 0x20;
|
||||||
}
|
}
|
||||||
this.vscroll ^= 0x20;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +185,7 @@ export class ANTIC {
|
|||||||
if (this.linesleft > 0) {
|
if (this.linesleft > 0) {
|
||||||
this.linesleft--;
|
this.linesleft--;
|
||||||
this.yofs++;
|
this.yofs++;
|
||||||
|
this.isfirstline = false;
|
||||||
if (this.mode >= 8 && this.linesleft) {
|
if (this.mode >= 8 && this.linesleft) {
|
||||||
this.scanaddr = this.startaddr; // reset line addr
|
this.scanaddr = this.startaddr; // reset line addr
|
||||||
}
|
}
|
||||||
@ -254,6 +257,7 @@ export class ANTIC {
|
|||||||
this.mode = op & 0xf;
|
this.mode = op & 0xf;
|
||||||
this.dliop = op;
|
this.dliop = op;
|
||||||
this.yofs = 0;
|
this.yofs = 0;
|
||||||
|
this.isfirstline = true;
|
||||||
did_dma = true;
|
did_dma = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -265,7 +269,7 @@ export class ANTIC {
|
|||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
case 7:
|
case 7:
|
||||||
if (this.isPlayfieldDMAEnabled() && this.yofs == 0 && (this.jmp || this.lms)) {
|
if (this.isPlayfieldDMAEnabled() && this.isfirstline && (this.jmp || this.lms)) {
|
||||||
if (this.h == 6) this.dlarg_lo = this.nextInsn();
|
if (this.h == 6) this.dlarg_lo = this.nextInsn();
|
||||||
if (this.h == 7) this.dlarg_hi = this.nextInsn();
|
if (this.h == 7) this.dlarg_hi = this.nextInsn();
|
||||||
did_dma = true;
|
did_dma = true;
|
||||||
@ -273,7 +277,7 @@ export class ANTIC {
|
|||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
// TODO? is this at cycle 8?
|
// TODO? is this at cycle 8?
|
||||||
if (this.yofs == 0) {
|
if (this.isfirstline) {
|
||||||
this.processDLIEntry();
|
this.processDLIEntry();
|
||||||
}
|
}
|
||||||
if (this.dliop & 0x80) { // TODO: what if DLI disabled?
|
if (this.dliop & 0x80) { // TODO: what if DLI disabled?
|
||||||
@ -299,7 +303,7 @@ export class ANTIC {
|
|||||||
if (this.h == this.left) { this.dmaclock |= 1; this.dmaidx = 0; }
|
if (this.h == this.left) { this.dmaclock |= 1; this.dmaidx = 0; }
|
||||||
if (this.h == this.right) { this.dmaclock &= ~1; this.dmaidx++; }
|
if (this.h == this.right) { this.dmaclock &= ~1; this.dmaidx++; }
|
||||||
if (this.dmaclock & 1) {
|
if (this.dmaclock & 1) {
|
||||||
if (this.mode < 8 && this.yofs == 0) { // only read chars on 1st line
|
if (this.mode < 8 && this.isfirstline) { // only read chars on 1st line
|
||||||
if (candma) {
|
if (candma) {
|
||||||
this.linebuf[this.dmaidx] = this.nextScreen(); // read char name
|
this.linebuf[this.dmaidx] = this.nextScreen(); // read char name
|
||||||
} else {
|
} else {
|
||||||
|
@ -65,7 +65,6 @@ export class GTIA {
|
|||||||
regs = new Uint8Array(0x20);
|
regs = new Uint8Array(0x20);
|
||||||
readregs = new Uint8Array(0x20);
|
readregs = new Uint8Array(0x20);
|
||||||
shiftregs = new Uint32Array(8);
|
shiftregs = new Uint32Array(8);
|
||||||
priortab = new Uint8Array(12);
|
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
an = 0;
|
an = 0;
|
||||||
@ -159,20 +158,37 @@ export class GTIA {
|
|||||||
return 0x100; // black
|
return 0x100; // black
|
||||||
}
|
}
|
||||||
anySpriteActive() {
|
anySpriteActive() {
|
||||||
return this.shiftregs[0] | this.shiftregs[1] | this.shiftregs[2]
|
return this.shiftregs[0] || this.shiftregs[1] || this.shiftregs[2]
|
||||||
| this.shiftregs[3] | this.shiftregs[4] | this.shiftregs[5]
|
|| this.shiftregs[3] || this.shiftregs[4] || this.shiftregs[5]
|
||||||
| this.shiftregs[6] | this.shiftregs[7];
|
|| this.shiftregs[6] || this.shiftregs[7];
|
||||||
}
|
}
|
||||||
processPlayerMissile() {
|
processPlayerMissile() {
|
||||||
// no p/m gfx, no collisions in blank area, but shift and trigger anyway
|
// no p/m gfx, just evaluate horiz. triggers
|
||||||
if (this.an == 2 || !this.anySpriteActive()) {
|
if (!this.anySpriteActive()) {
|
||||||
for (let i = 0; i < 8; i++) {
|
this.evalTrigger(0);
|
||||||
this.shiftObject(i);
|
this.evalTrigger(1);
|
||||||
}
|
this.evalTrigger(2);
|
||||||
|
this.evalTrigger(3);
|
||||||
|
this.evalTrigger(4);
|
||||||
|
this.evalTrigger(5);
|
||||||
|
this.evalTrigger(6);
|
||||||
|
this.evalTrigger(7);
|
||||||
|
this.pmcol = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// no collisions in blank area, but shift and trigger anyway
|
||||||
|
if (this.an == 2) {
|
||||||
|
this.shiftObject(0);
|
||||||
|
this.shiftObject(1);
|
||||||
|
this.shiftObject(2);
|
||||||
|
this.shiftObject(3);
|
||||||
|
this.shiftObject(4);
|
||||||
|
this.shiftObject(5);
|
||||||
|
this.shiftObject(6);
|
||||||
|
this.shiftObject(7);
|
||||||
this.pmcol = -1;
|
this.pmcol = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: multiple color player enable
|
|
||||||
// TODO: gtia, hi-res mode collisions
|
// TODO: gtia, hi-res mode collisions
|
||||||
// compute gfx and collisions for players/missiles
|
// compute gfx and collisions for players/missiles
|
||||||
let priobias = (this.regs[PRIOR] & 15) << 4; // TODO
|
let priobias = (this.regs[PRIOR] & 15) << 4; // TODO
|
||||||
@ -203,7 +219,9 @@ export class GTIA {
|
|||||||
this.readregs[M0PF + i] |= 1 << pfset;
|
this.readregs[M0PF + i] |= 1 << pfset;
|
||||||
}
|
}
|
||||||
this.readregs[M0PL + i] |= ppmask;
|
this.readregs[M0PL + i] |= ppmask;
|
||||||
let prio = PRIOR_TABLE[i + priobias];
|
let prio = (this.regs[PRIOR] & 0x10)
|
||||||
|
? PRIOR_TABLE[priobias + 15]
|
||||||
|
: PRIOR_TABLE[i + priobias];
|
||||||
if (prio < topprio) {
|
if (prio < topprio) {
|
||||||
topobj = i + 4;
|
topobj = i + 4;
|
||||||
topprio = prio;
|
topprio = prio;
|
||||||
@ -221,9 +239,7 @@ export class GTIA {
|
|||||||
shiftObject(i: number) {
|
shiftObject(i: number) {
|
||||||
let bit = (this.shiftregs[i] & 0x80000000) != 0;
|
let bit = (this.shiftregs[i] & 0x80000000) != 0;
|
||||||
this.shiftregs[i] <<= 1;
|
this.shiftregs[i] <<= 1;
|
||||||
if (this.regs[HPOSP0 + i] + this.hbias == this.count) {
|
this.evalTrigger(i);
|
||||||
this.triggerObject(i);
|
|
||||||
}
|
|
||||||
return bit;
|
return bit;
|
||||||
}
|
}
|
||||||
getObjectColor(i: number) {
|
getObjectColor(i: number) {
|
||||||
@ -233,6 +249,11 @@ export class GTIA {
|
|||||||
return this.regs[COLPM0 + (i & 3)];
|
return this.regs[COLPM0 + (i & 3)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
evalTrigger(i: number) {
|
||||||
|
if (this.regs[HPOSP0 + i] + this.hbias == this.count) {
|
||||||
|
this.triggerObject(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
triggerObject(i: number) {
|
triggerObject(i: number) {
|
||||||
let size, data;
|
let size, data;
|
||||||
if (!(this.pmDebugMask & (1<<i))) return;
|
if (!(this.pmDebugMask & (1<<i))) return;
|
||||||
@ -246,7 +267,7 @@ export class GTIA {
|
|||||||
}
|
}
|
||||||
if (size & 1) data = expandBits(data); else data <<= 8;
|
if (size & 1) data = expandBits(data); else data <<= 8;
|
||||||
if (size == 3) data = expandBits(data); else data <<= 16;
|
if (size == 3) data = expandBits(data); else data <<= 16;
|
||||||
this.shiftregs[i] = data;
|
this.shiftregs[i] |= data;
|
||||||
}
|
}
|
||||||
|
|
||||||
clockPulse1(): void {
|
clockPulse1(): void {
|
||||||
|
@ -369,14 +369,17 @@ describe('Platform Replay', () => {
|
|||||||
it('Should run atari5200', async () => {
|
it('Should run atari5200', async () => {
|
||||||
await testPlatform('atari8-5200', 'acid5200.rom', 1200, (platform, frameno) => {
|
await testPlatform('atari8-5200', 'acid5200.rom', 1200, (platform, frameno) => {
|
||||||
if (frameno == 1199) {
|
if (frameno == 1199) {
|
||||||
let s = '';
|
for (let j=0; j<1024; j+=40) {
|
||||||
for (let i=0; i<40; i++) {
|
var s = '';
|
||||||
let c = platform.readAddress(0x722+i-40) & 0x7f;
|
for (let i=0; i<38; i++) {
|
||||||
if (c < 0x40) c += 0x20;
|
let c = platform.readAddress(0x402+j+i) & 0x7f;
|
||||||
s += String.fromCharCode(c);
|
if (c < 0x40) c += 0x20;
|
||||||
|
s += String.fromCharCode(c);
|
||||||
|
}
|
||||||
|
s = s.trim();
|
||||||
|
if (s.startsWith("Passed:")) break;
|
||||||
}
|
}
|
||||||
s = s.trim();
|
assert.equal(s, "Passed: 14 Failed: 32 Skipped: 1");
|
||||||
assert.equal(s, "Passed: 13 Failed: 33 Skipped: 1");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user