c64- VIC functions and interrupt triggers

This commit is contained in:
saxxonpike 2012-11-05 19:05:25 +00:00
parent 4f2cd1263c
commit 788591ba77
4 changed files with 257 additions and 40 deletions

View File

@ -32,7 +32,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
// initialize cia timers
cia0 = new Cia(signal);
cia0.ports[0] = new DirectionalDataPort(0x00, 0x00);
cia0.ports[1] = new DirectionalDataPort(0x00, 0x00);
cia1 = new Cia(signal);
cia1.ports[0] = new DirectionalDataPort(0x00, 0x00);
cia1.ports[1] = new DirectionalDataPort(0x00, 0x00);
// initialize vic
signal = new ChipSignals();
@ -99,6 +103,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool CpuAEC { get { return _VicAECOutput; } }
public bool CpuIRQ { get { return _VicIRQOutput | _CiaIRQOutput[0] | _CiaIRQOutput[1]; } }
public bool CpuRDY { get { return _VicBAOutput; } }
public bool LPOutput { get { return _VicLPInput; } set { _VicLPInput = value; } }
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; } }

View File

@ -29,6 +29,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool SPMODE;
public bool[] START = new bool[2];
public int[] T = new int[2];
public int[] TLATCH = new int[2];
public int TOD10;
public bool TODIN;
public int TODHR;
@ -45,10 +46,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
signal = newSignal;
// power on state
this[0x04] = 0xFF;
this[0x05] = 0xFF;
this[0x06] = 0xFF;
this[0x07] = 0xFF;
TLATCH[0] = 0xFFFF;
TLATCH[1] = 0xFFFF;
T[0] = TLATCH[0];
T[1] = TLATCH[1];
this[0x0B] = 0x01;
}
@ -223,24 +225,68 @@ namespace BizHawk.Emulation.Computers.Commodore64
public class Cia
{
public int intMask;
public bool lastCNT;
public byte[] outputBitMask;
public DirectionalDataPort[] ports;
public CiaRegs regs;
public ChipSignals signal;
public bool thisCNT;
public bool[] underflow;
public Func<bool> ReadSerial;
public Action<bool> WriteSerial;
public Cia(ChipSignals newSignal)
{
signal = newSignal;
ReadSerial = ReadSerialDummy;
WriteSerial = WriteSerialDummy;
HardReset();
}
public void HardReset()
{
outputBitMask = new byte[] { 0x40, 0x80 };
ports = new DirectionalDataPort[2];
regs = new CiaRegs(signal, ports);
underflow = new bool[2];
}
public void PerformCycle()
{
lastCNT = thisCNT;
thisCNT = ReadSerial();
for (int i = 0; i < 2; i++)
{
if (regs.START[i])
{
TimerTick(i);
if (regs.PBON[i])
{
// output the clock data to port B
if (regs.OUTMODE[i])
{
// clear bit if set
ports[1].Data &= (byte)~outputBitMask[i];
}
if (underflow[i])
{
if (regs.OUTMODE[i])
{
// toggle bit
ports[1].Data ^= outputBitMask[i];
}
else
{
// set for a cycle
ports[1].Data |= outputBitMask[i];
}
}
}
}
}
}
public byte Read(ushort addr)
@ -259,14 +305,83 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
}
private bool ReadSerialDummy()
{
return false;
}
public void TimerDec(int index)
{
int timer = regs.T[index];
timer--;
if (timer < 0)
{
underflow[index] = true;
if (regs.RUNMODE[index])
{
// one shot timer
regs.START[index] = false;
}
timer = regs.TLATCH[index];
}
else
{
underflow[index] = false;
}
regs.T[index] = timer;
}
public void TimerTick(int index)
{
switch (regs.INMODE[index])
{
case 0:
TimerDec(index);
break;
case 1:
if (thisCNT & !lastCNT)
TimerDec(index);
break;
case 2:
if (underflow[0])
TimerDec(index);
break;
case 3:
if (underflow[0] || (thisCNT & !lastCNT))
TimerDec(index);
break;
}
}
public void Write(ushort addr, byte val)
{
switch (addr)
{
case 0x04:
regs.TLATCH[0] &= 0xFF00;
regs.TLATCH[0] |= val;
if (regs.LOAD[0])
regs.T[0] = regs.TLATCH[0];
break;
case 0x05:
regs.TLATCH[0] &= 0xFF;
regs.TLATCH[0] |= (int)val << 8;
if (regs.LOAD[0] || !regs.START[0])
regs.T[0] = regs.TLATCH[0];
break;
case 0x06:
regs.TLATCH[1] &= 0xFF00;
regs.TLATCH[1] |= val;
if (regs.LOAD[1])
regs.T[1] = regs.TLATCH[1];
break;
case 0x07:
regs.TLATCH[1] &= 0xFF;
regs.TLATCH[1] |= (int)val << 8;
if (regs.LOAD[1] || !regs.START[1])
regs.T[1] = regs.TLATCH[1];
break;
case 0x08:
if (regs.ALARM)
regs.ALARM10 = val & 0x0F;
@ -305,5 +420,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
}
private void WriteSerialDummy(bool val)
{
// do nothing
}
}
}

View File

@ -19,10 +19,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
Vic,
Sid,
ColorRam,
Cia0,
Cia1,
Cia2,
Expansion1,
Expansion2
Expansion0,
Expansion1
}
public class MemoryLayout
@ -38,8 +38,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
public class Memory
{
// chips
public Cia cia0;
public Cia cia1;
public Cia cia2;
public VicII vic;
public Sid sid;
@ -68,7 +68,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool readTrigger = true;
public bool writeTrigger = true;
public Memory(string sourceFolder, VicII newVic, Sid newSid, Cia newCia1, Cia newCia2)
public Memory(string sourceFolder, VicII newVic, Sid newSid, Cia newCia0, Cia newCia1)
{
ram = new byte[0x10000];
WipeMemory();
@ -84,9 +84,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
vic = newVic;
sid = newSid;
cia0 = newCia0;
cia1 = newCia1;
cia2 = newCia2;
cpuPort = new DirectionalDataPort(0x2F, 0x37);
cpuPort = new DirectionalDataPort(0x37, 0x2F);
layout = new MemoryLayout();
UpdateLayout();
@ -175,19 +175,19 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
else if (addr < 0x0D00)
{
result = MemoryDesignation.Cia1;
result = MemoryDesignation.Cia0;
}
else if (addr < 0x0E00)
{
result = MemoryDesignation.Cia2;
result = MemoryDesignation.Cia1;
}
else if (addr < 0x0F00)
{
result = MemoryDesignation.Expansion1;
result = MemoryDesignation.Expansion0;
}
else
{
result = MemoryDesignation.Expansion2;
result = MemoryDesignation.Expansion1;
}
}
@ -227,16 +227,16 @@ namespace BizHawk.Emulation.Computers.Commodore64
case MemoryDesignation.ColorRam:
result = colorRam[addr & 0x03FF];
break;
case MemoryDesignation.Cia0:
result = cia0.regs[addr & 0x0F];
break;
case MemoryDesignation.Cia1:
result = cia1.regs[addr & 0x0F];
break;
case MemoryDesignation.Cia2:
result = cia2.regs[addr & 0x0F];
break;
case MemoryDesignation.Expansion1:
case MemoryDesignation.Expansion0:
result = 0;
break;
case MemoryDesignation.Expansion2:
case MemoryDesignation.Expansion1:
result = 0;
break;
case MemoryDesignation.Kernal:
@ -293,16 +293,16 @@ namespace BizHawk.Emulation.Computers.Commodore64
case MemoryDesignation.ColorRam:
result = ReadColorRam(addr);
break;
case MemoryDesignation.Cia0:
result = cia0.Read(addr);
break;
case MemoryDesignation.Cia1:
result = cia1.Read(addr);
break;
case MemoryDesignation.Cia2:
result = cia2.Read(addr);
break;
case MemoryDesignation.Expansion1:
case MemoryDesignation.Expansion0:
result = 0;
break;
case MemoryDesignation.Expansion2:
case MemoryDesignation.Expansion1:
result = 0;
break;
case MemoryDesignation.Kernal:
@ -467,16 +467,16 @@ namespace BizHawk.Emulation.Computers.Commodore64
case MemoryDesignation.ColorRam:
colorRam[addr & 0x03FF] = (byte)(val & 0x0F);
break;
case MemoryDesignation.Cia0:
cia0.Write(addr, val);
break;
case MemoryDesignation.Cia1:
cia1.Write(addr, val);
break;
case MemoryDesignation.Cia2:
cia2.Write(addr, val);
case MemoryDesignation.Expansion0:
break;
case MemoryDesignation.Expansion1:
break;
case MemoryDesignation.Expansion2:
break;
case MemoryDesignation.RAM:
ram[addr] = val;
break;

View File

@ -131,7 +131,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
result |= (MxE[7] ? 0x80 : 0x00);
break;
case 0x16:
result &= 0xBF;
result &= 0xC0;
result |= XSCROLL & 0x07;
result |= (CSEL ? 0x08 : 0x00);
result |= (MCM ? 0x10 : 0x00);
@ -347,7 +347,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
IMBC = ((val & 0x02) != 0x00);
IMMC = ((val & 0x04) != 0x00);
ILP = ((val & 0x08) != 0x00);
IRQ = ((val & 0x80) != 0x00);
break;
case 0x1A:
ERST = ((val & 0x01) != 0x00);
@ -470,6 +469,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool borderOnVertical;
public int borderRight;
public int borderTop;
public int cycle;
public bool displayEnabled;
public int rasterInterruptLine;
public int rasterLineLeft;
public int rasterOffset;
@ -501,12 +502,12 @@ namespace BizHawk.Emulation.Computers.Commodore64
rasterTotalLines = 263;
rasterLineLeft = 0x19C;
visibleLeft = 0x1E9;
visibleRight = 0x18B;
visibleRight = 0x159;
visibleTop = 0x41;
visibleBottom = 0x13;
visibleRenderX = false;
visibleRenderY = true;
visibleWidth = 418;
visibleRenderY = false;
visibleWidth = 368;
visibleHeight = 217;
renderOffset = 0;
characterFetchOffset = rasterWidth - 3;
@ -519,6 +520,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
// initialize raster
rasterOffsetX = rasterLineLeft;
borderOnHorizontal = true;
borderOnVertical = true;
// initialize buffer
buffer = new int[rasterWidth * rasterTotalLines];
@ -531,12 +534,94 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void HardReset()
{
regs = new VicIIRegs();
signal.VicBA = true;
signal.VicIRQ = false;
UpdateBorder();
}
public void PerformCycle()
{
// display enable check on line $30
if (regs.RASTER == 0x30)
{
displayEnabled = (displayEnabled | regs.DEN);
}
// pixel clock is 8x the VIC clock
for (int i = 0; i < 8; i++)
{
int pixel;
// process raster position
if (rasterOffsetX >= rasterWidth)
{
// reset to the left side
rasterOffsetX -= rasterWidth;
regs.RASTER = rasterOffset >> 9;
cycle = 0;
// if vblank, reset the raster position
if (regs.RASTER == rasterTotalLines)
{
rasterOffset = 0;
regs.RASTER = 0;
regs.VCBASE = 0;
renderOffset = 0;
displayEnabled = false;
}
// check to see if we are within viewing area Y
if (regs.RASTER == visibleTop)
visibleRenderY = true;
if (regs.RASTER == visibleBottom)
visibleRenderY = false;
// check to see if we are on a horizontal border
if (displayEnabled && (regs.RASTER == borderTop || regs.RASTER == borderBottom))
borderOnHorizontal = !borderOnHorizontal;
// check for raster IRQ
if (regs.RASTER == rasterInterruptLine)
regs.IRST = true;
}
// check to see if we are within viewing area X
if (rasterOffsetX == visibleLeft)
visibleRenderX = true;
if (rasterOffsetX == visibleRight)
visibleRenderX = false;
// check to see if we are on a vertical border
if (rasterOffsetX == borderLeft)
borderOnVertical = false;
if (rasterOffsetX == borderRight)
borderOnVertical = true;
// draw the border if it is on, otherwise draw the screen
if (borderOnHorizontal || borderOnVertical)
pixel = regs.EC;
else
pixel = regs.BxC[0];
// plot the pixel if within visible range
if (visibleRenderX && visibleRenderY)
{
WritePixel(pixel);
}
// increment raster position
rasterOffset++;
rasterOffsetX++;
}
// check for anything that would've triggered an interrupt and raise the flag if so
if ((regs.IRST & regs.ERST) || (regs.IMMC & regs.EMMC) || (regs.IMBC & regs.EMBC) || (regs.ILP & regs.ELP))
{
regs.IRQ = true;
}
signal.VicIRQ = regs.IRQ;
cycle++;
}
public byte Read(ushort addr)
@ -565,7 +650,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
borderTop = regs.RSEL ? 0x033 : 0x037;
borderBottom = regs.RSEL ? 0x0FA : 0x0F6;
borderLeft = regs.CSEL ? 0x018 : 0x01F;
borderRight = regs.CSEL ? 0x14E : 0x157;
borderRight = regs.CSEL ? 0x157 : 0x14E;
}
public void Write(ushort addr, byte val)
@ -592,6 +677,17 @@ namespace BizHawk.Emulation.Computers.Commodore64
regs[addr] = val;
UpdateBorder();
break;
case 0x19:
// only allow clearing of these flags
if ((val & 0x01) == 0x00)
regs.IRST = false;
if ((val & 0x02) == 0x00)
regs.IMBC = false;
if ((val & 0x04) == 0x00)
regs.IMMC = false;
if ((val & 0x08) == 0x00)
regs.ILP = false;
break;
case 0x1E:
case 0x1F:
// can't write to these regs
@ -604,11 +700,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
private void WritePixel(int value)
{
if (visibleRenderX && visibleRenderY)
{
value &= 0x0F;
buffer[renderOffset++] = palette[value];
}
buffer[renderOffset++] = palette[value];
}
}
}