c64- VIC register class

This commit is contained in:
saxxonpike 2012-11-05 14:24:01 +00:00
parent 9d83249eba
commit 821553cda8
3 changed files with 499 additions and 415 deletions

View File

@ -21,7 +21,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public Memory mem;
public Sid sid;
public VicII vic;
public VicSignals vicSignal;
public ChipSignals signal;
private void HardReset()
{
@ -35,8 +35,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
cia2 = new Cia(Cia.DummyReadPort, Cia.DummyReadPort, Cia.DummyWritePort, Cia.DummyWritePort);
// initialize vic
vicSignal = new VicSignals();
vic = new VicII(vicSignal, VicIIMode.NTSC);
signal = new ChipSignals();
vic = new VicII(signal, VicIIMode.NTSC);
// initialize sid
sid = new Sid();
@ -88,4 +88,21 @@ namespace BizHawk.Emulation.Computers.Commodore64
mem.Write(addr, value);
}
}
public class ChipSignals
{
private bool[] _CiaIRQOutput = new bool[2];
private bool _VicAECOutput;
private bool _VicBAOutput;
private bool _VicIRQOutput;
private bool _VicLPInput;
public bool CpuAEC { get { return _VicAECOutput; } }
public bool CpuIRQ { get { return _VicIRQOutput | _CiaIRQOutput[0] | _CiaIRQOutput[1]; } }
public bool CpuRDY { get { return _VicBAOutput; } }
public bool VicAEC { get { return _VicAECOutput; } set { _VicAECOutput = value; } }
public bool VicBA { get { return _VicBAOutput; } set { _VicBAOutput = value; } }
public bool VicIRQ { get { return _VicIRQOutput; } set { _VicIRQOutput = value; } }
public bool VicLP { get { return _VicLPInput; } }
}
}

View File

@ -92,11 +92,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
for (int i = 0; i < cyclesPerSecond; i++)
{
if (vicSignal.Interrupt || cia1.interrupt || cia2.interrupt)
if (signal.CpuIRQ)
{
cpu.IRQ = true;
}
if (vicSignal.AllowCpu)
if (signal.CpuRDY)
{
cpu.ExecuteOne();
}

View File

@ -11,6 +11,429 @@ namespace BizHawk.Emulation.Computers.Commodore64
PAL
}
public class VicIIRegs
{
public bool BMM;
public int[] BxC = new int[4];
public int CB;
public bool CSEL;
public bool DEN;
public int EC;
public bool ECM;
public bool ELP;
public bool EMBC;
public bool EMMC;
public bool ERST;
public bool ILP;
public bool IMBC;
public bool IMMC;
public bool IRQ;
public bool IRST;
public int LPX;
public int LPY;
public bool MCM;
public int[] MMx = new int[2];
public int[] MxC = new int[8];
public bool[] MxD = new bool[8];
public bool[] MxDP = new bool[8];
public bool[] MxE = new bool[8];
public bool[] MxM = new bool[8];
public bool[] MxMC = new bool[8];
public int[] MxX = new int[8];
public bool[] MxXE = new bool[8];
public int[] MxY = new int[8];
public bool[] MxYE = new bool[8];
public int RASTER;
public int RASTERX;
public int RC;
public bool RES;
public bool RSEL;
public int VC;
public int VCBASE;
public int VM;
public int VMLI;
public int XSCROLL;
public int YSCROLL;
public VicIIRegs()
{
// power on state
this[0x16] = 0xC0;
this[0x18] = 0x01;
this[0x19] = 0x71;
this[0x1A] = 0xF0;
}
public byte this[int addr]
{
get
{
int result = 0xFF; // value for any open bits
addr &= 0x3F;
switch (addr)
{
case 0x00:
case 0x02:
case 0x04:
case 0x06:
case 0x08:
case 0x0A:
case 0x0C:
case 0x0E:
result = MxX[addr >> 1];
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0x09:
case 0x0B:
case 0x0D:
case 0x0F:
result = MxY[addr >> 1];
break;
case 0x10:
result = ((MxX[0] & 0x100) != 0) ? 0x01 : 0x00;
result |= ((MxX[1] & 0x100) != 0) ? 0x02 : 0x00;
result |= ((MxX[2] & 0x100) != 0) ? 0x04 : 0x00;
result |= ((MxX[3] & 0x100) != 0) ? 0x08 : 0x00;
result |= ((MxX[4] & 0x100) != 0) ? 0x10 : 0x00;
result |= ((MxX[5] & 0x100) != 0) ? 0x20 : 0x00;
result |= ((MxX[6] & 0x100) != 0) ? 0x40 : 0x00;
result |= ((MxX[7] & 0x100) != 0) ? 0x80 : 0x00;
break;
case 0x11:
result = YSCROLL & 0x07;
result |= (RSEL ? 0x08 : 0x00);
result |= (DEN ? 0x10 : 0x00);
result |= (BMM ? 0x20 : 0x00);
result |= (ECM ? 0x40 : 0x00);
result |= ((RASTER & 0x100) >> 1);
break;
case 0x12:
result = RASTER & 0xFF;
break;
case 0x13:
result = LPX;
break;
case 0x14:
result = LPY;
break;
case 0x15:
result = (MxE[0] ? 0x01 : 0x00);
result |= (MxE[1] ? 0x02 : 0x00);
result |= (MxE[2] ? 0x04 : 0x00);
result |= (MxE[3] ? 0x08 : 0x00);
result |= (MxE[4] ? 0x10 : 0x00);
result |= (MxE[5] ? 0x20 : 0x00);
result |= (MxE[6] ? 0x40 : 0x00);
result |= (MxE[7] ? 0x80 : 0x00);
break;
case 0x16:
result &= 0xBF;
result |= XSCROLL & 0x07;
result |= (CSEL ? 0x08 : 0x00);
result |= (MCM ? 0x10 : 0x00);
result |= (RES ? 0x20 : 0x00);
break;
case 0x17:
result = (MxYE[0] ? 0x01 : 0x00);
result |= (MxYE[1] ? 0x02 : 0x00);
result |= (MxYE[2] ? 0x04 : 0x00);
result |= (MxYE[3] ? 0x08 : 0x00);
result |= (MxYE[4] ? 0x10 : 0x00);
result |= (MxYE[5] ? 0x20 : 0x00);
result |= (MxYE[6] ? 0x40 : 0x00);
result |= (MxYE[7] ? 0x80 : 0x00);
break;
case 0x18:
result &= 0x01;
result |= (CB & 0x07) << 1;
result |= (VM & 0x0F) << 4;
break;
case 0x19:
result &= 0x70;
result |= (IRST ? 0x01 : 0x00);
result |= (IMBC ? 0x02 : 0x00);
result |= (IMMC ? 0x04 : 0x00);
result |= (ILP ? 0x08 : 0x00);
result |= (IRQ ? 0x80 : 0x00);
break;
case 0x1A:
result &= 0xF0;
result |= (ERST ? 0x01 : 0x00);
result |= (EMBC ? 0x02 : 0x00);
result |= (EMMC ? 0x04 : 0x00);
result |= (ELP ? 0x08 : 0x00);
break;
case 0x1B:
result = (MxDP[0] ? 0x01 : 0x00);
result |= (MxDP[1] ? 0x02 : 0x00);
result |= (MxDP[2] ? 0x04 : 0x00);
result |= (MxDP[3] ? 0x08 : 0x00);
result |= (MxDP[4] ? 0x10 : 0x00);
result |= (MxDP[5] ? 0x20 : 0x00);
result |= (MxDP[6] ? 0x40 : 0x00);
result |= (MxDP[7] ? 0x80 : 0x00);
break;
case 0x1C:
result = (MxMC[0] ? 0x01 : 0x00);
result |= (MxMC[1] ? 0x02 : 0x00);
result |= (MxMC[2] ? 0x04 : 0x00);
result |= (MxMC[3] ? 0x08 : 0x00);
result |= (MxMC[4] ? 0x10 : 0x00);
result |= (MxMC[5] ? 0x20 : 0x00);
result |= (MxMC[6] ? 0x40 : 0x00);
result |= (MxMC[7] ? 0x80 : 0x00);
break;
case 0x1D:
result = (MxXE[0] ? 0x01 : 0x00);
result |= (MxXE[1] ? 0x02 : 0x00);
result |= (MxXE[2] ? 0x04 : 0x00);
result |= (MxXE[3] ? 0x08 : 0x00);
result |= (MxXE[4] ? 0x10 : 0x00);
result |= (MxXE[5] ? 0x20 : 0x00);
result |= (MxXE[6] ? 0x40 : 0x00);
result |= (MxXE[7] ? 0x80 : 0x00);
break;
case 0x1E:
result = (MxM[0] ? 0x01 : 0x00);
result |= (MxM[1] ? 0x02 : 0x00);
result |= (MxM[2] ? 0x04 : 0x00);
result |= (MxM[3] ? 0x08 : 0x00);
result |= (MxM[4] ? 0x10 : 0x00);
result |= (MxM[5] ? 0x20 : 0x00);
result |= (MxM[6] ? 0x40 : 0x00);
result |= (MxM[7] ? 0x80 : 0x00);
break;
case 0x1F:
result = (MxD[0] ? 0x01 : 0x00);
result |= (MxD[1] ? 0x02 : 0x00);
result |= (MxD[2] ? 0x04 : 0x00);
result |= (MxD[3] ? 0x08 : 0x00);
result |= (MxD[4] ? 0x10 : 0x00);
result |= (MxD[5] ? 0x20 : 0x00);
result |= (MxD[6] ? 0x40 : 0x00);
result |= (MxD[7] ? 0x80 : 0x00);
break;
case 0x20:
result &= 0xF0;
result |= EC & 0x0F;
break;
case 0x21:
case 0x22:
case 0x23:
case 0x24:
result &= 0xF0;
result |= BxC[addr - 0x21] & 0x0F;
break;
case 0x25:
case 0x26:
result &= 0xF0;
result |= MMx[addr - 0x25] & 0x0F;
break;
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
case 0x2E:
result &= 0xF0;
result |= MxC[addr - 0x27] & 0x0F;
break;
default:
result = 0xFF;
break;
}
return (byte)(result);
}
set
{
int index;
int val = value;
addr &= 0x3F;
switch (addr)
{
case 0x00:
case 0x02:
case 0x04:
case 0x06:
case 0x08:
case 0x0A:
case 0x0C:
case 0x0E:
index = addr >> 1;
MxX[index] &= 0x100;
MxX[index] |= (val & 0xFF);
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0x09:
case 0x0B:
case 0x0D:
case 0x0F:
index = addr >> 1;
MxY[index] &= 0x100;
MxY[index] |= (val & 0xFF);
break;
case 0x10:
MxX[0] = (MxX[0] & 0xFF) | ((val & 0x01) << 8);
MxX[1] = (MxX[1] & 0xFF) | ((val & 0x02) << 7);
MxX[2] = (MxX[2] & 0xFF) | ((val & 0x04) << 6);
MxX[3] = (MxX[3] & 0xFF) | ((val & 0x08) << 5);
MxX[4] = (MxX[4] & 0xFF) | ((val & 0x10) << 4);
MxX[5] = (MxX[5] & 0xFF) | ((val & 0x20) << 3);
MxX[6] = (MxX[6] & 0xFF) | ((val & 0x40) << 2);
MxX[7] = (MxX[7] & 0xFF) | ((val & 0x80) << 1);
break;
case 0x11:
YSCROLL = (val & 0x07);
RSEL = ((val & 0x08) != 0x00);
DEN = ((val & 0x10) != 0x00);
BMM = ((val & 0x20) != 0x00);
ECM = ((val & 0x40) != 0x00);
RASTER &= 0xFF;
RASTER |= ((val & 0x80) << 1);
break;
case 0x12:
RASTER &= 0x100;
RASTER |= (val & 0xFF);
break;
case 0x13:
LPX = (val & 0xFF);
break;
case 0x14:
LPY = (val & 0xFF);
break;
case 0x15:
MxE[0] = ((val & 0x01) != 0x00);
MxE[1] = ((val & 0x02) != 0x00);
MxE[2] = ((val & 0x04) != 0x00);
MxE[3] = ((val & 0x08) != 0x00);
MxE[4] = ((val & 0x10) != 0x00);
MxE[5] = ((val & 0x20) != 0x00);
MxE[6] = ((val & 0x40) != 0x00);
MxE[7] = ((val & 0x80) != 0x00);
break;
case 0x16:
XSCROLL = (val & 0x07);
CSEL = ((val & 0x08) != 0x00);
MCM = ((val & 0x10) != 0x00);
RES = ((val & 0x20) != 0x00);
break;
case 0x17:
MxYE[0] = ((val & 0x01) != 0x00);
MxYE[1] = ((val & 0x02) != 0x00);
MxYE[2] = ((val & 0x04) != 0x00);
MxYE[3] = ((val & 0x08) != 0x00);
MxYE[4] = ((val & 0x10) != 0x00);
MxYE[5] = ((val & 0x20) != 0x00);
MxYE[6] = ((val & 0x40) != 0x00);
MxYE[7] = ((val & 0x80) != 0x00);
break;
case 0x18:
CB = (val & 0x0E) >> 1;
VM = (val & 0xF0) >> 4;
break;
case 0x19:
IRST = ((val & 0x01) != 0x00);
IMBC = ((val & 0x02) != 0x00);
IMMC = ((val & 0x04) != 0x00);
ILP = ((val & 0x08) != 0x00);
IRQ = ((val & 0x80) != 0x00);
break;
case 0x1A:
ERST = ((val & 0x01) != 0x00);
EMBC = ((val & 0x02) != 0x00);
EMMC = ((val & 0x04) != 0x00);
ELP = ((val & 0x08) != 0x00);
break;
case 0x1B:
MxDP[0] = ((val & 0x01) != 0x00);
MxDP[1] = ((val & 0x02) != 0x00);
MxDP[2] = ((val & 0x04) != 0x00);
MxDP[3] = ((val & 0x08) != 0x00);
MxDP[4] = ((val & 0x10) != 0x00);
MxDP[5] = ((val & 0x20) != 0x00);
MxDP[6] = ((val & 0x40) != 0x00);
MxDP[7] = ((val & 0x80) != 0x00);
break;
case 0x1C:
MxMC[0] = ((val & 0x01) != 0x00);
MxMC[1] = ((val & 0x02) != 0x00);
MxMC[2] = ((val & 0x04) != 0x00);
MxMC[3] = ((val & 0x08) != 0x00);
MxMC[4] = ((val & 0x10) != 0x00);
MxMC[5] = ((val & 0x20) != 0x00);
MxMC[6] = ((val & 0x40) != 0x00);
MxMC[7] = ((val & 0x80) != 0x00);
break;
case 0x1D:
MxXE[0] = ((val & 0x01) != 0x00);
MxXE[1] = ((val & 0x02) != 0x00);
MxXE[2] = ((val & 0x04) != 0x00);
MxXE[3] = ((val & 0x08) != 0x00);
MxXE[4] = ((val & 0x10) != 0x00);
MxXE[5] = ((val & 0x20) != 0x00);
MxXE[6] = ((val & 0x40) != 0x00);
MxXE[7] = ((val & 0x80) != 0x00);
break;
case 0x1E:
MxM[0] = ((val & 0x01) != 0x00);
MxM[1] = ((val & 0x02) != 0x00);
MxM[2] = ((val & 0x04) != 0x00);
MxM[3] = ((val & 0x08) != 0x00);
MxM[4] = ((val & 0x10) != 0x00);
MxM[5] = ((val & 0x20) != 0x00);
MxM[6] = ((val & 0x40) != 0x00);
MxM[7] = ((val & 0x80) != 0x00);
break;
case 0x1F:
MxD[0] = ((val & 0x01) != 0x00);
MxD[1] = ((val & 0x02) != 0x00);
MxD[2] = ((val & 0x04) != 0x00);
MxD[3] = ((val & 0x08) != 0x00);
MxD[4] = ((val & 0x10) != 0x00);
MxD[5] = ((val & 0x20) != 0x00);
MxD[6] = ((val & 0x40) != 0x00);
MxD[7] = ((val & 0x80) != 0x00);
break;
case 0x20:
EC = (val & 0x0F);
break;
case 0x21:
case 0x22:
case 0x23:
case 0x24:
BxC[addr - 0x21] = val & 0x0F;
break;
case 0x25:
case 0x26:
MMx[addr - 0x25] = val & 0x0F;
break;
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
case 0x2E:
MxC[addr - 0x27] = val & 0x0F;
break;
}
}
}
}
public class VicII
{
// buffer
@ -38,30 +461,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
Colors.ARGB(0x95, 0x95, 0x95)
};
// interrupts
public bool interrupt = true;
public bool lightPenInterrupt = true;
public bool lightPenInterruptEnabled;
public bool rasterInterrupt = true;
public bool rasterInterruptEnabled;
public bool spriteBackgroundInterrupt = true;
public bool spriteBackgroundInterruptEnabled;
public bool spriteSpriteInterrupt = true;
public bool spriteSpriteInterruptEnabled;
// memory
public bool characterFetch;
public int characterFetchOffset;
public int characterMemoryOffset;
public byte[] charBuffer;
public int charBufferOffset;
public bool fetching;
public int fetchOffsetX;
public int screenMemoryOffset;
// lightpen
public int lightPenX; // LPX
public int lightPenY; // LPY
// raster
public int[] backgroundColor; // B0C
@ -74,10 +475,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool borderOnVertical;
public int borderRight;
public int borderTop;
public bool extendHeight; // RSEL
public bool extendWidth; // CSEL
public int horizontalScroll; // XSCROLL
public bool multiColorMode; // MCM
public int rasterInterruptLine;
public int rasterLineLeft;
public int rasterOffset;
@ -98,26 +495,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int visibleTop;
public int visibleWidth;
// sprites
public bool[] spriteBackgroundCollision; // M0D
public bool[] spriteCollision; // M0M
public int[] spriteColor; // M0C
public bool[] spriteEnabled; // M0E
public int[] spriteExtraColor; // MM0
public bool[] spriteMultiColor; // M0MC
public bool[] spritePriority; // M0DP
public bool[] spriteStretchHorizontal; // M0XE
public bool[] spriteStretchVertical; // M0YE
public int[] spriteX; // M0X, M0X8
public int[] spriteY; // M0Y
public VicSignals cpuSignal;
public ChipSignals signal;
public Memory mem;
public byte[] regs;
public VicIIRegs regs;
public VicII(VicSignals signals, VicIIMode videoMode)
public VicII(ChipSignals newSignal, VicIIMode videoMode)
{
cpuSignal = signals;
signal = newSignal;
switch (videoMode)
{
@ -134,10 +518,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
visibleWidth = 418;
visibleHeight = 217;
renderOffset = 0;
borderLeft = 0x018;
borderRight = 0x158;
borderTop = 0x033;
borderBottom = 0x0FA;
characterFetchOffset = rasterWidth - 3;
break;
case VicIIMode.PAL:
@ -148,23 +528,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
// initialize raster
backgroundColor = new int[4];
charBuffer = new byte[40];
rasterOffsetX = rasterLineLeft;
rasterOffsetY = 0;
// initialize sprites
spriteBackgroundCollision = new bool[8];
spriteCollision = new bool[8];
spriteColor = new int[8];
spriteEnabled = new bool[8];
spriteExtraColor = new int[2];
spriteMultiColor = new bool[8];
spritePriority = new bool[8];
spriteStretchHorizontal = new bool[8];
spriteStretchVertical = new bool[8];
spriteX = new int[8];
spriteY = new int[8];
// initialize buffer
buffer = new int[rasterWidth * rasterTotalLines];
bufferSize = buffer.Length;
@ -175,331 +541,75 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void HardReset()
{
// power on state
regs = new byte[0x40];
Write(0x0016, 0xC0);
Write(0x0018, 0x01);
Write(0x0019, 0x71);
Write(0x001A, 0xF0);
for (ushort i = 0x0020; i <= 0x002E; i++)
Write(i, 0xF0);
// unused registers always return FF
for (int i = 0x2F; i <= 0x3F; i++)
regs[i] = 0xFF;
UpdateRegs();
}
public void LockBus()
{
cpuSignal.Lock();
regs = new VicIIRegs();
UpdateBorder();
}
public void PerformCycle()
{
for (int i = 0; i < 8; i++)
{
if (rasterOffsetX == visibleLeft)
visibleRenderX = true;
if (rasterOffsetX == visibleRight)
visibleRenderX = false;
if (rasterOffsetX == borderLeft)
borderOnHorizontal = false;
if (rasterOffsetX == borderRight)
borderOnHorizontal = true;
if ((rasterOffsetX == fetchOffsetX) && ((rasterOffsetY & 0x07) == verticalScroll))
{
cpuSignal.Lock();
fetching = true;
characterFetchOffset = (rasterOffsetY >> 3) * 40;
charBufferOffset = 0;
}
if (fetching)
{
if (charBufferOffset >= 0)
{
charBuffer[charBufferOffset] = mem.VicRead((ushort)(screenMemoryOffset + characterFetchOffset));
characterFetchOffset++;
}
charBufferOffset++;
if (charBufferOffset == 40)
{
fetching = false;
cpuSignal.Unlock();
}
}
if (borderOnVertical || borderOnHorizontal)
{
WritePixel(borderColor);
}
else
{
WritePixel(backgroundColor[0]);
}
rasterOffsetX++;
if (rasterOffsetX == rasterWidth)
rasterOffsetX = 0;
if (rasterOffsetX == rasterLineLeft)
{
rasterOffsetY++;
if (rasterOffsetY == visibleTop)
visibleRenderY = true;
if (rasterOffsetY == visibleBottom)
visibleRenderY = false;
if (rasterOffsetY == borderTop)
borderOnVertical = false;
if (rasterOffsetY == borderBottom)
borderOnVertical = true;
if (rasterOffsetY == rasterTotalLines)
{
rasterOffsetY = 0;
renderOffset = 0;
}
if (rasterInterruptEnabled && (rasterOffsetY == rasterInterruptLine))
{
rasterInterrupt = true;
}
}
}
interrupt =
(rasterInterrupt & rasterInterruptEnabled) |
(spriteSpriteInterrupt & spriteSpriteInterruptEnabled) |
(spriteBackgroundInterrupt & spriteBackgroundInterruptEnabled) |
(lightPenInterrupt & lightPenInterruptEnabled);
cpuSignal.Interrupt = interrupt;
UpdateRegs();
}
public byte Read(ushort addr)
{
return regs[addr & 0x3F];
}
public void UnlockBus()
{
cpuSignal.Unlock();
}
public void UpdateRegs()
{
// these registers update on their own
regs[0x11] = (byte)
((verticalScroll & 0x07) |
(extendHeight ? 0x08 : 0x00) |
(screenEnabled ? 0x10 : 0x00) |
(bitmapMode ? 0x20 : 0x00) |
(backgroundMode ? 0x40 : 0x00) |
((rasterOffsetY & 0x100) >> 1));
regs[0x12] = (byte)(rasterOffsetY & 0xFF);
regs[0x13] = (byte)(lightPenX >> 1);
regs[0x14] = (byte)(lightPenY);
regs[0x19] = (byte)
((rasterInterrupt ? 0x01 : 0x00) |
(spriteBackgroundInterrupt ? 0x02 : 0x00) |
(spriteSpriteInterrupt ? 0x04 : 0x00) |
(lightPenInterrupt ? 0x08 : 0x00) |
(interrupt ? 0x80 : 0x00));
}
public void Write(ushort addr, byte val)
{
int index = 0;
bool allowWrite = true;
byte result = 0;
addr &= 0x3F;
switch (addr)
{
case 0x00:
case 0x02:
case 0x04:
case 0x06:
case 0x08:
case 0x0A:
case 0x0C:
case 0x0E:
index = addr >> 1;
spriteX[index] &= 0xFF;
spriteX[index] |= val;
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0x09:
case 0x0B:
case 0x0D:
case 0x0F:
index = addr >> 1;
spriteY[index] &= 0xFF;
spriteY[index] |= val;
break;
case 0x10:
spriteX[0] = (spriteX[0] & 0xFF) | ((val & 0x01) << 8);
spriteX[1] = (spriteX[1] & 0xFF) | ((val & 0x02) << 7);
spriteX[2] = (spriteX[2] & 0xFF) | ((val & 0x04) << 6);
spriteX[3] = (spriteX[3] & 0xFF) | ((val & 0x08) << 5);
spriteX[4] = (spriteX[4] & 0xFF) | ((val & 0x10) << 4);
spriteX[5] = (spriteX[5] & 0xFF) | ((val & 0x20) << 3);
spriteX[6] = (spriteX[6] & 0xFF) | ((val & 0x40) << 2);
spriteX[7] = (spriteX[7] & 0xFF) | ((val & 0x80) << 1);
break;
case 0x11:
verticalScroll = val & 0x07;
extendHeight = ((val & 0x08) != 0x00);
screenEnabled = ((val & 0x10) != 0x00);
bitmapMode = ((val & 0x20) != 0x00);
backgroundMode = ((val & 0x40) != 0x00);
rasterInterruptLine = (rasterInterruptLine & 0xFF) | ((val & 0x80) << 1);
val = (byte)((val & 0x7F) | ((rasterOffsetY & 0x100) >> 1));
break;
case 0x12:
rasterInterruptLine = (rasterInterruptLine & 0x100) | val;
allowWrite = false;
break;
case 0x15:
spriteEnabled[0] = ((val & 0x01) != 0x00);
spriteEnabled[1] = ((val & 0x02) != 0x00);
spriteEnabled[2] = ((val & 0x04) != 0x00);
spriteEnabled[3] = ((val & 0x08) != 0x00);
spriteEnabled[4] = ((val & 0x10) != 0x00);
spriteEnabled[5] = ((val & 0x20) != 0x00);
spriteEnabled[6] = ((val & 0x40) != 0x00);
spriteEnabled[7] = ((val & 0x80) != 0x00);
break;
case 0x16:
horizontalScroll = val & 0x07;
extendWidth = ((val & 0x08) != 0x00);
multiColorMode = ((val & 0x10) != 0x00);
resetBit = ((val & 0x20) != 0x00);
val |= 0xC0;
break;
case 0x17:
spriteStretchVertical[0] = ((val & 0x01) != 0x00);
spriteStretchVertical[1] = ((val & 0x02) != 0x00);
spriteStretchVertical[2] = ((val & 0x04) != 0x00);
spriteStretchVertical[3] = ((val & 0x08) != 0x00);
spriteStretchVertical[4] = ((val & 0x10) != 0x00);
spriteStretchVertical[5] = ((val & 0x20) != 0x00);
spriteStretchVertical[6] = ((val & 0x40) != 0x00);
spriteStretchVertical[7] = ((val & 0x80) != 0x00);
break;
case 0x18:
characterMemoryOffset = (int)(val & 0x0E) << 10;
screenMemoryOffset = (int)(val & 0xF0) << 6;
break;
case 0x19:
rasterInterrupt = ((val & 0x01) != 0);
spriteSpriteInterrupt = ((val & 0x02) != 0);
spriteBackgroundInterrupt = ((val & 0x04) != 0);
lightPenInterrupt = ((val & 0x08) != 0);
allowWrite = false;
break;
case 0x1A:
rasterInterruptEnabled = ((val & 0x01) != 0);
spriteSpriteInterruptEnabled = ((val & 0x02) != 0);
spriteBackgroundInterruptEnabled = ((val & 0x04) != 0);
lightPenInterruptEnabled = ((val & 0x08) != 0);
break;
case 0x1B:
spritePriority[0] = ((val & 0x01) != 0x00);
spritePriority[1] = ((val & 0x02) != 0x00);
spritePriority[2] = ((val & 0x04) != 0x00);
spritePriority[3] = ((val & 0x08) != 0x00);
spritePriority[4] = ((val & 0x10) != 0x00);
spritePriority[5] = ((val & 0x20) != 0x00);
spritePriority[6] = ((val & 0x40) != 0x00);
spritePriority[7] = ((val & 0x80) != 0x00);
break;
case 0x1C:
spriteMultiColor[0] = ((val & 0x01) != 0x00);
spriteMultiColor[1] = ((val & 0x02) != 0x00);
spriteMultiColor[2] = ((val & 0x04) != 0x00);
spriteMultiColor[3] = ((val & 0x08) != 0x00);
spriteMultiColor[4] = ((val & 0x10) != 0x00);
spriteMultiColor[5] = ((val & 0x20) != 0x00);
spriteMultiColor[6] = ((val & 0x40) != 0x00);
spriteMultiColor[7] = ((val & 0x80) != 0x00);
break;
case 0x1D:
spriteStretchHorizontal[0] = ((val & 0x01) != 0x00);
spriteStretchHorizontal[1] = ((val & 0x02) != 0x00);
spriteStretchHorizontal[2] = ((val & 0x04) != 0x00);
spriteStretchHorizontal[3] = ((val & 0x08) != 0x00);
spriteStretchHorizontal[4] = ((val & 0x10) != 0x00);
spriteStretchHorizontal[5] = ((val & 0x20) != 0x00);
spriteStretchHorizontal[6] = ((val & 0x40) != 0x00);
spriteStretchHorizontal[7] = ((val & 0x80) != 0x00);
break;
case 0x1E:
spriteCollision[0] = ((val & 0x01) != 0x00);
spriteCollision[1] = ((val & 0x02) != 0x00);
spriteCollision[2] = ((val & 0x04) != 0x00);
spriteCollision[3] = ((val & 0x08) != 0x00);
spriteCollision[4] = ((val & 0x10) != 0x00);
spriteCollision[5] = ((val & 0x20) != 0x00);
spriteCollision[6] = ((val & 0x40) != 0x00);
spriteCollision[7] = ((val & 0x80) != 0x00);
break;
case 0x1F:
spriteBackgroundCollision[0] = ((val & 0x01) != 0x00);
spriteBackgroundCollision[1] = ((val & 0x02) != 0x00);
spriteBackgroundCollision[2] = ((val & 0x04) != 0x00);
spriteBackgroundCollision[3] = ((val & 0x08) != 0x00);
spriteBackgroundCollision[4] = ((val & 0x10) != 0x00);
spriteBackgroundCollision[5] = ((val & 0x20) != 0x00);
spriteBackgroundCollision[6] = ((val & 0x40) != 0x00);
spriteBackgroundCollision[7] = ((val & 0x80) != 0x00);
break;
case 0x20:
borderColor = val;
break;
case 0x21:
backgroundColor[0] = val;
break;
case 0x22:
backgroundColor[1] = val;
break;
case 0x23:
backgroundColor[2] = val;
break;
case 0x24:
backgroundColor[3] = val;
break;
case 0x25:
spriteExtraColor[0] = val;
break;
case 0x26:
spriteExtraColor[1] = val;
break;
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
case 0x2E:
index = addr - 0x27;
spriteColor[index] = val;
// collision regs clear after read
result = regs[addr];
regs[addr] = 0x00;
break;
default:
allowWrite = false;
result = regs[addr];
break;
}
if (allowWrite)
regs[addr] = val;
return result;
}
public void UpdateBorder()
{
borderTop = regs.RSEL ? 0x033 : 0x037;
borderBottom = regs.RSEL ? 0x0FA : 0x0F6;
borderLeft = regs.CSEL ? 0x018 : 0x01F;
borderRight = regs.CSEL ? 0x14E : 0x157;
}
public void Write(ushort addr, byte val)
{
addr &= 0x3F;
switch (addr)
{
case 0x11:
rasterInterruptLine &= 0xFF;
rasterInterruptLine |= (val & 0x80) << 1;
// raster upper bit can't be changed, save and restore the value
val &= 0x7F;
val |= (byte)(regs[addr] & 0x80);
regs[addr] = val;
UpdateBorder();
break;
case 0x12:
// raster interrupt lower 8 bits
rasterInterruptLine &= 0x100;
rasterInterruptLine |= (val & 0xFF);
break;
case 0x16:
regs[addr] = val;
UpdateBorder();
break;
case 0x1E:
case 0x1F:
// can't write to these regs
break;
default:
regs[addr] = val;
break;
}
}
private void WritePixel(int value)
@ -511,47 +621,4 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
}
}
public class VicSignals
{
public bool AllowCpu;
public bool Interrupt;
public int LockCounter;
public VicSignals()
{
AllowCpu = true;
Interrupt = false;
LockCounter = 0;
}
public void Lock()
{
if (AllowCpu)
{
LockCounter = 4;
}
}
public void PerformCycle()
{
if (AllowCpu)
{
if (LockCounter > 0)
{
LockCounter--;
if (LockCounter == 0)
{
AllowCpu = false;
}
}
}
}
public void Unlock()
{
AllowCpu = true;
}
}
}