1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-17 19:29:44 +00:00

more work on SMS VDP

This commit is contained in:
Steven Hugg 2018-11-30 17:46:21 -05:00
parent 62bf05c1f4
commit 8a1c88f3de
2 changed files with 178 additions and 4 deletions

View File

@ -141,7 +141,7 @@ const _SG1000Platform = function(mainElement, isSMS:boolean) {
}
loadROM(title, data) {
rom = padBytes(data, 0xc000);
rom = padBytes(data, 0xc000); // TODO
this.reset();
}

View File

@ -20,6 +20,7 @@ enum TMS9918A_Mode {
BITMAP_TEXT = 4,
BITMAP_MULTICOLOR = 5,
ILLEGAL = 6,
MODE4 = 7,
};
/**
@ -427,8 +428,7 @@ export class TMS9918A {
writeAddress(i:number) {
if (!this.latch) {
this.addressRegister = (this.addressRegister & 0xFF00) | i;
}
else {
} else {
switch ((i & 0xc0) >> 6) {
// Set read address
case 0:
@ -442,6 +442,7 @@ export class TMS9918A {
case 2:
this.setVDPWriteRegister(i);
break;
// Color RAM (SMS only)
case 3:
this.setVDPWriteCommand3(i);
break;
@ -699,8 +700,19 @@ export class SMSVDP extends TMS9918A {
writeToCRAM : boolean;
cram = new Uint8Array(32); // color RAM
cpalette = new Uint32Array(32); // color RAM (RGBA)
registers = new Uint8Array(16); // 8 more registers
updateMode(reg0:number, reg1:number) {
if (reg0 & 0x04) {
this.screenMode = TMS9918A_Mode.MODE4;
this.nameTable = (this.registers[2] & 0xf) << 10;
this.spriteAttributeTable = (this.registers[5] & 0x7f) << 7;
this.spritePatternTable = (this.registers[6] & 0x7) << 11;
} else {
super.updateMode(reg0, reg1);
}
}
setReadAddress(i:number) {
super.setReadAddress(i);
this.writeToCRAM = false;
@ -718,7 +730,9 @@ export class SMSVDP extends TMS9918A {
}
writeData(i:number) {
if (this.writeToCRAM) {
this.cram[this.addressRegister++ & (this.cram.length-1)] = i;
var palindex = this.addressRegister++ & (this.cram.length-1);
this.cram[palindex] = i;
this.cpalette[palindex] = RGBA((i&3)<<6, ((i>>2)&3)<<6, ((i>>4)&3)<<6);
this.addressRegister &= this.ramMask;
this.redrawRequired = true;
} else {
@ -734,5 +748,165 @@ export class SMSVDP extends TMS9918A {
super.restoreState(state);
this.cram.set(state.cram);
}
drawScanline(y:number) {
if (this.screenMode == TMS9918A_Mode.MODE4) // TODO: check for other uses
this.drawScanlineMode4(y); // special mode 4
else
super.drawScanline(y);
}
drawScanlineMode4(y:number) {
var imageData = this.datau32,
width = this.width,
imageDataAddr = (y * width),
drawWidth = 256,
drawHeight = 192, // TODO
hBorder = (width - drawWidth) >> 1,
vBorder = (this.height - drawHeight) >> 1,
fgColor = this.fgColor,
bgColor = this.bgColor,
ram = this.ram,
nameTable = this.nameTable,
patternTableMask = this.patternTableMask,
spriteAttributeTable = this.spriteAttributeTable,
spritePatternTable = this.spritePatternTable,
spriteSize = (this.registers[1] & 0x2) !== 0,
spriteMagnify = this.registers[1] & 0x1,
spriteDimension = (spriteSize ? 16 : 8) << (spriteMagnify ? 1 : 0),
maxSpritesOnLine = this.flicker ? 8 : 64,
cpalette = this.cpalette,
collision = false, ninthSprite = false, ninthSpriteIndex = 63,
x, color, rgbColor, name;
if (y >= vBorder && y < vBorder + drawHeight && this.displayOn) {
var y1 = y - vBorder;
// Pre-process sprites
if (true) {
var spriteBuffer = this.spriteBuffer;
spriteBuffer.fill(0);
var spritesOnLine = 0;
var endMarkerFound = false;
var s;
for (s = 0; s < 64 && spritesOnLine <= maxSpritesOnLine && !endMarkerFound; s++) {
var sy = ram[spriteAttributeTable + s];
if (sy !== 0xD0) {
if (sy > 0xD0) {
sy -= 256;
}
sy++;
var sy1 = sy + spriteDimension;
var y2 = -1;
if (s < 8 /*|| !bitmapMode*/) { // TODO?
if (y1 >= sy && y1 < sy1) {
y2 = y1;
}
}
else {
// Emulate sprite duplication bug
var yMasked = y1 & (((this.registers[4] & 0x03) << 6) | 0x3F);
if (yMasked >= sy && yMasked < sy1) {
y2 = yMasked;
}
else if (y1 >= 64 && y1 < 128 && y1 >= sy && y1 < sy1) {
y2 = y1;
}
}
if (y2 !== -1) {
if (spritesOnLine < maxSpritesOnLine) {
var sx = ram[spriteAttributeTable + s*2 + 0x80];
var sPatternNo = ram[spriteAttributeTable + s*2 + 0x81];
var sColor = 0; // TODO
//var sColor = ram[spriteAttributeAddr + 3] & 0x0F;
//if ((ram[spriteAttributeAddr + 3] & 0x80) !== 0) {
// sx -= 32;
//}
var sLine = (y2 - sy) >> spriteMagnify;
var sPatternBase = spritePatternTable + (sPatternNo << 3) + sLine;
for (var sx1 = 0; sx1 < spriteDimension; sx1++) {
var sx2 = sx + sx1;
if (sx2 >= 0 && sx2 < drawWidth) {
var sx3 = sx1 >> spriteMagnify;
var sPatternByte = ram[sPatternBase + (sx3 >= 8 ? 16 : 0)];
if ((sPatternByte & (0x80 >> (sx3 & 0x07))) !== 0) {
if (spriteBuffer[sx2] === 0) {
spriteBuffer[sx2] = sColor + 1;
}
else {
collision = true;
}
}
}
}
}
spritesOnLine++;
}
}
else {
endMarkerFound = true;
}
}
if (spritesOnLine > 8) {
ninthSprite = true;
ninthSpriteIndex = s;
}
}
// Draw
var rowOffset = (y1 >> 3) << 6;
var lineOffset = y1 & 7;
for (x = 0; x < width; x++) {
if (x >= hBorder && x < hBorder + drawWidth) {
var x1 = x - hBorder;
var nameOfs = nameTable + rowOffset + ((x1 >> 3) << 1);
name = ram[nameOfs] + (ram[nameOfs+1] << 8);
var patofs = ((((name & 0x1ff) << 3) + lineOffset) << 2);
var pat0 = ram[patofs+0];
var pat1 = ram[patofs+1];
var pat2 = ram[patofs+2];
var pat3 = ram[patofs+3];
pat0 >>= x1 & 7;
pat1 >>= x1 & 7;
pat2 >>= x1 & 7;
pat3 >>= x1 & 7;
color = (pat0&1) | ((pat1&1)<<1) | ((pat2&1)<<2) | ((pat3&1)<<3);
if (color === 0) {
color = bgColor;
}
// Sprites
if (true) {
var spriteColor = spriteBuffer[x1] - 1;
if (spriteColor > 0) {
color = spriteColor;
}
}
}
else {
color = bgColor;
}
rgbColor = cpalette[color];
imageData[imageDataAddr++] = rgbColor;
}
}
// Top/bottom border
else {
rgbColor = this.cpalette[bgColor]; // TODO?
for (x = 0; x < width; x++) {
imageData[imageDataAddr++] = rgbColor;
}
}
if (y === vBorder + drawHeight) {
this.statusRegister |= 0x80;
if (this.interruptsOn) {
this.cru.setVDPInterrupt(true);
}
}
if (collision) {
this.statusRegister |= 0x20;
}
if ((this.statusRegister & 0x40) === 0) {
this.statusRegister |= ninthSpriteIndex;
}
if (ninthSprite) {
this.statusRegister |= 0x40;
}
}
};