vcs: changed .cfg file for TigerVision (3E) mapper
vcs: mappers 3E/3F don't correct bank offsets, so banks must not overlap ca65: parse .proc symbols
This commit is contained in:
parent
2e2996bd73
commit
73c74c519e
|
@ -837,7 +837,7 @@ export class CharmapEditor extends PixNode {
|
||||||
chooser.width = this.fmt.w || 1;
|
chooser.width = this.fmt.w || 1;
|
||||||
chooser.height = this.fmt.h || 1;
|
chooser.height = this.fmt.h || 1;
|
||||||
chooser.recreate(agrid, (index, viewer) => {
|
chooser.recreate(agrid, (index, viewer) => {
|
||||||
var yscale = Math.ceil(192 / this.fmt.w);
|
var yscale = Math.ceil(256 / this.fmt.w); // TODO: variable scale?
|
||||||
var xscale = yscale * (this.fmt.aspect || 1.0);
|
var xscale = yscale * (this.fmt.aspect || 1.0);
|
||||||
var editview = this.createEditor(aeditor, viewer, xscale, yscale);
|
var editview = this.createEditor(aeditor, viewer, xscale, yscale);
|
||||||
this.context.setCurrentEditor(aeditor, $(viewer.canvas), this);
|
this.context.setCurrentEditor(aeditor, $(viewer.canvas), this);
|
||||||
|
|
|
@ -2442,8 +2442,9 @@ export function getPlatformAndRepo() {
|
||||||
qs.repo = repo_id;
|
qs.repo = repo_id;
|
||||||
if (repo.platform_id && !qs.platform)
|
if (repo.platform_id && !qs.platform)
|
||||||
qs.platform = platform_id = repo.platform_id;
|
qs.platform = platform_id = repo.platform_id;
|
||||||
if (!qs.file && repo.mainPath)
|
if (repo.mainPath && !qs.file)
|
||||||
qs.file = repo.mainPath;
|
qs.file = repo.mainPath;
|
||||||
|
// TODO: update repo definition if new main file compiles successfully
|
||||||
//requestPersistPermission(true, true);
|
//requestPersistPermission(true, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -60,7 +60,9 @@ function getToolForFilename_vcs(fn: string) {
|
||||||
if (fn.endsWith(".wiz")) return "wiz";
|
if (fn.endsWith(".wiz")) return "wiz";
|
||||||
if (fn.endsWith(".bb") || fn.endsWith(".bas")) return "bataribasic";
|
if (fn.endsWith(".bb") || fn.endsWith(".bas")) return "bataribasic";
|
||||||
if (fn.endsWith(".ca65")) return "ca65";
|
if (fn.endsWith(".ca65")) return "ca65";
|
||||||
|
//if (fn.endsWith(".inc")) return "ca65";
|
||||||
if (fn.endsWith(".c")) return "cc65";
|
if (fn.endsWith(".c")) return "cc65";
|
||||||
|
//if (fn.endsWith(".h")) return "cc65";
|
||||||
if (fn.endsWith(".ecs")) return "ecs";
|
if (fn.endsWith(".ecs")) return "ecs";
|
||||||
return "dasm";
|
return "dasm";
|
||||||
}
|
}
|
||||||
|
@ -222,11 +224,13 @@ class VCSPlatform extends BasePlatform {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
fixState(state) {
|
fixState(state) {
|
||||||
var ofs = (state.ca && state.ca.bo) || 0;
|
// TODO: DASM listing prevents us from using RORG offset
|
||||||
if (state.ca && state.ca.fo && (state.c.PC & 0xfff) >= 2048)
|
// TODO: how to handle 1000/3000/etc vs overlapping addresses?
|
||||||
ofs = state.ca.fo; // 3E/3F fixed-slice formats
|
if (state.ca.f != '3E' && state.ca.f != '3F') {
|
||||||
// TODO: for batari BASIC
|
var ofs = (state.ca && state.ca.bo) || 0;
|
||||||
state.c.EPC = state.c.PC + ofs; // EPC = effective PC for ROM
|
// TODO: for batari BASIC
|
||||||
|
state.c.EPC = state.c.PC + ofs; // EPC = effective PC for ROM
|
||||||
|
}
|
||||||
}
|
}
|
||||||
loadState(state) {
|
loadState(state) {
|
||||||
return Javatari.room.console.loadState(state);
|
return Javatari.room.console.loadState(state);
|
||||||
|
@ -294,7 +298,8 @@ class VCSPlatform extends BasePlatform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bankSwitchStateToString(state) {
|
bankSwitchStateToString(state) {
|
||||||
return (state.ca && state.ca.bo !== undefined) ? "BankOffset "+hex(state.ca.bo,4)+"\n" : "";
|
if (state.ca?.ro >= 0) return "RAMOffset "+hex(state.ca.ro,4)+"\n";
|
||||||
|
return (state.ca?.bo >= 0) ? "BankOffset "+hex(state.ca.bo,4)+"\n" : "";
|
||||||
}
|
}
|
||||||
piaStateToLongString(p) {
|
piaStateToLongString(p) {
|
||||||
return "Timer " + p.t + "/" + p.c + "\nINTIM $" + hex(p.IT,2) + " (" + p.IT + ")\nINSTAT $" + hex(p.IS,2) + "\n";
|
return "Timer " + p.t + "/" + p.c + "\nINTIM $" + hex(p.IT,2) + " (" + p.IT + ")\nINSTAT $" + hex(p.IS,2) + "\n";
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { describe } from "mocha";
|
||||||
|
import { OpcodeMetadata, Platform } from "../common/baseplatform";
|
||||||
|
import { CodeAnalyzer_vcs } from "../common/analysis";
|
||||||
|
import { MOS6502 } from "../common/cpu/MOS6502";
|
||||||
|
import assert from "assert";
|
||||||
|
|
||||||
|
class Test6502Platform implements Platform {
|
||||||
|
cpu = new MOS6502();
|
||||||
|
ram = new Uint8Array(65536);
|
||||||
|
|
||||||
|
start(): void | Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
reset(): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
isRunning(): boolean {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getToolForFilename(s: string): string {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getDefaultExtension(): string {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
pause(): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
resume(): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
loadROM(title: string, rom: any) {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
getOpcodeMetadata?(opcode: number, offset: number): OpcodeMetadata {
|
||||||
|
return this.cpu.cpu.getOpcodeMetadata(opcode, offset);
|
||||||
|
}
|
||||||
|
getOriginPC(): number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
readAddress?(addr:number) : number {
|
||||||
|
return this.ram[addr] || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('6502 analysis', function () {
|
||||||
|
it('Should analyze 6502', function () {
|
||||||
|
let platform = new Test6502Platform();
|
||||||
|
platform.ram.set([0xea,0x85,0x02,0xa9,0x60,0x20,0x04,0x00,0xea,0x4c,0x01,0x00]);
|
||||||
|
let analysis = new CodeAnalyzer_vcs(platform);
|
||||||
|
analysis.showLoopTimingForPC(0x0);
|
||||||
|
console.log(analysis);
|
||||||
|
assert.equal(analysis.pc2minclocks[0x0], 304);
|
||||||
|
assert.equal(analysis.pc2maxclocks[0x0], 304);
|
||||||
|
assert.equal(analysis.pc2minclocks[0x1], 19);
|
||||||
|
assert.equal(analysis.pc2maxclocks[0x0], 304);
|
||||||
|
assert.equal(analysis.pc2minclocks[0x3], 0);
|
||||||
|
assert.equal(analysis.pc2maxclocks[0x3], 0);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,20 +1,41 @@
|
||||||
# Linker config file for targeting the Atari 2600.
|
# Linker config file for targeting the Atari 2600.
|
||||||
# From http://wiki.cc65.org/doku.php?id=cc65:atari_2600
|
# From http://wiki.cc65.org/doku.php?id=cc65:atari_2600
|
||||||
|
# Modified for TigerVision (3E) mapper
|
||||||
|
|
||||||
MEMORY {
|
MEMORY {
|
||||||
RAM: start = $80, size=$80, type = rw, define = yes;
|
RAM: start = $80, size=$70, type = rw, define = yes;
|
||||||
ROM: start = $F000, size=$1000, type = ro, file = %O, define = yes;
|
|
||||||
TIA: start = $00, size=$40, type = rw, define = yes;
|
TIA: start = $00, size=$40, type = rw, define = yes;
|
||||||
RIOT: start = $280, size=$20, type = rw, define = yes;
|
RIOT: start = $280, size=$20, type = rw, define = yes;
|
||||||
|
ROM0: start = $1000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=0;
|
||||||
|
ROM1: start = $3000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=1;
|
||||||
|
ROM2: start = $5000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=2;
|
||||||
|
ROM3: start = $7000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=3;
|
||||||
|
ROM4: start = $9000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=4;
|
||||||
|
ROM5: start = $b000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=5;
|
||||||
|
ROM6: start = $d000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=6;
|
||||||
|
ROM7: start = $f000, size=$800, type=ro, file=%O, define=yes, fill=yes, bank=7;
|
||||||
|
RAM0: start = $f000, size=$400, type=rw, define=yes;
|
||||||
|
PERM: start = $f800, size=$800, type=ro, file=%O, define=yes, fill=yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGMENTS {
|
SEGMENTS {
|
||||||
RODATA: load=ROM, type=ro, align=$100;
|
ROM0: load=ROM0, type=ro, align=$100, optional=yes;
|
||||||
STARTUP: load=ROM, type=ro, optional=yes;
|
ROM1: load=ROM1, type=ro, align=$100, optional=yes;
|
||||||
CODE: load=ROM, type=ro, define=yes;
|
ROM2: load=ROM2, type=ro, align=$100, optional=yes;
|
||||||
DATA: load=ROM, run=RAM, type=rw, define=yes;
|
ROM3: load=ROM3, type=ro, align=$100, optional=yes;
|
||||||
|
ROM4: load=ROM4, type=ro, align=$100, optional=yes;
|
||||||
|
ROM5: load=ROM5, type=ro, align=$100, optional=yes;
|
||||||
|
ROM6: load=ROM6, type=ro, align=$100, optional=yes;
|
||||||
|
ROM7: load=ROM7, type=ro, align=$100, optional=yes;
|
||||||
|
|
||||||
|
RODATA: load=PERM, type=ro, align=$100;
|
||||||
|
STARTUP: load=PERM, type=ro, optional=yes;
|
||||||
|
CODE: load=PERM, type=ro, define=yes;
|
||||||
|
DATA: load=ROM0, run=RAM, type=rw, define=yes;
|
||||||
BSS: load=RAM, type=bss, define=yes;
|
BSS: load=RAM, type=bss, define=yes;
|
||||||
VECTORS: load=ROM, type=ro, start=$FFFA;
|
VECTORS: load=PERM, type=ro, start=$FFFA;
|
||||||
|
XDATA: load=ROM0, run=RAM0, type=rw, define=yes, optional=yes;
|
||||||
|
|
||||||
ZEROPAGE: load=RAM, type=zp;
|
ZEROPAGE: load=RAM, type=zp;
|
||||||
TIA: load=TIA, type=rw, define = yes, optional = yes;
|
TIA: load=TIA, type=rw, define = yes, optional = yes;
|
||||||
RIOT: load=RIOT, type=rw, define = yes, optional = yes;
|
RIOT: load=RIOT, type=rw, define = yes, optional = yes;
|
||||||
|
|
|
@ -62,30 +62,41 @@ function parseCA65Listing(asmfn: string, code: string, symbols, segments, params
|
||||||
insns: null
|
insns: null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var linem = insnLineMatch.exec(line);
|
let linem = insnLineMatch.exec(line);
|
||||||
var topfile = linem && linem[3] == '1';
|
let topfile = linem && linem[3] == '1';
|
||||||
if (topfile) linenum++;
|
if (topfile) {
|
||||||
if (topfile && linem[1]) {
|
let insns = linem[4]?.trim() || '';
|
||||||
var offset = parseInt(linem[1], 16);
|
// skip extra insns for macro expansions
|
||||||
var insns = linem[4].trim();
|
if (!(insns != '' && linem[5] == '')) {
|
||||||
if (insns.length) {
|
linenum++;
|
||||||
//console.log(curpath, linenum, offset, segofs, insns);
|
}
|
||||||
if (!dbg) {
|
if (linem[1]) {
|
||||||
lines.push({
|
var offset = parseInt(linem[1], 16);
|
||||||
path: curpath,
|
if (insns.length) {
|
||||||
line: linenum,
|
//console.log(dbg, curpath, linenum, offset, segofs, insns);
|
||||||
offset: offset + segofs,
|
if (!dbg) {
|
||||||
insns: insns,
|
lines.push({
|
||||||
iscode: true // TODO: can't really tell unless we parse it
|
path: curpath,
|
||||||
});
|
line: linenum,
|
||||||
}
|
offset: offset + segofs,
|
||||||
} else {
|
insns: insns,
|
||||||
var sym = linem[5];
|
iscode: true // TODO: can't really tell unless we parse it
|
||||||
if (sym.endsWith(':') && !sym.startsWith('@')) {
|
});
|
||||||
var symofs = symbols[sym.substring(0, sym.length - 1)];
|
}
|
||||||
if (typeof symofs === 'number') {
|
} else {
|
||||||
segofs = symofs - offset;
|
var sym = null;
|
||||||
//console.log(sym, segofs, symofs, '-', offset);
|
var label = linem[5];
|
||||||
|
if (label?.endsWith(':')) {
|
||||||
|
sym = label.substring(0, label.length-1);
|
||||||
|
} else if (label?.toLowerCase().startsWith('.proc')) {
|
||||||
|
sym = label.split(' ')[1];
|
||||||
|
}
|
||||||
|
if (sym && !sym.startsWith('@')) {
|
||||||
|
var symofs = symbols[sym];
|
||||||
|
if (typeof symofs === 'number') {
|
||||||
|
segofs = symofs - offset;
|
||||||
|
//console.log(sym, segofs, symofs, '-', offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +235,7 @@ export function linkLD65(step: BuildStep): BuildStepResult {
|
||||||
lstout = lstout.split('\n\n')[1] || lstout; // remove header
|
lstout = lstout.split('\n\n')[1] || lstout; // remove header
|
||||||
putWorkFile(fn, lstout);
|
putWorkFile(fn, lstout);
|
||||||
//const asmpath = fn.replace(/\.lst$/, '.ca65'); // TODO! could be .s
|
//const asmpath = fn.replace(/\.lst$/, '.ca65'); // TODO! could be .s
|
||||||
let isECS = step.debuginfo?.entities != null; // TODO
|
let isECS = step.debuginfo?.systems?.Init != null; // TODO
|
||||||
if (isECS) {
|
if (isECS) {
|
||||||
var asmlines = [];
|
var asmlines = [];
|
||||||
var srclines = parseCA65Listing(fn, lstout, symbolmap, segments, params, true, listings);
|
var srclines = parseCA65Listing(fn, lstout, symbolmap, segments, params, true, listings);
|
||||||
|
|
Loading…
Reference in New Issue