c64- CIA register class, data port class

This commit is contained in:
saxxonpike 2012-11-05 16:56:58 +00:00
parent ef4bb14d59
commit 4f2cd1263c
7 changed files with 314 additions and 248 deletions

View File

@ -83,6 +83,7 @@
<Compile Include="Computers\Commodore64\C64.cs" />
<Compile Include="Computers\Commodore64\Cartridge.cs" />
<Compile Include="Computers\Commodore64\Cia.cs" />
<Compile Include="Computers\Commodore64\DataPort.cs" />
<Compile Include="Computers\Commodore64\MemBus.cs" />
<Compile Include="Computers\Commodore64\Sid.cs" />
<Compile Include="Computers\Commodore64\VicII.cs" />

View File

@ -15,8 +15,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
public byte[] inputFile;
// chipset
public Cia cia0;
public Cia cia1;
public Cia cia2;
public MOS6502X cpu;
public Memory mem;
public Sid sid;
@ -31,8 +31,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
cpu.DummyReadMemory = PeekMemory;
// initialize cia timers
cia1 = new Cia(Cia.DummyReadPort, Cia.DummyReadPort, Cia.DummyWritePort, Cia.DummyWritePort);
cia2 = new Cia(Cia.DummyReadPort, Cia.DummyReadPort, Cia.DummyWritePort, Cia.DummyWritePort);
cia0 = new Cia(signal);
cia1 = new Cia(signal);
// initialize vic
signal = new ChipSignals();
@ -43,15 +43,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
// initialize memory (this must be done AFTER all other chips are initialized)
string romPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "C64Kernal");
mem = new Memory(romPath, vic, sid, cia1, cia2);
mem = new Memory(romPath, vic, sid, cia0, cia1);
vic.mem = mem;
// initialize ports
cia2.ReadPortA = mem.CIA2ReadPortA;
cia2.ReadPortB = mem.CIA2ReadPortB;
cia2.WritePortA = mem.CIA2WritePortA;
cia2.WritePortB = mem.CIA2WritePortB;
// initialize media
Cartridge cart = new Cartridge(inputFile);
if (cart.valid)
@ -91,12 +85,17 @@ namespace BizHawk.Emulation.Computers.Commodore64
public class ChipSignals
{
private bool[] _CiaSerialInput = new bool[2];
private bool[] _CiaIRQOutput = new bool[2];
private bool _VicAECOutput;
private bool _VicBAOutput;
private bool _VicIRQOutput;
private bool _VicLPInput;
public bool CiaIRQ0 { get { return _CiaIRQOutput[0]; } set { _CiaIRQOutput[0] = value; } }
public bool CiaIRQ1 { get { return _CiaIRQOutput[1]; } set { _CiaIRQOutput[1] = value; } }
public bool CiaSerial0 { get { return _CiaSerialInput[0]; } }
public bool CiaSerial1 { get { return _CiaSerialInput[1]; } }
public bool CpuAEC { get { return _VicAECOutput; } }
public bool CpuIRQ { get { return _VicIRQOutput | _CiaIRQOutput[0] | _CiaIRQOutput[1]; } }
public bool CpuRDY { get { return _VicBAOutput; } }

View File

@ -102,8 +102,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
vic.PerformCycle();
sid.PerformCycle();
cia0.PerformCycle();
cia1.PerformCycle();
cia2.PerformCycle();
}
if (_islag)

View File

@ -5,259 +5,305 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class CiaRegs
{
public bool ALARM;
public int ALARM10;
public int ALARMHR;
public int ALARMMIN;
public bool ALARMPM;
public int ALARMSEC;
public int[] DOR = new int[2];
public bool IALARM;
public bool IFLG;
public int[] INMODE = new int[2];
public bool IRQ;
public bool ISP;
public bool[] IT = new bool[2];
public bool[] LOAD = new bool[2];
public bool[] OUTMODE = new bool[2];
public bool[] PBON = new bool[2];
public int[] PR = new int[2];
public bool[] RUNMODE = new bool[2];
public int SDR;
public bool SPMODE;
public bool[] START = new bool[2];
public int[] T = new int[2];
public int TOD10;
public bool TODIN;
public int TODHR;
public int TODMIN;
public bool TODPM;
public int TODSEC;
private DirectionalDataPort[] ports;
private ChipSignals signal;
public CiaRegs(ChipSignals newSignal, DirectionalDataPort[] newPorts)
{
ports = newPorts;
signal = newSignal;
// power on state
this[0x04] = 0xFF;
this[0x05] = 0xFF;
this[0x06] = 0xFF;
this[0x07] = 0xFF;
this[0x0B] = 0x01;
}
public byte this[int addr]
{
get
{
// value of open bits
int result = 0x00;
addr &= 0x0F;
switch (addr)
{
case 0x00:
result = ports[0].Data;
break;
case 0x01:
result = ports[1].Data;
break;
case 0x02:
result = ports[0].Direction;
break;
case 0x03:
result = ports[1].Direction;
break;
case 0x04:
result = (T[0] & 0xFF);
break;
case 0x05:
result = ((T[0] >> 8) & 0xFF);
break;
case 0x06:
result = (T[1] & 0xFF);
break;
case 0x07:
result = ((T[1] >> 8) & 0xFF);
break;
case 0x08:
result |= (TOD10 & 0x0F);
break;
case 0x09:
result &= 0x80;
result |= (TODSEC & 0x7F);
break;
case 0x0A:
result &= 0x80;
result |= (TODMIN & 0x7F);
break;
case 0x0B:
result &= 0x40;
result |= ((TODHR & 0x3F) | (TODPM ? 0x80 : 0x00));
break;
case 0x0C:
result = SDR;
break;
case 0x0D:
result &= 0x9F;
result |= (IT[0] ? 0x01 : 0x00);
result |= (IT[1] ? 0x02 : 0x00);
result |= (IALARM ? 0x04 : 0x00);
result |= (ISP ? 0x08 : 0x00);
result |= (IFLG ? 0x10 : 0x00);
result |= (IRQ ? 0x80 : 0x00);
break;
case 0x0E:
result = (START[0] ? 0x01 : 0x00);
result = (PBON[0] ? 0x02 : 0x00);
result = (OUTMODE[0] ? 0x04 : 0x00);
result = (RUNMODE[0] ? 0x08 : 0x00);
result = (LOAD[0] ? 0x10 : 0x00);
result = ((INMODE[0] & 0x01) << 5);
result = (SPMODE ? 0x40 : 0x00);
result = (TODIN ? 0x80 : 0x00);
break;
case 0x0F:
result = (START[1] ? 0x01 : 0x00);
result = (PBON[1] ? 0x02 : 0x00);
result = (OUTMODE[1] ? 0x04 : 0x00);
result = (RUNMODE[1] ? 0x08 : 0x00);
result = (LOAD[1] ? 0x10 : 0x00);
result = ((INMODE[1] & 0x03) << 5);
result = (ALARM ? 0x80 : 0x00);
break;
}
return (byte)(result & 0xFF);
}
set
{
byte val = value;
addr &= 0x0F;
switch (addr)
{
case 0x00:
ports[0].Data = val;
break;
case 0x01:
ports[1].Data = val;
break;
case 0x02:
ports[0].Direction = val;
break;
case 0x03:
ports[1].Direction = val;
break;
case 0x04:
T[0] &= 0xFF00;
T[0] |= val;
break;
case 0x05:
T[0] &= 0x00FF;
T[0] |= ((int)val << 8);
break;
case 0x06:
T[1] &= 0xFF00;
T[1] |= val;
break;
case 0x07:
T[1] &= 0x00FF;
T[1] |= ((int)val << 8);
break;
case 0x08:
TOD10 = val & 0x0F;
break;
case 0x09:
TODSEC = val & 0x7F;
break;
case 0x0A:
TODMIN = val & 0x7F;
break;
case 0x0B:
val &= 0x9F;
TODHR = val;
TODPM = ((val & 0x80) != 0x00);
break;
case 0x0C:
SDR = val;
break;
case 0x0D:
IT[0] = ((val & 0x01) != 0x00);
IT[1] = ((val & 0x02) != 0x00);
IALARM = ((val & 0x04) != 0x00);
ISP = ((val & 0x08) != 0x00);
IFLG = ((val & 0x10) != 0x00);
IRQ = ((val & 0x80) != 0x00);
break;
case 0x0E:
START[0] = ((val & 0x01) != 0x00);
PBON[0] = ((val & 0x02) != 0x00);
OUTMODE[0] = ((val & 0x04) != 0x00);
RUNMODE[0] = ((val & 0x08) != 0x00);
LOAD[0] = ((val & 0x10) != 0x00);
INMODE[0] = ((val & 0x20) >> 5);
SPMODE = ((val & 0x40) != 0x00);
TODIN = ((val & 0x80) != 0x00);
break;
case 0x0F:
START[1] = ((val & 0x01) != 0x00);
PBON[1] = ((val & 0x02) != 0x00);
OUTMODE[1] = ((val & 0x04) != 0x00);
RUNMODE[1] = ((val & 0x08) != 0x00);
LOAD[1] = ((val & 0x10) != 0x00);
INMODE[1] = ((val & 0x60) >> 5);
ALARM = ((val & 0x80) != 0x00);
break;
}
}
}
}
public class Cia
{
public int alarmTime;
public bool alarmWriteEnabled;
public int cycles;
public bool flagPin;
public bool flagPinInterrupt;
public bool flagPinInterruptEnabled;
public bool[] generatePositiveEdgeOnUnderflow = new bool[2];
public bool interrupt;
public bool[] loadStartValue = new bool[2];
public bool palMode;
public byte[] regs;
public int shiftRegisterCycles;
public bool shiftRegisterInterrupt;
public bool shiftRegisterInterruptEnabled;
public bool shiftRegisterIsOutput;
public bool[] stopOnUnderflow = new bool[2];
public int timeOfDay;
public bool timeOfDayAlarmInterrupt;
public bool timeOfDayAlarmInterruptEnabled;
public int[] timerConfig = new int[2];
public bool[] timerEnabled = new bool[2];
public bool[] timerInterruptEnabled = new bool[2];
public ushort[] timerLatch = new ushort[2];
public bool[] timerUnderflowMonitor = new bool[2];
public ushort[] timerValue = new ushort[2];
public bool[] underflowTimerInterrupt = new bool[2];
public bool[] underflowTimerInterruptEnabled = new bool[2];
public int intMask;
public DirectionalDataPort[] ports;
public CiaRegs regs;
public ChipSignals signal;
public Func<byte> ReadPortA;
public Func<byte> ReadPortB;
public Action<byte, byte> WritePortA;
public Action<byte, byte> WritePortB;
public Cia(Func<byte> funcReadPortA, Func<byte> funcReadPortB, Action<byte, byte> actWritePortA, Action<byte, byte> actWritePortB)
public Cia(ChipSignals newSignal)
{
ReadPortA = funcReadPortA;
ReadPortB = funcReadPortB;
WritePortA = actWritePortA;
WritePortB = actWritePortB;
signal = newSignal;
HardReset();
}
static public byte DummyReadPort()
{
return 0x00;
}
static public void DummyWritePort(byte val, byte direction)
{
// do nothing
}
public void HardReset()
{
regs = new byte[0x10];
Write(0x0004, 0xFF);
Write(0x0005, 0xFF);
Write(0x0006, 0xFF);
Write(0x0007, 0xFF);
Write(0x000B, 0x01);
ports = new DirectionalDataPort[2];
regs = new CiaRegs(signal, ports);
}
public void PerformCycle()
{
unchecked
{
for (int i = 0; i < 2; i++)
{
if (timerConfig[i] == 0)
TimerTick(i);
}
}
regs[0x04] = (byte)(timerValue[0] & 0xFF);
regs[0x05] = (byte)(timerValue[0] >> 8);
regs[0x06] = (byte)(timerValue[1] & 0xFF);
regs[0x07] = (byte)(timerValue[1] >> 8);
}
public void PollSerial(ref bool bit)
{
// this has the same effect as raising CNT
for (int i = 0; i < 2; i++)
{
switch (timerConfig[i])
{
case 1:
case 3:
TimerTick(i);
break;
}
}
if (shiftRegisterIsOutput)
{
bit = ((regs[0x0C] & 0x01) != 0x00);
regs[0x0C] >>= 1;
}
else
{
regs[0x0C] >>= 1;
if (bit)
regs[0x0C] |= 0x80;
}
}
public byte Read(ushort addr)
{
byte result = 0;
addr &= 0x0F;
byte result;
switch (addr)
{
case 0x00:
result = ReadPortA();
regs[addr] = result;
break;
case 0x01:
result = ReadPortB();
regs[addr] = result;
break;
case 0x0D:
result = regs[addr];
shiftRegisterInterrupt = false;
timeOfDayAlarmInterrupt = false;
underflowTimerInterrupt[0] = false;
underflowTimerInterrupt[1] = false;
interrupt = false;
UpdateInterruptReg();
break;
// reading this reg clears it
result = regs[0x0D];
regs[0x0D] = 0x00;
return result;
default:
result = regs[addr];
break;
return regs[addr];
}
return result;
}
public void TimerTick(int index)
{
if (timerEnabled[index])
{
unchecked
{
timerValue[index]--;
}
if (timerValue[index] == 0xFFFF)
{
if (underflowTimerInterruptEnabled[index])
{
underflowTimerInterrupt[index] = true;
interrupt = true;
}
// timer B can count on timer A's underflows
if (index == 0)
{
switch (timerConfig[1])
{
case 2:
case 3:
TimerTick(1);
break;
}
}
}
}
}
public void UpdateInterruptReg()
{
byte result;
result = (byte)(shiftRegisterInterrupt ? 0x01 : 0x00);
result |= (byte)(timeOfDayAlarmInterrupt ? 0x02 : 0x00);
result |= (byte)(underflowTimerInterrupt[0] ? 0x04 : 0x00);
result |= (byte)(underflowTimerInterrupt[1] ? 0x08 : 0x00);
result |= (byte)(flagPinInterrupt ? 0x10 : 0x00);
result |= (byte)(interrupt ? 0x80 : 0x00);
regs[0x0D] = result;
}
public void Write(ushort addr, byte val)
{
bool allowWrite = true;
addr &= 0x0F;
switch (addr)
{
case 0x00:
WritePortA(val, regs[0x02]);
allowWrite = false;
case 0x08:
if (regs.ALARM)
regs.ALARM10 = val & 0x0F;
else
regs[addr] = val;
break;
case 0x01:
WritePortB(val, regs[0x03]);
allowWrite = false;
case 0x09:
if (regs.ALARM)
regs.ALARMSEC = val & 0x7F;
else
regs[addr] = val;
break;
case 0x04:
timerValue[0] &= 0xFF00;
timerValue[0] |= val;
case 0x0A:
if (regs.ALARM)
regs.ALARMMIN = val & 0x7F;
else
regs[addr] = val;
break;
case 0x05:
timerValue[0] &= 0xFF;
timerValue[0] |= (ushort)(val << 8);
break;
case 0x06:
timerValue[1] &= 0xFF00;
timerValue[1] |= val;
break;
case 0x07:
timerValue[1] &= 0xFF;
timerValue[1] |= (ushort)(val << 8);
case 0x0B:
if (regs.ALARM)
{
regs.ALARMHR = val & 0x1F;
regs.ALARMPM = ((val & 0x80) != 0x00);
}
else
regs[addr] = val;
break;
case 0x0D:
if ((val & 0x01) != 0x00)
timerInterruptEnabled[0] = ((val & 0x80) != 0x00);
if ((val & 0x02) != 0x00)
timerInterruptEnabled[1] = ((val & 0x80) != 0x00);
if ((val & 0x04) != 0x00)
timeOfDayAlarmInterruptEnabled = ((val & 0x80) != 0x00);
if ((val & 0x08) != 0x00)
shiftRegisterInterruptEnabled = ((val & 0x80) != 0x00);
if ((val & 0x10) != 0x00)
flagPinInterruptEnabled = ((val & 0x80) != 0x00);
allowWrite = false;
break;
case 0x0E:
timerEnabled[0] = ((val & 0x01) != 0x00);
timerUnderflowMonitor[0] = ((val & 0x02) != 0x00);
generatePositiveEdgeOnUnderflow[0] = ((val & 0x04) != 0x00);
stopOnUnderflow[0] = ((val & 0x08) != 0x00);
loadStartValue[0] = ((val & 0x10) != 0x00);
timerConfig[0] = ((val & 0x20) >> 5);
shiftRegisterIsOutput = ((val & 0x40) != 0x00);
palMode = ((val & 0x80) != 0x00);
break;
case 0x0F:
timerEnabled[1] = ((val & 0x01) != 0x00);
timerUnderflowMonitor[1] = ((val & 0x02) != 0x00);
generatePositiveEdgeOnUnderflow[1] = ((val & 0x04) != 0x00);
stopOnUnderflow[1] = ((val & 0x08) != 0x00);
loadStartValue[1] = ((val & 0x10) != 0x00);
timerConfig[1] = ((val & 0x60) >> 5);
alarmWriteEnabled = ((val & 0x80) != 0x00);
intMask &= ~val;
if ((val & 0x80) != 0x00)
intMask ^= val;
break;
default:
regs[addr] = val;
break;
}
if (allowWrite)
regs[addr] = val;
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class DirectionalDataPort
{
private int _data;
public byte Direction;
public DirectionalDataPort(byte initData, byte initDirection)
{
_data = initData;
Direction = initDirection;
}
public byte Data
{
get
{
return (byte)(_data);
}
set
{
_data &= ~Direction;
_data |= (value & Direction);
}
}
}
}

View File

@ -64,8 +64,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
// registers
public byte busData;
public byte cpu00; // register $00
public byte cpu01; // register $01
public DirectionalDataPort cpuPort;
public bool readTrigger = true;
public bool writeTrigger = true;
@ -87,8 +86,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
sid = newSid;
cia1 = newCia1;
cia2 = newCia2;
cpu00 = 0x2F;
cpu01 = 0x37;
cpuPort = new DirectionalDataPort(0x2F, 0x37);
layout = new MemoryLayout();
UpdateLayout();
@ -202,11 +200,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
if (addr == 0x0000)
{
result = cpu00;
result = cpuPort.Direction;
}
else if (addr == 0x0001)
{
result = cpu01;
result = cpuPort.Data;
}
else
{
@ -268,11 +266,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
if (addr == 0x0000)
{
result = cpu00;
result = cpuPort.Direction;
}
else if (addr == 0x0001)
{
result = cpu01;
result = cpuPort.Data;
}
else
{
@ -335,9 +333,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void UpdateLayout()
{
bool loRom = ((cpu01 & 0x01) != 0);
bool hiRom = ((cpu01 & 0x02) != 0);
bool ioEnable = ((cpu01 & 0x04) != 0);
byte cpuData = cpuPort.Data;
bool loRom = ((cpuData & 0x01) != 0);
bool hiRom = ((cpuData & 0x02) != 0);
bool ioEnable = ((cpuData & 0x04) != 0);
if (loRom && hiRom && exRomPin && gamePin)
{
@ -446,12 +445,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
if (addr == 0x0000)
{
cpu00 = val;
cpuPort.Direction = val;
}
else if (addr == 0x0001)
{
cpu01 &= (byte)(~cpu00);
cpu01 |= (byte)(cpu00 & val);
cpuPort.Data = val;
UpdateLayout();
}
else

View File

@ -44,7 +44,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
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;
@ -465,11 +464,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int characterFetchOffset;
// raster
public int[] backgroundColor; // B0C
public bool backgroundMode; // ECM
public bool bitmapMode; // BMM
public int borderBottom;
public int borderColor;
public int borderLeft;
public bool borderOnHorizontal;
public bool borderOnVertical;
@ -479,13 +474,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int rasterLineLeft;
public int rasterOffset;
public int rasterOffsetX;
public int rasterOffsetY; // RASTER, RST8
public int rasterTotalLines;
public int rasterWidth;
public int renderOffset;
public bool resetBit; // RES
public bool screenEnabled; // DEN
public int verticalScroll; // YSCROLL
public int visibleBottom;
public int visibleHeight;
public int visibleLeft;
@ -495,9 +486,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int visibleTop;
public int visibleWidth;
public ChipSignals signal;
public Memory mem;
public VicIIRegs regs;
public ChipSignals signal;
public VicII(ChipSignals newSignal, VicIIMode videoMode)
{
@ -527,9 +518,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
// initialize raster
backgroundColor = new int[4];
rasterOffsetX = rasterLineLeft;
rasterOffsetY = 0;
// initialize buffer
buffer = new int[rasterWidth * rasterTotalLines];
@ -547,6 +536,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void PerformCycle()
{
}
public byte Read(ushort addr)