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