500 lines
20 KiB
C#
500 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.Emulation.Computers.Commodore64.MOS
|
|
{
|
|
sealed public partial class Vic
|
|
{
|
|
|
|
public byte Peek(int addr)
|
|
{
|
|
return ReadRegister((addr & 0x3F));
|
|
}
|
|
|
|
public void Poke(int addr, byte val)
|
|
{
|
|
WriteRegister((addr & 0x3F), val);
|
|
}
|
|
|
|
public byte Read(int addr)
|
|
{
|
|
byte result;
|
|
addr &= 0x3F;
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x1E:
|
|
case 0x1F:
|
|
// reading clears these
|
|
result = ReadRegister(addr);
|
|
WriteRegister(addr, 0);
|
|
break;
|
|
default:
|
|
result = ReadRegister((addr & 0x3F));
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private byte ReadRegister(int addr)
|
|
{
|
|
byte result = 0xFF; //unused bit value
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x00:
|
|
case 0x02:
|
|
case 0x04:
|
|
case 0x06:
|
|
case 0x08:
|
|
case 0x0A:
|
|
case 0x0C:
|
|
case 0x0E:
|
|
result = (byte)(sprites[addr >> 1].x & 0xFF);
|
|
break;
|
|
case 0x01:
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x07:
|
|
case 0x09:
|
|
case 0x0B:
|
|
case 0x0D:
|
|
case 0x0F:
|
|
result = (byte)(sprites[addr >> 1].y & 0xFF);
|
|
break;
|
|
case 0x10:
|
|
result = (byte)(
|
|
((sprites[0].x >> 8) & 0x01) |
|
|
((sprites[1].x >> 7) & 0x02) |
|
|
((sprites[2].x >> 6) & 0x04) |
|
|
((sprites[3].x >> 5) & 0x08) |
|
|
((sprites[4].x >> 4) & 0x10) |
|
|
((sprites[5].x >> 3) & 0x20) |
|
|
((sprites[6].x >> 2) & 0x40) |
|
|
((sprites[7].x >> 1) & 0x80)
|
|
);
|
|
break;
|
|
case 0x11:
|
|
result = (byte)(
|
|
(yScroll & 0x7) |
|
|
(rowSelect ? 0x08 : 0x00) |
|
|
(displayEnable ? 0x10 : 0x00) |
|
|
(bitmapMode ? 0x20 : 0x00) |
|
|
(extraColorMode ? 0x40 : 0x00) |
|
|
((rasterLine & 0x100) >> 1)
|
|
);
|
|
break;
|
|
case 0x12:
|
|
result = (byte)(rasterLine & 0xFF);
|
|
break;
|
|
case 0x13:
|
|
result = (byte)(lightPenX & 0xFF);
|
|
break;
|
|
case 0x14:
|
|
result = (byte)(lightPenY & 0xFF);
|
|
break;
|
|
case 0x15:
|
|
result = (byte)(
|
|
(sprites[0].enable ? 0x01 : 0x00) |
|
|
(sprites[1].enable ? 0x02 : 0x00) |
|
|
(sprites[2].enable ? 0x04 : 0x00) |
|
|
(sprites[3].enable ? 0x08 : 0x00) |
|
|
(sprites[4].enable ? 0x10 : 0x00) |
|
|
(sprites[5].enable ? 0x20 : 0x00) |
|
|
(sprites[6].enable ? 0x40 : 0x00) |
|
|
(sprites[7].enable ? 0x80 : 0x00)
|
|
);
|
|
break;
|
|
case 0x16:
|
|
result &= 0xC0;
|
|
result |= (byte)(
|
|
(xScroll & 0x7) |
|
|
(columnSelect ? 0x08 : 0x00) |
|
|
(multicolorMode ? 0x10 : 0x00)
|
|
);
|
|
break;
|
|
case 0x17:
|
|
result = (byte)(
|
|
(sprites[0].yExpand ? 0x01 : 0x00) |
|
|
(sprites[1].yExpand ? 0x02 : 0x00) |
|
|
(sprites[2].yExpand ? 0x04 : 0x00) |
|
|
(sprites[3].yExpand ? 0x08 : 0x00) |
|
|
(sprites[4].yExpand ? 0x10 : 0x00) |
|
|
(sprites[5].yExpand ? 0x20 : 0x00) |
|
|
(sprites[6].yExpand ? 0x40 : 0x00) |
|
|
(sprites[7].yExpand ? 0x80 : 0x00)
|
|
);
|
|
break;
|
|
case 0x18:
|
|
result &= 0x01;
|
|
result |= (byte)(
|
|
((pointerVM & 0xF) << 4) |
|
|
((pointerCB & 0x7) << 1)
|
|
);
|
|
break;
|
|
case 0x19:
|
|
result &= 0x70;
|
|
result |= (byte)(
|
|
(intRaster ? 0x01 : 0x00) |
|
|
(intSpriteDataCollision ? 0x02 : 0x00) |
|
|
(intSpriteCollision ? 0x04 : 0x00) |
|
|
(intLightPen ? 0x08 : 0x00) |
|
|
(pinIRQ ? 0x00 : 0x80)
|
|
);
|
|
break;
|
|
case 0x1A:
|
|
result &= 0xF0;
|
|
result |= (byte)(
|
|
(enableIntRaster ? 0x01 : 0x00) |
|
|
(enableIntSpriteDataCollision ? 0x02 : 0x00) |
|
|
(enableIntSpriteCollision ? 0x04 : 0x00) |
|
|
(enableIntLightPen ? 0x08 : 0x00)
|
|
);
|
|
break;
|
|
case 0x1B:
|
|
result = (byte)(
|
|
(sprites[0].priority ? 0x01 : 0x00) |
|
|
(sprites[1].priority ? 0x02 : 0x00) |
|
|
(sprites[2].priority ? 0x04 : 0x00) |
|
|
(sprites[3].priority ? 0x08 : 0x00) |
|
|
(sprites[4].priority ? 0x10 : 0x00) |
|
|
(sprites[5].priority ? 0x20 : 0x00) |
|
|
(sprites[6].priority ? 0x40 : 0x00) |
|
|
(sprites[7].priority ? 0x80 : 0x00)
|
|
);
|
|
break;
|
|
case 0x1C:
|
|
result = (byte)(
|
|
(sprites[0].multicolor ? 0x01 : 0x00) |
|
|
(sprites[1].multicolor ? 0x02 : 0x00) |
|
|
(sprites[2].multicolor ? 0x04 : 0x00) |
|
|
(sprites[3].multicolor ? 0x08 : 0x00) |
|
|
(sprites[4].multicolor ? 0x10 : 0x00) |
|
|
(sprites[5].multicolor ? 0x20 : 0x00) |
|
|
(sprites[6].multicolor ? 0x40 : 0x00) |
|
|
(sprites[7].multicolor ? 0x80 : 0x00)
|
|
);
|
|
break;
|
|
case 0x1D:
|
|
result = (byte)(
|
|
(sprites[0].xExpand ? 0x01 : 0x00) |
|
|
(sprites[1].xExpand ? 0x02 : 0x00) |
|
|
(sprites[2].xExpand ? 0x04 : 0x00) |
|
|
(sprites[3].xExpand ? 0x08 : 0x00) |
|
|
(sprites[4].xExpand ? 0x10 : 0x00) |
|
|
(sprites[5].xExpand ? 0x20 : 0x00) |
|
|
(sprites[6].xExpand ? 0x40 : 0x00) |
|
|
(sprites[7].xExpand ? 0x80 : 0x00)
|
|
);
|
|
break;
|
|
case 0x1E:
|
|
result = (byte)(
|
|
(sprites[0].collideSprite ? 0x01 : 0x00) |
|
|
(sprites[1].collideSprite ? 0x02 : 0x00) |
|
|
(sprites[2].collideSprite ? 0x04 : 0x00) |
|
|
(sprites[3].collideSprite ? 0x08 : 0x00) |
|
|
(sprites[4].collideSprite ? 0x10 : 0x00) |
|
|
(sprites[5].collideSprite ? 0x20 : 0x00) |
|
|
(sprites[6].collideSprite ? 0x40 : 0x00) |
|
|
(sprites[7].collideSprite ? 0x80 : 0x00)
|
|
);
|
|
break;
|
|
case 0x1F:
|
|
result = (byte)(
|
|
(sprites[0].collideData ? 0x01 : 0x00) |
|
|
(sprites[1].collideData ? 0x02 : 0x00) |
|
|
(sprites[2].collideData ? 0x04 : 0x00) |
|
|
(sprites[3].collideData ? 0x08 : 0x00) |
|
|
(sprites[4].collideData ? 0x10 : 0x00) |
|
|
(sprites[5].collideData ? 0x20 : 0x00) |
|
|
(sprites[6].collideData ? 0x40 : 0x00) |
|
|
(sprites[7].collideData ? 0x80 : 0x00)
|
|
);
|
|
break;
|
|
case 0x20:
|
|
result &= 0xF0;
|
|
result |= (byte)(borderColor & 0x0F);
|
|
break;
|
|
case 0x21:
|
|
result &= 0xF0;
|
|
result |= (byte)(backgroundColor0 & 0x0F);
|
|
break;
|
|
case 0x22:
|
|
result &= 0xF0;
|
|
result |= (byte)(backgroundColor1 & 0x0F);
|
|
break;
|
|
case 0x23:
|
|
result &= 0xF0;
|
|
result |= (byte)(backgroundColor2 & 0x0F);
|
|
break;
|
|
case 0x24:
|
|
result &= 0xF0;
|
|
result |= (byte)(backgroundColor3 & 0x0F);
|
|
break;
|
|
case 0x25:
|
|
result &= 0xF0;
|
|
result |= (byte)(spriteMulticolor0 & 0x0F);
|
|
break;
|
|
case 0x26:
|
|
result &= 0xF0;
|
|
result |= (byte)(spriteMulticolor1 & 0x0F);
|
|
break;
|
|
case 0x27:
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2A:
|
|
case 0x2B:
|
|
case 0x2C:
|
|
case 0x2D:
|
|
case 0x2E:
|
|
result &= 0xF0;
|
|
result |= (byte)(sprites[addr - 0x27].color & 0xF);
|
|
break;
|
|
default:
|
|
// not connected
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public void Write(int addr, byte val)
|
|
{
|
|
addr &= 0x3F;
|
|
switch (addr)
|
|
{
|
|
case 0x19:
|
|
// interrupts are cleared by writing a 1
|
|
if ((val & 0x01) != 0)
|
|
intRaster = false;
|
|
if ((val & 0x02) != 0)
|
|
intSpriteDataCollision = false;
|
|
if ((val & 0x04) != 0)
|
|
intSpriteCollision = false;
|
|
if ((val & 0x08) != 0)
|
|
intLightPen = false;
|
|
UpdatePins();
|
|
break;
|
|
case 0x1A:
|
|
WriteRegister(addr, val);
|
|
break;
|
|
case 0x1E:
|
|
case 0x1F:
|
|
// can't write to these
|
|
break;
|
|
case 0x2F:
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3A:
|
|
case 0x3B:
|
|
case 0x3C:
|
|
case 0x3D:
|
|
case 0x3E:
|
|
case 0x3F:
|
|
// not connected
|
|
break;
|
|
default:
|
|
WriteRegister(addr, val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void WriteRegister(int addr, byte val)
|
|
{
|
|
switch (addr)
|
|
{
|
|
case 0x00:
|
|
case 0x02:
|
|
case 0x04:
|
|
case 0x06:
|
|
case 0x08:
|
|
case 0x0A:
|
|
case 0x0C:
|
|
case 0x0E:
|
|
sprites[addr >> 1].x &= 0x100;
|
|
sprites[addr >> 1].x |= val;
|
|
break;
|
|
case 0x01:
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x07:
|
|
case 0x09:
|
|
case 0x0B:
|
|
case 0x0D:
|
|
case 0x0F:
|
|
sprites[addr >> 1].y = val;
|
|
break;
|
|
case 0x10:
|
|
sprites[0].x = (sprites[0].x & 0xFF) | ((val & 0x01) << 8);
|
|
sprites[1].x = (sprites[1].x & 0xFF) | ((val & 0x02) << 7);
|
|
sprites[2].x = (sprites[2].x & 0xFF) | ((val & 0x04) << 6);
|
|
sprites[3].x = (sprites[3].x & 0xFF) | ((val & 0x08) << 5);
|
|
sprites[4].x = (sprites[4].x & 0xFF) | ((val & 0x10) << 4);
|
|
sprites[5].x = (sprites[5].x & 0xFF) | ((val & 0x20) << 3);
|
|
sprites[6].x = (sprites[6].x & 0xFF) | ((val & 0x40) << 2);
|
|
sprites[7].x = (sprites[7].x & 0xFF) | ((val & 0x80) << 1);
|
|
break;
|
|
case 0x11:
|
|
yScroll = (val & 0x07);
|
|
rowSelect = ((val & 0x08) != 0);
|
|
displayEnable = ((val & 0x10) != 0);
|
|
bitmapMode = ((val & 0x20) != 0);
|
|
extraColorMode = ((val & 0x40) != 0);
|
|
rasterInterruptLine &= 0xFF;
|
|
rasterInterruptLine |= (val & 0x80) << 1;
|
|
UpdateBorder();
|
|
UpdateVideoMode();
|
|
break;
|
|
case 0x12:
|
|
rasterInterruptLine &= 0x100;
|
|
rasterInterruptLine |= val;
|
|
break;
|
|
case 0x13:
|
|
lightPenX = val;
|
|
break;
|
|
case 0x14:
|
|
lightPenY = val;
|
|
break;
|
|
case 0x15:
|
|
sprites[0].enable = ((val & 0x01) != 0);
|
|
sprites[1].enable = ((val & 0x02) != 0);
|
|
sprites[2].enable = ((val & 0x04) != 0);
|
|
sprites[3].enable = ((val & 0x08) != 0);
|
|
sprites[4].enable = ((val & 0x10) != 0);
|
|
sprites[5].enable = ((val & 0x20) != 0);
|
|
sprites[6].enable = ((val & 0x40) != 0);
|
|
sprites[7].enable = ((val & 0x80) != 0);
|
|
break;
|
|
case 0x16:
|
|
xScroll = (val & 0x07);
|
|
columnSelect = ((val & 0x08) != 0);
|
|
multicolorMode = ((val & 0x10) != 0);
|
|
UpdateBorder();
|
|
UpdateVideoMode();
|
|
break;
|
|
case 0x17:
|
|
sprites[0].yExpand = ((val & 0x01) != 0);
|
|
sprites[1].yExpand = ((val & 0x02) != 0);
|
|
sprites[2].yExpand = ((val & 0x04) != 0);
|
|
sprites[3].yExpand = ((val & 0x08) != 0);
|
|
sprites[4].yExpand = ((val & 0x10) != 0);
|
|
sprites[5].yExpand = ((val & 0x20) != 0);
|
|
sprites[6].yExpand = ((val & 0x40) != 0);
|
|
sprites[7].yExpand = ((val & 0x80) != 0);
|
|
break;
|
|
case 0x18:
|
|
pointerVM = ((val >> 4) & 0xF);
|
|
pointerCB = ((val >> 1) & 0x7);
|
|
break;
|
|
case 0x19:
|
|
intRaster = ((val & 0x01) != 0);
|
|
intSpriteDataCollision = ((val & 0x02) != 0);
|
|
intSpriteCollision = ((val & 0x04) != 0);
|
|
intLightPen = ((val & 0x08) != 0);
|
|
UpdatePins();
|
|
break;
|
|
case 0x1A:
|
|
enableIntRaster = ((val & 0x01) != 0);
|
|
enableIntSpriteDataCollision = ((val & 0x02) != 0);
|
|
enableIntSpriteCollision = ((val & 0x04) != 0);
|
|
enableIntLightPen = ((val & 0x08) != 0);
|
|
UpdatePins();
|
|
break;
|
|
case 0x1B:
|
|
sprites[0].priority = ((val & 0x01) != 0);
|
|
sprites[1].priority = ((val & 0x02) != 0);
|
|
sprites[2].priority = ((val & 0x04) != 0);
|
|
sprites[3].priority = ((val & 0x08) != 0);
|
|
sprites[4].priority = ((val & 0x10) != 0);
|
|
sprites[5].priority = ((val & 0x20) != 0);
|
|
sprites[6].priority = ((val & 0x40) != 0);
|
|
sprites[7].priority = ((val & 0x80) != 0);
|
|
break;
|
|
case 0x1C:
|
|
sprites[0].multicolor = ((val & 0x01) != 0);
|
|
sprites[1].multicolor = ((val & 0x02) != 0);
|
|
sprites[2].multicolor = ((val & 0x04) != 0);
|
|
sprites[3].multicolor = ((val & 0x08) != 0);
|
|
sprites[4].multicolor = ((val & 0x10) != 0);
|
|
sprites[5].multicolor = ((val & 0x20) != 0);
|
|
sprites[6].multicolor = ((val & 0x40) != 0);
|
|
sprites[7].multicolor = ((val & 0x80) != 0);
|
|
break;
|
|
case 0x1D:
|
|
sprites[0].xExpand = ((val & 0x01) != 0);
|
|
sprites[1].xExpand = ((val & 0x02) != 0);
|
|
sprites[2].xExpand = ((val & 0x04) != 0);
|
|
sprites[3].xExpand = ((val & 0x08) != 0);
|
|
sprites[4].xExpand = ((val & 0x10) != 0);
|
|
sprites[5].xExpand = ((val & 0x20) != 0);
|
|
sprites[6].xExpand = ((val & 0x40) != 0);
|
|
sprites[7].xExpand = ((val & 0x80) != 0);
|
|
break;
|
|
case 0x1E:
|
|
sprites[0].collideSprite = ((val & 0x01) != 0);
|
|
sprites[1].collideSprite = ((val & 0x02) != 0);
|
|
sprites[2].collideSprite = ((val & 0x04) != 0);
|
|
sprites[3].collideSprite = ((val & 0x08) != 0);
|
|
sprites[4].collideSprite = ((val & 0x10) != 0);
|
|
sprites[5].collideSprite = ((val & 0x20) != 0);
|
|
sprites[6].collideSprite = ((val & 0x40) != 0);
|
|
sprites[7].collideSprite = ((val & 0x80) != 0);
|
|
break;
|
|
case 0x1F:
|
|
sprites[0].collideData = ((val & 0x01) != 0);
|
|
sprites[1].collideData = ((val & 0x02) != 0);
|
|
sprites[2].collideData = ((val & 0x04) != 0);
|
|
sprites[3].collideData = ((val & 0x08) != 0);
|
|
sprites[4].collideData = ((val & 0x10) != 0);
|
|
sprites[5].collideData = ((val & 0x20) != 0);
|
|
sprites[6].collideData = ((val & 0x40) != 0);
|
|
sprites[7].collideData = ((val & 0x80) != 0);
|
|
break;
|
|
case 0x20:
|
|
borderColor = (val & 0xF);
|
|
break;
|
|
case 0x21:
|
|
backgroundColor0 = (val & 0xF);
|
|
break;
|
|
case 0x22:
|
|
backgroundColor1 = (val & 0xF);
|
|
break;
|
|
case 0x23:
|
|
backgroundColor2 = (val & 0xF);
|
|
break;
|
|
case 0x24:
|
|
backgroundColor3 = (val & 0xF);
|
|
break;
|
|
case 0x25:
|
|
spriteMulticolor0 = (val & 0xF);
|
|
break;
|
|
case 0x26:
|
|
spriteMulticolor1 = (val & 0xF);
|
|
break;
|
|
case 0x27:
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2A:
|
|
case 0x2B:
|
|
case 0x2C:
|
|
case 0x2D:
|
|
case 0x2E:
|
|
sprites[addr - 0x27].color = (val & 0xF);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|