diff --git a/src/common/analysis.ts b/src/common/analysis.ts index 00500fed..8f01e67a 100644 --- a/src/common/analysis.ts +++ b/src/common/analysis.ts @@ -133,6 +133,14 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer { meta.minCycles = meta.maxCycles = 0; } 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 this.traceInstructions(addr, minclocks, maxclocks, addr, constraints); 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; + } +} + diff --git a/src/common/devices.ts b/src/common/devices.ts index 284d57cd..63ce23bd 100644 --- a/src/common/devices.ts +++ b/src/common/devices.ts @@ -314,26 +314,25 @@ export abstract class BasicScanlineMachine extends BasicMachine implements Raste advanceFrame(trap: TrapCondition) : number { this.preFrame(); - var clock = 0; var endLineClock = 0; var steps = 0; this.probe.logNewFrame(); + this.frameCycles = 0; for (var sl=0; sl> 7); grparams = {dirty:this.grdirty, grswitch:GR_TXMODE, mem:this.ram}; ap2disp; - rnd = 1; kbdlatch = 0; soundstate = 0; // language card switches @@ -83,7 +82,7 @@ export class AppleII extends BasicScanlineMachine { readConst: (a) => { return 0; }, - read: (a) => { return this.noise(); }, + read: (a) => { return this.floatbus(); }, write: (a,v) => { } }; @@ -101,7 +100,6 @@ export class AppleII extends BasicScanlineMachine { return { c: this.cpu.saveState(), ram: this.ram.slice(), - rnd: this.rnd, kbdlatch: this.kbdlatch, soundstate: this.soundstate, grswitch: this.grparams.grswitch, @@ -115,7 +113,6 @@ export class AppleII extends BasicScanlineMachine { loadState(s:AppleIIState) { this.cpu.loadState(s.c); this.ram.set(s.ram); - this.rnd = s.rnd; this.kbdlatch = s.kbdlatch; this.soundstate = s.soundstate; this.grparams.grswitch = s.grswitch; @@ -145,7 +142,6 @@ export class AppleII extends BasicScanlineMachine { } reset() { super.reset(); - this.rnd = 1; this.auxRAMselected = false; this.auxRAMbank = 1; this.writeinhibit = true; @@ -162,9 +158,6 @@ export class AppleII extends BasicScanlineMachine { this.cpu.advanceClock(); if ((this.cpu.getPC()>>8) < 0xc6) break; } - } - noise() : number { - return (this.rnd = xorshift32(this.rnd)) & 0xff; } readConst(address: number): number { if (address < 0xc000) { @@ -215,18 +208,18 @@ export class AppleII extends BasicScanlineMachine { case 1: case 2: case 3: - return this.noise() & 0x7f; + return this.floatbus() & 0x7f; // joystick case 4: case 5: - return this.noise() | 0x80; + return this.floatbus() | 0x80; default: - return this.noise(); + return this.floatbus(); } case 7: // joy reset if (address == 0xc070) - return this.noise() | 0x80; + return this.floatbus() | 0x80; case 8: return this.doLanguageCardIO(address); 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) { var slot = (address >> 8) & 7; return (this.slots[slot] && this.slots[slot].readROM(address & 0xff)) | 0; - } - return this.noise(); + } + return this.floatbus(); } write(address:number, val:number) : void { address &= 0xffff; @@ -256,6 +249,18 @@ export class AppleII extends BasicScanlineMachine { 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) { super.connectVideo(pixels); @@ -358,7 +363,7 @@ export class AppleII extends BasicScanlineMachine { break; } this.setupLanguageCardConstants(); - return this.noise(); + return this.floatbus(); } setupLanguageCardConstants() { @@ -456,8 +461,18 @@ var Apple2Display = function(pixels : Uint32Array, apple : AppleGRParams) { 0x0250, 0x0650, 0x0a50, 0x0e50, 0x1250, 0x1650, 0x1a50, 0x1e50, 0x02d0, 0x06d0, 0x0ad0, 0x0ed0, 0x12d0, 0x16d0, 0x1ad0, 0x1ed0, 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; @@ -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) { var yb = y*XSIZE; @@ -1084,7 +1108,7 @@ class DiskII extends DiskIIState implements SlotDevice, SavesState if (this.track_data) { return (this.track_data[this.track_index] & 0xff); } else - return this.emu.noise() | 0x80; + return this.emu.floatbus() | 0x80; } write_latch(value: number) { @@ -1189,7 +1213,7 @@ class DiskII extends DiskIIState implements SlotDevice, SavesState */ return this.write_protect ? 0x80 : 0x00; } - return this.emu.noise(); + return this.emu.floatbus(); } } diff --git a/src/platform/apple2.ts b/src/platform/apple2.ts index c49dba89..c312f917 100644 --- a/src/platform/apple2.ts +++ b/src/platform/apple2.ts @@ -57,6 +57,7 @@ class Apple2MAMEPlatform extends BaseMAMEPlatform implements Platform { import { AppleII } from "../machine/apple2"; import { Base6502MachinePlatform } from "../common/baseplatform"; +import { CodeAnalyzer_apple2 } from "../common/analysis"; class NewApple2Platform extends Base6502MachinePlatform implements Platform { @@ -82,7 +83,15 @@ class NewApple2Platform extends Base6502MachinePlatform implements Plat if (rom && rom.length == 35*16*256) return ".dsk"; // DSK image return ".bin"; }; + /* + newCodeAnalyzer() { + return new CodeAnalyzer_apple2(this); + } + getOriginPC() { + return 0x803; // TODO? + } + */ } -PLATFORMS['apple2.mame'] = Apple2MAMEPlatform; +//PLATFORMS['apple2.mame'] = Apple2MAMEPlatform; PLATFORMS['apple2'] = NewApple2Platform;