c64- VIC functions and interrupt triggers
This commit is contained in:
parent
4f2cd1263c
commit
788591ba77
|
@ -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; } }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue