c64- rewrote video code, more accurate scanline behavior

This commit is contained in:
saxxonpike 2012-11-07 03:23:40 +00:00
parent 513793a177
commit 30c0564bda
1 changed files with 160 additions and 183 deletions

View File

@ -480,9 +480,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int borderRight; public int borderRight;
public int borderTop; public int borderTop;
public int characterColumn; public int characterColumn;
public byte characterData;
public int characterIndex; public int characterIndex;
public byte[] characterMemory; public byte[] characterMemory;
public bool charactersEnabled; public bool charactersEnabled;
public byte colorData;
public byte[] colorMemory; public byte[] colorMemory;
public int cycle; public int cycle;
public int cycleLeft; public int cycleLeft;
@ -499,7 +501,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int renderOffset; public int renderOffset;
public byte[,] spriteData; public byte[,] spriteData;
public int spriteFetchCycle; public int spriteFetchCycle;
public int spriteFetchIndex;
public ushort[] spritePointers; public ushort[] spritePointers;
public int spriteFetchStartCycle;
public VicIITask task; public VicIITask task;
public int totalCycles; public int totalCycles;
public bool vBlank; public bool vBlank;
@ -530,13 +534,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
rasterTotalLines = 263; rasterTotalLines = 263;
rasterLineLeft = 0x19C; rasterLineLeft = 0x19C;
cycleLeft = 0; cycleLeft = 0;
spriteFetchCycle = 58; spriteFetchCycle = 59;
visibleLeft = 0x008; visibleLeft = 0x008;
visibleRight = 0x168; visibleRight = 0x168;
visibleTop = 0x023; //0x041; visibleTop = 0x023; //0x041;
visibleBottom = 0x004; //0x013; visibleBottom = 0x004; //0x013;
visibleRenderX = false; visibleRenderX = false;
visibleRenderY = true; visibleRenderY = false;
visibleWidth = 352; visibleWidth = 352;
visibleHeight = 232; visibleHeight = 232;
renderOffset = 0; renderOffset = 0;
@ -562,48 +566,19 @@ namespace BizHawk.Emulation.Computers.Commodore64
spriteData = new byte[8, 64]; spriteData = new byte[8, 64];
// initialize screen buffer // initialize screen buffer
characterMemory = new byte[41]; characterMemory = new byte[40];
colorMemory = new byte[41]; colorMemory = new byte[40];
characterIndex = -1;
charactersEnabled = false;
// initialize registers // initialize registers
HardReset(); HardReset();
} }
private void GetBitmapData()
{
if (characterIndex < 0 || characterIndex >= 40)
bitmapData = 0;
else
{
int cMemIndex = characterMemory[characterIndex];
if (regs.ECM)
cMemIndex &= 0x3F;
ushort offset = (ushort)((regs.CB << 11) + (cMemIndex * 8) + regs.RC);
bitmapData = mem.VicRead(offset);
}
}
private void GetScreenData(int index)
{
ushort offset = (ushort)((regs.VM << 10) + regs.VC);
characterMemory[index] = mem.VicRead(offset);
colorMemory[index] = mem.colorRam[regs.VC];
}
private void GetSpriteData(int index)
{
ushort offset = (ushort)((regs.VM << 10) + 0x3F8 + index);
spritePointers[index] = (ushort)((regs.VM << 10) + (mem.VicRead(offset) * 64));
for (ushort i = 0; i < 64; i++)
spriteData[index, i] = mem.VicRead((ushort)(spritePointers[index] + i));
}
public void HardReset() public void HardReset()
{ {
idle = true;
refreshAddress = 0x3FFF; refreshAddress = 0x3FFF;
regs = new VicIIRegs(); regs = new VicIIRegs();
regs.RC = 7;
signal.VicAEC = true; signal.VicAEC = true;
signal.VicIRQ = false; signal.VicIRQ = false;
UpdateBorder(); UpdateBorder();
@ -611,20 +586,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void PerformCycle() public void PerformCycle()
{ {
// reset VC and VCBASE if on scan 0 // display enable check on line 030 (this must be run every cycle)
if (regs.RASTER == 0x00) if (regs.RASTER == 0x030)
{
regs.VCBASE = 0;
regs.VC = 0;
}
// display enable check on line $30
if (regs.RASTER == 0x30)
{
displayEnabled = (displayEnabled | regs.DEN); displayEnabled = (displayEnabled | regs.DEN);
}
// badline calculation (for when the VIC must pause the CPU to get character data) // badline check
if (regs.RASTER >= 0x030 && regs.RASTER < 0x0F8) if (regs.RASTER >= 0x030 && regs.RASTER < 0x0F8)
badLine = ((regs.YSCROLL == (regs.RASTER & 0x07)) && displayEnabled); badLine = ((regs.YSCROLL == (regs.RASTER & 0x07)) && displayEnabled);
else else
@ -633,116 +599,74 @@ namespace BizHawk.Emulation.Computers.Commodore64
if (badLine) if (badLine)
idle = false; idle = false;
// decide what to do this cycle // these actions are exclusive
if (cycle == 0) if ((regs.RASTER == 0x000 && cycle == 1) || (regs.RASTER > 0x000 && cycle == 0))
{ {
// if vblank, reset the raster position // IRQ is processed on cycle 1 of line 0 and cycle 0 on all other lines
regs.RASTER++;
if (regs.RASTER == rasterTotalLines)
{
rasterOffset = 0;
regs.RASTER = 0;
renderOffset = 0;
displayEnabled = false;
refreshAddress = 0x3FFF;
}
// check to see if we are within viewing area Y
if (regs.RASTER == visibleBottom)
visibleRenderY = false;
if (regs.RASTER == visibleTop)
visibleRenderY = true;
// check for raster IRQ
if (regs.RASTER == rasterInterruptLine) if (regs.RASTER == rasterInterruptLine)
regs.IRST = true; regs.IRST = true;
} }
else if (cycle >= 1 && cycle < 10)
{
// fetch sprite data 3-7
int index = (cycle >> 1) + 3;
if (regs.MxE[index])
{
signal.VicAEC = false;
if ((cycle & 0x01) == 0x00)
{
GetSpriteData(index);
}
}
else
{
signal.VicAEC = true;
}
}
else if (cycle >= 10 && cycle < 15) else if (cycle >= 10 && cycle < 15)
{ {
// dram refresh // dram refresh
mem.VicRead((ushort)refreshAddress); mem.VicRead((ushort)refreshAddress);
refreshAddress = (refreshAddress - 1) & 0xFF; refreshAddress = (refreshAddress - 1) & 0xFF;
refreshAddress |= 0x3F00; refreshAddress |= 0x3F00;
// VIC internal register reset on cycle 13
if (cycle == 13)
{
regs.VC = regs.VCBASE;
regs.VMLI = 0;
characterIndex = -4;
characterColumn = 0;
if (badLine)
{
regs.RC = 0;
}
}
} }
else if (cycle >= 15 && cycle < 55) else if (cycle >= 15 && cycle < 55)
{ {
// screen memory c-access
if (badLine) if (badLine)
{ PerformCycleScreenFetch();
// fetch video data }
signal.VicAEC = false; else if (cycle == 55)
GetScreenData(cycle - 15); {
} //signal.VicAEC = true;
else
{
signal.VicAEC = true;
}
regs.VC++;
regs.VMLI++;
} }
else if (cycle == 57) else if (cycle == 57)
{ {
// increment VIC row counter
if (regs.RC == 7) if (regs.RC == 7)
{ {
idle = true; idle = true;
regs.VCBASE = regs.VC; regs.VCBASE = regs.VC;
} }
else if (!idle)
{
regs.RC = (regs.RC + 1) & 0x07; regs.RC = (regs.RC + 1) & 0x07;
}
}
else if (cycle >= spriteFetchCycle)
{
// fetch sprite data 0-2
int index = (cycle - spriteFetchCycle) >> 1;
if (regs.MxE[index])
{
signal.VicAEC = false;
if ((cycle & 0x01) == 0x00)
{
GetSpriteData(index);
}
}
else
{
signal.VicAEC = true;
}
}
else
{
// idle
} }
// these actions can fall within the other ranges
if (cycle == 13)
{
regs.VC = regs.VCBASE;
regs.VMLI = 0;
characterColumn = 0;
if (badLine)
{
regs.RC = 0;
}
bitmapData = 0;
colorData = 0;
characterData = 0;
}
else if (cycle == spriteFetchStartCycle)
{
spriteFetchIndex = 0;
}
// sprite fetch
if (spriteFetchIndex < 8)
{
PerformCycleSpriteFetch(spriteFetchIndex, spriteFetchCycle);
spriteFetchCycle++;
if (spriteFetchCycle >= 2)
{
spriteFetchCycle = 0;
spriteFetchIndex++;
}
}
// border check
if (cycle == 63) if (cycle == 63)
{ {
if ((regs.RASTER == borderTop) && (regs.DEN)) if ((regs.RASTER == borderTop) && (regs.DEN))
@ -751,6 +675,75 @@ namespace BizHawk.Emulation.Computers.Commodore64
borderOnVertical = true; borderOnVertical = true;
} }
PerformCycleRender();
// increment cycle
cycle++;
if (cycle == totalCycles)
{
cycle = 0;
PerformCycleAdvanceRaster();
}
UpdateInterrupts();
signal.VicIRQ = regs.IRQ;
}
private void PerformCycleAdvanceRaster()
{
regs.RASTER++;
// if we reach the bottom, reset to the top
if (regs.RASTER == rasterTotalLines)
{
regs.RASTER = 0;
regs.VCBASE = 0;
displayEnabled = false;
}
// check to see if we are within viewing area Y
if (regs.RASTER == visibleBottom)
{
visibleRenderY = false;
renderOffset = 0;
}
if (regs.RASTER == visibleTop)
visibleRenderY = true;
}
private void PerformCycleGraphicFetch()
{
if (idle)
{
if (regs.ECM)
mem.VicRead(0x39FF);
else
mem.VicRead(0x3FFF);
}
else
{
characterIndex = regs.VMLI - 1;
if (characterIndex < 0 || characterIndex >= 40)
{
bitmapData = 0;
colorData = 0;
characterData = 0;
}
else
{
characterData = characterMemory[characterIndex];
if (regs.ECM)
characterData &= 0x3F;
bitmapData = mem.VicRead((ushort)((regs.CB << 11) + (characterData * 8) + regs.RC));
colorData = colorMemory[characterIndex];
}
regs.VC++;
regs.VMLI++;
}
}
private void PerformCycleRender()
{
// determine the plot mode // determine the plot mode
if (!regs.ECM && !regs.BMM && !regs.MCM) if (!regs.ECM && !regs.BMM && !regs.MCM)
Plotter = Plot000; Plotter = Plot000;
@ -771,21 +764,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
if ((rasterOffsetX & 0x07) == regs.XSCROLL) // draw screen memory if needed
if (!idle && cycle >= 15 && cycle < 55)
{ {
characterColumn = 0; if ((rasterOffsetX & 0x07) == regs.XSCROLL)
characterIndex++; {
GetBitmapData(); characterColumn = 0;
} PerformCycleGraphicFetch();
}
// pixel clock is 8x the VIC clock
int pixel;
// process raster position
if (rasterOffsetX >= rasterWidth)
{
// reset to the left side
rasterOffsetX -= rasterWidth;
} }
// check to see if we are within viewing area X // check to see if we are within viewing area X
@ -797,7 +783,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
// check to see if we are at the border // check to see if we are at the border
if (rasterOffsetX == borderRight) if (rasterOffsetX == borderRight)
borderOnMain = true; borderOnMain = true;
if (rasterOffsetX == borderLeft) if (rasterOffsetX == borderLeft)
{ {
if (regs.RASTER == borderBottom) if (regs.RASTER == borderBottom)
@ -808,46 +793,38 @@ namespace BizHawk.Emulation.Computers.Commodore64
borderOnMain = false; borderOnMain = false;
} }
// draw the border if it is on, otherwise draw the screen // render pixel
if (borderOnMain || borderOnVertical)
{
pixel = regs.EC;
}
else
{
if (characterIndex >= 0 && characterIndex < 40)
pixel = Plotter();
else
pixel = regs.BxC[0];
}
// plot the pixel if within visible range
if (visibleRenderX && visibleRenderY) if (visibleRenderX && visibleRenderY)
{ {
/* if (borderOnMain || borderOnVertical)
if (regs.RC == 0x00) WritePixel(regs.EC);
pixel ^= 0x08; else
if ((regs.RASTER & 0x07) == regs.YSCROLL) WritePixel(Plotter());
pixel ^= 0x01;*/
WritePixel(pixel);
} }
characterColumn++;
// increment raster position
rasterOffset++; rasterOffset++;
rasterOffsetX++; rasterOffsetX++;
characterColumn++; if (rasterOffsetX == rasterWidth)
{
rasterOffsetX -= rasterWidth;
}
} }
UpdateInterrupts(); }
signal.VicIRQ = regs.IRQ; private void PerformCycleScreenFetch()
{
ushort offset = (ushort)((regs.VM << 10) + regs.VC);
characterMemory[regs.VMLI] = mem.VicRead(offset);
colorMemory[regs.VMLI] = mem.colorRam[regs.VC];
}
cycle++; private void PerformCycleSpriteFetch(int index, int fetchCycle)
if (cycle == totalCycles) {
cycle = 0; ushort offset = (ushort)((regs.VM << 10) + 0x3F8 + index);
spritePointers[index] = (ushort)((regs.VM << 10) + (mem.VicRead(offset) * 64));
hBlank = !visibleRenderX; for (ushort i = 0; i < 64; i++)
vBlank = !visibleRenderY; spriteData[index, i] = mem.VicRead((ushort)(spritePointers[index] + i));
} }
// standard text mode // standard text mode
@ -858,7 +835,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
byte charData = bitmapData; byte charData = bitmapData;
charData <<= characterColumn; charData <<= characterColumn;
if ((charData & 0x80) != 0x00) if ((charData & 0x80) != 0x00)
return colorMemory[characterIndex]; return colorData;
} }
return regs.BxC[0]; return regs.BxC[0];
} }
@ -868,7 +845,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
{ {
if (characterColumn >= 0) if (characterColumn >= 0)
{ {
if ((colorMemory[characterIndex] & 0x08) != 0x00) if ((colorData & 0x08) != 0x00)
{ {
int offset = characterColumn; int offset = characterColumn;
byte charData = bitmapData; byte charData = bitmapData;
@ -883,7 +860,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
case 2: case 2:
return regs.BxC[charData]; return regs.BxC[charData];
default: default:
return colorMemory[characterIndex] & 0x07; return colorData & 0x07;
} }
} }
else else
@ -914,9 +891,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
byte charData = bitmapData; byte charData = bitmapData;
charData <<= characterColumn; charData <<= characterColumn;
if ((charData & 0x80) != 0x00) if ((charData & 0x80) != 0x00)
return colorMemory[characterIndex]; return colorData;
else else
return regs.BxC[characterMemory[characterIndex] >> 6]; return regs.BxC[characterData >> 6];
} }
return regs.BxC[0]; return regs.BxC[0];
} }