1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-29 14:51:17 +00:00

apple2: floating bus, no scanline rendering yet

This commit is contained in:
Steven Hugg 2020-07-23 21:52:53 -05:00
parent 8b96c82e65
commit 82c18e04aa
4 changed files with 76 additions and 27 deletions

View File

@ -133,6 +133,14 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer {
meta.minCycles = meta.maxCycles = 0; meta.minCycles = meta.maxCycles = 0;
} }
break; break;
// TODO: only Apple2 (vapor lock)
case 0xad:
if (lob == 0x61 && hib == 0xc0) { // LDA $C061
minclocks = 0;
maxclocks = 4; // uncertainty?
meta.minCycles = meta.maxCycles = 0;
}
break;
case 0x20: // JSR case 0x20: // JSR
this.traceInstructions(addr, minclocks, maxclocks, addr, constraints); this.traceInstructions(addr, minclocks, maxclocks, addr, constraints);
var result = this.jsrresult[addr]; var result = this.jsrresult[addr];
@ -228,3 +236,12 @@ export class CodeAnalyzer_nes extends CodeAnalyzer6502 {
} }
} }
export class CodeAnalyzer_apple2 extends CodeAnalyzer6502 {
constructor(platform : Platform) {
super(platform);
this.MAX_CLOCKS = 65;
this.START_CLOCKS = 0;
this.WRAP_CLOCKS = true;
}
}

View File

@ -314,26 +314,25 @@ export abstract class BasicScanlineMachine extends BasicMachine implements Raste
advanceFrame(trap: TrapCondition) : number { advanceFrame(trap: TrapCondition) : number {
this.preFrame(); this.preFrame();
var clock = 0;
var endLineClock = 0; var endLineClock = 0;
var steps = 0; var steps = 0;
this.probe.logNewFrame(); this.probe.logNewFrame();
this.frameCycles = 0;
for (var sl=0; sl<this.numTotalScanlines; sl++) { for (var sl=0; sl<this.numTotalScanlines; sl++) {
endLineClock += this.cpuCyclesPerLine; // could be fractional endLineClock += this.cpuCyclesPerLine; // could be fractional
this.scanline = sl; this.scanline = sl;
this.frameCycles = clock;
this.startScanline(); this.startScanline();
while (clock < endLineClock) { while (this.frameCycles < endLineClock) {
if (trap && trap()) { if (trap && trap()) {
sl = 999; sl = 999;
break; break;
} }
clock += this.advanceCPU(); this.frameCycles += this.advanceCPU();
steps++; steps++;
} }
this.drawScanline(); this.drawScanline();
this.probe.logNewScanline(); this.probe.logNewScanline();
this.probe.logClocks(Math.floor(clock-endLineClock)); //remainder this.probe.logClocks(Math.floor(this.frameCycles - endLineClock)); // remainder of prev. line
} }
this.postFrame(); this.postFrame();
return steps; // TODO: return steps, not clock? for recorder return steps; // TODO: return steps, not clock? for recorder

View File

@ -12,7 +12,7 @@ const HDR_SIZE = PGM_BASE - LOAD_BASE;
interface AppleIIStateBase { interface AppleIIStateBase {
ram : Uint8Array; ram : Uint8Array;
rnd,soundstate : number; soundstate : number;
auxRAMselected,writeinhibit : boolean; auxRAMselected,writeinhibit : boolean;
auxRAMbank : number; auxRAMbank : number;
} }
@ -38,7 +38,7 @@ export class AppleII extends BasicScanlineMachine {
// approx: http://www.cs.columbia.edu/~sedwards/apple2fpga/ // approx: http://www.cs.columbia.edu/~sedwards/apple2fpga/
cpuFrequency = 1022727; cpuFrequency = 1022727;
sampleRate = this.cpuFrequency; sampleRate = this.cpuFrequency;
cpuCyclesPerLine = 912/14; // approx: http://www.cs.columbia.edu/~sedwards/apple2fpga/ cpuCyclesPerLine = 65;
cpuCyclesPerFrame = this.cpuCyclesPerLine * 262; cpuCyclesPerFrame = this.cpuCyclesPerLine * 262;
canvasWidth = 280; canvasWidth = 280;
numVisibleScanlines = 192; numVisibleScanlines = 192;
@ -51,7 +51,6 @@ export class AppleII extends BasicScanlineMachine {
grdirty = new Array(0xc000 >> 7); grdirty = new Array(0xc000 >> 7);
grparams = {dirty:this.grdirty, grswitch:GR_TXMODE, mem:this.ram}; grparams = {dirty:this.grdirty, grswitch:GR_TXMODE, mem:this.ram};
ap2disp; ap2disp;
rnd = 1;
kbdlatch = 0; kbdlatch = 0;
soundstate = 0; soundstate = 0;
// language card switches // language card switches
@ -83,7 +82,7 @@ export class AppleII extends BasicScanlineMachine {
readConst: (a) => { readConst: (a) => {
return 0; return 0;
}, },
read: (a) => { return this.noise(); }, read: (a) => { return this.floatbus(); },
write: (a,v) => { } write: (a,v) => { }
}; };
@ -101,7 +100,6 @@ export class AppleII extends BasicScanlineMachine {
return { return {
c: this.cpu.saveState(), c: this.cpu.saveState(),
ram: this.ram.slice(), ram: this.ram.slice(),
rnd: this.rnd,
kbdlatch: this.kbdlatch, kbdlatch: this.kbdlatch,
soundstate: this.soundstate, soundstate: this.soundstate,
grswitch: this.grparams.grswitch, grswitch: this.grparams.grswitch,
@ -115,7 +113,6 @@ export class AppleII extends BasicScanlineMachine {
loadState(s:AppleIIState) { loadState(s:AppleIIState) {
this.cpu.loadState(s.c); this.cpu.loadState(s.c);
this.ram.set(s.ram); this.ram.set(s.ram);
this.rnd = s.rnd;
this.kbdlatch = s.kbdlatch; this.kbdlatch = s.kbdlatch;
this.soundstate = s.soundstate; this.soundstate = s.soundstate;
this.grparams.grswitch = s.grswitch; this.grparams.grswitch = s.grswitch;
@ -145,7 +142,6 @@ export class AppleII extends BasicScanlineMachine {
} }
reset() { reset() {
super.reset(); super.reset();
this.rnd = 1;
this.auxRAMselected = false; this.auxRAMselected = false;
this.auxRAMbank = 1; this.auxRAMbank = 1;
this.writeinhibit = true; this.writeinhibit = true;
@ -162,9 +158,6 @@ export class AppleII extends BasicScanlineMachine {
this.cpu.advanceClock(); this.cpu.advanceClock();
if ((this.cpu.getPC()>>8) < 0xc6) break; if ((this.cpu.getPC()>>8) < 0xc6) break;
} }
}
noise() : number {
return (this.rnd = xorshift32(this.rnd)) & 0xff;
} }
readConst(address: number): number { readConst(address: number): number {
if (address < 0xc000) { if (address < 0xc000) {
@ -215,18 +208,18 @@ export class AppleII extends BasicScanlineMachine {
case 1: case 1:
case 2: case 2:
case 3: case 3:
return this.noise() & 0x7f; return this.floatbus() & 0x7f;
// joystick // joystick
case 4: case 4:
case 5: case 5:
return this.noise() | 0x80; return this.floatbus() | 0x80;
default: default:
return this.noise(); return this.floatbus();
} }
case 7: case 7:
// joy reset // joy reset
if (address == 0xc070) if (address == 0xc070)
return this.noise() | 0x80; return this.floatbus() | 0x80;
case 8: case 8:
return this.doLanguageCardIO(address); return this.doLanguageCardIO(address);
case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
@ -235,8 +228,8 @@ export class AppleII extends BasicScanlineMachine {
} else if (address >= 0xc100 && address < 0xc800) { } else if (address >= 0xc100 && address < 0xc800) {
var slot = (address >> 8) & 7; var slot = (address >> 8) & 7;
return (this.slots[slot] && this.slots[slot].readROM(address & 0xff)) | 0; return (this.slots[slot] && this.slots[slot].readROM(address & 0xff)) | 0;
} }
return this.noise(); return this.floatbus();
} }
write(address:number, val:number) : void { write(address:number, val:number) : void {
address &= 0xffff; address &= 0xffff;
@ -256,6 +249,18 @@ export class AppleII extends BasicScanlineMachine {
this.ram[address + this.bank2wroffset] = val; this.ram[address + this.bank2wroffset] = val;
} }
} }
// http://www.deater.net/weave/vmwprod/megademo/vapor_lock.html
// https://retrocomputing.stackexchange.com/questions/14012/what-is-dram-refresh-and-why-is-the-weird-apple-ii-video-memory-layout-affected
// http://www.apple-iigs.info/doc/fichiers/TheappleIIcircuitdescription1.pdf
// http://rich12345.tripod.com/aiivideo/softalk.html
// https://github.com/MiSTer-devel/Apple-II_MiSTer/blob/master/rtl/timing_generator.vhd
floatbus() : number {
var fcyc = this.frameCycles;
var yline = Math.floor(fcyc / 65);
var xcyc = Math.floor(fcyc % 65);
var addr = this.ap2disp.getAddressForScanline(yline);
return this.readConst(addr + xcyc);
}
connectVideo(pixels:Uint32Array) { connectVideo(pixels:Uint32Array) {
super.connectVideo(pixels); super.connectVideo(pixels);
@ -358,7 +363,7 @@ export class AppleII extends BasicScanlineMachine {
break; break;
} }
this.setupLanguageCardConstants(); this.setupLanguageCardConstants();
return this.noise(); return this.floatbus();
} }
setupLanguageCardConstants() { setupLanguageCardConstants() {
@ -456,8 +461,18 @@ var Apple2Display = function(pixels : Uint32Array, apple : AppleGRParams) {
0x0250, 0x0650, 0x0a50, 0x0e50, 0x1250, 0x1650, 0x1a50, 0x1e50, 0x0250, 0x0650, 0x0a50, 0x0e50, 0x1250, 0x1650, 0x1a50, 0x1e50,
0x02d0, 0x06d0, 0x0ad0, 0x0ed0, 0x12d0, 0x16d0, 0x1ad0, 0x1ed0, 0x02d0, 0x06d0, 0x0ad0, 0x0ed0, 0x12d0, 0x16d0, 0x1ad0, 0x1ed0,
0x0350, 0x0750, 0x0b50, 0x0f50, 0x1350, 0x1750, 0x1b50, 0x1f50, 0x0350, 0x0750, 0x0b50, 0x0f50, 0x1350, 0x1750, 0x1b50, 0x1f50,
0x03d0, 0x07d0, 0x0bd0, 0x0fd0, 0x13d0, 0x17d0, 0x1bd0, 0x1fd0 0x03d0, 0x07d0, 0x0bd0, 0x0fd0, 0x13d0, 0x17d0, 0x1bd0, 0x1fd0,
]; // just for floating bus, y >= 192
0x0078, 0x0478, 0x0878, 0x0c78, 0x1078, 0x1478, 0x1878, 0x1c78,
0x00f8, 0x04f8, 0x08f8, 0x0cf8, 0x10f8, 0x14f8, 0x18f8, 0x1cf8,
0x0178, 0x0578, 0x0978, 0x0d78, 0x1178, 0x1578, 0x1978, 0x1d78,
0x01f8, 0x05f8, 0x09f8, 0x0df8, 0x11f8, 0x15f8, 0x19f8, 0x1df8,
0x0278, 0x0678, 0x0a78, 0x0e78, 0x1278, 0x1678, 0x1a78, 0x1e78,
0x02f8, 0x06f8, 0x0af8, 0x0ef8, 0x12f8, 0x16f8, 0x1af8, 0x1ef8,
0x0378, 0x0778, 0x0b78, 0x0f78, 0x1378, 0x1778, 0x1b78, 0x1f78,
0x03f8, 0x07f8, 0x0bf8, 0x0ff8, 0x13f8, 0x17f8, 0x1bf8, 0x1ff8,
0x0000, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400,
];
var colors_lut; var colors_lut;
@ -582,6 +597,15 @@ var Apple2Display = function(pixels : Uint32Array, apple : AppleGRParams) {
} }
} }
this.getAddressForScanline = function(y:number) : number {
var base = hires_lut[y];
if ((apple.grswitch & GR_HIRES) && (y < 160 || !(apple.grswitch & GR_MIXMODE)))
base = base | ((apple.grswitch & GR_PAGE1) ? 0x4000 : 0x2000);
else
base = (base & 0x3ff) | ((apple.grswitch & GR_PAGE1) ? 0x800 : 0x400);
return base;
}
function drawHiresLines(y, maxy) function drawHiresLines(y, maxy)
{ {
var yb = y*XSIZE; var yb = y*XSIZE;
@ -1084,7 +1108,7 @@ class DiskII extends DiskIIState implements SlotDevice, SavesState<DiskIIState>
if (this.track_data) { if (this.track_data) {
return (this.track_data[this.track_index] & 0xff); return (this.track_data[this.track_index] & 0xff);
} else } else
return this.emu.noise() | 0x80; return this.emu.floatbus() | 0x80;
} }
write_latch(value: number) { write_latch(value: number) {
@ -1189,7 +1213,7 @@ class DiskII extends DiskIIState implements SlotDevice, SavesState<DiskIIState>
*/ */
return this.write_protect ? 0x80 : 0x00; return this.write_protect ? 0x80 : 0x00;
} }
return this.emu.noise(); return this.emu.floatbus();
} }
} }

View File

@ -57,6 +57,7 @@ class Apple2MAMEPlatform extends BaseMAMEPlatform implements Platform {
import { AppleII } from "../machine/apple2"; import { AppleII } from "../machine/apple2";
import { Base6502MachinePlatform } from "../common/baseplatform"; import { Base6502MachinePlatform } from "../common/baseplatform";
import { CodeAnalyzer_apple2 } from "../common/analysis";
class NewApple2Platform extends Base6502MachinePlatform<AppleII> implements Platform { class NewApple2Platform extends Base6502MachinePlatform<AppleII> implements Platform {
@ -82,7 +83,15 @@ class NewApple2Platform extends Base6502MachinePlatform<AppleII> implements Plat
if (rom && rom.length == 35*16*256) return ".dsk"; // DSK image if (rom && rom.length == 35*16*256) return ".dsk"; // DSK image
return ".bin"; return ".bin";
}; };
/*
newCodeAnalyzer() {
return new CodeAnalyzer_apple2(this);
}
getOriginPC() {
return 0x803; // TODO?
}
*/
} }
PLATFORMS['apple2.mame'] = Apple2MAMEPlatform; //PLATFORMS['apple2.mame'] = Apple2MAMEPlatform;
PLATFORMS['apple2'] = NewApple2Platform; PLATFORMS['apple2'] = NewApple2Platform;