Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement 65c02 and use it on Tube #434

Merged
merged 1 commit into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions 6502.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use strict";
import * as utils from "./utils.js";
import * as opcodes from "./6502.opcodes.js";
import * as via from "./via.js";
import { Acia } from "./acia.js";
import { Serial } from "./serial.js";
Expand Down Expand Up @@ -107,7 +106,7 @@ class Base6502 {
this.a = this.x = this.y = this.s = 0;
this.p = new Flags();
this.pc = 0;
this.opcodes = model.nmos ? opcodes.Cpu6502(this) : opcodes.Cpu65c12(this);
this.opcodes = model.opcodesFactory(this);
this.disassembler = this.opcodes.disassembler;
this.forceTracing = false;
this.runner = this.opcodes.runInstruction;
Expand Down
105 changes: 101 additions & 4 deletions 6502.opcodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,52 @@ function getOp(op, arg) {
read: true,
write: true,
};
case "RMB0":
case "RMB1":
case "RMB2":
case "RMB3":
case "RMB4":
case "RMB5":
case "RMB6":
case "RMB7":
return {
op: [`REG = REG & (${~(1 << (op[3] - "0"))});`],
read: true,
write: true,
};
case "SMB0":
case "SMB1":
case "SMB2":
case "SMB3":
case "SMB4":
case "SMB5":
case "SMB6":
case "SMB7":
return {
op: [`REG = REG | ${1 << (op[3] - "0")};`],
read: true,
write: true,
};
case "BBR0":
case "BBR1":
case "BBR2":
case "BBR3":
case "BBR4":
case "BBR5":
case "BBR6":
case "BBR7":
return { op: `cpu.branch(!(REG & ${1 << (op[3] - "0")}));`, read: true };
case "BBS0":
case "BBS1":
case "BBS2":
case "BBS3":
case "BBS4":
case "BBS5":
case "BBS6":
case "BBS7":
return { op: `cpu.branch(REG & ${1 << (op[3] - "0")});`, read: true };
}
return null;
throw new Error(`Unrecognised operation '${op}'`);
}

const opcodes6502 = {
Expand Down Expand Up @@ -902,6 +946,42 @@ const opcodes65c12 = {
0xfe: "INC abs,x",
};

const opcodes65c02 = {
...opcodes65c12,
0x07: "RMB0 zp",
0x17: "RMB1 zp",
0x27: "RMB2 zp",
0x37: "RMB3 zp",
0x47: "RMB4 zp",
0x57: "RMB5 zp",
0x67: "RMB6 zp",
0x77: "RMB7 zp",
0x87: "SMB0 zp",
0x97: "SMB1 zp",
0xa7: "SMB2 zp",
0xb7: "SMB3 zp",
0xc7: "SMB4 zp",
0xd7: "SMB5 zp",
0xe7: "SMB6 zp",
0xf7: "SMB7 zp",
0x0f: "BBR0 zp,branch",
0x1f: "BBR1 zp,branch",
0x2f: "BBR2 zp,branch",
0x3f: "BBR3 zp,branch",
0x4f: "BBR4 zp,branch",
0x5f: "BBR5 zp,branch",
0x6f: "BBR6 zp,branch",
0x7f: "BBR7 zp,branch",
0x8f: "BBS0 zp,branch",
0x9f: "BBS1 zp,branch",
0xaf: "BBS2 zp,branch",
0xbf: "BBS3 zp,branch",
0xcf: "BBS4 zp,branch",
0xdf: "BBS5 zp,branch",
0xef: "BBS6 zp,branch",
0xff: "BBS7 zp,branch",
};

class Disassemble6502 {
constructor(cpu, opcodes) {
this.cpu = cpu;
Expand Down Expand Up @@ -986,7 +1066,7 @@ function makeCpuFunctions(cpu, opcodes, is65c12) {
switch (arg) {
case undefined:
// Many of these ops need a little special casing.
if (op.read || op.write) throw "Unsupported " + opcodeString;
if (op.read || op.write) throw new Error(`Unsupported ${opcodeString}`);
ig.append(op.preop);
ig.tick(Math.max(2, 1 + (op.extra || 0)));
ig.append(op.op);
Expand All @@ -995,6 +1075,19 @@ function makeCpuFunctions(cpu, opcodes, is65c12) {
case "branch":
return [op.op]; // special cased here, would be nice to pull out of cpu

case "zp,branch":
ig.tick(2);
ig.append("const addr = cpu.getb() | 0;");
if (op.read) {
ig.zpReadOp("addr", "REG");
if (op.write) {
ig.tick(1); // Spurious write
}
}
ig.append(op.op);
if (op.write) ig.zpWriteOp("addr", "REG");
return ig.render();

case "zp":
case "zpx": // Seems to be enough to keep tests happy, but needs investigation.
case "zp,x":
Expand Down Expand Up @@ -1082,7 +1175,7 @@ function makeCpuFunctions(cpu, opcodes, is65c12) {

case "imm":
if (op.write) {
throw "This isn't possible";
throw new Error("This isn't possible");
}
if (op.read) {
// NOP imm
Expand Down Expand Up @@ -1188,7 +1281,7 @@ function makeCpuFunctions(cpu, opcodes, is65c12) {
return ig.render();

default:
throw "Unknown arg type " + arg;
throw new Error(`Unknown arg type ${arg}`);
}
}

Expand Down Expand Up @@ -1309,3 +1402,7 @@ export function Cpu6502(cpu) {
export function Cpu65c12(cpu) {
return makeCpuFunctions(cpu, opcodes65c12, true);
}

export function Cpu65c02(cpu) {
return makeCpuFunctions(cpu, opcodes65c02, true);
}
9 changes: 7 additions & 2 deletions fake6502.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Fakes out a 6502
// Fakes out various 6502s for testing purposes.
"use strict";

import { FakeVideo } from "./video.js";
import { FakeSoundChip } from "./soundchip.js";
import { TEST_6502, TEST_65C12 } from "./models.js";
import { findModel, TEST_6502, TEST_65C02, TEST_65C12 } from "./models.js";
import { FakeDdNoise } from "./ddnoise.js";
import { Cpu6502 } from "./6502.js";
import { Cmos } from "./cmos.js";
Expand All @@ -19,9 +19,14 @@ export function fake6502(model, opts) {
opts = opts || {};
const video = opts.video || fakeVideo;
model = model || TEST_6502;
if (opts.tube) model.tube = findModel("Tube65c02");
return new Cpu6502(model, dbgr, video, soundChip, new FakeDdNoise(), new FakeMusic5000(), new Cmos());
}

export function fake65C02() {
return fake6502(TEST_65C02);
}

export function fake65C12() {
return fake6502(TEST_65C12);
}
53 changes: 40 additions & 13 deletions models.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,55 @@

import { NoiseAwareWdFdc } from "./wd-fdc.js";
import { NoiseAwareIntelFdc } from "./intel-fdc.js";
import * as opcodes from "./6502.opcodes.js";

const CpuModel = Object.freeze({
MOS6502: 0,
CMOS65C02: 1,
CMOS65C12: 2,
});

class Model {
constructor(name, synonyms, os, nmos, isMaster, swram, fdc, tube, cmosOverride) {
constructor(name, synonyms, os, cpuModel, isMaster, swram, fdc, tube, cmosOverride) {
this.name = name;
this.synonyms = synonyms;
this.os = os;
this.nmos = nmos;
this._cpuModel = cpuModel;
this.isMaster = isMaster;
this.Fdc = fdc;
this.swram = swram;
this.isTest = false;
this.tube = tube;
this.cmosOverride = cmosOverride;
}

get nmos() {
return this._cpuModel === CpuModel.MOS6502;
}

get opcodesFactory() {
switch (this._cpuModel) {
case CpuModel.MOS6502:
return opcodes.Cpu6502;
case CpuModel.CMOS65C02:
return opcodes.Cpu65c02;
case CpuModel.CMOS65C12:
return opcodes.Cpu65c12;
}
throw new Error("Unknown CPU model");
}
}

function pickAdfs(cmos) {
cmos[19] = (cmos[19] & 0xf0) | 13;
return cmos;
}

function pickAnfs(cmos) {
cmos[19] = (cmos[19] & 0xf0) | 8;
return cmos;
}

function pickDfs(cmos) {
cmos[19] = (cmos[19] & 0xf0) | 9;
return cmos;
Expand Down Expand Up @@ -74,7 +99,7 @@ export const allModels = [
"BBC B with DFS 1.2",
["B-DFS1.2"],
["os.rom", "BASIC.ROM", "b/DFS-1.2.rom"],
true,
CpuModel.MOS6502,
false,
beebSwram,
NoiseAwareIntelFdc,
Expand All @@ -83,7 +108,7 @@ export const allModels = [
"BBC B with DFS 0.9",
["B-DFS0.9", "B"],
["os.rom", "BASIC.ROM", "b/DFS-0.9.rom"],
true,
CpuModel.MOS6502,
false,
beebSwram,
NoiseAwareIntelFdc,
Expand All @@ -92,7 +117,7 @@ export const allModels = [
"BBC B with 1770 (DFS)",
["B1770"],
["os.rom", "BASIC.ROM", "b1770/dfs1770.rom", "b1770/zADFS.ROM"],
true,
CpuModel.MOS6502,
false,
beebSwram,
NoiseAwareWdFdc,
Expand All @@ -102,7 +127,7 @@ export const allModels = [
"BBC B with 1770 (ADFS)",
["B1770A"],
["os.rom", "BASIC.ROM", "b1770/zADFS.ROM", "b1770/dfs1770.rom"],
true,
CpuModel.MOS6502,
false,
beebSwram,
NoiseAwareWdFdc,
Expand All @@ -111,7 +136,7 @@ export const allModels = [
"BBC Master 128 (DFS)",
["Master"],
["master/mos3.20"],
false,
CpuModel.CMOS65C12,
true,
masterSwram,
NoiseAwareWdFdc,
Expand All @@ -122,7 +147,7 @@ export const allModels = [
"BBC Master 128 (ADFS)",
["MasterADFS"],
["master/mos3.20"],
false,
CpuModel.CMOS65C12,
true,
masterSwram,
NoiseAwareWdFdc,
Expand All @@ -133,14 +158,14 @@ export const allModels = [
"BBC Master 128 (ANFS)",
["MasterANFS"],
["master/mos3.20"],
false,
CpuModel.CMOS65C12,
true,
masterSwram,
NoiseAwareWdFdc,
null,
pickAnfs,
),
new Model("Tube65C02", [], ["tube/6502Tube.rom"], false, false), // Although this can not be explicitly selected as a model, it is required by the configuration builder later
new Model("Tube65C02", [], ["tube/6502Tube.rom"], CpuModel.CMOS65C02, false), // Although this can not be explicitly selected as a model, it is required by the configuration builder later
];

export function findModel(name) {
Expand All @@ -155,16 +180,18 @@ export function findModel(name) {
return null;
}

export const TEST_6502 = new Model("TEST", ["TEST"], [], true, false, beebSwram, NoiseAwareIntelFdc);
export const TEST_6502 = new Model("TEST", ["TEST"], [], CpuModel.MOS6502, false, beebSwram, NoiseAwareIntelFdc);
TEST_6502.isTest = true;
export const TEST_65C12 = new Model("TEST", ["TEST"], [], false, false, masterSwram, NoiseAwareIntelFdc);
export const TEST_65C02 = new Model("TEST", ["TEST"], [], CpuModel.CMOS65C02, false, masterSwram, NoiseAwareIntelFdc);
TEST_65C02.isTest = true;
export const TEST_65C12 = new Model("TEST", ["TEST"], [], CpuModel.CMOS65C12, false, masterSwram, NoiseAwareIntelFdc);
TEST_65C12.isTest = true;

export const basicOnly = new Model(
"Basic only",
["Basic only"],
["master/mos3.20"],
false,
CpuModel.CMOS65C12,
true,
masterSwram,
NoiseAwareWdFdc,
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
"test-long:cpu": "node tests/test-suite.js",
"test:unit": "mocha tests/unit",
"test:integration": "mocha tests/integration",
"test:dormann": "node tests/test-dormann.js",
"test": "npm-run-all -p test:*",
"test-long": "npm-run-all -p test-long:*",
"benchmark": "node app-bench.js"
Expand Down
Loading