sms: fixed a few cases w/ http://www.smspower.org/Homebrew/SMSVDPTest-SMS
This commit is contained in:
parent
2dd5d88d55
commit
403b4264fc
|
@ -10,6 +10,7 @@ import { ColecoVision_PRESETS } from "./coleco";
|
||||||
// http://www.smspower.org/Development/Index
|
// http://www.smspower.org/Development/Index
|
||||||
// http://www.smspower.org/uploads/Development/sg1000.txt
|
// http://www.smspower.org/uploads/Development/sg1000.txt
|
||||||
// http://www.smspower.org/uploads/Development/richard.txt
|
// http://www.smspower.org/uploads/Development/richard.txt
|
||||||
|
// http://www.smspower.org/uploads/Development/msvdp-20021112.txt
|
||||||
|
|
||||||
// TODO: merge w/ coleco
|
// TODO: merge w/ coleco
|
||||||
export var SG1000_PRESETS = [
|
export var SG1000_PRESETS = [
|
||||||
|
@ -68,8 +69,8 @@ class SG1000Platform extends BaseZ80Platform {
|
||||||
inputs = new Uint8Array(4);
|
inputs = new Uint8Array(4);
|
||||||
mainElement : HTMLElement;
|
mainElement : HTMLElement;
|
||||||
|
|
||||||
isSMS = false; // TODO: remove
|
|
||||||
currentScanline : number;
|
currentScanline : number;
|
||||||
|
startLineTstates : number;
|
||||||
|
|
||||||
constructor(mainElement : HTMLElement) {
|
constructor(mainElement : HTMLElement) {
|
||||||
super();
|
super();
|
||||||
|
@ -96,13 +97,19 @@ class SG1000Platform extends BaseZ80Platform {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getVCounter() : number { return 0; }
|
||||||
|
getHCounter() : number { return 0; }
|
||||||
|
setMemoryControl(v:number) { }
|
||||||
|
setIOPortControl(v:number) { }
|
||||||
|
|
||||||
newIOBus() {
|
newIOBus() {
|
||||||
return {
|
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 this.isSMS ? this.currentScanline : 0;
|
case 0x40: return this.getVCounter();
|
||||||
|
case 0x41: return this.getHCounter();
|
||||||
case 0x80: return this.vdp.readData();
|
case 0x80: return this.vdp.readData();
|
||||||
case 0x81: return this.vdp.readStatus();
|
case 0x81: return this.vdp.readStatus();
|
||||||
case 0xc0: return this.inputs[0] ^ 0xff;
|
case 0xc0: return this.inputs[0] ^ 0xff;
|
||||||
|
@ -115,10 +122,12 @@ class SG1000Platform extends BaseZ80Platform {
|
||||||
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 this.vdp.writeData(val);
|
case 0x00: return this.setMemoryControl(val);
|
||||||
case 0x81: return this.vdp.writeAddress(val);
|
case 0x01: return this.setIOPortControl(val);
|
||||||
case 0x40:
|
case 0x40:
|
||||||
case 0x41: return this.psg.setData(val);
|
case 0x41: return this.psg.setData(val);
|
||||||
|
case 0x80: return this.vdp.writeData(val);
|
||||||
|
case 0x81: return this.vdp.writeAddress(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -159,6 +168,7 @@ class SG1000Platform extends BaseZ80Platform {
|
||||||
advance(novideo : boolean) {
|
advance(novideo : boolean) {
|
||||||
for (var sl=0; sl<this.numTotalScanlines; sl++) {
|
for (var sl=0; sl<this.numTotalScanlines; sl++) {
|
||||||
this.currentScanline = sl;
|
this.currentScanline = sl;
|
||||||
|
this.startLineTstates = this.cpu.getTstates();
|
||||||
this.runCPU(this.cpu, this.cpuCyclesPerLine);
|
this.runCPU(this.cpu, this.cpuCyclesPerLine);
|
||||||
this.vdp.drawScanline(sl);
|
this.vdp.drawScanline(sl);
|
||||||
}
|
}
|
||||||
|
@ -232,11 +242,12 @@ class SG1000Platform extends BaseZ80Platform {
|
||||||
|
|
||||||
class SMSPlatform extends SG1000Platform {
|
class SMSPlatform extends SG1000Platform {
|
||||||
|
|
||||||
isSMS = true;
|
|
||||||
|
|
||||||
cartram : RAM = new RAM(0);
|
cartram : RAM = new RAM(0);
|
||||||
pagingRegisters = new Uint8Array(4);
|
pagingRegisters = new Uint8Array(4);
|
||||||
romPageMask : number;
|
romPageMask : number;
|
||||||
|
// TODO: add to state
|
||||||
|
latchedHCounter = 0;
|
||||||
|
ioControlFlags = 0;
|
||||||
// TODO: hide bottom scanlines
|
// TODO: hide bottom scanlines
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
|
@ -248,6 +259,26 @@ class SMSPlatform extends SG1000Platform {
|
||||||
return new SMSVDP(frameData, cru, flicker);
|
return new SMSVDP(frameData, cru, flicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getVCounter() {
|
||||||
|
var y = this.currentScanline;
|
||||||
|
return (y <= 0xda) ? (y) : (y - 6);
|
||||||
|
}
|
||||||
|
getHCounter() {
|
||||||
|
return this.latchedHCounter;
|
||||||
|
}
|
||||||
|
computeHCounter() {
|
||||||
|
var t0 = this.startLineTstates;
|
||||||
|
var t1 = this.cpu.getTstates();
|
||||||
|
return (t1-t0) & 0xff; // TODO
|
||||||
|
}
|
||||||
|
setIOPortControl(v:number) {
|
||||||
|
if ((v ^ this.ioControlFlags) & 0xa0) { // either joystick TH pin
|
||||||
|
this.latchedHCounter = this.computeHCounter();
|
||||||
|
//console.log("H:"+hex(this.latchedHCounter)+" V:"+hex(this.getVCounter()));
|
||||||
|
}
|
||||||
|
this.ioControlFlags = v;
|
||||||
|
}
|
||||||
|
|
||||||
newRAM() { return new RAM(0x2000); }
|
newRAM() { return new RAM(0x2000); }
|
||||||
|
|
||||||
getPagedROM(a:number, reg:number) {
|
getPagedROM(a:number, reg:number) {
|
||||||
|
|
|
@ -43,8 +43,8 @@ export class TMS9918A {
|
||||||
latch : boolean;
|
latch : boolean;
|
||||||
prefetchByte : number;
|
prefetchByte : number;
|
||||||
|
|
||||||
displayOn = null;
|
displayOn : boolean = false;
|
||||||
interruptsOn = null;
|
interruptsOn : boolean = false;
|
||||||
screenMode : number;
|
screenMode : number;
|
||||||
bitmapMode : boolean;
|
bitmapMode : boolean;
|
||||||
textMode : boolean;
|
textMode : boolean;
|
||||||
|
@ -493,6 +493,7 @@ export class TMS9918A {
|
||||||
|
|
||||||
writeData(i:number) {
|
writeData(i:number) {
|
||||||
this.ram[this.addressRegister++] = i;
|
this.ram[this.addressRegister++] = i;
|
||||||
|
this.prefetchByte = i;
|
||||||
this.addressRegister &= this.ramMask;
|
this.addressRegister &= this.ramMask;
|
||||||
this.latch = false;
|
this.latch = false;
|
||||||
this.redrawRequired = true;
|
this.redrawRequired = true;
|
||||||
|
@ -674,6 +675,9 @@ export class SMSVDP extends TMS9918A {
|
||||||
cpalette = new Uint32Array(32); // color RAM (RGBA)
|
cpalette = new Uint32Array(32); // color RAM (RGBA)
|
||||||
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);
|
||||||
|
numVisibleLines = 192;
|
||||||
|
lineCounter = 0; // TODO: state
|
||||||
|
lineInterruptPending = false; // TODO: state
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
super.reset();
|
super.reset();
|
||||||
|
@ -682,6 +686,10 @@ export class SMSVDP extends TMS9918A {
|
||||||
this.cpalette.fill(0);
|
this.cpalette.fill(0);
|
||||||
this.vramUntwiddled.fill(0);
|
this.vramUntwiddled.fill(0);
|
||||||
}
|
}
|
||||||
|
readStatus() {
|
||||||
|
this.lineInterruptPending = false;
|
||||||
|
return super.readStatus();
|
||||||
|
}
|
||||||
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;
|
||||||
|
@ -713,6 +721,7 @@ export class SMSVDP extends TMS9918A {
|
||||||
var palindex = this.addressRegister++ & (this.cram.length-1);
|
var palindex = this.addressRegister++ & (this.cram.length-1);
|
||||||
this.cram[palindex] = i;
|
this.cram[palindex] = i;
|
||||||
this.cpalette[palindex] = RGBA((i&3)<<6, ((i>>2)&3)<<6, ((i>>4)&3)<<6);
|
this.cpalette[palindex] = RGBA((i&3)<<6, ((i>>2)&3)<<6, ((i>>4)&3)<<6);
|
||||||
|
this.prefetchByte = i;
|
||||||
this.addressRegister &= this.ramMask;
|
this.addressRegister &= this.ramMask;
|
||||||
this.redrawRequired = true;
|
this.redrawRequired = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -722,16 +731,6 @@ export class SMSVDP extends TMS9918A {
|
||||||
}
|
}
|
||||||
this.latch = false;
|
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;
|
||||||
|
@ -934,25 +933,24 @@ export class SMSVDP extends TMS9918A {
|
||||||
count = count | 0;
|
count = count | 0;
|
||||||
const borderIndex = 16 + (this.registers[7] & 0xf);
|
const borderIndex = 16 + (this.registers[7] & 0xf);
|
||||||
const borderRGB = this.cpalette[borderIndex];
|
const borderRGB = this.cpalette[borderIndex];
|
||||||
for (var i = 0; i < count; i++)
|
this.fb32.fill(borderRGB, lineAddr, lineAddr+count);
|
||||||
this.fb32[lineAddr + i] = borderRGB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rasterize_line(line:number) {
|
rasterize_line(line:number) {
|
||||||
|
line |= 0;
|
||||||
var vdp_regs = this.registers;
|
var vdp_regs = this.registers;
|
||||||
var drawHeight = 192; // TODO?
|
var drawWidth = 256;
|
||||||
var hBorder = (this.width - 256) >> 1;
|
var drawHeight = this.numVisibleLines; // TODO?
|
||||||
var vBorder = (this.height - 192) >> 1; // TODO?
|
var hBorder = (this.width - drawWidth) >> 1;
|
||||||
line = (line - vBorder*0) | 0; // TODO?
|
var vBorder = (this.height - drawHeight) >> 1; // TODO?
|
||||||
const startAddr = (line * this.width) | 0;
|
const startAddr = ((line + vBorder) * this.width) | 0;
|
||||||
const lineAddr = (startAddr + hBorder) | 0;
|
const lineAddr = (startAddr + hBorder) | 0;
|
||||||
if (!(line >= 0 && line < 224 && this.displayOn)) {
|
if (!this.displayOn || line < 0 || line >= drawHeight) {
|
||||||
|
if (line < this.height)
|
||||||
this.border_clear(startAddr, this.width);
|
this.border_clear(startAddr, this.width);
|
||||||
}
|
else if (line >= 262-vBorder)
|
||||||
else if ((vdp_regs[1] & 64) === 0) {
|
this.border_clear((line-262+vBorder)*this.width, this.width);
|
||||||
this.border_clear(startAddr, this.width);
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
var effectiveLine = line + vdp_regs[9];
|
var effectiveLine = line + vdp_regs[9];
|
||||||
if (effectiveLine >= 224) {
|
if (effectiveLine >= 224) {
|
||||||
effectiveLine -= 224;
|
effectiveLine -= 224;
|
||||||
|
@ -973,12 +971,29 @@ export class SMSVDP extends TMS9918A {
|
||||||
this.border_clear(lineAddr, 8);
|
this.border_clear(lineAddr, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// frame interrupts
|
||||||
if (line == drawHeight) {
|
if (line == drawHeight) {
|
||||||
this.statusRegister |= 0x80;
|
this.statusRegister |= 0x80;
|
||||||
if (this.interruptsOn) {
|
if (this.interruptsOn) {
|
||||||
this.cru.setVDPInterrupt(true);
|
this.cru.setVDPInterrupt(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// line interrupts
|
||||||
|
if (line <= drawHeight) {
|
||||||
|
if (this.lineCounter > 0) {
|
||||||
|
this.lineCounter--;
|
||||||
|
} else {
|
||||||
|
this.lineCounter = this.registers[0xa];
|
||||||
|
this.lineInterruptPending = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.lineCounter = this.registers[0xa];
|
||||||
|
}
|
||||||
|
if (this.lineInterruptPending) {
|
||||||
|
if (this.registers[0] & 0x10) {
|
||||||
|
// TODO this.cru.setVDPInterrupt(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getDebugTables() {
|
getDebugTables() {
|
||||||
|
|
Loading…
Reference in New Issue