mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-07 04:30:46 +00:00
sms: made into classes, more vdp fixed (still need to pass vdptest); debug fn bound to platform
This commit is contained in:
parent
23f32b2dd3
commit
2dd5d88d55
@ -83,7 +83,7 @@ export interface Platform {
|
|||||||
runToPC?(pc:number) : void;
|
runToPC?(pc:number) : void;
|
||||||
runUntilReturn?() : void;
|
runUntilReturn?() : void;
|
||||||
stepBack?() : void;
|
stepBack?() : void;
|
||||||
runEval?(evalfunc/* : DebugEvalCondition*/) : void;
|
runEval?(evalfunc : DebugEvalCondition) : void;
|
||||||
|
|
||||||
getOpcodeMetadata?(opcode:number, offset:number) : OpcodeMetadata; //TODO
|
getOpcodeMetadata?(opcode:number, offset:number) : OpcodeMetadata; //TODO
|
||||||
getSP?() : number;
|
getSP?() : number;
|
||||||
@ -113,9 +113,9 @@ export interface MemoryBus {
|
|||||||
write : (address:number, value:number) => void;
|
write : (address:number, value:number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type DebugCondition = () => boolean;
|
export type DebugCondition = () => boolean;
|
||||||
type DebugEvalCondition = (c:CpuState) => boolean;
|
export type DebugEvalCondition = (c:CpuState) => boolean;
|
||||||
type BreakpointCallback = (EmuState) => void;
|
export type BreakpointCallback = (s:EmuState) => void;
|
||||||
|
|
||||||
export interface EmuRecorder {
|
export interface EmuRecorder {
|
||||||
frameRequested() : boolean;
|
frameRequested() : boolean;
|
||||||
|
@ -47,50 +47,66 @@ var SG1000_KEYCODE_MAP = makeKeycodeMap([
|
|||||||
[Keys.VK_1, 1, 0x10],
|
[Keys.VK_1, 1, 0x10],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// standard emulator
|
class SG1000Platform extends BaseZ80Platform {
|
||||||
|
|
||||||
const _SG1000Platform = function(mainElement, isSMS:boolean) {
|
cpuFrequency = 3579545; // MHz
|
||||||
|
canvasWidth = 304;
|
||||||
|
numTotalScanlines = 262;
|
||||||
|
numVisibleScanlines = 240;
|
||||||
|
cpuCyclesPerLine;
|
||||||
|
|
||||||
const cpuFrequency = 3579545; // MHz
|
cpu;
|
||||||
const canvasWidth = 304;
|
ram : RAM;
|
||||||
const numTotalScanlines = 262;
|
membus;
|
||||||
const numVisibleScanlines = 240;
|
iobus;
|
||||||
const cpuCyclesPerLine = Math.round(cpuFrequency / 60 / numTotalScanlines);
|
rom = new Uint8Array(0);
|
||||||
|
video;
|
||||||
|
vdp;
|
||||||
|
timer;
|
||||||
|
audio;
|
||||||
|
psg;
|
||||||
|
inputs = new Uint8Array(4);
|
||||||
|
mainElement : HTMLElement;
|
||||||
|
|
||||||
var cpu, ram, membus, iobus, rom;
|
isSMS = false; // TODO: remove
|
||||||
var video, vdp, timer;
|
currentScanline : number;
|
||||||
var audio, psg;
|
|
||||||
var inputs = new Uint8Array(4);
|
|
||||||
|
|
||||||
class SG1000Platform extends BaseZ80Platform implements Platform {
|
constructor(mainElement : HTMLElement) {
|
||||||
|
super();
|
||||||
currentScanline;
|
this.mainElement = mainElement;
|
||||||
|
}
|
||||||
|
|
||||||
getPresets() { return SG1000_PRESETS; }
|
getPresets() { return SG1000_PRESETS; }
|
||||||
|
|
||||||
start() {
|
newRAM() {
|
||||||
var ramSize = isSMS ? 0x2000 : 0x400;
|
return new RAM(0x400);
|
||||||
ram = new RAM(ramSize);
|
}
|
||||||
membus = {
|
|
||||||
|
newMembus() {
|
||||||
|
var ramSize = this.ram.mem.length;
|
||||||
|
return {
|
||||||
read: newAddressDecoder([
|
read: newAddressDecoder([
|
||||||
[0xc000, 0xffff, ramSize-1, function(a) { return ram.mem[a]; }],
|
[0xc000, 0xffff, ramSize-1, (a) => { return this.ram.mem[a]; }],
|
||||||
[0x0000, 0xbfff, 0xffff, function(a) { return rom ? rom[a] : 0; }],
|
[0x0000, 0xbfff, 0xffff, (a) => { return this.rom[a]; }],
|
||||||
]),
|
]),
|
||||||
write: newAddressDecoder([
|
write: newAddressDecoder([
|
||||||
[0xc000, 0xffff, ramSize-1, function(a,v) { ram.mem[a] = v; }],
|
[0xc000, 0xffff, ramSize-1, (a,v) => { this.ram.mem[a] = v; }],
|
||||||
]),
|
]),
|
||||||
isContended: function() { return false; },
|
isContended: () => { return false; },
|
||||||
};
|
};
|
||||||
iobus = {
|
}
|
||||||
|
|
||||||
|
newIOBus() {
|
||||||
|
return {
|
||||||
read: (addr:number) => {
|
read: (addr:number) => {
|
||||||
addr &= 0xff;
|
addr &= 0xff;
|
||||||
//console.log('IO read', hex(addr,4));
|
//console.log('IO read', hex(addr,4));
|
||||||
switch (addr & 0xc1) {
|
switch (addr & 0xc1) {
|
||||||
case 0x40: return isSMS ? this.currentScanline : 0;
|
case 0x40: return this.isSMS ? this.currentScanline : 0;
|
||||||
case 0x80: return vdp.readData();
|
case 0x80: return this.vdp.readData();
|
||||||
case 0x81: return vdp.readStatus();
|
case 0x81: return this.vdp.readStatus();
|
||||||
case 0xc0: return inputs[0] ^ 0xff;
|
case 0xc0: return this.inputs[0] ^ 0xff;
|
||||||
case 0xc1: return inputs[1] ^ 0xff;
|
case 0xc1: return this.inputs[1] ^ 0xff;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
@ -99,105 +115,103 @@ const _SG1000Platform = function(mainElement, isSMS:boolean) {
|
|||||||
val &= 0xff;
|
val &= 0xff;
|
||||||
//console.log('IO write', hex(addr,4), hex(val,2));
|
//console.log('IO write', hex(addr,4), hex(val,2));
|
||||||
switch (addr & 0xc1) {
|
switch (addr & 0xc1) {
|
||||||
case 0x80: return vdp.writeData(val);
|
case 0x80: return this.vdp.writeData(val);
|
||||||
case 0x81: return vdp.writeAddress(val);
|
case 0x81: return this.vdp.writeAddress(val);
|
||||||
case 0x40:
|
case 0x40:
|
||||||
case 0x41: return psg.setData(val);
|
case 0x41: return this.psg.setData(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cpu = this.newCPU(membus, iobus);
|
}
|
||||||
video = new RasterVideo(mainElement,canvasWidth,numVisibleScanlines,{overscan:true});
|
|
||||||
video.create();
|
newVDP(frameData, cru, flicker) {
|
||||||
audio = new MasterAudio();
|
return new TMS9918A(frameData, cru, flicker);
|
||||||
psg = new SN76489_Audio(audio);
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.cpuCyclesPerLine = Math.round(this.cpuFrequency / 60 / this.numTotalScanlines);
|
||||||
|
this.ram = this.newRAM();
|
||||||
|
this.membus = this.newMembus();
|
||||||
|
this.iobus = this.newIOBus();
|
||||||
|
this.cpu = this.newCPU(this.membus, this.iobus);
|
||||||
|
this.video = new RasterVideo(this.mainElement, this.canvasWidth, this.numVisibleScanlines, {overscan:true});
|
||||||
|
this.video.create();
|
||||||
|
this.audio = new MasterAudio();
|
||||||
|
this.psg = new SN76489_Audio(this.audio);
|
||||||
var cru = {
|
var cru = {
|
||||||
setVDPInterrupt: (b) => {
|
setVDPInterrupt: (b) => {
|
||||||
if (b) {
|
if (b) {
|
||||||
cpu.nonMaskableInterrupt();
|
this.cpu.nonMaskableInterrupt();
|
||||||
} else {
|
} else {
|
||||||
// TODO: reset interrupt?
|
// TODO: reset interrupt?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var vdpclass = isSMS ? SMSVDP : TMS9918A;
|
this.vdp = this.newVDP(this.video.getFrameData(), cru, true); // true = 4 sprites/line
|
||||||
vdp = new vdpclass(video.getFrameData(), cru, true); // true = 4 sprites/line
|
setKeyboardFromMap(this.video, this.inputs, SG1000_KEYCODE_MAP); // TODO
|
||||||
setKeyboardFromMap(video, inputs, SG1000_KEYCODE_MAP);
|
this.timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
||||||
timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readAddress(addr) {
|
readAddress(addr) {
|
||||||
return membus.read(addr);
|
return this.membus.read(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
advance(novideo : boolean) {
|
advance(novideo : boolean) {
|
||||||
for (var sl=0; sl<numTotalScanlines; sl++) {
|
for (var sl=0; sl<this.numTotalScanlines; sl++) {
|
||||||
this.currentScanline = sl;
|
this.currentScanline = sl;
|
||||||
this.runCPU(cpu, cpuCyclesPerLine);
|
this.runCPU(this.cpu, this.cpuCyclesPerLine);
|
||||||
vdp.drawScanline(sl);
|
this.vdp.drawScanline(sl);
|
||||||
}
|
}
|
||||||
video.updateFrame();
|
this.video.updateFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadROM(title, data) {
|
loadROM(title, data) {
|
||||||
if (data.length < 0xc000) {
|
this.rom = padBytes(data, 0xc000);
|
||||||
rom = padBytes(data, 0xc000);
|
|
||||||
} else {
|
|
||||||
switch (data.length) {
|
|
||||||
case 0x10000:
|
|
||||||
case 0x20000:
|
|
||||||
case 0x40000:
|
|
||||||
rom = data;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw "Unknown rom size: $" + hex(data.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadState(state) {
|
loadState(state) {
|
||||||
cpu.loadState(state.c);
|
this.cpu.loadState(state.c);
|
||||||
ram.mem.set(state.b);
|
this.ram.mem.set(state.b);
|
||||||
vdp.restoreState(state.vdp);
|
this.vdp.restoreState(state.vdp);
|
||||||
inputs.set(state.in);
|
this.inputs.set(state.in);
|
||||||
}
|
}
|
||||||
saveState() {
|
saveState() {
|
||||||
return {
|
return {
|
||||||
c:this.getCPUState(),
|
c:this.getCPUState(),
|
||||||
b:ram.mem.slice(0),
|
b:this.ram.mem.slice(0),
|
||||||
vdp:vdp.getState(),
|
vdp:this.vdp.getState(),
|
||||||
in:inputs.slice(0),
|
in:this.inputs.slice(0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
loadControlsState(state) {
|
loadControlsState(state) {
|
||||||
inputs.set(state.in);
|
this.inputs.set(state.in);
|
||||||
}
|
}
|
||||||
saveControlsState() {
|
saveControlsState() {
|
||||||
return {
|
return {
|
||||||
in:inputs.slice(0)
|
in:this.inputs.slice(0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
getCPUState() {
|
getCPUState() {
|
||||||
return cpu.saveState();
|
return this.cpu.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
isRunning() {
|
isRunning() {
|
||||||
return timer && timer.isRunning();
|
return this.timer && this.timer.isRunning();
|
||||||
}
|
}
|
||||||
pause() {
|
pause() {
|
||||||
timer.stop();
|
this.timer.stop();
|
||||||
audio.stop();
|
this.audio.stop();
|
||||||
}
|
}
|
||||||
resume() {
|
resume() {
|
||||||
timer.start();
|
this.timer.start();
|
||||||
audio.start();
|
this.audio.start();
|
||||||
}
|
}
|
||||||
reset() {
|
reset() {
|
||||||
cpu.reset();
|
this.cpu.reset();
|
||||||
cpu.setTstates(0);
|
this.cpu.setTstates(0);
|
||||||
vdp.reset();
|
this.vdp.reset();
|
||||||
psg.reset();
|
this.psg.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
getDebugCategories() {
|
getDebugCategories() {
|
||||||
@ -210,19 +224,117 @@ const _SG1000Platform = function(mainElement, isSMS:boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
vdpStateToLongString(ppu) {
|
vdpStateToLongString(ppu) {
|
||||||
return vdp.getRegsString();
|
return this.vdp.getRegsString();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return new SG1000Platform();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
||||||
const _SMSPlatform = function(mainElement) {
|
class SMSPlatform extends SG1000Platform {
|
||||||
this.__proto__ = new (_SG1000Platform as any)(mainElement, true);
|
|
||||||
|
isSMS = true;
|
||||||
|
|
||||||
|
cartram : RAM = new RAM(0);
|
||||||
|
pagingRegisters = new Uint8Array(4);
|
||||||
|
romPageMask : number;
|
||||||
|
// TODO: hide bottom scanlines
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
super.reset();
|
||||||
|
this.pagingRegisters.set([0,0,1,2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
newVDP(frameData, cru, flicker) {
|
||||||
|
return new SMSVDP(frameData, cru, flicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
newRAM() { return new RAM(0x2000); }
|
||||||
|
|
||||||
|
getPagedROM(a:number, reg:number) {
|
||||||
|
//if (!(a&0xff)) console.log(hex(a), reg, this.pagingRegisters[reg], this.romPageMask);
|
||||||
|
return this.rom[a + ((this.pagingRegisters[reg] & this.romPageMask) << 14)]; // * $4000
|
||||||
|
}
|
||||||
|
|
||||||
|
newMembus() {
|
||||||
|
return {
|
||||||
|
read: newAddressDecoder([
|
||||||
|
[0xc000, 0xffff, 0x1fff, (a) => { return this.ram.mem[a]; }],
|
||||||
|
[0x0000, 0x03ff, 0x3ff, (a) => { return this.rom[a]; }],
|
||||||
|
[0x0400, 0x3fff, 0x3fff, (a) => { return this.getPagedROM(a,1); }],
|
||||||
|
[0x4000, 0x7fff, 0x3fff, (a) => { return this.getPagedROM(a,2); }],
|
||||||
|
[0x8000, 0xbfff, 0x3fff, (a) => {
|
||||||
|
var reg0 = this.pagingRegisters[0]; // RAM select?
|
||||||
|
if (reg0 & 0x8) {
|
||||||
|
return this.cartram.mem[(reg0 & 0x4) ? a+0x4000 : a];
|
||||||
|
} else {
|
||||||
|
return this.getPagedROM(a,3);
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
]),
|
||||||
|
write: newAddressDecoder([
|
||||||
|
[0xc000, 0xfffb, 0x1fff, (a,v) => {
|
||||||
|
this.ram.mem[a] = v;
|
||||||
|
}],
|
||||||
|
[0xfffc, 0xffff, 0x3, (a,v) => {
|
||||||
|
this.pagingRegisters[a] = v;
|
||||||
|
this.ram.mem[a+0x1ffc] = v;
|
||||||
|
}],
|
||||||
|
[0x8000, 0xbfff, 0x3fff, (a,v) => {
|
||||||
|
var reg0 = this.pagingRegisters[0]; // RAM select?
|
||||||
|
if (reg0 & 0x8) {
|
||||||
|
if (this.cartram.mem.length == 0)
|
||||||
|
this.cartram = new RAM(0x8000); // create cartridge RAM lazily
|
||||||
|
this.cartram.mem[(reg0 & 0x4) ? a+0x4000 : a] = v;
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
]),
|
||||||
|
isContended: () => { return false; },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
loadROM(title, data) {
|
||||||
|
if (data.length <= 0xc000) {
|
||||||
|
this.rom = padBytes(data, 0xc000);
|
||||||
|
this.romPageMask = 3; // only pages 0, 1, 2
|
||||||
|
} else {
|
||||||
|
switch (data.length) {
|
||||||
|
case 0x10000:
|
||||||
|
case 0x20000:
|
||||||
|
case 0x40000:
|
||||||
|
case 0x80000:
|
||||||
|
this.rom = data;
|
||||||
|
this.romPageMask = (data.length >> 14) - 1; // div $4000
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw "Unknown rom size: $" + hex(data.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("romPageMask: " + hex(this.romPageMask));
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadState(state) {
|
||||||
|
super.loadState(state);
|
||||||
|
this.pagingRegisters.set(state.pr);
|
||||||
|
this.cartram.mem.set(state.cr);
|
||||||
|
}
|
||||||
|
saveState() {
|
||||||
|
var state = super.saveState();
|
||||||
|
state['pr'] = this.pagingRegisters.slice(0);
|
||||||
|
state['cr'] = this.cartram.mem.slice(0);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
getDebugInfo(category, state) {
|
||||||
|
switch (category) {
|
||||||
|
case 'CPU':
|
||||||
|
return super.getDebugInfo(category, state) +
|
||||||
|
"\nBank Regs: " + this.pagingRegisters + "\n";
|
||||||
|
default: return super.getDebugInfo(category, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
||||||
PLATFORMS['sms-sg1000-libcv'] = _SG1000Platform;
|
PLATFORMS['sms-sg1000-libcv'] = SG1000Platform;
|
||||||
PLATFORMS['sms-sms-libcv'] = _SMSPlatform;
|
PLATFORMS['sms-sms-libcv'] = SMSPlatform;
|
||||||
|
10
src/ui.ts
10
src/ui.ts
@ -7,7 +7,7 @@ import * as bootstrap from "bootstrap";
|
|||||||
import { CodeProject } from "./project";
|
import { CodeProject } from "./project";
|
||||||
import { WorkerResult, WorkerOutput, VerilogOutput, SourceFile, WorkerError, FileData } from "./workertypes";
|
import { WorkerResult, WorkerOutput, VerilogOutput, SourceFile, WorkerError, FileData } from "./workertypes";
|
||||||
import { ProjectWindows } from "./windows";
|
import { ProjectWindows } from "./windows";
|
||||||
import { Platform, Preset, DebugSymbols } from "./baseplatform";
|
import { Platform, Preset, DebugSymbols, DebugEvalCondition } from "./baseplatform";
|
||||||
import { PLATFORMS } from "./emu";
|
import { PLATFORMS } from "./emu";
|
||||||
import * as Views from "./views";
|
import * as Views from "./views";
|
||||||
import { createNewPersistentStore } from "./store";
|
import { createNewPersistentStore } from "./store";
|
||||||
@ -716,7 +716,7 @@ function runToCursor() {
|
|||||||
if (platform.runToPC) {
|
if (platform.runToPC) {
|
||||||
platform.runToPC(pc);
|
platform.runToPC(pc);
|
||||||
} else {
|
} else {
|
||||||
platform.runEval(function(c) {
|
platform.runEval((c) => {
|
||||||
return c.PC == pc;
|
return c.PC == pc;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -748,7 +748,7 @@ function resetAndDebug() {
|
|||||||
platform.reset();
|
platform.reset();
|
||||||
setupBreakpoint("reset");
|
setupBreakpoint("reset");
|
||||||
if (platform.runEval)
|
if (platform.runEval)
|
||||||
platform.runEval(function(c) { return true; }); // break immediately
|
platform.runEval((c) => { return true; }); // break immediately
|
||||||
else
|
else
|
||||||
; // TODO???
|
; // TODO???
|
||||||
} else {
|
} else {
|
||||||
@ -760,9 +760,9 @@ var lastBreakExpr = "c.PC == 0x6000";
|
|||||||
function _breakExpression() {
|
function _breakExpression() {
|
||||||
var exprs = window.prompt("Enter break expression", lastBreakExpr);
|
var exprs = window.prompt("Enter break expression", lastBreakExpr);
|
||||||
if (exprs) {
|
if (exprs) {
|
||||||
var fn = new Function('c', 'return (' + exprs + ');');
|
var fn = new Function('c', 'return (' + exprs + ');').bind(platform);
|
||||||
setupBreakpoint();
|
setupBreakpoint();
|
||||||
platform.runEval(fn);
|
platform.runEval(fn as DebugEvalCondition);
|
||||||
lastBreakExpr = exprs;
|
lastBreakExpr = exprs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,19 +91,14 @@ export class TMS9918A {
|
|||||||
RGBA(204, 204, 204),
|
RGBA(204, 204, 204),
|
||||||
RGBA(255, 255, 255)
|
RGBA(255, 255, 255)
|
||||||
];
|
];
|
||||||
|
|
||||||
this.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
for (i = 0; i < this.ram.length; i++) {
|
this.ram.fill(0);
|
||||||
this.ram[i] = 0;
|
this.registers.fill(0);
|
||||||
}
|
|
||||||
for (i = 0; i < this.registers.length; i++) {
|
|
||||||
this.registers[i] = 0;
|
|
||||||
}
|
|
||||||
this.addressRegister = 0;
|
this.addressRegister = 0;
|
||||||
this.statusRegister = 0;
|
this.statusRegister = 0;
|
||||||
|
|
||||||
@ -499,6 +494,7 @@ export class TMS9918A {
|
|||||||
writeData(i:number) {
|
writeData(i:number) {
|
||||||
this.ram[this.addressRegister++] = i;
|
this.ram[this.addressRegister++] = i;
|
||||||
this.addressRegister &= this.ramMask;
|
this.addressRegister &= this.ramMask;
|
||||||
|
this.latch = false;
|
||||||
this.redrawRequired = true;
|
this.redrawRequired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,6 +512,7 @@ export class TMS9918A {
|
|||||||
var i = this.prefetchByte;
|
var i = this.prefetchByte;
|
||||||
this.prefetchByte = this.ram[this.addressRegister++];
|
this.prefetchByte = this.ram[this.addressRegister++];
|
||||||
this.addressRegister &= this.ramMask;
|
this.addressRegister &= this.ramMask;
|
||||||
|
this.latch = false;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,6 +675,13 @@ export class SMSVDP extends TMS9918A {
|
|||||||
registers = new Uint8Array(16); // 8 more registers (actually only 5)
|
registers = new Uint8Array(16); // 8 more registers (actually only 5)
|
||||||
vramUntwiddled = new Uint8Array(0x8000);
|
vramUntwiddled = new Uint8Array(0x8000);
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
super.reset();
|
||||||
|
this.writeToCRAM = false;
|
||||||
|
this.cram.fill(0);
|
||||||
|
this.cpalette.fill(0);
|
||||||
|
this.vramUntwiddled.fill(0);
|
||||||
|
}
|
||||||
updateMode(reg0:number, reg1:number) {
|
updateMode(reg0:number, reg1:number) {
|
||||||
if (reg0 & 0x04) {
|
if (reg0 & 0x04) {
|
||||||
this.screenMode = TMS9918A_Mode.MODE4;
|
this.screenMode = TMS9918A_Mode.MODE4;
|
||||||
@ -697,11 +701,12 @@ export class SMSVDP extends TMS9918A {
|
|||||||
}
|
}
|
||||||
setVDPWriteRegister(i:number) {
|
setVDPWriteRegister(i:number) {
|
||||||
super.setVDPWriteRegister(i);
|
super.setVDPWriteRegister(i);
|
||||||
this.writeToCRAM = false;
|
//this.writeToCRAM = false; // TODO?
|
||||||
this.ramMask = 0x3fff;
|
this.ramMask = 0x3fff;
|
||||||
}
|
}
|
||||||
setVDPWriteCommand3(i:number) {
|
setVDPWriteCommand3(i:number) {
|
||||||
this.writeToCRAM = true;
|
this.writeToCRAM = true;
|
||||||
|
//this.addressRegister &= 0x1f; // TODO?
|
||||||
}
|
}
|
||||||
writeData(i:number) {
|
writeData(i:number) {
|
||||||
if (this.writeToCRAM) {
|
if (this.writeToCRAM) {
|
||||||
@ -715,7 +720,18 @@ export class SMSVDP extends TMS9918A {
|
|||||||
super.writeData(i);
|
super.writeData(i);
|
||||||
this.writeTwiddled(oldAddress, i);
|
this.writeTwiddled(oldAddress, i);
|
||||||
}
|
}
|
||||||
|
this.latch = false;
|
||||||
}
|
}
|
||||||
|
readData() : number {
|
||||||
|
if (this.writeToCRAM) {
|
||||||
|
var palindex = this.addressRegister++ & (this.cram.length-1);
|
||||||
|
this.addressRegister &= this.ramMask;
|
||||||
|
return this.cram[palindex];
|
||||||
|
} else {
|
||||||
|
return super.readData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writeTwiddled(vdp_addr:number, val:number) {
|
writeTwiddled(vdp_addr:number, val:number) {
|
||||||
var planarBase = vdp_addr & 0x3ffc;
|
var planarBase = vdp_addr & 0x3ffc;
|
||||||
var twiddledBase = planarBase * 2;
|
var twiddledBase = planarBase * 2;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user