8bitworkshop/gen/chunk-ADS54WVP.js.map

8 lines
13 KiB
Plaintext

{
"version": 3,
"sources": ["../src/common/analysis.ts"],
"sourcesContent": ["\nimport { hex, byte2signed } from \"./util\";\nimport { OpcodeMetadata, Platform } from \"./baseplatform\";\n\nconst debug = false;\n\nexport interface CodeAnalyzer {\n showLoopTimingForPC(pc: number);\n pc2clockrange: { [key: number]: ClockRange };\n MAX_CLOCKS: number;\n}\n\n/// VCS TIMING ANALYSIS\n\n// [taken, not taken]\nconst BRANCH_CONSTRAINTS = [\n [{ N: 0 }, { N: 1 }],\n [{ N: 1 }, { N: 0 }],\n [{ V: 0 }, { V: 1 }],\n [{ V: 1 }, { V: 0 }],\n [{ C: 0 }, { C: 1 }],\n [{ C: 1 }, { C: 0 }],\n [{ Z: 0 }, { Z: 1 }],\n [{ Z: 1 }, { Z: 0 }]\n];\n\nfunction constraintEquals(a, b) {\n if (a == null || b == null)\n return null;\n for (var n in a) {\n if (b[n] !== 'undefined')\n return a[n] == b[n];\n }\n for (var n in b) {\n if (a[n] !== 'undefined')\n return a[n] == b[n];\n }\n return null;\n}\n\ninterface ClockRange {\n minclocks: number;\n maxclocks: number;\n}\n\nabstract class CodeAnalyzer6502 implements CodeAnalyzer {\n pc2clockrange: { [key: number]: ClockRange } = {};\n jsrresult: { [key: number]: ClockRange } = {};\n START_CLOCKS: number;\n MAX_CLOCKS: number;\n WRAP_CLOCKS: boolean;\n platform: Platform;\n MAX_CYCLES: number = 2000;\n\n constructor(platform: Platform) {\n this.platform = platform;\n }\n\n getClockCountsAtPC(pc) {\n var opcode = this.platform.readAddress(pc);\n var meta = this.platform.getOpcodeMetadata(opcode, pc);\n return meta; // minCycles, maxCycles\n }\n\n traceInstructions(pc: number, minclocks: number, maxclocks: number, subaddr: number, constraints) {\n if (debug) console.log(\"trace\", hex(pc), minclocks, maxclocks);\n if (!constraints) constraints = {};\n var modified = true;\n var abort = false;\n for (let i = 0; modified && !abort; i++) {\n if (i >= this.MAX_CYCLES) {\n console.log(\"too many cycles @\", hex(pc), \"routine\", hex(subaddr));\n break;\n }\n modified = false;\n if (this.WRAP_CLOCKS) {\n // wrap clocks\n minclocks = minclocks % this.MAX_CLOCKS;\n maxclocks = maxclocks % this.MAX_CLOCKS;\n if (maxclocks == minclocks - 1) {\n if (debug) console.log(\"0-75\", hex(pc), minclocks, maxclocks);\n minclocks = 0;\n maxclocks = this.MAX_CLOCKS - 1;\n }\n } else {\n // truncate clocks\n minclocks = Math.min(this.MAX_CLOCKS, minclocks);\n maxclocks = Math.min(this.MAX_CLOCKS, maxclocks);\n }\n let meta = this.getClockCountsAtPC(pc);\n let lob = this.platform.readAddress(pc + 1);\n let hib = this.platform.readAddress(pc + 2);\n let addr = lob + (hib << 8);\n let pc0 = pc;\n let pcrange = this.pc2clockrange[pc0];\n if (pcrange == null) {\n this.pc2clockrange[pc0] = pcrange = { minclocks: minclocks, maxclocks: maxclocks };\n if (debug) console.log(\"new\", hex(pc), hex(pc0), hex(subaddr), minclocks, maxclocks);\n modified = true;\n }\n //console.log(hex(pc),minclocks,maxclocks, pcrange);\n if (pcrange.minclocks != minclocks || pcrange.maxclocks != maxclocks) {\n if (this.WRAP_CLOCKS && (minclocks <= maxclocks) != (pcrange.minclocks <= pcrange.maxclocks)) {\n if (debug) console.log(\"wrap\", hex(pc), hex(pc0), hex(subaddr), minclocks, maxclocks, pcrange);\n pcrange.minclocks = minclocks = 0;\n pcrange.maxclocks = maxclocks = this.MAX_CLOCKS - 1;\n modified = true;\n }\n if (minclocks < pcrange.minclocks) {\n if (debug) console.log(\"min\", hex(pc), hex(pc0), hex(subaddr), minclocks, maxclocks, pcrange);\n pcrange.minclocks = minclocks;\n modified = true;\n }\n if (maxclocks > pcrange.maxclocks) {\n if (debug) console.log(\"max\", hex(pc), hex(pc0), hex(subaddr), minclocks, maxclocks, pcrange);\n pcrange.maxclocks = maxclocks;\n modified = true;\n }\n }\n if (!meta.insnlength) {\n console.log(\"Illegal instruction!\", hex(pc), hex(meta.opcode), meta);\n break;\n }\n pc += meta.insnlength;\n var oldconstraints = constraints;\n constraints = null;\n let syncMaxCycles = this.getMaxCyclesForSync(meta, lob, hib);\n if (typeof syncMaxCycles === 'number') {\n minclocks = 0;\n maxclocks = syncMaxCycles;\n meta.minCycles = meta.maxCycles = 0;\n } else {\n // TODO: if jump to zero-page, maybe assume RTS?\n switch (meta.opcode) {\n case 0x19: case 0x1d:\n case 0x39: case 0x3d:\n case 0x59: case 0x5d:\n case 0x79: case 0x7d:\n case 0xb9: case 0xbb:\n case 0xbc: case 0xbd: case 0xbe: case 0xbf:\n case 0xd9: case 0xdd:\n case 0xf9: case 0xfd:\n if (lob == 0) meta.maxCycles -= 1; // no page boundary crossed\n break;\n case 0x20: // JSR\n // TODO: handle bare RTS case\n minclocks += meta.minCycles;\n maxclocks += meta.maxCycles;\n this.traceInstructions(addr, minclocks, maxclocks, addr, constraints);\n var result = this.jsrresult[addr];\n if (result) {\n minclocks = result.minclocks;\n maxclocks = result.maxclocks;\n } else {\n console.log(\"No JSR result!\", hex(pc), hex(addr));\n minclocks = maxclocks;\n //return;\n }\n break;\n case 0x4c: // JMP\n pc = addr; // TODO: make sure in ROM space\n break;\n case 0x40: // RTI\n abort = true;\n break;\n case 0x60: // RTS\n if (subaddr) { // TODO: 0 doesn't work\n // TODO: combine with previous result\n var result = this.jsrresult[subaddr];\n if (!result) {\n result = { minclocks: minclocks, maxclocks: maxclocks };\n } else {\n result = {\n minclocks: Math.min(minclocks, result.minclocks),\n maxclocks: Math.max(maxclocks, result.maxclocks)\n }\n }\n this.jsrresult[subaddr] = result;\n console.log(\"RTS\", hex(pc), hex(subaddr), this.jsrresult[subaddr]);\n }\n return;\n case 0x10: case 0x30: // branch\n case 0x50: case 0x70:\n case 0x90: case 0xB0:\n case 0xD0: case 0xF0:\n var newpc = pc + byte2signed(lob);\n var crosspage = (pc >> 8) != (newpc >> 8);\n if (!crosspage) meta.maxCycles--;\n // TODO: other instructions might modify flags too\n var cons = BRANCH_CONSTRAINTS[Math.floor((meta.opcode - 0x10) / 0x20)];\n var cons0 = constraintEquals(oldconstraints, cons[0]);\n var cons1 = constraintEquals(oldconstraints, cons[1]);\n // recursively trace the taken branch\n if (true || cons0 !== false) { // TODO?\n this.traceInstructions(newpc, minclocks + meta.maxCycles, maxclocks + meta.maxCycles, subaddr, cons[0]);\n }\n // abort if we will always take the branch\n if (cons1 === false) {\n console.log(\"branch always taken\", hex(pc), oldconstraints, cons[1]);\n abort = true;\n }\n constraints = cons[1]; // not taken\n meta.maxCycles = meta.minCycles; // branch not taken, no extra clock(s)\n break;\n case 0x6c:\n console.log(\"Instruction not supported!\", hex(pc), hex(meta.opcode), meta); // TODO\n return;\n }\n }\n // add min/max instruction time to min/max clocks bound\n if (debug) console.log(\"add\", hex(pc), meta.minCycles, meta.maxCycles);\n minclocks += meta.minCycles;\n maxclocks += meta.maxCycles;\n }\n }\n\n showLoopTimingForPC(pc: number) {\n this.pc2clockrange = {};\n this.jsrresult = {};\n // recurse through all traces\n this.traceInstructions(pc | this.platform.getOriginPC(), this.START_CLOCKS, this.MAX_CLOCKS, 0, {});\n }\n\n getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) {\n }\n}\n\n// 76 cycles\nexport class CodeAnalyzer_vcs extends CodeAnalyzer6502 {\n constructor(platform: Platform) {\n super(platform);\n this.MAX_CLOCKS = 76; // 1 scanline\n this.START_CLOCKS = 0; // TODO?\n this.WRAP_CLOCKS = true;\n }\n getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) {\n if (meta.opcode == 0x85) {\n if (lob == 0x2) { // STA WSYNC\n return 0;\n }\n }\n }\n}\n\n// https://wiki.nesdev.com/w/index.php/PPU_rendering#Line-by-line_timing\n// TODO: sprite 0 hit, CPU stalls\nexport class CodeAnalyzer_nes extends CodeAnalyzer6502 {\n constructor(platform: Platform) {\n super(platform);\n this.MAX_CLOCKS = 114; // 341 clocks for 3 scanlines\n this.START_CLOCKS = 0;\n this.WRAP_CLOCKS = true;\n }\n getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) {\n if (meta.opcode == 0x2c) {\n if (lob == 0x02 && hib == 0x20) { // BIT $2002\n return 4; // uncertainty b/c of assumed branch poll\n }\n }\n }\n}\n\nexport class CodeAnalyzer_apple2 extends CodeAnalyzer6502 {\n constructor(platform: Platform) {\n super(platform);\n this.MAX_CLOCKS = 65;\n this.START_CLOCKS = 0;\n this.WRAP_CLOCKS = true;\n }\n getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) {\n if (meta.opcode == 0xad) {\n if (lob == 0x61 && hib == 0xc0) { // LDA $C061\n return 4; // uncertainty b/c of assumed branch poll\n }\n }\n }\n}\n\n"],
"mappings": "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",
"names": []
}