commodore64: new core with focus on low-level comm between chips and activity on both phases of the clock

This commit is contained in:
saxxonpike 2012-11-27 05:11:40 +00:00
parent 76487941be
commit 95d228f413
52 changed files with 3227 additions and 10560 deletions

View File

@ -79,38 +79,31 @@
<Link>VersionInfo.cs</Link>
</Compile>
<Compile Include="Buffer.cs" />
<Compile Include="Computers\Commodore64\1541.cs" />
<Compile Include="Computers\Commodore64\C64.core.cs" />
<Compile Include="Computers\Commodore64\C64.Core.cs" />
<Compile Include="Computers\Commodore64\C64.cs" />
<Compile Include="Computers\Commodore64\C64.PeekPoke.cs" />
<Compile Include="Computers\Commodore64\Cartridge.cs" />
<Compile Include="Computers\Commodore64\CartridgeMappers.cs" />
<Compile Include="Computers\Commodore64\Cia.cs" />
<Compile Include="Computers\Commodore64\CiaState.cs" />
<Compile Include="Computers\Commodore64\D64.cs" />
<Compile Include="Computers\Commodore64\DataPort.cs" />
<Compile Include="Computers\Commodore64\Disk.cs" />
<Compile Include="Computers\Commodore64\G64.cs" />
<Compile Include="Computers\Commodore64\IMedia.cs" />
<Compile Include="Computers\Commodore64\Input.cs" />
<Compile Include="Computers\Commodore64\PRGFile.cs" />
<Compile Include="Computers\Commodore64\MemBus.cs" />
<Compile Include="Computers\Commodore64\Savestate.cs" />
<Compile Include="Computers\Commodore64\SerialCable.cs" />
<Compile Include="Computers\Commodore64\Sid.cs" />
<Compile Include="Computers\Commodore64\SidEnvelopeGenerator.cs" />
<Compile Include="Computers\Commodore64\SidSoundProvider.cs" />
<Compile Include="Computers\Commodore64\SidState.cs" />
<Compile Include="Computers\Commodore64\SidWaveformCalculator.cs" />
<Compile Include="Computers\Commodore64\SidWaveformGenerator.cs" />
<Compile Include="Computers\Commodore64\Timing.cs" />
<Compile Include="Computers\Commodore64\Via.cs" />
<Compile Include="Computers\Commodore64\VicII.cs" />
<Compile Include="Computers\Commodore64\VicIIPipeline.cs" />
<Compile Include="Computers\Commodore64\VicIIPipelineBuilder.cs" />
<Compile Include="Computers\Commodore64\VicIIVideoProvider.cs" />
<Compile Include="Computers\Commodore64\VicIIRegs.cs" />
<Compile Include="Computers\Commodore64\VicState.cs" />
<Compile Include="Computers\Commodore64\Memory.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip2114.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip23XX.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip4864.cs" />
<Compile Include="Computers\Commodore64\MOS\IStandardIO.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6510.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6522.cs" />
<Compile Include="Computers\Commodore64\Media\D64.cs" />
<Compile Include="Computers\Commodore64\Media\Disk.cs" />
<Compile Include="Computers\Commodore64\Media\G64.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6526.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6567.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6581.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6569.cs" />
<Compile Include="Computers\Commodore64\C64.Savestate.cs" />
<Compile Include="Computers\Commodore64\MOS\MOSPLA.cs" />
<Compile Include="Computers\Commodore64\MOS\Port.cs" />
<Compile Include="Computers\Commodore64\MOS\Sid.cs" />
<Compile Include="Computers\Commodore64\MOS\Sid.SoundProvider.cs" />
<Compile Include="Computers\Commodore64\MOS\Sid.SyncSoundProvider.cs" />
<Compile Include="Computers\Commodore64\MOS\Timer.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.cs" />
<Compile Include="Computers\Commodore64\MOS\Vic.VideoProvider.cs" />
<Compile Include="Consoles\Atari\2600\Atari2600.cs" />
<Compile Include="Consoles\Atari\2600\Atari2600.Core.cs" />
<Compile Include="Consoles\Atari\2600\Mappers\m3Fe.cs" />
@ -559,6 +552,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Computers\Commodore64\docs\" />
<Folder Include="Computers\Commodore64\Peripheral\" />
</ItemGroup>
<ItemGroup />
<ItemGroup>

View File

@ -1,210 +0,0 @@
using BizHawk.Emulation.CPUs.M6502;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class Drive1541
{
// the 1541 drive:
//
// 2kb ram, mapped 0000-07FF
// two 6522 VIA chips, mapped at 1800 (communication to C64) and 1C00 (drive mechanics)
// drive ROM, mapped C000-FFFF
// default 1800:
// 07 00 1A FF 05 00 FF FF
// 04 00 00 00 00 00 00 00
// default 1C00:
// 90 00 00 00 05 00 FF FF
// 04 00 00 00 00 00 80 00
private Cia cia;
public MOS6502X cpu;
public int cyclesPerRevolution;
public int cyclesPerSecond;
public Disk disk;
public byte[] ram;
public byte[] rom;
public double rpm;
public ChipSignals signal;
public Via via0;
public Via via1;
public Drive1541(byte[] driveRom, Region driveRegion, Cia ciaInterface)
{
rom = new byte[driveRom.Length];
Array.Copy(driveRom, rom, driveRom.Length);
cia = ciaInterface;
switch (driveRegion)
{
case Region.NTSC:
cyclesPerSecond = 14318181 / 14;
break;
case Region.PAL:
cyclesPerSecond = 14318181 / 18;
break;
}
HardReset();
}
public void Eject()
{
disk = null;
}
public void HardReset()
{
cpu = new MOS6502X();
cpu.PC = (ushort)(Read(0xFFFC) + (Read(0xFFFD) << 8));
cpu.ReadMemory = Read;
cpu.WriteMemory = Write;
cpu.DummyReadMemory = Read;
ram = new byte[0x800];
via0 = new Via();
via1 = new Via();
SetRPM(300.0);
// attach VIA/CIA
via0.Connect(cia.ConnectSerialPort(1));
// set VIA values
via0.Poke(0x0, 0x07);
via0.Poke(0x2, 0x1A);
via0.Poke(0x3, 0xFF);
via0.Poke(0x4, 0x05);
via0.Poke(0x6, 0xFF);
via0.Poke(0x7, 0xFF);
via0.Poke(0x8, 0x04);
via0.Poke(0xE, 0x80);
via1.Poke(0x0, 0x90);
via1.Poke(0x4, 0x05);
via1.Poke(0x6, 0xFF);
via1.Poke(0x7, 0xFF);
via1.Poke(0x8, 0x04);
via1.Poke(0xE, 0x80);
}
public void Insert(Disk newDisk)
{
disk = newDisk;
}
public byte Peek(int addr)
{
addr &= 0xFFFF;
if (addr < 0x0800)
{
return ram[addr];
}
else if (addr >= 0x1800 && addr < 0x1C00)
{
return via0.Peek(addr);
}
else if (addr >= 0x1C00 && addr < 0x2000)
{
return via1.Peek(addr);
}
else if (addr >= 0xC000)
{
return rom[addr & 0x3FFF];
}
return 0xFF;
}
public byte PeekVia0(int addr)
{
return via0.Peek(addr);
}
public byte PeekVia1(int addr)
{
return via1.Peek(addr);
}
public void PerformCycle()
{
cpu.IRQ = via0.IRQ | via1.IRQ;
cpu.ExecuteOne();
via0.PerformCycle();
via1.PerformCycle();
}
public void Poke(int addr, byte val)
{
addr &= 0xFFFF;
if (addr < 0x0800)
{
ram[addr] = val;
}
else if (addr >= 0x1800 && addr < 0x1C00)
{
via0.Poke(addr, val);
}
else if (addr >= 0x1C00 && addr < 0x2000)
{
via1.Poke(addr, val);
}
}
public void PokeVia0(int addr, byte val)
{
via0.Poke(addr, val);
}
public void PokeVia1(int addr, byte val)
{
via1.Poke(addr, val);
}
public byte Read(ushort addr)
{
if (addr < 0x0800)
{
return ram[addr];
}
else if (addr >= 0x1800 && addr < 0x1C00)
{
return via0.Read(addr);
}
else if (addr >= 0x1C00 && addr < 0x2000)
{
return via1.Read(addr);
}
else if (addr >= 0xC000)
{
return rom[addr & 0x3FFF];
}
return 0xFF;
}
public void SetRPM(double newRPM)
{
rpm = newRPM;
cyclesPerRevolution = (int)((double)cyclesPerSecond / newRPM / (double)60);
}
public void Write(ushort addr, byte val)
{
if (addr < 0x0800)
{
ram[addr] = val;
}
else if (addr >= 0x1800 && addr < 0x1C00)
{
via0.Write(addr, val);
}
else if (addr >= 0x1C00 && addr < 0x2000)
{
via1.Write(addr, val);
}
}
}
}

View File

@ -0,0 +1,179 @@
using BizHawk.Emulation.CPUs.M6502;
using BizHawk.Emulation.Computers.Commodore64.MOS;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public enum Region
{
NTSC,
PAL
}
// emulated chips:
// U1: 6526 CIA0
// U2: 6526 CIA1
// U4: KERNAL & BASIC ROM
// U5: CHARACTER ROM
// U6: 6510 CPU
// U7: VIC 6567 (NTSC) or 6569 (PAL)
// U8: Memory multiplexer
// U9: SID 6581 or 8580
// U10: RAM
// U11: RAM
// U19: 2114 color RAM
public partial class C64 : IEmulator
{
// ------------------------------------
C64Chips chips;
// ------------------------------------
private void Init(Region initRegion)
{
chips = new C64Chips(initRegion);
InitRoms();
// configure video
CoreOutputComm.VsyncDen = chips.vic.CyclesPerFrame;
CoreOutputComm.VsyncNum = chips.vic.CyclesPerSecond;
}
private void InitRoms()
{
string sourceFolder = CoreInputComm.C64_FirmwaresPath;
if (sourceFolder == null)
sourceFolder = @".\C64\Firmwares";
string basicFile = "basic";
string charFile = "chargen";
string kernalFile = "kernal";
string basicPath = Path.Combine(sourceFolder, basicFile);
string charPath = Path.Combine(sourceFolder, charFile);
string kernalPath = Path.Combine(sourceFolder, kernalFile);
if (!File.Exists(basicPath)) HandleFirmwareError(basicFile);
if (!File.Exists(charPath)) HandleFirmwareError(charFile);
if (!File.Exists(kernalPath)) HandleFirmwareError(kernalFile);
byte[] basicRom = File.ReadAllBytes(basicPath);
byte[] charRom = File.ReadAllBytes(charPath);
byte[] kernalRom = File.ReadAllBytes(kernalPath);
chips.basicRom = new Chip23XX(Chip23XXmodel.Chip2364, basicRom);
chips.kernalRom = new Chip23XX(Chip23XXmodel.Chip2364, kernalRom);
chips.charRom = new Chip23XX(Chip23XXmodel.Chip2332, charRom);
}
// ------------------------------------
public bool DriveLED
{
get
{
return false;
}
}
public void Execute(uint count)
{
for (; count > 0; count--)
{
chips.ExecutePhase1();
chips.ExecutePhase2();
}
}
public void HardReset()
{
chips.HardReset();
}
private byte Peek(int addr)
{
return chips.cpu.Peek(addr);
}
private void Poke(int addr, byte val)
{
chips.cpu.Poke(addr, val);
}
// ------------------------------------
}
public class C64Chips
{
public Chip23XX basicRom; //u4
public Chip23XX charRom; //u5
public MOS6526 cia0; //u1
public MOS6526 cia1; //u2
public Chip2114 colorRam; //u19
public MOS6510 cpu; //u6
public Chip23XX kernalRom; //u4
public MOSPLA pla; //
public Chip4864 ram; //u10+11
public Sid sid; //u9
public Vic vic; //u7
public C64Chips(Region initRegion)
{
cia0 = new MOS6526(initRegion);
cia1 = new MOS6526(initRegion);
pla = new MOSPLA(this, cia1.ReadPort0);
switch (initRegion)
{
case Region.NTSC:
vic = new MOS6567(this);
break;
case Region.PAL:
vic = new MOS6569(this);
break;
}
colorRam = new Chip2114();
cpu = new MOS6510(this);
ram = new Chip4864();
sid = new MOS6581();
}
public void ExecutePhase1()
{
cia0.ExecutePhase1();
cia1.ExecutePhase1();
sid.ExecutePhase1();
vic.ExecutePhase1();
cpu.ExecutePhase1();
}
public void ExecutePhase2()
{
cia0.ExecutePhase2();
cia1.ExecutePhase2();
sid.ExecutePhase2();
vic.ExecutePhase2();
cpu.ExecutePhase2();
}
public void HardReset()
{
// note about hard reset: NOT identical to cold start
// reset all chips
cia0.HardReset();
cia1.HardReset();
colorRam.HardReset();
cpu.HardReset();
pla.HardReset();
ram.HardReset();
sid.HardReset();
vic.HardReset();
}
}
}

View File

@ -1,124 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class C64 : IEmulator
{
public byte PeekCia0(int addr)
{
return cia0.Peek(addr);
}
public byte PeekCia1(int addr)
{
return cia1.Peek(addr);
}
public byte PeekColorRAM(int addr)
{
return (byte)(mem.colorRam[addr & 0x3FF] & 0xF);
}
public byte PeekDiskDrive(int addr)
{
if (diskDriveAttached)
return diskDrive.Peek(addr);
return 0xFF;
}
public byte PeekMemory(ushort addr)
{
return mem.Peek(addr);
}
public byte PeekMemoryInt(int addr)
{
return mem.Peek((ushort)(addr & 0xFFFF));
}
public byte PeekRAM(int addr)
{
return mem.ram[addr];
}
public byte PeekSid(int addr)
{
return sid.regs[addr];
}
public byte PeekVia0(int addr)
{
if (diskDriveAttached)
return diskDrive.PeekVia0(addr);
return 0xFF;
}
public byte PeekVia1(int addr)
{
if (diskDriveAttached)
return diskDrive.PeekVia1(addr);
return 0xFF;
}
public byte PeekVic(int addr)
{
return vic.Peek(addr);
}
public void PokeCia0(int addr, byte val)
{
cia0.Poke(addr, val);
}
public void PokeCia1(int addr, byte val)
{
cia1.Poke(addr, val);
}
public void PokeColorRAM(int addr, byte val)
{
mem.colorRam[addr & 0x3FF] = (byte)(val & 0xF);
}
public void PokeDiskDrive(int addr, byte val)
{
if (diskDriveAttached)
diskDrive.Poke(addr, val);
}
public void PokeMemoryInt(int addr, byte val)
{
mem.Poke((ushort)(addr & 0xFFFF), val);
}
public void PokeRAM(int addr, byte val)
{
mem.PokeRam(addr, val);
}
public void PokeSid(int addr, byte val)
{
sid.Poke(addr, val);
}
public void PokeVia0(int addr, byte val)
{
if (diskDriveAttached)
diskDrive.PokeVia0(addr, val);
}
public void PokeVia1(int addr, byte val)
{
if (diskDriveAttached)
diskDrive.PokeVia1(addr, val);
}
public void PokeVic(int addr, byte val)
{
vic.Poke(addr, val);
}
}
}

View File

@ -55,37 +55,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
void SyncState(Serializer ser)
{
// global stuffs
ser.BeginSection("GAME");
ser.Sync("Lag", ref _lagcount);
ser.Sync("Frame", ref _frame);
ser.Sync("IsLag", ref _islag);
ser.EndSection();
// cpu creates its own section..
cpu.SyncState(ser);
ser.BeginSection("MEM");
mem.SyncState(ser);
ser.EndSection();
ser.BeginSection("VIC");
vic.SyncState(ser);
ser.EndSection();
ser.BeginSection("SID");
sid.SyncState(ser);
ser.EndSection();
ser.BeginSection("CIA0");
cia0.SyncState(ser);
ser.EndSection();
ser.BeginSection("CIA1");
cia1.SyncState(ser);
ser.EndSection();
// TODO: drive
}
}
}

View File

@ -1,201 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BizHawk.Emulation.CPUs.M6502;
namespace BizHawk.Emulation.Computers.Commodore64
{
public enum Region
{
NTSC,
PAL
}
public partial class C64 : IEmulator
{
// input
public Input input;
// source
public Cartridge cart = null;
public Drive1541 diskDrive = null;
public bool diskDriveAttached = false;
public string extension;
public byte[] inputFile;
public List<IMedia> mediaAttached = new List<IMedia>();
// chipset
public Cia cia0;
public Cia cia1;
public MOS6502X cpu;
public Memory mem;
public Sid sid;
public VicII vic;
public ChipSignals signal;
// cpu
private bool haltCPU;
public bool DriveLED
{
get
{
if (diskDriveAttached)
{
return (diskDrive.Peek(0x1C00) & 0x8) != 0;
}
else
{
return false;
}
}
}
public void HardReset()
{
mem.HardReset();
cia0.HardReset();
cia1.HardReset();
vic.HardReset();
sid.HardReset();
if (diskDriveAttached)
diskDrive.HardReset();
}
private void Init(Region initRegion)
{
// initalize cpu
cpu = new MOS6502X();
cpu.ReadMemory = ReadMemoryCPU;
cpu.WriteMemory = WriteMemory;
cpu.DummyReadMemory = PeekMemory;
// initialize cia timers
cia0 = new Cia(initRegion);
cia1 = new Cia(initRegion);
// initialize vic
signal = new ChipSignals();
vic = new VicII(signal, initRegion);
// set vsync rate
switch (initRegion)
{
case Region.NTSC:
CoreOutputComm.VsyncDen = vic.CyclesPerFrame * 14;
CoreOutputComm.VsyncNum = 14318181;
break;
case Region.PAL:
CoreOutputComm.VsyncDen = vic.CyclesPerFrame * 18;
CoreOutputComm.VsyncNum = 17734472;
break;
}
// initialize sid
sid = new Sid(initRegion, 44100); // we'll assume 44.1k for now until there's a better way
// initialize memory (this must be done AFTER all other chips are initialized)
string romPath = CoreInputComm.C64_FirmwaresPath;
if (romPath == null)
{
romPath = @".\C64\Firmwares";
}
mem = new Memory(romPath, vic, sid, cia0, cia1);
vic.mem = mem;
// initialize cpu hard reset vector
cpu.PC = (ushort)(ReadMemory(0xFFFC) + (ReadMemory(0xFFFD) << 8));
cpu.BCD_Enabled = true;
// initailize input
input = new Input(new DataPortConnector[] { cia0.ConnectPort(0), cia0.ConnectPort(1) });
cia0.AttachWriteHook(0, input.WritePortA);
cia0.AttachWriteHook(1, input.WritePortB);
// initialize media
switch (extension.ToUpper())
{
case @".G64":
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1);
diskDrive.Insert(G64.Read(inputFile));
break;
case @".D64":
diskDrive = new Drive1541(File.ReadAllBytes(Path.Combine(romPath, @"dos1541")), initRegion, cia1);
diskDrive.Insert(D64.Read(inputFile));
break;
case @".PRG":
if (inputFile.Length > 2)
mediaAttached.Add(new PRGFile(inputFile, mem, cpu));
break;
case @".CRT":
Cartridge newCart = new Cartridge(inputFile, mem);
if (newCart.valid)
{
cart = newCart;
mediaAttached.Add(cart);
}
break;
}
diskDriveAttached = (diskDrive != null);
}
public void PollInput()
{
input.Poll();
signal.KeyboardNMI = input.restorePressed;
}
public byte ReadMemory(ushort addr)
{
return mem.Read(addr);
}
private byte ReadMemoryCPU(ushort addr)
{
if (!signal.CpuRDY || !signal.CpuAEC)
haltCPU = true;
return mem.Read(addr);
}
public void WriteMemory(ushort addr, byte value)
{
mem.Write(addr, value);
}
public void WriteMemoryCPU(ushort addr, byte value)
{
if (!signal.CpuAEC)
haltCPU = true;
mem.Write(addr, value);
}
}
public class ChipSignals
{
private bool[] _CiaSerialInput = new bool[2];
private bool[] _CiaIRQOutput = new bool[2];
private bool _KeyboardNMIOutput;
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]; } }
public bool CpuNMI { get { return _CiaIRQOutput[1] | _KeyboardNMIOutput; } }
public bool CpuRDY { get { return !_VicBAOutput; } }
public bool KeyboardNMI { get { return _KeyboardNMIOutput; } set { _KeyboardNMIOutput = value; } }
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; } }
public bool VicLP { get { return _VicLPInput; } }
}
}

View File

@ -9,6 +9,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class C64 : IEmulator
{
private uint cyclesPerFrame;
private string extension;
private byte[] inputFile;
public C64(GameInfo game, byte[] rom, string romextension)
{
inputFile = rom;
@ -17,6 +21,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
CoreOutputComm = new CoreOutputComm();
CoreInputComm = new CoreInputComm();
Init(Region.PAL);
cyclesPerFrame = (uint)chips.vic.CyclesPerFrame;
CoreOutputComm.UsesDriveLed = true;
}
@ -52,14 +57,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
// audio/video
public void EndAsyncSound() { } //TODO
public ISoundProvider SoundProvider { get { return sid; } }
public ISoundProvider SoundProvider { get { return chips.sid; } }
public bool StartAsyncSound() { return true; } //TODO
public ISyncSoundProvider SyncSoundProvider { get { return new SidSyncSoundProvider(sid); } }
public IVideoProvider VideoProvider { get { return vic; } }
public ISyncSoundProvider SyncSoundProvider { get { return chips.sid; } }
public IVideoProvider VideoProvider { get { return chips.vic; } }
// controller
public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition; } }
public IController Controller { get { return input.controller; } set { input.controller = value; } }
public IController Controller { get { return null; } set { } }
public static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition
{
Name = "Commodore 64 Controller", //TODO
@ -84,59 +89,23 @@ namespace BizHawk.Emulation.Computers.Commodore64
// process frame
public void FrameAdvance(bool render, bool rendersound)
{
int cyclesPerFrame = vic.CyclesPerFrame;
// bizhawk interface setup
_frame++;
mem.inputWasRead = false;
// apply any media if needed
foreach (IMedia media in mediaAttached)
{
if (!media.Loaded() && media.Ready())
{
media.Apply();
}
}
// refresh the input values
PollInput();
// perform the cycle
for (int i = 0; i < cyclesPerFrame; i++)
{
if (!haltCPU)
{
cpu.IRQ = signal.CpuIRQ;
cpu.NMI = signal.CpuNMI;
cpu.ExecuteOne();
}
vic.PerformCycle();
cia0.PerformCycle();
signal.CiaIRQ0 = cia0.IRQ;
cia1.PerformCycle();
signal.CiaIRQ1 = cia1.IRQ;
sid.PerformCycle();
if (diskDriveAttached)
diskDrive.PerformCycle();
if (signal.CpuAEC)
haltCPU = false;
}
_islag = !mem.inputWasRead;
chips.pla.InputWasRead = false;
Execute(cyclesPerFrame);
_islag = !chips.pla.InputWasRead;
if (_islag)
{
LagCount++;
}
_frame++;
CoreOutputComm.DriveLED = DriveLED;
}
private void HandleFirmwareError(string file)
{
System.Windows.Forms.MessageBox.Show("the C64 core is referencing a firmware file which could not be found. Please make sure it's in your configured C64 firmwares folder. The referenced filename is: " + file);
throw new FileNotFoundException();
}
public byte[] SaveStateBinary()
{
MemoryStream ms = new MemoryStream();
@ -149,16 +118,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
private void SetupMemoryDomains()
{
var domains = new List<MemoryDomain>(1);
domains.Add(new MemoryDomain("System Bus", 0x10000, Endian.Little, new Func<int, byte>(PeekMemoryInt), new Action<int, byte>(PokeMemoryInt)));
domains.Add(new MemoryDomain("RAM", 0x10000, Endian.Little, new Func<int, byte>(PeekRAM), new Action<int, byte>(PokeRAM)));
domains.Add(new MemoryDomain("CIA0", 0x10, Endian.Little, new Func<int, byte>(PeekCia0), new Action<int, byte>(PokeCia0)));
domains.Add(new MemoryDomain("CIA1", 0x10, Endian.Little, new Func<int, byte>(PeekCia1), new Action<int, byte>(PokeCia1)));
domains.Add(new MemoryDomain("SID", 0x20, Endian.Little, new Func<int, byte>(PeekSid), new Action<int, byte>(PokeSid)));
domains.Add(new MemoryDomain("VIC", 0x40, Endian.Little, new Func<int, byte>(PeekVic), new Action<int, byte>(PokeVic)));
domains.Add(new MemoryDomain("CRAM", 0x400, Endian.Little, new Func<int, byte>(PeekColorRAM), new Action<int, byte>(PokeColorRAM)));
domains.Add(new MemoryDomain("DISKRAM", 0x10000, Endian.Little, new Func<int, byte>(PeekDiskDrive), new Action<int, byte>(PokeDiskDrive)));
domains.Add(new MemoryDomain("DISKVIA0", 0x10, Endian.Little, new Func<int, byte>(PeekVia0), new Action<int, byte>(PokeVia0)));
domains.Add(new MemoryDomain("DISKVIA1", 0x10, Endian.Little, new Func<int, byte>(PeekVia1), new Action<int, byte>(PokeVia1)));
domains.Add(new MemoryDomain("System Bus", 0x10000, Endian.Little, new Func<int, byte>(Peek), new Action<int, byte>(Poke)));
memoryDomains = domains.AsReadOnly();
}
}

View File

@ -1,199 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class CartridgeChip
{
public int address;
public int bank;
public byte[] data;
public ushort romMask;
public int type;
}
public partial class Cartridge : IMedia
{
public Func<ushort, byte> Read;
public Func<ushort, byte> ReadPort;
public Action<ushort, byte> WritePort;
public List<CartridgeChip> chips;
public bool exRomPin;
public bool gamePin;
public CartridgeChip selectedChip;
public int type;
public bool valid;
public int version;
private bool loaded;
private Memory mem;
public Cartridge(byte[] rom, Memory memory)
{
mem = memory;
chips = new List<CartridgeChip>();
if (rom.Length >= 0x50)
{
MemoryStream source = new MemoryStream(rom);
BinaryReader reader = new BinaryReader(source);
string idString;
// note: cartridge files store values big-endian.
idString = new string(reader.ReadChars(16));
if (idString == "C64 CARTRIDGE ")
{
int headerLength = 0;
headerLength = reader.ReadByte();
headerLength <<= 8;
headerLength |= reader.ReadByte();
headerLength <<= 8;
headerLength |= reader.ReadByte();
headerLength <<= 8;
headerLength |= reader.ReadByte();
version = reader.ReadByte();
version <<= 8;
version |= reader.ReadByte();
type = reader.ReadByte();
type <<= 8;
type |= reader.ReadByte();
if (type != 0x0000)
{
// the emulator does not support anything other than type 0 right now
valid = false;
return;
}
exRomPin = (reader.ReadByte() == 1);
gamePin = (reader.ReadByte() == 1);
reader.ReadBytes(6); // reserved
reader.ReadBytes(32); // name
// skip the rest, don't need this info
if (headerLength > 0x40)
{
reader.ReadBytes(headerLength - 0x40);
}
while (source.Position < rom.Length)
{
string chipID = new string(reader.ReadChars(4));
if (chipID == "CHIP")
{
CartridgeChip chip = new CartridgeChip();
int packetLength;
packetLength = reader.ReadByte();
packetLength <<= 8;
packetLength |= reader.ReadByte();
packetLength <<= 8;
packetLength |= reader.ReadByte();
packetLength <<= 8;
packetLength |= reader.ReadByte();
packetLength -= 16;
chip.type = reader.ReadByte();
chip.type <<= 8;
chip.type |= reader.ReadByte();
chip.bank = reader.ReadByte();
chip.bank <<= 8;
chip.bank |= reader.ReadByte();
chip.address = reader.ReadByte();
chip.address <<= 8;
chip.address |= reader.ReadByte();
int size;
size = reader.ReadByte();
size <<= 8;
size |= reader.ReadByte();
chip.data = reader.ReadBytes(size);
chip.romMask = (ushort)(size - 1);
packetLength -= size;
if (packetLength > 0)
{
// discard extra bytes
reader.ReadBytes(packetLength);
}
chips.Add(chip);
}
else
{
break;
}
}
valid = (chips.Count > 0);
if (valid)
UpdateMapper();
}
reader.Close();
source.Dispose();
}
}
public void Apply()
{
mem.cart = this;
UpdateRomPins();
loaded = true;
}
public bool Loaded()
{
return loaded;
}
private byte ReadDummy(ushort addr)
{
return 0;
}
public bool Ready()
{
return true;
}
private void UpdateMapper()
{
Read = ReadDummy;
ReadPort = ReadDummy;
WritePort = WriteDummy;
switch (type)
{
case 0x0000:
Read = Read0000;
ReadPort = ReadPort0000;
WritePort = WritePort0000;
break;
}
}
private void UpdateRomPins()
{
mem.exRomPin = exRomPin;
mem.gamePin = gamePin;
mem.UpdateLayout();
}
private void WriteDummy(ushort addr, byte val)
{
}
}
}

View File

@ -1,419 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class Cartridge : IMedia
{
public int bank;
private byte Read0000(ushort addr)
{
// standard cart, no banking
CartridgeChip currentChip = chips[0];
return currentChip.data[addr & currentChip.romMask];
}
private byte Read0001(ushort addr)
{
return 0;
}
private byte Read0002(ushort addr)
{
return 0;
}
private byte Read0003(ushort addr)
{
return 0;
}
private byte Read0004(ushort addr)
{
return 0;
}
private byte Read0005(ushort addr)
{
return 0;
}
private byte Read0006(ushort addr)
{
return 0;
}
private byte Read0007(ushort addr)
{
return 0;
}
private byte Read0008(ushort addr)
{
return 0;
}
private byte Read0009(ushort addr)
{
return 0;
}
private byte Read000A(ushort addr)
{
return 0;
}
private byte Read000B(ushort addr)
{
return 0;
}
private byte Read000C(ushort addr)
{
return 0;
}
private byte Read000D(ushort addr)
{
return 0;
}
private byte Read000E(ushort addr)
{
return 0;
}
private byte Read000F(ushort addr)
{
return 0;
}
private byte Read0010(ushort addr)
{
return 0;
}
private byte Read0011(ushort addr)
{
return 0;
}
private byte Read0012(ushort addr)
{
return 0;
}
private byte Read0013(ushort addr)
{
return 0;
}
private byte Read0014(ushort addr)
{
return 0;
}
private byte Read0015(ushort addr)
{
return 0;
}
private byte Read0016(ushort addr)
{
return 0;
}
private byte Read0017(ushort addr)
{
return 0;
}
private byte Read0018(ushort addr)
{
return 0;
}
private byte Read0019(ushort addr)
{
return 0;
}
private byte Read001A(ushort addr)
{
return 0;
}
private byte Read001B(ushort addr)
{
return 0;
}
private byte ReadPort0000(ushort addr)
{
return 0;
}
private byte ReadPort0001(ushort addr)
{
return 0;
}
private byte ReadPort0002(ushort addr)
{
return 0;
}
private byte ReadPort0003(ushort addr)
{
return 0;
}
private byte ReadPort0004(ushort addr)
{
return 0;
}
private byte ReadPort0005(ushort addr)
{
return 0;
}
private byte ReadPort0006(ushort addr)
{
return 0;
}
private byte ReadPort0007(ushort addr)
{
return 0;
}
private byte ReadPort0008(ushort addr)
{
return 0;
}
private byte ReadPort0009(ushort addr)
{
return 0;
}
private byte ReadPort000A(ushort addr)
{
return 0;
}
private byte ReadPort000B(ushort addr)
{
return 0;
}
private byte ReadPort000C(ushort addr)
{
return 0;
}
private byte ReadPort000D(ushort addr)
{
return 0;
}
private byte ReadPort000E(ushort addr)
{
return 0;
}
private byte ReadPort000F(ushort addr)
{
return 0;
}
private byte ReadPort0010(ushort addr)
{
return 0;
}
private byte ReadPort0011(ushort addr)
{
return 0;
}
private byte ReadPort0012(ushort addr)
{
return 0;
}
private byte ReadPort0013(ushort addr)
{
return 0;
}
private byte ReadPort0014(ushort addr)
{
return 0;
}
private byte ReadPort0015(ushort addr)
{
return 0;
}
private byte ReadPort0016(ushort addr)
{
return 0;
}
private byte ReadPort0017(ushort addr)
{
return 0;
}
private byte ReadPort0018(ushort addr)
{
return 0;
}
private byte ReadPort0019(ushort addr)
{
return 0;
}
private byte ReadPort001A(ushort addr)
{
return 0;
}
private byte ReadPort001B(ushort addr)
{
return 0;
}
private void WritePort0000(ushort addr, byte val)
{
}
private void WritePort0001(ushort addr, byte val)
{
}
private void WritePort0002(ushort addr, byte val)
{
}
private void WritePort0003(ushort addr, byte val)
{
}
private void WritePort0004(ushort addr, byte val)
{
}
private void WritePort0005(ushort addr, byte val)
{
}
private void WritePort0006(ushort addr, byte val)
{
}
private void WritePort0007(ushort addr, byte val)
{
}
private void WritePort0008(ushort addr, byte val)
{
}
private void WritePort0009(ushort addr, byte val)
{
}
private void WritePort000A(ushort addr, byte val)
{
}
private void WritePort000B(ushort addr, byte val)
{
}
private void WritePort000C(ushort addr, byte val)
{
}
private void WritePort000D(ushort addr, byte val)
{
}
private void WritePort000E(ushort addr, byte val)
{
}
private void WritePort000F(ushort addr, byte val)
{
}
private void WritePort0010(ushort addr, byte val)
{
}
private void WritePort0011(ushort addr, byte val)
{
}
private void WritePort0012(ushort addr, byte val)
{
}
private void WritePort0013(ushort addr, byte val)
{
bank = (val & 0x7F) % chips.Count;
if ((bank & 0x80) != 0x00)
{
exRomPin = false;
gamePin = false;
}
else
{
exRomPin = true;
gamePin = false;
}
UpdateRomPins();
}
private void WritePort0014(ushort addr, byte val)
{
}
private void WritePort0015(ushort addr, byte val)
{
}
private void WritePort0016(ushort addr, byte val)
{
}
private void WritePort0017(ushort addr, byte val)
{
}
private void WritePort0018(ushort addr, byte val)
{
}
private void WritePort0019(ushort addr, byte val)
{
}
private void WritePort001A(ushort addr, byte val)
{
}
private void WritePort001B(ushort addr, byte val)
{
}
}
}

View File

@ -1,652 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class CiaRegs
{
public bool ALARM; // alarm enabled
public int ALARM10; // alarm 10ths of a second
public int ALARMHR; // alarm hours
public int ALARMMIN; // alarm minutes
public bool ALARMPM; // alarm AM/PM
public int ALARMSEC; // alarm seconds
public bool CNT; // external counter bit input
public bool EIALARM; // enable alarm interrupt (internal)
public bool EIFLG; // enable flag pin interrupt (internal)
public bool EISP; // enable shift register interrupt (internal)
public bool[] EIT = new bool[2]; // enable timer interrupt (internal)
public bool FLG; // external flag bit input
public bool IALARM; // alarm interrupt triggered
public bool IFLG; // interrupt triggered on FLAG pin
public int[] INMODE = new int[2]; // timer input mode
public bool IRQ; // interrupt triggered
public bool ISP; // shift register interrupt
public bool[] IT = new bool[2]; // timer interrupt
public bool[] LOAD = new bool[2]; // force load timer
public bool[] OUTMODE = new bool[2]; // timer output mode
public bool[] PBON = new bool[2]; // port bit modify on
public bool[] RUNMODE = new bool[2]; // running mode
public int SDR; // serial shift register
public int SDRCOUNT; // serial shift register bit count
public bool SPMODE; // shift register mode
public bool[] START = new bool[2]; // timer enabled
public int[] T = new int[2]; // timer counter
public bool[] TICK = new bool[2]; // execute timer tick
public int[] TLATCH = new int[2]; // timer latch (internal)
public int TOD10; // time of day 10ths of a second
public bool TODIN; // time of day/alarm set
public int TODHR; // time of day hour
public int TODMIN; // time of day minute
public bool TODPM; // time of day AM/PM
public bool TODREADLATCH; // read latch (internal)
public int TODREADLATCH10; // tod read latch (internal)
public int TODREADLATCHSEC; // tod read latch (internal)
public int TODREADLATCHMIN; // tod read latch (internal)
public int TODREADLATCHHR; // tod read latch (internal)
public int TODSEC; // time of day seconds
public DataPortBus[] ports;
public DataPortConnector[] connectors;
public CiaRegs()
{
ports = new DataPortBus[2];
ports[0] = new DataPortBus();
ports[1] = new DataPortBus();
connectors = new DataPortConnector[2];
connectors[0] = ports[0].Connect();
connectors[1] = ports[1].Connect();
HardReset();
}
public byte this[int addr]
{
get
{
// value of open bits
int result = 0x00;
addr &= 0x0F;
switch (addr)
{
case 0x00:
result = connectors[0].Data;
break;
case 0x01:
result = connectors[1].Data;
break;
case 0x02:
result = connectors[0].Direction;
break;
case 0x03:
result = connectors[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:
connectors[0].Data = val;
break;
case 0x01:
connectors[1].Data = val;
break;
case 0x02:
connectors[0].Direction = val;
break;
case 0x03:
connectors[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 void HardReset()
{
// power on state
for (int i = 0; i < 0x10; i++)
this[i] = 0x00;
TLATCH[0] = 0xFFFF;
TLATCH[1] = 0xFFFF;
T[0] = TLATCH[0];
T[1] = TLATCH[1];
this[0x0B] = 0x01;
connectors[0].Latch = 0xFF;
connectors[1].Latch = 0xFF;
connectors[0].Direction = 0xFF;
connectors[1].Direction = 0xFF;
}
}
public partial class Cia
{
public int intMask;
public bool lastCNT;
public byte[] outputBitMask = new byte[] { 0x40, 0x80 };
private CiaRegs regs = new CiaRegs();
public int todCounter;
public int todFrequency;
public bool[] underflow;
public Func<bool> ReadSerial;
public Action<bool> WriteSerial;
public Cia(Region newRegion)
{
ReadSerial = ReadSerialDummy;
WriteSerial = WriteSerialDummy;
switch (newRegion)
{
case Region.NTSC:
todFrequency = 14318181 / 14 / 10;
break;
case Region.PAL:
todFrequency = 14318181 / 18 / 10;
break;
}
HardReset();
}
private void AdvanceTOD()
{
bool overflow;
int tenths = regs.TOD10;
int seconds = regs.TODSEC;
int minutes = regs.TODMIN;
int hours = regs.TODHR;
bool ampm = regs.TODPM;
todCounter = todFrequency;
tenths = BCDAdd(tenths, 1, out overflow);
if (tenths >= 10)
{
tenths = 0;
seconds = BCDAdd(seconds, 1, out overflow);
if (overflow)
{
seconds = 0;
minutes = BCDAdd(minutes, 1, out overflow);
if (overflow)
{
minutes = 0;
hours = BCDAdd(hours, 1, out overflow);
if (hours > 12)
{
hours = 1;
ampm = !ampm;
}
}
}
}
regs.TOD10 = tenths;
regs.TODSEC = seconds;
regs.TODMIN = minutes;
regs.TODHR = hours;
regs.TODPM = ampm;
}
public void AttachWriteHook(int index, Action act)
{
regs.ports[index].AttachWriteHook(act);
}
private int BCDAdd(int i, int j, out bool overflow)
{
int lo;
int hi;
int result;
lo = (i & 0x0F) + (j & 0x0F);
hi = (i & 0x70) + (j & 0x70);
if (lo > 0x09)
{
hi += 0x10;
lo += 0x06;
}
if (hi > 0x50)
{
hi += 0xA0;
}
overflow = hi >= 0x60;
result = (hi & 0x70) + (lo & 0x0F);
return result;
}
public DataPortConnector ConnectPort(int index)
{
return regs.ports[index].Connect();
}
public DataPortConnector ConnectSerialPort(int index)
{
DataPortConnector result = regs.ports[index].Connect();
regs.ports[index].AttachInputConverter(result, new DataPortSerialInputConverter());
regs.ports[index].AttachOutputConverter(result, new DataPortSerialOutputConverter());
return result;
}
public void HardReset()
{
regs.HardReset();
underflow = new bool[2];
todCounter = todFrequency;
}
public bool IRQ
{
get
{
return regs.IRQ;
}
}
public byte Peek(int addr)
{
addr &= 0xF;
return regs[addr];
}
public void PerformCycle()
{
// process time of day counter
todCounter--;
if (todCounter <= 0)
AdvanceTOD();
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
regs[0x01] &= (byte)~outputBitMask[i];
}
if (underflow[i])
{
if (regs.OUTMODE[i])
{
// toggle bit
regs[0x01] ^= outputBitMask[i];
}
else
{
// set for a cycle
regs[0x01] |= outputBitMask[i];
}
}
}
}
}
lastCNT = regs.CNT;
regs.CNT = false;
UpdateInterrupt();
}
public void Poke(int addr, byte val)
{
addr &= 0xF;
regs[addr] = val;
}
public byte Read(ushort addr)
{
byte result;
addr &= 0xF;
switch (addr)
{
case 0x08:
regs.TODREADLATCH = false;
return (byte)regs.TODREADLATCH10;
case 0x09:
if (!regs.TODREADLATCH)
return regs[addr];
else
return (byte)regs.TODREADLATCHSEC;
case 0x0A:
if (!regs.TODREADLATCH)
return regs[addr];
else
return (byte)regs.TODREADLATCHMIN;
case 0x0B:
regs.TODREADLATCH = true;
regs.TODREADLATCH10 = regs.TOD10;
regs.TODREADLATCHSEC = regs.TODSEC;
regs.TODREADLATCHMIN = regs.TODMIN;
regs.TODREADLATCHHR = regs.TODHR;
return (byte)regs.TODREADLATCHHR;
case 0x0D:
// reading this reg clears it
result = regs[0x0D];
regs[0x0D] = 0x00;
UpdateInterrupt();
return result;
default:
return regs[addr];
}
}
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.IT[index] |= underflow[index];
regs.T[index] = timer & 0xFFFF;
}
public void TimerTick(int index)
{
switch (regs.INMODE[index])
{
case 0:
regs.TICK[index] = true;
break;
case 1:
regs.TICK[index] |= (regs.CNT && !lastCNT);
break;
case 2:
regs.TICK[index] |= underflow[0];
break;
case 3:
regs.TICK[index] |= (regs.CNT && !lastCNT) || underflow[0];
break;
}
if (regs.TICK[index])
{
TimerDec(index);
regs.TICK[index] = false;
}
}
public void UpdateInterrupt()
{
bool irq = false;
irq |= (regs.EIT[0] & regs.IT[0]);
irq |= (regs.EIT[1] & regs.IT[1]);
irq |= (regs.EIFLG & regs.IFLG);
irq |= (regs.EISP & regs.ISP);
irq |= (regs.EIALARM & regs.IALARM);
regs.IRQ = irq;
}
public void Write(ushort addr, byte val)
{
addr &= 0xF;
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;
else
regs[addr] = val;
break;
case 0x09:
if (regs.ALARM)
regs.ALARMSEC = val & 0x7F;
else
regs[addr] = val;
break;
case 0x0A:
if (regs.ALARM)
regs.ALARMMIN = val & 0x7F;
else
regs[addr] = val;
break;
case 0x0B:
if (regs.ALARM)
{
regs.ALARMHR = val & 0x1F;
regs.ALARMPM = ((val & 0x80) != 0x00);
}
else
{
regs[addr] = val;
}
break;
case 0x0D:
intMask &= ~val;
if ((val & 0x80) != 0x00)
intMask ^= val;
regs.EIT[0] = ((intMask & 0x01) != 0x00);
regs.EIT[1] = ((intMask & 0x02) != 0x00);
regs.EIALARM = ((intMask & 0x04) != 0x00);
regs.EISP = ((intMask & 0x08) != 0x00);
regs.EIFLG = ((intMask & 0x10) != 0x00);
UpdateInterrupt();
break;
default:
regs[addr] = val;
break;
}
}
public void WriteCNT(bool val)
{
if (!lastCNT && val)
{
if (!regs.SPMODE)
{
// read bit into shift register
bool inputBit = ReadSerial();
regs.SDR = ((regs.SDR << 1) | (inputBit ? 0x01 : 0x00)) & 0xFF;
regs.SDRCOUNT = (regs.SDRCOUNT - 1) & 0x7;
if (regs.SDRCOUNT == 0)
{
regs.ISP = true;
}
}
else
{
// write bit out from shift register
bool outputBit = ((regs.SDR & 0x01) != 0);
regs.SDR >>= 1;
WriteSerial(outputBit);
regs.SDRCOUNT = (regs.SDRCOUNT - 1) & 0x7;
if (regs.SDRCOUNT == 0)
{
regs.ISP = true;
}
}
}
regs.CNT = val;
}
public void WriteFLG(bool val)
{
regs.FLG = val;
regs.IFLG |= val;
}
private void WriteSerialDummy(bool val)
{
// do nothing
}
}
}

View File

@ -1,89 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class Cia
{
public void SyncState(Serializer ser)
{
ser.Sync("ALARM", ref regs.ALARM);
ser.Sync("ALARM10", ref regs.ALARM10);
ser.Sync("ALARMHR", ref regs.ALARMHR);
ser.Sync("ALARMMIN", ref regs.ALARMMIN);
ser.Sync("ALARMPM", ref regs.ALARMPM);
ser.Sync("ALARMSEC", ref regs.ALARMSEC);
ser.Sync("CNT", ref regs.CNT);
ser.Sync("EIALARM", ref regs.EIALARM);
ser.Sync("EIFLG", ref regs.EIFLG);
ser.Sync("EISP", ref regs.EISP);
ser.Sync("EIT0", ref regs.EIT[0]);
ser.Sync("EIT1", ref regs.EIT[1]);
ser.Sync("FLG", ref regs.FLG);
ser.Sync("IALARM", ref regs.IALARM);
ser.Sync("IFLG", ref regs.IFLG);
ser.Sync("INMODE0", ref regs.INMODE[0]);
ser.Sync("INMODE1", ref regs.INMODE[1]);
ser.Sync("IRQ", ref regs.IRQ);
ser.Sync("ISP", ref regs.ISP);
ser.Sync("IT0", ref regs.IT[0]);
ser.Sync("IT1", ref regs.IT[1]);
ser.Sync("LOAD0", ref regs.LOAD[0]);
ser.Sync("LOAD1", ref regs.LOAD[1]);
ser.Sync("OUTMODE0", ref regs.OUTMODE[0]);
ser.Sync("OUTMODE1", ref regs.OUTMODE[1]);
ser.Sync("PBON0", ref regs.PBON[0]);
ser.Sync("PBON1", ref regs.PBON[1]);
ser.Sync("RUNMODE0", ref regs.RUNMODE[0]);
ser.Sync("RUNMODE1", ref regs.RUNMODE[1]);
ser.Sync("SDR", ref regs.SDR);
ser.Sync("SDRCOUNT", ref regs.SDRCOUNT);
ser.Sync("SPMODE", ref regs.SPMODE);
ser.Sync("START0", ref regs.START[0]);
ser.Sync("START1", ref regs.START[1]);
ser.Sync("T0", ref regs.T[0]);
ser.Sync("T1", ref regs.T[1]);
ser.Sync("TICK0", ref regs.TICK[0]);
ser.Sync("TICK1", ref regs.TICK[1]);
ser.Sync("TLATCH0", ref regs.TLATCH[0]);
ser.Sync("TLATCH1", ref regs.TLATCH[1]);
ser.Sync("TOD10", ref regs.TOD10);
ser.Sync("TODHR", ref regs.TODHR);
ser.Sync("TODMIN", ref regs.TODMIN);
ser.Sync("TODPM", ref regs.TODPM);
ser.Sync("TODREADLATCH", ref regs.TODREADLATCH);
ser.Sync("TODREADLATCH10", ref regs.TODREADLATCH10);
ser.Sync("TODREADLATCHSEC", ref regs.TODREADLATCHSEC);
ser.Sync("TODREADLATCHMIN", ref regs.TODREADLATCHMIN);
ser.Sync("TODREADLATCHHR", ref regs.TODREADLATCHHR);
ser.Sync("TODSEC", ref regs.TODSEC);
// ports
byte dir0 = regs.connectors[0].Direction;
byte dir1 = regs.connectors[1].Direction;
byte latch0 = regs.connectors[0].Latch;
byte latch1 = regs.connectors[0].Latch;
ser.Sync("DIR0", ref dir0);
ser.Sync("DIR1", ref dir1);
ser.Sync("PORT0", ref latch0);
ser.Sync("PORT1", ref latch1);
if (ser.IsReader)
{
regs.connectors[0].Direction = dir0;
regs.connectors[0].Latch = latch0;
regs.connectors[1].Direction = dir1;
regs.connectors[1].Latch = latch1;
}
// state
ser.Sync("INTMASK", ref intMask);
ser.Sync("LASTCNT", ref lastCNT);
ser.Sync("TODCOUNTER", ref todCounter);
ser.Sync("TODFREQUENCY", ref todFrequency);
ser.Sync("UNDERFLOW0", ref underflow[0]);
ser.Sync("UNDERFLOW1", ref underflow[1]);
}
}
}

View File

@ -1,371 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class DataPortBus
{
protected bool[] connected = new bool[2];
protected DataPortConnector[] connectors;
protected byte[] direction = new byte[2];
protected DataPortConverter[] inputConverters;
protected byte[] latch = new byte[2];
protected DataPortConverter[] outputConverters;
protected List<int> servingHooks = new List<int>();
protected List<Action> writeHooks = new List<Action>();
public DataPortBus()
{
inputConverters = new DataPortConverter[2];
inputConverters[0] = new DataPortConverter();
inputConverters[1] = new DataPortConverter();
outputConverters = new DataPortConverter[2];
outputConverters[0] = new DataPortConverter();
outputConverters[1] = new DataPortConverter();
connectors = new DataPortConnector[2];
connectors[0] = new DataPortConnector(ReadData0, ReadDirection0, ReadLatch0, ReadRemoteLatch0, WriteData0, WriteDirection0, WriteLatch0);
connectors[1] = new DataPortConnector(ReadData1, ReadDirection1, ReadLatch1, ReadRemoteLatch1, WriteData1, WriteDirection1, WriteLatch1);
connected[0] = false;
connected[1] = false;
direction[0] = 0x00;
direction[1] = 0x00;
latch[0] = 0x00;
latch[1] = 0x00;
}
public void AttachInputConverter(DataPortConnector connector, DataPortConverter converter)
{
if (connector.Equals(connectors[0]))
{
inputConverters[0] = converter;
}
else if (connector.Equals(connectors[1]))
{
inputConverters[1] = converter;
}
}
public void AttachOutputConverter(DataPortConnector connector, DataPortConverter converter)
{
if (connector.Equals(connectors[0]))
{
outputConverters[0] = converter;
}
else if (connector.Equals(connectors[1]))
{
outputConverters[1] = converter;
}
}
public void AttachWriteHook(Action act)
{
writeHooks.Add(act);
servingHooks.Add(0);
}
protected void ClearHooks()
{
int count = servingHooks.Count;
for (int i = 0; i < count; i++)
servingHooks[i]--;
}
public DataPortConnector Connect()
{
if (!connected[0])
{
connected[0] = true;
direction[0] = 0xFF;
return connectors[0];
}
else if (!connected[1])
{
connected[1] = true;
direction[1] = 0xFF;
return connectors[1];
}
throw new Exception("Two connections to this bus have already been established..");
}
public void Connect(DataPortConnector connection)
{
if (!connected[0])
{
connected[0] = true;
connectors[0] = connection;
}
else if (!connected[1])
{
connected[1] = true;
connectors[1] = connection;
}
throw new Exception("Two connections to this bus have already been established..");
}
public void Disconnect(DataPortConnector connector)
{
if (connector.Equals(connectors[0]))
{
connected[0] = false;
latch[0] = 0;
direction[0] = 0;
}
else if (connector.Equals(connectors[1]))
{
connected[1] = false;
latch[1] = 0;
direction[1] = 0;
}
}
protected void ExecuteWriteHooks()
{
int count = servingHooks.Count;
for (int i = 0; i < count; i++)
{
if (servingHooks[i] == 0)
{
servingHooks[i]++;
writeHooks[i]();
}
else
{
servingHooks[i]++;
}
}
ClearHooks();
}
protected virtual byte ReadData0()
{
byte result;
if (connected[1])
result = (byte)((~direction[0] & latch[1]) | (direction[0] & latch[0]));
else
result = latch[0];
return inputConverters[0].Convert(result, latch[1]);
}
protected virtual byte ReadData1()
{
byte result;
if (connected[0])
result = (byte)((~direction[1] & latch[0]) | (direction[1] & latch[1]));
else
result = latch[1];
return inputConverters[1].Convert(result, latch[0]);
}
protected virtual byte ReadDirection0()
{
return direction[0];
}
protected virtual byte ReadDirection1()
{
return direction[1];
}
protected virtual byte ReadLatch0()
{
return latch[0];
}
protected virtual byte ReadLatch1()
{
return latch[1];
}
protected virtual byte ReadRemoteLatch0()
{
return latch[1];
}
protected virtual byte ReadRemoteLatch1()
{
return latch[0];
}
protected virtual void WriteData0(byte val)
{
byte result = latch[0];
result &= (byte)~direction[0];
result |= (byte)(val & direction[0]);
latch[0] = outputConverters[0].Convert(result, latch[1]);
ExecuteWriteHooks();
}
protected virtual void WriteData1(byte val)
{
byte result = latch[1];
result &= (byte)~direction[1];
result |= (byte)(val & direction[1]);
latch[1] = outputConverters[1].Convert(result, latch[0]);
ExecuteWriteHooks();
}
protected virtual void WriteDirection0(byte val)
{
direction[0] = val;
ExecuteWriteHooks();
}
protected virtual void WriteDirection1(byte val)
{
direction[1] = val;
ExecuteWriteHooks();
}
protected virtual void WriteLatch0(byte val)
{
latch[0] = val;
}
protected virtual void WriteLatch1(byte val)
{
latch[1] = val;
}
}
public class DataPortConnector
{
private Func<byte> ReadData;
private Func<byte> ReadDirection;
private Func<byte> ReadLatch;
private Func<byte> ReadRemoteLatch;
private Action<byte> WriteData;
private Action<byte> WriteDirection;
private Action<byte> WriteLatch;
public DataPortConnector()
{
ReadData = ReadDataDummy;
ReadDirection = ReadDataDummy;
ReadLatch = ReadDataDummy;
ReadRemoteLatch = ReadDataDummy;
WriteData = WriteDataDummy;
WriteDirection = WriteDataDummy;
WriteLatch = WriteDataDummy;
}
public DataPortConnector(DataPortConnector source)
{
ReadData = source.ReadData;
ReadDirection = source.ReadDirection;
ReadLatch = source.ReadLatch;
ReadRemoteLatch = source.ReadRemoteLatch;
WriteData = source.WriteData;
WriteDirection = source.WriteDirection;
WriteLatch = source.WriteLatch;
}
public DataPortConnector(Func<byte> newReadData, Func<byte> newReadDirection, Func<byte> newReadLatch, Func<byte> newReadRemoteLatch, Action<byte> newWriteData, Action<byte> newWriteDirection, Action<byte> newWriteLatch)
{
ReadData = newReadData;
ReadDirection = newReadDirection;
ReadLatch = newReadLatch;
ReadRemoteLatch = newReadRemoteLatch;
WriteData = newWriteData;
WriteDirection = newWriteDirection;
WriteLatch = newWriteLatch;
}
public byte Data
{
get
{
return ReadData();
}
set
{
WriteData(value);
}
}
public byte Direction
{
get
{
return ReadDirection();
}
set
{
WriteDirection(value);
}
}
public byte Latch
{
get
{
return ReadLatch();
}
set
{
WriteLatch(value);
}
}
public DataPortListener Listener()
{
return new DataPortListener(ReadData, ReadDirection);
}
private byte ReadDataDummy()
{
return 0x00;
}
public byte RemoteLatch
{
get
{
return ReadRemoteLatch();
}
}
private void WriteDataDummy(byte val)
{
return;
}
}
public class DataPortConverter
{
public virtual byte Convert(byte input, byte remote)
{
// the base converter transfers the values directly
return input;
}
}
public class DataPortListener
{
private Func<byte> ReadData;
private Func<byte> ReadDirection;
public DataPortListener(Func<byte> newReadData, Func<byte> newReadDirection)
{
ReadData = newReadData;
ReadDirection = newReadDirection;
}
public byte Data
{
get
{
return ReadData();
}
}
public byte Direction
{
get
{
return ReadDirection();
}
}
}
}

View File

@ -1,118 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class Input
{
static string[,] keyboardMatrix = new string[,]
{
{"Key Insert/Delete", "Key Return", "Key Cursor Left/Right", "Key F7", "Key F1", "Key F3", "Key F5", "Key Cursor Up/Down"},
{"Key 3", "Key W", "Key A", "Key 4", "Key Z", "Key S", "Key E", "Key Left Shift"},
{"Key 5", "Key R", "Key D", "Key 6", "Key C", "Key F", "Key T", "Key X"},
{"Key 7", "Key Y", "Key G", "Key 8", "Key B", "Key H", "Key U", "Key V"},
{"Key 9", "Key I", "Key J", "Key 0", "Key M", "Key K", "Key O", "Key N"},
{"Key Plus", "Key P", "Key L", "Key Minus", "Key Period", "Key Colon", "Key At", "Key Comma"},
{"Key Pound", "Key Asterisk", "Key Semicolon", "Key Clear/Home", "Key Right Shift", "Key Equal", "Key Up Arrow", "Key Slash"},
{"Key 1", "Key Left Arrow", "Key Control", "Key 2", "Key Space", "Key Commodore", "Key Q", "Key Run/Stop"}
};
static string[,] joystickMatrix = new string[,]
{
{"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button"},
{"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button"}
};
public IController controller;
public bool restorePressed;
private byte[] joystickLatch = new byte[2];
private byte keyboardColumnData = 0xFF;
private byte[] keyboardLatch = new byte[8];
private byte keyboardRowData = 0xFF;
private DataPortConnector[] ports;
public Input(DataPortConnector[] newPorts)
{
ports = newPorts;
// set full output
ports[0].Direction = 0xFF;
ports[1].Direction = 0xFF;
}
private byte GetJoystickBits(int index)
{
byte result = 0xE0;
result |= controller[joystickMatrix[index, 0]] ? (byte)0x00 : (byte)0x01;
result |= controller[joystickMatrix[index, 1]] ? (byte)0x00 : (byte)0x02;
result |= controller[joystickMatrix[index, 2]] ? (byte)0x00 : (byte)0x04;
result |= controller[joystickMatrix[index, 3]] ? (byte)0x00 : (byte)0x08;
result |= controller[joystickMatrix[index, 4]] ? (byte)0x00 : (byte)0x10;
return result;
}
private byte GetKeyboardBits(int row)
{
byte result;
result = controller[keyboardMatrix[row, 0]] ? (byte)0x00 : (byte)0x01;
result |= controller[keyboardMatrix[row, 1]] ? (byte)0x00 : (byte)0x02;
result |= controller[keyboardMatrix[row, 2]] ? (byte)0x00 : (byte)0x04;
result |= controller[keyboardMatrix[row, 3]] ? (byte)0x00 : (byte)0x08;
result |= controller[keyboardMatrix[row, 4]] ? (byte)0x00 : (byte)0x10;
result |= controller[keyboardMatrix[row, 5]] ? (byte)0x00 : (byte)0x20;
result |= controller[keyboardMatrix[row, 6]] ? (byte)0x00 : (byte)0x40;
result |= controller[keyboardMatrix[row, 7]] ? (byte)0x00 : (byte)0x80;
return result;
}
public void Poll()
{
restorePressed = controller["Key Restore"];
for (int i = 0; i < 2; i++)
joystickLatch[i] = GetJoystickBits(i);
for (int i = 0; i < 8; i++)
keyboardLatch[i] = GetKeyboardBits(i);
UpdatePortData();
}
private void UpdatePortData()
{
int keyboardShift = keyboardColumnData;
byte port0result = 0xFF;
byte port1result = 0xFF;
port0result = (byte)(joystickLatch[1]);
for (int i = 0; i < 8; i++)
{
if ((keyboardShift & 0x01) == 0x00)
{
port1result &= keyboardLatch[i];
}
keyboardShift >>= 1;
}
port1result &= joystickLatch[0];
ports[0].Data = port0result;
ports[1].Data = port1result;
}
public void WritePortA()
{
// keyboard matrix column select
keyboardColumnData = ports[0].RemoteLatch;
UpdatePortData();
}
public void WritePortB()
{
// keyboard matrix row select
keyboardRowData = ports[1].RemoteLatch;
UpdatePortData();
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// used as Color RAM in C64
public class Chip2114 : IStandardIO
{
private byte[] ram;
public Chip2114()
{
HardReset();
}
public void HardReset()
{
ram = new byte[0x400];
}
public byte Peek(int addr)
{
return ram[addr & 0x3FF];
}
public byte Peek(int addr, byte bus)
{
return (byte)(ram[addr & 0x3FF] | (bus & 0xF0));
}
public void Poke(int addr, byte val)
{
ram[addr & 0x3FF] = (byte)(val & 0xF);
}
public byte Read(ushort addr)
{
return (byte)(ram[addr & 0x3FF]);
}
public byte Read(ushort addr, byte bus)
{
return (byte)(ram[addr & 0x3FF] | (bus & 0xF0));
}
public void Write(ushort addr, byte val)
{
ram[addr & 0x3FF] = (byte)(val & 0xF);
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// ROM chips
// 2332: 32 kbit (4kbyte)
// 2364: 64 kbit (8kbyte)
// 23128: 128 kbit (16kbyte)
public enum Chip23XXmodel
{
Chip2332,
Chip2364,
Chip23128
}
public class Chip23XX : IStandardIO
{
private uint addrMask;
private byte[] rom;
public Chip23XX(Chip23XXmodel model, byte[] data)
{
switch (model)
{
case Chip23XXmodel.Chip2332:
rom = new byte[0x1000];
addrMask = 0xFFF;
break;
case Chip23XXmodel.Chip2364:
rom = new byte[0x2000];
addrMask = 0x1FFF;
break;
case Chip23XXmodel.Chip23128:
rom = new byte[0x4000];
addrMask = 0x3FFF;
break;
default:
throw new Exception("Invalid chip model.");
}
Array.Copy(data, rom, rom.Length);
}
public byte Peek(int addr)
{
return rom[addr & (int)addrMask];
}
public void Poke(int addr, byte val)
{
// do nothing (this is rom)
}
public byte Read(ushort addr)
{
return rom[addr & addrMask];
}
public void Write(ushort addr, byte val)
{
// do nothing (this is rom)
}
}
}

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// DRAM for the c64
// 4164 = 64 kbit
// 4464 = 256 kbit
// 4864 = 512 kbit
// for purposes of simplification we'll just
// use one 4864, the C64 can use sets of 4164 or
// 4464 typically
public class Chip4864 : IStandardIO
{
private byte[] ram;
public Chip4864()
{
HardReset();
}
public void HardReset()
{
ram = new byte[0x10000];
}
public byte Peek(int addr)
{
return ram[addr & 0xFFFF];
}
public void Poke(int addr, byte val)
{
ram[addr & 0xFFFF] = val;
}
public byte Read(ushort addr)
{
return ram[addr];
}
public void Write(ushort addr, byte val)
{
ram[addr] = val;
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public interface IStandardIO
{
byte Peek(int addr);
void Poke(int addr, byte val);
byte Read(ushort addr);
void Write(ushort addr, byte val);
}
}

View File

@ -0,0 +1,202 @@
using BizHawk.Emulation.CPUs.M6502;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// an extension of the 6502 processor
public class MOS6510 : IStandardIO
{
// ------------------------------------
private C64Chips chips;
private MOS6502X cpu;
private bool freezeCpu;
private bool pinAEC;
private bool pinCassetteButton;
private bool pinCassetteMotor;
private bool pinCassetteOutput;
private bool pinCharen;
private bool pinIRQ;
private bool pinLoram;
private bool pinHiram;
private bool pinNMI;
private bool pinRDY;
private byte portDir;
// ------------------------------------
public MOS6510(C64Chips newChips)
{
chips = newChips;
cpu = new MOS6502X();
// configure cpu r/w
cpu.DummyReadMemory = Read;
cpu.ReadMemory = Read;
cpu.WriteMemory = Write;
// configure data port defaults
portDir = 0x2F;
SetPortData(0x37);
}
public void HardReset()
{
cpu.Reset();
cpu.FlagI = true;
cpu.BCD_Enabled = true;
cpu.PC = (ushort)(chips.pla.Read(0xFFFC) | (chips.pla.Read(0xFFFD) << 8));
}
// ------------------------------------
public void ExecutePhase1()
{
UpdatePins();
}
public void ExecutePhase2()
{
UpdatePins();
if (pinAEC && !freezeCpu)
{
// the 6502 core expects active high
// so we reverse the polarity here
cpu.NMI = !pinNMI;
cpu.IRQ = !pinIRQ;
cpu.ExecuteOne();
}
}
private void UpdatePins()
{
pinAEC = chips.vic.AEC;
pinIRQ = chips.vic.IRQ && chips.cia0.IRQ;
pinNMI = chips.cia1.IRQ;
pinRDY = chips.vic.BA;
if (pinRDY)
freezeCpu = false;
}
// ------------------------------------
public byte Peek(int addr)
{
if (addr == 0x0000)
return PortDirection;
else if (addr == 0x0001)
return PortData;
else
return chips.pla.Peek(addr);
}
public void Poke(int addr, byte val)
{
if (addr == 0x0000)
portDir = val;
else if (addr == 0x0001)
SetPortData(val);
else
chips.pla.Poke(addr, val);
}
public byte Read(ushort addr)
{
// cpu freezes after first read when RDY is low
if (!pinRDY)
freezeCpu = true;
if (addr == 0x0000)
return PortDirection;
else if (addr == 0x0001)
return PortData;
else
return chips.pla.Read(addr);
}
public void Write(ushort addr, byte val)
{
if (addr == 0x0000)
PortDirection = val;
else if (addr == 0x0001)
PortData = val;
else
chips.pla.Write(addr, val);
}
// ------------------------------------
public bool AEC
{
get { return pinAEC; }
}
public bool IRQ
{
get { return pinIRQ; }
}
public bool NMI
{
get { return pinNMI; }
}
public bool RDY
{
get { return pinRDY; }
}
public byte PortData
{
get
{
byte result = 0x00;
result |= pinLoram ? (byte)0x01 : (byte)0x00;
result |= pinHiram ? (byte)0x02 : (byte)0x00;
result |= pinCharen ? (byte)0x04 : (byte)0x00;
result |= pinCassetteOutput ? (byte)0x08 : (byte)0x00;
result |= pinCassetteButton ? (byte)0x10 : (byte)0x00;
result |= pinCassetteMotor ? (byte)0x20 : (byte)0x00;
return result;
}
set
{
byte val = Port.CPUWrite(PortData, value, portDir);
SetPortData(val);
}
}
public byte PortDirection
{
get { return portDir; }
set { portDir = value; }
}
private void SetPortData(byte val)
{
pinCassetteOutput = ((val & 0x08) != 0);
pinCassetteButton = ((val & 0x10) != 0);
pinCassetteMotor = ((val & 0x20) != 0);
if (!chips.pla.UltimaxMode)
{
pinLoram = ((val & 0x01) != 0);
pinHiram = ((val & 0x02) != 0);
pinCharen = ((val & 0x04) != 0);
chips.pla.LoRam = pinLoram;
chips.pla.HiRam = pinHiram;
chips.pla.Charen = pinCharen;
}
}
// ------------------------------------
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// via
public class MOS6522 : Timer, IStandardIO
{
// ------------------------------------
public void ExecutePhase1()
{
}
public void ExecutePhase2()
{
}
// ------------------------------------
public byte Peek(int addr)
{
return 0;
}
public void Poke(int addr, byte val)
{
}
public byte Read(ushort addr)
{
return 0;
}
public void Write(ushort addr, byte val)
{
}
// ------------------------------------
}
}

View File

@ -0,0 +1,342 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// MOS technology 6526 "CIA"
//
// emulation notes:
// * CS, R/W and RS# pins are not emulated. (not needed)
// * A low RES pin is emulated via HardReset().
public class MOS6526 : Timer, IStandardIO
{
// ------------------------------------
private enum InMode
{
Phase2,
CNT,
TimerAUnderflow,
TimerAUnderflowCNT
}
private enum OutMode
{
Pulse,
Toggle
}
private enum RunMode
{
Continuous,
Oneshot
}
private enum SPMode
{
Input,
Output
}
// ------------------------------------
private bool intAlarm;
private bool intFlag;
private bool intSP;
private bool[] intTimer;
private bool pinCnt;
private bool pinFlag;
private bool pinPC;
private InMode[] timerInMode;
private OutMode[] timerOutMode;
private bool[] timerPortEnable;
private byte[] tod;
private byte[] todAlarm;
private bool todAlarmPM;
private bool todPM;
private uint todCounter;
private uint todCounterLatch;
// ------------------------------------
public MOS6526(Region region)
{
intTimer = new bool[2];
timerInMode = new InMode[2];
timerOutMode = new OutMode[2];
timerPortEnable = new bool[2];
tod = new byte[4];
todAlarm = new byte[4];
switch (region)
{
case Region.NTSC:
todCounterLatch = 14318181 / 140;
break;
case Region.PAL:
todCounterLatch = 17734472 / 180;
break;
}
HardReset();
}
// ------------------------------------
public void ExecutePhase1()
{
// unsure if the timer actually operates in ph1
}
public void ExecutePhase2()
{
pinPC = true;
TimerRun(0);
TimerRun(1);
}
public void HardReset()
{
HardResetInternal();
intTimer[0] = false;
intTimer[1] = false;
timerPortEnable[0] = false;
timerPortEnable[1] = false;
timerInMode[0] = InMode.Phase2;
timerInMode[1] = InMode.Phase2;
timerOn[0] = false;
timerOn[1] = false;
timerOutMode[0] = OutMode.Pulse;
timerOutMode[1] = OutMode.Pulse;
tod[0] = 0;
tod[1] = 0;
tod[2] = 0;
tod[3] = 0x12;
todAlarm[0] = 0;
todAlarm[1] = 0;
todAlarm[2] = 0;
todAlarm[3] = 0;
todCounter = todCounterLatch;
pinCnt = false;
pinFlag = true;
pinPC = true;
}
// ------------------------------------
private byte BCDAdd(byte i, byte j, out bool overflow)
{
uint lo;
uint hi;
uint result;
lo = (i & (uint)0x0F) + (j & (uint)0x0F);
hi = (i & (uint)0x70) + (j & (uint)0x70);
if (lo > 0x09)
{
hi += 0x10;
lo += 0x06;
}
if (hi > 0x50)
{
hi += 0xA0;
}
overflow = hi >= 0x60;
result = (hi & 0x70) + (lo & 0x0F);
return (byte)(result & 0xFF);
}
private void TimerRun(uint index)
{
}
private void TODRun()
{
bool todV;
if (todCounter == 0)
{
todCounter = todCounterLatch;
tod[0] = BCDAdd(tod[0], 1, out todV);
if (tod[0] >= 10)
{
tod[0] = 0;
tod[1] = BCDAdd(tod[1], 1, out todV);
if (todV)
{
tod[1] = 0;
tod[2] = BCDAdd(tod[2], 1, out todV);
if (todV)
{
tod[2] = 0;
tod[3] = BCDAdd(tod[3], 1, out todV);
if (tod[3] > 12)
{
tod[3] = 1;
}
else if (tod[3] == 12)
{
todPM = !todPM;
}
}
}
}
}
}
// ------------------------------------
public bool CNT
{
get { return pinCnt; }
set { pinCnt = value; }
}
public bool FLAG
{
get { return pinFlag; }
set
{
if (pinFlag && !value)
intFlag = true;
pinFlag = value;
}
}
public bool PC
{
get { return pinPC; }
}
public byte Peek(int addr)
{
return ReadRegister((ushort)(addr & 0xF));
}
public void Poke(int addr, byte val)
{
WriteRegister((ushort)(addr & 0xF), val);
}
public byte Read(ushort addr)
{
addr &= 0xF;
byte val;
switch (addr)
{
case 0x01:
val = ReadRegister(addr);
pinPC = false;
break;
default:
val = ReadRegister(addr);
break;
}
return val;
}
private byte ReadRegister(ushort addr)
{
byte val = 0x00; //unused pin value
switch (addr)
{
case 0x0:
break;
case 0x1:
break;
case 0x2:
break;
case 0x3:
break;
case 0x4:
break;
case 0x5:
break;
case 0x6:
break;
case 0x7:
break;
case 0x8:
break;
case 0x9:
break;
case 0xA:
break;
case 0xB:
break;
case 0xC:
break;
case 0xD:
break;
case 0xE:
break;
case 0xF:
break;
}
return val;
}
public void Write(ushort addr, byte val)
{
addr &= 0xF;
switch (addr)
{
case 0x1:
WriteRegister(addr, val);
pinPC = false;
break;
default:
WriteRegister(addr, val);
break;
}
}
public void WriteRegister(ushort addr, byte val)
{
switch (addr)
{
case 0x0:
break;
case 0x1:
break;
case 0x2:
break;
case 0x3:
break;
case 0x4:
break;
case 0x5:
break;
case 0x6:
break;
case 0x7:
break;
case 0x8:
break;
case 0x9:
break;
case 0xA:
break;
case 0xB:
break;
case 0xC:
break;
case 0xD:
break;
case 0xE:
break;
case 0xF:
break;
}
}
// ------------------------------------
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// vic ntsc
public class MOS6567 : Vic, IStandardIO
{
static uint[][] pipeline = new uint[5][];
public MOS6567(C64Chips newChips)
: base(newChips, 65, 263, pipeline, 14318181 / 14)
{
}
}
}

View File

@ -0,0 +1,332 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// vic pal
public class MOS6569 : Vic, IStandardIO
{
static uint[][] pipeline = new uint[][]
{
new uint[] // xposition
{
0x0194, 0x0198,
0x019C, 0x01A0,
0x01A4, 0x01A8,
0x01AC, 0x01B0,
0x01B4, 0x01B8,
0x01BC, 0x01C0,
0x01C4, 0x01C8,
0x01CC, 0x01D0,
0x01D4, 0x01D8,
0x01DC, 0x01E0,
0x01E4, 0x01E8,
0x01EC, 0x01F0,
0x01F4, 0x0000,
0x0004, 0x0008,
0x000C, 0x0010,
0x0014, 0x0018,
0x001C, 0x0020,
0x0024, 0x0028,
0x002C, 0x0030,
0x0034, 0x0038,
0x003C, 0x0040,
0x0044, 0x0048,
0x004C, 0x0050,
0x0054, 0x0058,
0x005C, 0x0060,
0x0064, 0x0068,
0x006C, 0x0070,
0x0074, 0x0078,
0x007C, 0x0080,
0x0084, 0x0088,
0x008C, 0x0090,
0x0094, 0x0098,
0x009C, 0x00A0,
0x00A4, 0x00A8,
0x00AC, 0x00B0,
0x00B4, 0x00B8,
0x00BC, 0x00C0,
0x00C4, 0x00C8,
0x00CC, 0x00D0,
0x00D4, 0x00D8,
0x00DC, 0x00E0,
0x00E4, 0x00E8,
0x00EC, 0x00F0,
0x00F4, 0x00F8,
0x00FC, 0x0100,
0x0104, 0x0108,
0x010C, 0x0110,
0x0114, 0x0118,
0x011C, 0x0120,
0x0124, 0x0128,
0x012C, 0x0130,
0x0134, 0x0138,
0x013C, 0x0140,
0x0144, 0x0148,
0x014C, 0x0150,
0x0154, 0x0158,
0x015C, 0x0160,
0x0164, 0x0168,
0x016C, 0x0170,
0x0174, 0x0178,
0x017C, 0x0180,
0x0184, 0x0188,
0x018C, 0x0190
},
new uint[] // fetch (100=ref 200=c 300=g 400=i 500=none)
{
0x0003, 0x0013,
0x0023, 0x0033,
0x0004, 0x0014,
0x0024, 0x0034,
0x0005, 0x0015,
0x0025, 0x0035,
0x0006, 0x0016,
0x0026, 0x0036,
0x0007, 0x0017,
0x0027, 0x0037,
0x0100, 0x0500,
0x0100, 0x0500,
0x0100, 0x0500,
0x0100, 0x0500,
0x0100, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0200,
0x0300, 0x0500,
0x0400, 0x0500,
0x0400, 0x0500,
0x0000, 0x0010,
0x0020, 0x0030,
0x0001, 0x0011,
0x0021, 0x0031,
0x0002, 0x0012,
0x0022, 0x0032
},
new uint[] // BA
{
0x0834, 0x0834,
0x0345, 0x0345,
0x0845, 0x0845,
0x0456, 0x0456,
0x0856, 0x0856,
0x0567, 0x0567,
0x0867, 0x0867,
0x0887, 0x0887,
0x0887, 0x0887,
0x0000, 0x0000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x1000, 0x1000,
0x0880, 0x0880,
0x0880, 0x0880,
0x0801, 0x0801,
0x0012, 0x0012,
0x0812, 0x0812,
0x0123, 0x0123,
0x0823, 0x0823,
0x0234, 0x0234
},
new uint[] // actions
{
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, pipelineUpdateVc,
0, pipelineChkSprChunch,
0, pipelineUpdateMcBase,
0, pipelineChkBrdL1,
0, pipelineChkBrdL0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
pipelineChkSprDma, 0,
pipelineChkSprDma, pipelineChkBrdR0 | pipelineChkSprExp,
0, pipelineChkBrdR1,
pipelineChkSprDisp, pipelineUpdateRc,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0
}
};
public MOS6569(C64Chips newChips)
: base(newChips, 63, 312, pipeline, 17734472 / 18)
{
}
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// sid
public class MOS6581 : Sid, IStandardIO
{
}
}

View File

@ -0,0 +1,557 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// emulates the PLA
// which handles all bank switching
public class MOSPLA : IStandardIO
{
// ------------------------------------
private enum PLABank
{
None,
RAM,
BasicROM,
KernalROM,
CharROM,
IO,
CartridgeLo,
CartridgeHi,
Vic,
Sid,
ColorRam,
Cia0,
Cia1,
Expansion0,
Expansion1
}
private struct PLACpuMap
{
public PLABank layout1000;
public PLABank layout8000;
public PLABank layoutA000;
public PLABank layoutC000;
public PLABank layoutD000;
public PLABank layoutE000;
}
// ------------------------------------
private byte bus;
private C64Chips chips;
private bool cia0portRead;
private PLACpuMap map;
private bool pinCharen;
private bool pinExRom;
private bool pinGame;
private bool pinHiRam;
private bool pinLoRam;
private bool ultimax;
private Func<byte> vicBankPortRead;
public MOSPLA(C64Chips newChips, Func<byte>newVicBankPortRead)
{
chips = newChips;
vicBankPortRead = newVicBankPortRead;
}
public void HardReset()
{
pinCharen = true;
pinExRom = true;
pinGame = true;
pinHiRam = true;
pinLoRam = true;
UpdateMap();
}
// ------------------------------------
public bool Charen
{
get { return pinCharen; }
set { pinCharen = value; UpdateMap(); }
}
public bool ExRom
{
get { return pinExRom; }
set { pinExRom = value; UpdateMap(); }
}
public bool Game
{
get { return pinGame; }
set { pinGame = value; UpdateMap(); }
}
public bool HiRam
{
get { return pinHiRam; }
set { pinHiRam = value; UpdateMap(); }
}
public bool InputWasRead
{
get { return cia0portRead; }
set { cia0portRead = value; }
}
public bool LoRam
{
get { return pinLoRam; }
set { pinLoRam = value; UpdateMap(); }
}
public bool UltimaxMode
{
get { return ultimax; }
}
private void UpdateMap()
{
if (ultimax)
return;
if (pinCharen && pinHiRam && pinLoRam && pinGame && pinExRom)
{
// 11111
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.BasicROM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.KernalROM;
}
else if (!pinCharen && pinHiRam && pinLoRam && pinGame && pinExRom)
{
// 01111
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.BasicROM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.CharROM;
map.layoutE000 = PLABank.KernalROM;
}
else if (pinCharen && !pinHiRam && pinLoRam && pinGame)
{
// 1011X
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.RAM;
}
else if (pinCharen && !pinHiRam && pinLoRam && !pinGame && !pinExRom)
{
// 10100
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.RAM;
}
else if (!pinCharen && !pinHiRam && pinLoRam && pinGame)
{
// 0011X
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.CharROM;
map.layoutE000 = PLABank.RAM;
}
else if (!pinCharen && !pinHiRam && pinLoRam && !pinGame && !pinExRom)
{
// 00100
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.RAM;
map.layoutE000 = PLABank.RAM;
}
else if (!pinHiRam && !pinLoRam && pinGame)
{
// X001X
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.RAM;
map.layoutE000 = PLABank.RAM;
}
else if (pinCharen && pinHiRam && !pinLoRam && pinGame)
{
// 1101X
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.KernalROM;
}
else if (pinCharen && !pinHiRam && !pinLoRam && !pinExRom)
{
// 100X0
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.KernalROM;
}
else if (!pinCharen && pinHiRam && !pinLoRam && pinGame)
{
// 0101X
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.CharROM;
map.layoutE000 = PLABank.KernalROM;
}
else if (!pinCharen && !pinHiRam && !pinLoRam && !pinExRom)
{
// 000X0
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.RAM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.CharROM;
map.layoutE000 = PLABank.KernalROM;
}
else if (pinCharen && pinHiRam && pinLoRam && pinGame && !pinExRom)
{
// 11110
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.CartridgeLo;
map.layoutA000 = PLABank.BasicROM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.KernalROM;
}
else if (!pinCharen && pinHiRam && pinLoRam && pinGame && !pinExRom)
{
// 01110
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.CartridgeLo;
map.layoutA000 = PLABank.BasicROM;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.CharROM;
map.layoutE000 = PLABank.KernalROM;
}
else if (pinCharen && pinHiRam && !pinLoRam && !pinGame && !pinExRom)
{
// 11000
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.CartridgeHi;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.KernalROM;
}
else if (!pinCharen && pinHiRam && !pinLoRam && !pinGame && !pinExRom)
{
// 01000
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.RAM;
map.layoutA000 = PLABank.CartridgeHi;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.CharROM;
map.layoutE000 = PLABank.KernalROM;
}
else if (pinCharen && pinHiRam && pinLoRam && !pinGame && !pinExRom)
{
// 11100
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.CartridgeLo;
map.layoutA000 = PLABank.CartridgeHi;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.KernalROM;
}
else if (!pinCharen && pinHiRam && pinLoRam && !pinGame && !pinExRom)
{
// 01100
map.layout1000 = PLABank.RAM;
map.layout8000 = PLABank.CartridgeLo;
map.layoutA000 = PLABank.CartridgeHi;
map.layoutC000 = PLABank.RAM;
map.layoutD000 = PLABank.CharROM;
map.layoutE000 = PLABank.KernalROM;
}
else if (!pinGame && pinExRom)
{
// XXX01 (ultimax)
// once in this mode, it is not supposed to change
map.layout1000 = PLABank.None;
map.layout8000 = PLABank.CartridgeLo;
map.layoutA000 = PLABank.None;
map.layoutC000 = PLABank.None;
map.layoutD000 = PLABank.IO;
map.layoutE000 = PLABank.CartridgeHi;
ultimax = true;
}
else
{
throw new Exception("Memory configuration missing from PLA, fix this!");
}
}
// ------------------------------------
private PLABank Bank(ushort addr)
{
if (addr < 0x1000)
return PLABank.RAM;
else if (addr >= 0x1000 && addr < 0x8000)
return map.layout1000;
else if (addr >= 0x8000 && addr < 0xA000)
return map.layout8000;
else if (addr >= 0xA000 && addr < 0xC000)
return map.layoutA000;
else if (addr >= 0xC000 && addr < 0xD000)
return map.layoutC000;
else if (addr >= 0xD000 && addr < 0xE000)
{
if (map.layoutD000 == PLABank.IO)
{
if (addr >= 0xD000 && addr < 0xD400)
return PLABank.Vic;
else if (addr >= 0xD400 && addr < 0xD800)
return PLABank.Sid;
else if (addr >= 0xD800 && addr < 0xDC00)
return PLABank.ColorRam;
else if (addr >= 0xDC00 && addr < 0xDD00)
return PLABank.Cia0;
else if (addr >= 0xDD00 && addr < 0xDE00)
return PLABank.Cia1;
else if (addr >= 0xDE00 && addr < 0xDF00)
return PLABank.Expansion0;
else
return PLABank.Expansion1;
}
else
{
return map.layoutD000;
}
}
else
{
return map.layoutE000;
}
}
public byte Peek(int addr)
{
switch (Bank((ushort)(addr & 0xFFFF)))
{
case PLABank.BasicROM:
return chips.basicRom.Peek(addr);
case PLABank.CartridgeHi:
return 0;
case PLABank.CartridgeLo:
return 0;
case PLABank.CharROM:
return chips.charRom.Peek(addr);
case PLABank.Cia0:
return chips.cia0.Peek(addr);
case PLABank.Cia1:
return chips.cia1.Peek(addr);
case PLABank.ColorRam:
return chips.colorRam.Peek(addr, bus);
case PLABank.Expansion0:
return 0;
case PLABank.Expansion1:
return 0;
case PLABank.KernalROM:
return chips.kernalRom.Peek(addr);
case PLABank.None:
return 0xFF;
case PLABank.RAM:
return chips.ram.Peek(addr);
case PLABank.Sid:
return chips.sid.Peek(addr);
case PLABank.Vic:
return chips.vic.Peek(addr);
}
return 0xFF;
}
public void Poke(int addr, byte val)
{
switch (Bank((ushort)(addr & 0xFFFF)))
{
case PLABank.BasicROM:
chips.basicRom.Poke(addr, val);
break;
case PLABank.CartridgeHi:
break;
case PLABank.CartridgeLo:
break;
case PLABank.CharROM:
chips.charRom.Poke(addr, val);
break;
case PLABank.Cia0:
chips.cia0.Poke(addr, val);
break;
case PLABank.Cia1:
chips.cia1.Poke(addr, val);
break;
case PLABank.ColorRam:
chips.colorRam.Poke(addr, val);
break;
case PLABank.Expansion0:
break;
case PLABank.Expansion1:
break;
case PLABank.KernalROM:
chips.kernalRom.Poke(addr, val);
break;
case PLABank.None:
break;
case PLABank.RAM:
chips.ram.Poke(addr, val);
break;
case PLABank.Sid:
chips.sid.Poke(addr, val);
break;
case PLABank.Vic:
chips.vic.Poke(addr, val);
break;
}
}
public byte Read(ushort addr)
{
switch (Bank(addr))
{
case PLABank.BasicROM:
bus = chips.basicRom.Read(addr);
break;
case PLABank.CartridgeHi:
bus = 0;
break;
case PLABank.CartridgeLo:
bus = 0;
break;
case PLABank.CharROM:
bus = chips.charRom.Read(addr);
break;
case PLABank.Cia0:
if (addr == 0xDC00 || addr == 0xDC01)
cia0portRead = true;
bus = chips.cia0.Read(addr);
break;
case PLABank.Cia1:
bus = chips.cia1.Read(addr);
break;
case PLABank.ColorRam:
bus = chips.colorRam.Read(addr, bus);
break;
case PLABank.Expansion0:
bus = 0;
break;
case PLABank.Expansion1:
bus = 0;
break;
case PLABank.KernalROM:
bus = chips.kernalRom.Read(addr);
break;
case PLABank.None:
bus = 0xFF;
break;
case PLABank.RAM:
bus = chips.ram.Read(addr);
break;
case PLABank.Sid:
bus = chips.sid.Read(addr);
break;
case PLABank.Vic:
bus = chips.vic.Read(addr);
break;
}
return bus;
}
public byte ReadVic(ushort addr)
{
addr &= 0x3FFF;
if (ultimax)
{
if (addr >= 0x3000)
return 0; //todo: change to ROMHI
else
return chips.ram.Read(addr);
}
else
{
if ((addr & 0x7000) == 0x1000)
{
return chips.charRom.Read(addr);
}
else
{
ushort bank = (ushort)(vicBankPortRead() & 0x3);
bank <<= 14;
addr |= bank;
return chips.ram.Read(addr);
}
}
}
public void Write(ushort addr, byte val)
{
switch (Bank(addr))
{
case PLABank.BasicROM:
chips.basicRom.Write(addr, val);
break;
case PLABank.CartridgeHi:
break;
case PLABank.CartridgeLo:
break;
case PLABank.CharROM:
chips.charRom.Write(addr, val);
break;
case PLABank.Cia0:
chips.cia0.Write(addr, val);
break;
case PLABank.Cia1:
chips.cia1.Write(addr, val);
break;
case PLABank.ColorRam:
chips.colorRam.Write(addr, val);
break;
case PLABank.Expansion0:
break;
case PLABank.Expansion1:
break;
case PLABank.KernalROM:
chips.kernalRom.Write(addr, val);
break;
case PLABank.None:
break;
case PLABank.RAM:
chips.ram.Write(addr, val);
break;
case PLABank.Sid:
chips.sid.Write(addr, val);
break;
case PLABank.Vic:
chips.vic.Write(addr, val);
break;
}
}
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
static public class Port
{
static public byte CPUWrite(byte latch, byte val, byte dir)
{
byte result;
result = (byte)(latch & ~dir);
result |= (byte)(val & dir);
return result;
}
static public byte ExternalWrite(byte latch, byte val, byte dir)
{
byte result;
result = (byte)(latch & dir);
result |= (byte)(val & ~dir);
return result;
}
static public PortAdapter GetAdapter(Func<byte> newRead, Action<byte> newWrite)
{
return new PortAdapter(newRead, newWrite);
}
}
public class PortAdapter
{
private Action<byte> actWrite;
private Func<byte> funcRead;
public PortAdapter(Func<byte> newRead, Action<byte> newWrite)
{
funcRead = newRead;
actWrite = newWrite;
}
public byte Data
{
get
{
return funcRead();
}
set
{
actWrite(value);
}
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public abstract partial class Sid : ISoundProvider
{
public void GetSamples(short[] samples)
{
// produce no samples for now
}
public int MaxVolume
{
get
{
return 255;
}
set
{
// no change in volume
}
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public abstract partial class Sid : ISyncSoundProvider
{
public void GetSamples(out short[] samples, out int nsamp)
{
samples = new short[0];
nsamp = 0;
}
public void DiscardSamples()
{
// todo
}
}
}

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public abstract partial class Sid : IStandardIO
{
// ------------------------------------
private class Envelope
{
}
private class Voice
{
}
// ------------------------------------
public void HardReset()
{
}
// ------------------------------------
public void ExecutePhase1()
{
}
public void ExecutePhase2()
{
}
// ------------------------------------
public byte Peek(int addr)
{
return 0;
}
public void Poke(int addr, byte val)
{
}
public byte Read(ushort addr)
{
return 0;
}
public void Write(ushort addr, byte val)
{
}
}
}

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
// base class for MOS Technology timer chips
public abstract class Timer
{
protected bool pinIRQ;
protected byte[] portData;
protected byte[] portDir;
protected uint[] timer;
protected uint[] timerLatch;
protected bool[] timerOn;
public Timer()
{
portData = new byte[2];
portDir = new byte[2];
timer = new uint[2];
timerLatch = new uint[2];
timerOn = new bool[2];
}
public PortAdapter Adapter0()
{
return Port.GetAdapter(ReadPort0, ExternalWritePort0);
}
public PortAdapter Adapter1()
{
return Port.GetAdapter(ReadPort1, ExternalWritePort1);
}
private void ExternalWritePort(uint index, byte data)
{
portData[index] = Port.ExternalWrite(portData[index], data, portDir[index]);
}
private void ExternalWritePort0(byte data)
{
ExternalWritePort(0, data);
}
private void ExternalWritePort1(byte data)
{
ExternalWritePort(1, data);
}
protected void HardResetInternal()
{
timer[0] = 0xFFFF;
timer[1] = 0xFFFF;
timerLatch[0] = timer[0];
timerLatch[1] = timer[1];
pinIRQ = true;
portDir[0] = 0x00;
portDir[1] = 0x00;
}
public bool IRQ
{
get
{
return pinIRQ;
}
}
public byte ReadPort0()
{
return portData[0];
}
public byte ReadPort1()
{
return portData[1];
}
protected void SyncInternal(Serializer ser)
{
}
private void WritePort(uint index, byte data)
{
portData[index] = Port.CPUWrite(portData[index], data, portDir[index]);
}
public void WritePort0(byte data)
{
WritePort(0, data);
}
public void WritePort1(byte data)
{
WritePort(1, data);
}
}
}

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public abstract partial class Vic : IVideoProvider
{
private int[] buf;
private int bufHeight;
private uint bufLength;
private uint bufOffset;
private int bufWidth;
// palette
private int[] palette =
{
Colors.ARGB(0x00, 0x00, 0x00),
Colors.ARGB(0xFF, 0xFF, 0xFF),
Colors.ARGB(0x68, 0x37, 0x2B),
Colors.ARGB(0x70, 0xA4, 0xB2),
Colors.ARGB(0x6F, 0x3D, 0x86),
Colors.ARGB(0x58, 0x8D, 0x43),
Colors.ARGB(0x35, 0x28, 0x79),
Colors.ARGB(0xB8, 0xC7, 0x6F),
Colors.ARGB(0x6F, 0x4F, 0x25),
Colors.ARGB(0x43, 0x39, 0x00),
Colors.ARGB(0x9A, 0x67, 0x59),
Colors.ARGB(0x44, 0x44, 0x44),
Colors.ARGB(0x6C, 0x6C, 0x6C),
Colors.ARGB(0x9A, 0xD2, 0x84),
Colors.ARGB(0x6C, 0x5E, 0xB5),
Colors.ARGB(0x95, 0x95, 0x95)
};
public int BackgroundColor
{
get { return Colors.ARGB(0, 0, 0); }
}
public int BufferHeight
{
get { return bufHeight; }
}
public int BufferWidth
{
get { return bufWidth; }
}
public int[] GetVideoBuffer()
{
return buf;
}
public int VirtualWidth
{
get { return bufWidth; }
}
private void WritePixel(uint pixel)
{
if (borderOnMain || borderOnVertical)
buf[bufOffset] = palette[borderColor];
else
buf[bufOffset] = palette[pixel];
bufOffset++;
if (bufOffset == bufLength)
bufOffset = 0;
}
}
}

View File

@ -0,0 +1,975 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64.MOS
{
public abstract partial class Vic : IStandardIO
{
// ------------------------------------
private class Sprite
{
public bool collideData;
public bool collideSprite;
public uint color;
public bool enable;
public uint mc;
public uint mcbase;
public bool multicolor;
public uint pointer;
public bool priority;
public uint sr;
public uint x;
public bool xExpand;
public uint y;
public bool yExpand;
public void HardReset()
{
collideData = false;
collideSprite = false;
color = 0;
enable = false;
mc = 0;
mcbase = 0;
multicolor = false;
pointer = 0;
priority = false;
sr = 0;
x = 0;
xExpand = false;
y = 0;
yExpand = false;
}
}
private Sprite[] sprites;
private uint backgroundColor0;
private uint backgroundColor1;
private uint backgroundColor2;
private uint backgroundColor3;
private uint baCount;
private bool badline;
private bool badlineEnable;
private bool bitmapMode;
private bool borderCheckLEnable;
private bool borderCheckREnable;
private uint borderColor;
private bool borderOnMain;
private bool borderOnVertical;
private uint[] bufferC;
private uint[] bufferG;
private byte bus;
private bool columnSelect;
private uint cycle;
private uint cycleIndex;
private uint dataC;
private uint dataG;
private bool displayEnable;
private bool enableIntLightPen;
private bool enableIntRaster;
private bool enableIntSpriteCollision;
private bool enableIntSpriteDataCollision;
private bool extraColorMode;
private bool idle;
private bool intLightPen;
private bool intRaster;
private bool intSpriteCollision;
private bool intSpriteDataCollision;
private uint lastRasterLine;
private uint lightPenX;
private uint lightPenY;
private bool multicolorMode;
private uint pointerCB;
private uint pointerVM;
private uint rasterInterruptLine;
private uint rasterLine;
private uint rasterX;
private uint rc;
private uint refreshCounter;
private bool rowSelect;
private uint spriteMulticolor0;
private uint spriteMulticolor1;
private uint sr;
private uint srCount;
private uint vc;
private uint vcbase;
private uint vmli;
private uint xScroll;
private uint yScroll;
// ------------------------------------
private C64Chips chips;
private int cyclesPerSec;
private bool pinAEC;
private bool pinBA;
private bool pinIRQ;
private uint[][] pipeline;
private uint totalCycles;
private uint totalLines;
// ------------------------------------
public Vic(C64Chips newChips, uint newCycles, uint newLines, uint[][] newPipeline, int newCyclesPerSec)
{
chips = newChips;
totalCycles = newCycles;
totalLines = newLines;
pipeline = newPipeline;
cyclesPerSec = newCyclesPerSec;
bufWidth = (int)(totalCycles * 8);
bufHeight = (int)(totalLines);
buf = new int[bufWidth * bufHeight];
bufLength = (uint)buf.Length;
sprites = new Sprite[8];
for (uint i = 0; i < 8; i++)
sprites[i] = new Sprite();
bufferC = new uint[40];
bufferG = new uint[40];
}
public void HardReset()
{
pinAEC = true;
pinBA = true;
pinIRQ = false;
bufOffset = 0;
backgroundColor0 = 0;
backgroundColor1 = 0;
backgroundColor2 = 0;
backgroundColor3 = 0;
baCount = 4;
badline = false;
badlineEnable = false;
bitmapMode = false;
borderCheckLEnable = false;
borderCheckREnable = false;
borderColor = 0;
borderOnMain = true;
borderOnVertical = true;
columnSelect = false;
displayEnable = false;
enableIntLightPen = false;
enableIntRaster = false;
enableIntSpriteCollision = false;
enableIntSpriteDataCollision = false;
extraColorMode = false;
idle = true;
intLightPen = false;
intRaster = false;
intSpriteCollision = false;
intSpriteDataCollision = false;
lastRasterLine = 0;
lightPenX = 0;
lightPenY = 0;
multicolorMode = false;
pointerCB = 0;
pointerVM = 0;
rasterInterruptLine = 0;
rasterLine = 0;
rasterX = 0;
rc = 7;
refreshCounter = 0xFF;
rowSelect = false;
spriteMulticolor0 = 0;
spriteMulticolor1 = 0;
sr = 0;
srCount = 0;
vc = 0;
vcbase = 0;
vmli = 0;
xScroll = 0;
yScroll = 0;
for (uint i = 0; i < 8; i++)
sprites[i].HardReset();
for (uint i = 0; i < 40; i++)
{
bufferC[i] = 0;
bufferG[i] = 0;
}
}
private void UpdateBA()
{
if (pinBA)
baCount = 4;
else if (baCount > 0)
baCount--;
}
private void UpdatePins()
{
pinIRQ = !(
(enableIntRaster & intRaster) |
(enableIntSpriteDataCollision & intSpriteDataCollision) |
(enableIntSpriteCollision & intSpriteCollision) |
(enableIntLightPen & intLightPen));
}
// ------------------------------------
protected const uint pipelineUpdateVc = 1;
protected const uint pipelineChkSprChunch = 2;
protected const uint pipelineUpdateMcBase = 4;
protected const uint pipelineChkBrdL1 = 8;
protected const uint pipelineChkBrdL0 = 16;
protected const uint pipelineChkSprDma = 32;
protected const uint pipelineChkBrdR0 = 64;
protected const uint pipelineChkSprExp = 128;
protected const uint pipelineChkBrdR1 = 256;
protected const uint pipelineChkSprDisp = 512;
protected const uint pipelineUpdateRc = 1024;
// ------------------------------------
public void ExecutePhase1()
{
// always assert access over the bus in ph1
pinAEC = false;
// raster IRQ compare
if ((cycle == 0 && rasterLine > 0) || (cycle == 1 && rasterLine == 0))
{
if (rasterLine != lastRasterLine)
if (rasterLine == rasterInterruptLine)
intRaster = true;
lastRasterLine = rasterLine;
}
// display enable compare
if (rasterLine == 0x030)
badlineEnable |= displayEnable;
// badline compare
if (badlineEnable && rasterLine >= 0x030 && rasterLine < 0x0F7 && ((rasterLine & 0x7) == yScroll))
badline = true;
if (badline)
idle = false;
ParseCycle();
Render();
// must always come last
UpdatePins();
}
public void ExecutePhase2()
{
ParseCycle();
// advance cycle and optionally raster line
cycle++;
if (cycle == totalCycles)
{
vcbase = 0;
cycleIndex = 0;
cycle = 0;
rasterLine++;
if (rasterLine == totalLines)
rasterLine = 0;
}
// if the BA counter is nonzero, allow CPU bus access
UpdateBA();
if (baCount > 0)
pinAEC = true;
Render();
// must always come last
UpdatePins();
}
private void ParseCycle()
{
ushort addr = 0x3FFF;
uint cycleBAsprite0;
uint cycleBAsprite1;
uint cycleBAsprite2;
uint cycleFetchSpriteIndex;
uint fetch = pipeline[1][cycleIndex];
uint ba = pipeline[2][cycleIndex];
uint act = pipeline[3][cycleIndex];
// apply X location
rasterX = pipeline[0][cycleIndex];
// perform fetch
switch (fetch & 0xFF00)
{
case 0x0100:
// fetch R
refreshCounter = (refreshCounter - 1) & 0xFF;
addr = (ushort)(0x3F00 | refreshCounter);
bus = chips.pla.ReadVic(addr);
break;
case 0x0200:
// fetch C
if (!idle)
{
if (badline)
{
addr = (ushort)((pointerVM << 10) | vc);
bus = chips.pla.ReadVic(addr);
dataC = bus;
}
else
{
dataC = bufferC[vmli];
}
}
else
{
dataC = 0;
}
break;
case 0x0300:
// fetch G
if (idle)
addr = 0x3FFF;
else
{
if (bitmapMode)
addr = (ushort)(rc | (vc << 3) | ((pointerCB & 0x4) << 11));
else
addr = (ushort)(rc | (dataG << 3) | (pointerCB << 9));
}
if (extraColorMode)
addr &= 0x39FF;
bus = chips.pla.ReadVic(addr);
dataG = bus;
vmli++;
vc++;
break;
case 0x0400:
// fetch I
addr = (extraColorMode ? (ushort)0x39FF : (ushort)0x3FFF);
bus = chips.pla.ReadVic(addr);
dataG = bus;
dataC = 0;
break;
case 0x0500:
// no fetch
break;
default:
cycleFetchSpriteIndex = (fetch & 0x7);
switch (fetch & 0xF0)
{
case 0x00:
// fetch P
addr = (ushort)(0x1F8 | (pointerVM << 10) | cycleFetchSpriteIndex);
bus = chips.pla.ReadVic(addr);
sprites[cycleFetchSpriteIndex].pointer = bus;
break;
case 0x10:
case 0x20:
case 0x30:
// fetch S
addr = (ushort)(sprites[cycleFetchSpriteIndex].mc | sprites[cycleFetchSpriteIndex].pointer << 6);
bus = chips.pla.ReadVic(addr);
sprites[cycleFetchSpriteIndex].sr <<= 8;
sprites[cycleFetchSpriteIndex].sr |= bus;
break;
}
break;
}
// perform BA flag manipulation
switch (ba)
{
case 0x0000:
pinBA = true;
break;
case 0x1000:
pinBA = !badline;
break;
default:
cycleBAsprite0 = ba & 0x000F;
cycleBAsprite1 = ba & 0x00F0;
cycleBAsprite2 = ba & 0x0F00;
if ((cycleBAsprite0 < 8 && sprites[cycleBAsprite0].enable) ||
(cycleBAsprite1 < 8 && sprites[cycleBAsprite1].enable) ||
(cycleBAsprite2 < 8 && sprites[cycleBAsprite2].enable))
pinBA = false;
break;
}
// perform actions
borderCheckLEnable = false;
borderCheckREnable = false;
if (!columnSelect && (act & pipelineChkBrdL0) != 0)
borderCheckLEnable = true;
if (columnSelect && (act & pipelineChkBrdL1) != 0)
borderCheckLEnable = true;
if (!columnSelect && (act & pipelineChkBrdR0) != 0)
borderCheckREnable = true;
if (columnSelect && (act & pipelineChkBrdR1) != 0)
borderCheckREnable = true;
if ((act & pipelineChkSprChunch) != 0)
{
}
if ((act & pipelineChkSprDisp) != 0)
{
}
if ((act & pipelineChkSprDma) != 0)
{
}
if ((act & pipelineChkSprExp) != 0)
{
}
if ((act & pipelineUpdateMcBase) != 0)
{
}
if ((act & pipelineUpdateRc) != 0)
{
if (rc == 7)
{
idle = true;
vcbase = vc;
}
if (!idle)
rc++;
}
if ((act & pipelineUpdateVc) != 0)
{
vc = vcbase;
vmli = 0;
if (badline)
rc = 0;
}
cycleIndex++;
}
private void Render()
{
if (borderCheckLEnable)
{
}
if (borderCheckREnable)
{
}
WritePixel(0);
WritePixel(0);
WritePixel(0);
WritePixel(0);
}
// ------------------------------------
public bool AEC { get { return pinAEC; } }
public bool BA { get { return pinBA; } }
public bool IRQ { get { return pinIRQ; } }
// ------------------------------------
public int CyclesPerFrame
{
get
{
return (int)(totalCycles * totalLines);
}
}
public int CyclesPerSecond
{
get
{
return cyclesPerSec;
}
}
// ------------------------------------
public byte Peek(int addr)
{
return ReadRegister((ushort)(addr & 0x3F));
}
public void Poke(int addr, byte val)
{
WriteRegister((ushort)(addr & 0x3F), val);
}
public byte Read(ushort addr)
{
byte result;
addr &= 0x3F;
switch (addr)
{
case 0x1E:
case 0x1F:
// reading clears these
result = ReadRegister(addr);
WriteRegister(addr, 0);
break;
default:
result = ReadRegister((ushort)(addr & 0x3F));
break;
}
return result;
}
private byte ReadRegister(ushort 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)(
(byte)(yScroll & 0x7) |
(rowSelect ? (byte)0x08 : (byte)0x00) |
(displayEnable ? (byte)0x10 : (byte)0x00) |
(bitmapMode ? (byte)0x20 : (byte)0x00) |
(extraColorMode ? (byte)0x40 : (byte)0x00) |
(byte)((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 &= 0xBF;
result |= (byte)(
(byte)(xScroll & 0x7) |
(columnSelect ? (byte)0x08 : (byte)0x00) |
(multicolorMode ? (byte)0x10 : (byte)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 &= 0xFE;
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(ushort 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;
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(ushort 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) | ((uint)(val & 0x01) << 8);
sprites[1].x = (sprites[1].x & 0xFF) | ((uint)(val & 0x02) << 7);
sprites[2].x = (sprites[2].x & 0xFF) | ((uint)(val & 0x04) << 6);
sprites[3].x = (sprites[3].x & 0xFF) | ((uint)(val & 0x08) << 5);
sprites[4].x = (sprites[4].x & 0xFF) | ((uint)(val & 0x10) << 4);
sprites[5].x = (sprites[5].x & 0xFF) | ((uint)(val & 0x20) << 3);
sprites[6].x = (sprites[6].x & 0xFF) | ((uint)(val & 0x40) << 2);
sprites[7].x = (sprites[7].x & 0xFF) | ((uint)(val & 0x80) << 1);
break;
case 0x11:
yScroll = (val & (uint)0x07);
rowSelect = ((val & 0x08) != 0);
displayEnable = ((val & 0x10) != 0);
bitmapMode = ((val & 0x20) != 0);
extraColorMode = ((val & 0x40) != 0);
rasterInterruptLine &= 0xFF;
rasterInterruptLine |= (uint)(val & 0x80) << 1;
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 & (uint)0x07);
columnSelect = ((val & 0x08) != 0);
multicolorMode = ((val & 0x10) != 0);
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 = (uint)((val >> 4) & 0xF);
pointerCB = (uint)((val >> 1) & 0x7);
break;
case 0x19:
intRaster = ((val & 0x01) != 0);
intSpriteDataCollision = ((val & 0x02) != 0);
intSpriteCollision = ((val & 0x04) != 0);
intLightPen = ((val & 0x08) != 0);
break;
case 0x1A:
enableIntRaster = ((val & 0x01) != 0);
enableIntSpriteDataCollision = ((val & 0x02) != 0);
enableIntSpriteCollision = ((val & 0x04) != 0);
enableIntLightPen = ((val & 0x08) != 0);
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 = (uint)(val & 0xF);
break;
case 0x21:
backgroundColor0 = (uint)(val & 0xF);
break;
case 0x22:
backgroundColor1 = (uint)(val & 0xF);
break;
case 0x23:
backgroundColor2 = (uint)(val & 0xF);
break;
case 0x24:
backgroundColor3 = (uint)(val & 0xF);
break;
case 0x25:
spriteMulticolor0 = (uint)(val & 0xF);
break;
case 0x26:
spriteMulticolor1 = (uint)(val & 0xF);
break;
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
case 0x2E:
sprites[addr - 0x27].color = (uint)(val & 0xF);
break;
default:
break;
}
}
}
}

View File

@ -1,635 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public enum MemoryDesignation
{
Disabled,
RAM,
Basic,
Kernal,
IO,
Character,
ROMLo,
ROMHi,
Vic,
Sid,
ColorRam,
Cia0,
Cia1,
Expansion0,
Expansion1
}
public class MemoryLayout
{
public MemoryDesignation Mem1000 = MemoryDesignation.RAM;
public MemoryDesignation Mem8000 = MemoryDesignation.RAM;
public MemoryDesignation MemA000 = MemoryDesignation.RAM;
public MemoryDesignation MemC000 = MemoryDesignation.RAM;
public MemoryDesignation MemD000 = MemoryDesignation.RAM;
public MemoryDesignation MemE000 = MemoryDesignation.RAM;
}
public class Memory
{
// chips
public Cia cia0;
public Cia cia1;
public VicII vic;
public Sid sid;
// storage
public Cartridge cart;
// roms
public byte[] basicRom;
public byte[] charRom;
public bool exRomPin = true;
public bool gamePin = true;
public byte[] kernalRom;
public MemoryLayout layout;
// ram
public byte[] colorRam;
public byte[] ram;
public bool vicCharEnabled;
public ushort vicOffset;
// registers
public byte busData;
public bool inputWasRead;
public bool readTrigger = true;
public bool writeTrigger = true;
// ports
public DataPortConnector cpuIO;
public DataPortConnector cpuPort;
public DataPortBus cpuPortBus = new DataPortBus();
void HandleFirmwareError(string file)
{
System.Windows.Forms.MessageBox.Show("the C64 core is referencing a firmware file which could not be found. Please make sure it's in your configured C64 firmwares folder. The referenced filename is: " + file);
throw new FileNotFoundException();
}
public Memory(string sourceFolder, VicII newVic, Sid newSid, Cia newCia0, Cia newCia1)
{
string basicFile = "basic";
string charFile = "chargen";
string kernalFile = "kernal";
string basicPath = Path.Combine(sourceFolder, basicFile);
string charPath = Path.Combine(sourceFolder, charFile);
string kernalPath = Path.Combine(sourceFolder, kernalFile);
if (!File.Exists(basicPath)) HandleFirmwareError(basicFile);
if (!File.Exists(charPath)) HandleFirmwareError(charFile);
if (!File.Exists(kernalPath)) HandleFirmwareError(kernalFile);
basicRom = File.ReadAllBytes(basicPath);
charRom = File.ReadAllBytes(charPath);
kernalRom = File.ReadAllBytes(kernalPath);
vic = newVic;
sid = newSid;
cia0 = newCia0;
cia1 = newCia1;
cpuPort = cpuPortBus.Connect();
cpuPort.Latch = 0x00;
cpuPort.Direction = 0x1F;
cpuPortBus.AttachWriteHook(UpdateLayout);
cpuIO = cpuPortBus.Connect();
cpuIO.Latch = 0x17;
cia1.AttachWriteHook(0, UpdateVicOffset);
HardReset();
}
public byte this[ushort index]
{
get
{
return ram[index];
}
set
{
ram[index] = value;
}
}
public MemoryDesignation GetDesignation(ushort addr)
{
MemoryDesignation result;
if (addr < 0x1000)
{
result = MemoryDesignation.RAM;
}
else if (addr < 0x8000)
{
result = layout.Mem1000;
}
else if (addr < 0xA000)
{
result = layout.Mem8000;
}
else if (addr < 0xC000)
{
result = layout.MemA000;
}
else if (addr < 0xD000)
{
result = layout.MemC000;
}
else if (addr < 0xE000)
{
result = layout.MemD000;
}
else
{
result = layout.MemE000;
}
if (result == MemoryDesignation.IO)
{
addr &= 0x0FFF;
if (addr < 0x0400)
{
result = MemoryDesignation.Vic;
}
else if (addr < 0x0800)
{
result = MemoryDesignation.Sid;
}
else if (addr < 0x0C00)
{
result = MemoryDesignation.ColorRam;
}
else if (addr < 0x0D00)
{
result = MemoryDesignation.Cia0;
}
else if (addr < 0x0E00)
{
result = MemoryDesignation.Cia1;
}
else if (addr < 0x0F00)
{
result = MemoryDesignation.Expansion0;
}
else
{
result = MemoryDesignation.Expansion1;
}
}
return result;
}
public void HardReset()
{
layout = new MemoryLayout();
ram = new byte[0x10000];
colorRam = new byte[0x1000];
WipeMemory();
cpuPort.Direction = 0x2F;
cpuPort.Data = 0x37;
UpdateVicOffset();
}
public byte Peek(ushort addr)
{
byte result;
if (addr == 0x0000)
{
result = cpuPort.Direction;
}
else if (addr == 0x0001)
{
result = cpuPort.Data;
}
else
{
MemoryDesignation des = GetDesignation(addr);
switch (des)
{
case MemoryDesignation.Basic:
result = basicRom[addr & 0x1FFF];
break;
case MemoryDesignation.Character:
result = charRom[addr & 0x0FFF];
break;
case MemoryDesignation.Vic:
result = vic.Peek(addr & 0x3F);
break;
case MemoryDesignation.Sid:
result = sid.Peek(addr & 0x1F);
break;
case MemoryDesignation.ColorRam:
result = (byte)(colorRam[addr & 0x03FF] | (busData & 0xF0));
break;
case MemoryDesignation.Cia0:
result = cia0.Peek(addr & 0x0F);
break;
case MemoryDesignation.Cia1:
result = cia1.Peek(addr & 0x0F);
break;
case MemoryDesignation.Expansion0:
result = 0;
break;
case MemoryDesignation.Expansion1:
result = 0;
break;
case MemoryDesignation.Kernal:
result = kernalRom[addr & 0x1FFF];
break;
case MemoryDesignation.RAM:
result = ram[addr];
break;
case MemoryDesignation.ROMHi:
result = cart.chips[cart.bank].data[addr & cart.chips[cart.bank].romMask];
break;
case MemoryDesignation.ROMLo:
result = cart.chips[cart.bank].data[addr & cart.chips[cart.bank].romMask];
break;
default:
return 0;
}
}
busData = result;
return result;
}
public byte PeekRam(int addr)
{
return ram[addr & 0xFFFF];
}
public void Poke(ushort addr, byte val)
{
return;
/*
if (addr == 0x0000)
{
cpuPort.Direction = val;
}
else if (addr == 0x0001)
{
cpuPort.Data = val;
UpdateLayout();
}
else
{
MemoryDesignation des = GetDesignation(addr);
switch (des)
{
case MemoryDesignation.Vic:
vic.Poke(addr, val);
break;
case MemoryDesignation.Sid:
sid.Poke(addr, val);
break;
case MemoryDesignation.ColorRam:
colorRam[addr & 0x03FF] = (byte)(val & 0x0F);
break;
case MemoryDesignation.Cia0:
cia0.Poke(addr, val);
break;
case MemoryDesignation.Cia1:
cia1.Poke(addr, val);
break;
case MemoryDesignation.Expansion0:
if (cart != null)
cart.WritePort(addr, val);
break;
case MemoryDesignation.Expansion1:
break;
case MemoryDesignation.RAM:
break;
default:
break;
}
// write through to ram
if (des != MemoryDesignation.Disabled)
{
ram[addr] = val;
}
}
*/
}
public void PokeRam(int addr, byte val)
{
ram[addr & 0xFFFF] = val;
}
public byte Read(ushort addr)
{
byte result;
if (addr == 0x0000)
{
result = cpuPort.Direction;
}
else if (addr == 0x0001)
{
result = cpuPort.Data;
}
else
{
MemoryDesignation des = GetDesignation(addr);
switch (des)
{
case MemoryDesignation.Basic:
result = basicRom[addr & 0x1FFF];
break;
case MemoryDesignation.Character:
result = charRom[addr & 0x0FFF];
break;
case MemoryDesignation.Vic:
result = vic.Read(addr);
break;
case MemoryDesignation.Sid:
result = sid.Read(addr);
break;
case MemoryDesignation.ColorRam:
result = ReadColorRam(addr);
break;
case MemoryDesignation.Cia0:
if ((addr & 0xF) < 0x02)
inputWasRead = true;
result = cia0.Read(addr);
break;
case MemoryDesignation.Cia1:
result = cia1.Read(addr);
break;
case MemoryDesignation.Expansion0:
if (cart != null)
result = cart.ReadPort(addr);
else
result = 0;
break;
case MemoryDesignation.Expansion1:
result = 0;
break;
case MemoryDesignation.Kernal:
result = kernalRom[addr & 0x1FFF];
break;
case MemoryDesignation.RAM:
result = ram[addr];
break;
case MemoryDesignation.ROMHi:
result = cart.Read(addr);
break;
case MemoryDesignation.ROMLo:
result = cart.Read(addr);
break;
default:
return 0;
}
}
busData = result;
return result;
}
public byte ReadColorRam(ushort addr)
{
return (byte)((busData & 0xF0) | (colorRam[addr & 0x03FF]));
}
public void SyncState(Serializer ser)
{
ser.Sync("BUSDATA", ref busData);
ser.Sync("EXROMPIN", ref exRomPin);
ser.Sync("GAMEPIN", ref gamePin);
ser.Sync("INPUTWASREAD", ref inputWasRead);
ser.Sync("COLORRAM", ref colorRam, false);
ser.Sync("RAM", ref ram, false);
byte cpuData = cpuPort.Latch;
byte cpuDir = cpuPort.Direction;
ser.Sync("CPUPORT", ref cpuData);
ser.Sync("CPUDIR", ref cpuDir);
if (ser.IsReader)
{
cpuPort.Latch = cpuData;
cpuPort.Direction = cpuDir;
UpdateLayout();
UpdateVicOffset();
}
}
public void UpdateLayout()
{
byte cpuData = cpuPort.Data;
bool loRom = ((cpuData & 0x01) != 0);
bool hiRom = ((cpuData & 0x02) != 0);
bool ioEnable = ((cpuData & 0x04) != 0);
if (loRom && hiRom && gamePin && exRomPin)
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.RAM;
layout.MemA000 = MemoryDesignation.Basic;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = ioEnable ? MemoryDesignation.IO : MemoryDesignation.Character;
layout.MemE000 = MemoryDesignation.Kernal;
}
else if (loRom && !hiRom && gamePin)
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.RAM;
layout.MemA000 = MemoryDesignation.RAM;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = ioEnable ? MemoryDesignation.IO : MemoryDesignation.Character;
layout.MemE000 = MemoryDesignation.RAM;
}
else if (loRom && !hiRom && !exRomPin && !gamePin)
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.RAM;
layout.MemA000 = MemoryDesignation.RAM;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = ioEnable ? MemoryDesignation.IO : MemoryDesignation.RAM;
layout.MemE000 = MemoryDesignation.RAM;
}
else if ((!loRom && hiRom && gamePin) || (!loRom && !hiRom && !exRomPin))
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.RAM;
layout.MemA000 = MemoryDesignation.RAM;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = ioEnable ? MemoryDesignation.IO : MemoryDesignation.Character;
layout.MemE000 = MemoryDesignation.Kernal;
}
else if (!loRom && !hiRom && gamePin)
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.RAM;
layout.MemA000 = MemoryDesignation.RAM;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = MemoryDesignation.RAM;
layout.MemE000 = MemoryDesignation.RAM;
}
else if (loRom && hiRom && gamePin && !exRomPin)
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.ROMLo;
layout.MemA000 = MemoryDesignation.Basic;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = ioEnable ? MemoryDesignation.IO : MemoryDesignation.Character;
layout.MemE000 = MemoryDesignation.Kernal;
}
else if (!loRom && hiRom && !gamePin && !exRomPin)
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.RAM;
layout.MemA000 = MemoryDesignation.ROMHi;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = ioEnable ? MemoryDesignation.IO : MemoryDesignation.Character;
layout.MemE000 = MemoryDesignation.Kernal;
}
else if (loRom && hiRom && !gamePin && !exRomPin)
{
layout.Mem1000 = MemoryDesignation.RAM;
layout.Mem8000 = MemoryDesignation.ROMLo;
layout.MemA000 = MemoryDesignation.ROMHi;
layout.MemC000 = MemoryDesignation.RAM;
layout.MemD000 = ioEnable ? MemoryDesignation.IO : MemoryDesignation.Character;
layout.MemE000 = MemoryDesignation.Kernal;
}
else if (!gamePin && exRomPin)
{
layout.Mem1000 = MemoryDesignation.Disabled;
layout.Mem8000 = MemoryDesignation.ROMLo;
layout.MemA000 = MemoryDesignation.Disabled;
layout.MemC000 = MemoryDesignation.Disabled;
layout.MemD000 = MemoryDesignation.IO;
layout.MemE000 = MemoryDesignation.ROMHi;
}
}
private void UpdateVicOffset()
{
switch (cia1.Peek(0x00) & 0x03)
{
case 0:
vicCharEnabled = false;
vicOffset = 0xC000;
break;
case 1:
vicCharEnabled = true;
vicOffset = 0x8000;
break;
case 2:
vicCharEnabled = false;
vicOffset = 0x4000;
break;
default:
vicCharEnabled = true;
vicOffset = 0x0000;
break;
}
}
public byte VicRead(ushort addr)
{
addr = (ushort)(addr & 0x3FFF);
if (vicCharEnabled && (addr >= 0x1000 && addr < 0x2000))
{
return charRom[addr & 0x0FFF];
}
else
{
return ram[addr | vicOffset];
}
}
public void WipeMemory()
{
// memory is striped in sections 00/FF
for (int i = 0; i < 0x10000; i += 0x80)
{
for (int j = 0; j < 0x40; j++)
ram[i + j] = 0x00;
for (int j = 0x40; j < 0x80; j++)
ram[i + j] = 0xFF;
}
for (int i = 0; i < 0x1000; i++)
{
colorRam[i] = 0x0E;
}
}
public void Write(ushort addr, byte val)
{
if (addr == 0x0000)
{
cpuPort.Direction = val;
}
else if (addr == 0x0001)
{
cpuPort.Data = val;
}
else
{
MemoryDesignation des = GetDesignation(addr);
switch (des)
{
case MemoryDesignation.Vic:
vic.Write(addr, val);
break;
case MemoryDesignation.Sid:
sid.Write(addr, val);
break;
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.Expansion0:
if (cart != null)
cart.WritePort(addr, val);
break;
case MemoryDesignation.Expansion1:
break;
case MemoryDesignation.RAM:
break;
default:
break;
}
// write through to ram
if (des != MemoryDesignation.Disabled)
{
ram[addr] = val;
}
}
busData = val;
}
}
}

View File

@ -5,10 +5,7 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public interface IMedia
class Memory
{
void Apply();
bool Loaded();
bool Ready();
}
}

View File

@ -1,58 +0,0 @@
using BizHawk.Emulation.CPUs.M6502;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class PRGFile : IMedia
{
private MOS6502X cpu;
private byte[] data;
private bool loaded;
private Memory mem;
public PRGFile(byte[] file, Memory checkMem, MOS6502X targetCpu)
{
cpu = targetCpu;
mem = checkMem;
data = file;
}
public void Apply()
{
int address = data[1];
address <<= 8;
address |= data[0];
int count = data.Length;
for (int i = 2; i < count; i++)
{
mem.Write((ushort)(address & 0xFFFF), data[i]);
address++;
}
loaded = true;
}
public bool Loaded()
{
return loaded;
}
public bool Ready()
{
// wait for READY. to be on display
return (
mem[0x04C8] == 0x12 &&
mem[0x04C9] == 0x05 &&
mem[0x04CA] == 0x01 &&
mem[0x04CB] == 0x04 &&
mem[0x04CC] == 0x19 &&
mem[0x04CD] == 0x2E &&
mem[0x04CE] == 0x20
);
}
}
}

View File

@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class DataPortSerialInputConverter : DataPortConverter
{
public override byte Convert(byte local, byte remote)
{
int via = (local & 0x70);
via |= ((remote & 0x08) == 0) ? 0x80 : 0x00; //CIA ATNOUT - VIA ATNIN
via |= ((remote & 0x10) == 0) ? 0x04 : 0x00; //CIA CLKOUT - VIA CLKIN
via |= ((remote & 0x20) == 0) ? 0x01 : 0x00; //CIA DATOUT - VIA DATIN
via |= ((remote & 0x40) == 0) ? 0x08 : 0x00; //CIA CLKIN - VIA CLKOUT
via |= ((remote & 0x80) == 0) ? 0x02 : 0x00; //CIA DATIN - VIA DATOUT
return (byte)via;
}
}
public class DataPortSerialOutputConverter : DataPortConverter
{
public override byte Convert(byte local, byte remote)
{
int cia = (remote & 0x7);
cia |= ((local & 0x01) == 0) ? 0x20 : 0x00; //VIA DATIN - CIA DATOUT
cia |= ((local & 0x02) == 0) ? 0x80 : 0x00; //VIA DATOUT - CIA DATIN
cia |= ((local & 0x04) == 0) ? 0x10 : 0x00; //VIA CLKIN - CIA CLKOUT
cia |= ((local & 0x08) == 0) ? 0x40 : 0x00; //VIA CLKOUT - CIA CLKIN
cia |= ((local & 0x80) == 0) ? 0x08 : 0x00; //VIA DATIN - CIA DATOUT
return (byte)cia;
}
}
}

View File

@ -1,305 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public enum SidMode
{
Sid6581,
Sid8580
}
public class VoiceRegs
{
public EnvelopeGenerator Envelope;
public WaveformGenerator Generator;
public WaveformGenerator SyncSource;
public int EnvelopeLatch;
public int GeneratorLatch;
public VoiceRegs()
{
Envelope = new EnvelopeGenerator();
Generator = new WaveformGenerator();
}
public void Clock()
{
Generator.Clock();
GeneratorLatch = Generator.Output(SyncSource);
Envelope.Clock();
EnvelopeLatch = Envelope.Output;
}
public short Output()
{
int result = (GeneratorLatch * EnvelopeLatch) >> 4;
result -= 32768;
if (result > 32767)
result = 32767;
else if (result < -32768)
result = -32768;
return (short)result;
}
public void Reset()
{
Generator.Reset();
Envelope.Reset();
}
}
public class SidRegs
{
public bool BP;
public bool D3;
public int FC;
public bool[] FILT = new bool[3];
public bool FILTEX;
public bool HP;
public bool LP;
public int POTX;
public int POTY;
public int RES;
public int VOL;
public VoiceRegs[] Voices;
public SidRegs()
{
Voices = new VoiceRegs[3];
Voices[0] = new VoiceRegs();
Voices[1] = new VoiceRegs();
Voices[2] = new VoiceRegs();
Voices[0].SyncSource = Voices[2].Generator;
Voices[1].SyncSource = Voices[0].Generator;
Voices[2].SyncSource = Voices[1].Generator;
}
public byte this[int addr]
{
get
{
int result;
addr &= 0x1F;
switch (addr)
{
case 0x19:
result = POTX;
break;
case 0x1A:
result = POTY;
break;
case 0x1B:
result = Voices[2].GeneratorLatch >> 4;
break;
case 0x1C:
result = Voices[2].EnvelopeLatch;
break;
default:
result = 0;
break;
}
return (byte)(result & 0xFF);
}
set
{
int val = value;
int index;
addr &= 0x1F;
switch (addr)
{
case 0x00:
case 0x07:
case 0x0E:
index = addr / 7;
Voices[index].Generator.Frequency &= 0xFF00;
Voices[index].Generator.Frequency |= value;
break;
case 0x01:
case 0x08:
case 0x0F:
index = addr / 7;
Voices[index].Generator.Frequency &= 0xFF;
Voices[index].Generator.Frequency |= (int)value << 8;
break;
case 0x02:
case 0x09:
case 0x10:
index = addr / 7;
Voices[index].Generator.PulseWidth &= 0x0F00;
Voices[index].Generator.PulseWidth |= value;
break;
case 0x03:
case 0x0A:
case 0x11:
index = addr / 7;
Voices[index].Generator.PulseWidth &= 0xFF;
Voices[index].Generator.PulseWidth |= (int)(value & 0xF) << 8;
break;
case 0x04:
case 0x0B:
case 0x12:
index = addr / 7;
Voices[index].Generator.Control = value;
Voices[index].Envelope.Gate = ((value & 0x01) != 0x00);
break;
case 0x05:
case 0x0C:
case 0x13:
index = addr / 7;
Voices[index].Envelope.Attack = (value >> 4);
Voices[index].Envelope.Decay = (value & 0xF);
break;
case 0x06:
case 0x0D:
case 0x14:
index = addr / 7;
Voices[index].Envelope.Sustain = (value >> 4);
Voices[index].Envelope.Release = (value & 0xF);
break;
case 0x15:
FC &= 0x7F8;
FC |= val & 0x7;
break;
case 0x16:
FC &= 0x7;
FC |= val << 3;
break;
case 0x17:
FILT[0] = ((val & 0x01) != 0x00);
FILT[1] = ((val & 0x02) != 0x00);
FILT[2] = ((val & 0x04) != 0x00);
FILTEX = ((val & 0x08) != 0x00);
RES = (val >> 4);
break;
case 0x18:
VOL = (val & 0xF);
LP = ((val & 0x10) != 0x00);
BP = ((val & 0x20) != 0x00);
HP = ((val & 0x40) != 0x00);
D3 = ((val & 0x80) != 0x00);
break;
}
}
}
}
public partial class Sid : ISoundProvider
{
private int[] syncIndex = { 2, 0, 1 };
private VoiceRegs[] voices;
public Func<int> ReadPotX;
public Func<int> ReadPotY;
public int clock;
public int cyclesPerSample;
public int output;
public SidRegs regs;
public Sid(Region newRegion, int sampleRate)
{
ReadPotX = DummyReadPot;
ReadPotY = DummyReadPot;
switch (newRegion)
{
case Region.NTSC:
cyclesPerSample = 14318181 / 14 / sampleRate;
break;
case Region.PAL:
cyclesPerSample = 17734472 / 18 / sampleRate;
break;
}
InitSound(sampleRate);
HardReset();
}
private int DummyReadPot()
{
return 0;
}
public void HardReset()
{
regs = new SidRegs();
voices = regs.Voices;
}
public byte Peek(int addr)
{
return regs[addr & 0x1F];
}
public void PerformCycle()
{
// process each voice
voices[0].Clock();
voices[1].Clock();
voices[2].Clock();
// sync voices
voices[0].Generator.Synchronize(voices[1].Generator, voices[2].Generator);
voices[1].Generator.Synchronize(voices[2].Generator, voices[0].Generator);
voices[2].Generator.Synchronize(voices[0].Generator, voices[1].Generator);
// finalize sample and put into buffer
SubmitSample();
// query pots every 512 cycles
if ((clock & 0x1FF) == 0x000)
{
regs.POTX = ReadPotX() & 0xFF;
regs.POTY = ReadPotY() & 0xFF;
}
clock = (clock + 1) & 0xFFFFFF;
}
public void Poke(int addr, byte val)
{
regs[addr & 0x1F] = val;
}
public byte Read(ushort addr)
{
addr &= 0x1F;
switch (addr)
{
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
// can only read these regs
return regs[addr];
default:
return 0;
}
}
public void Write(ushort addr, byte val)
{
addr &= 0x1F;
switch (addr)
{
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
// can't write these regs
break;
default:
regs[addr] = val;
break;
}
}
}
}

View File

@ -1,255 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
// constants for the EnvelopeGenerator and calculation
// methods are based from the libsidplayfp residfp library.
public partial class EnvelopeGenerator
{
public enum EnvelopeState
{
Attack, Decay, Release
}
// value table for the envelope shift register
static int[] adsrTable = new int[]
{
0x7F00, 0x0006, 0x003C, 0x0330,
0x20C0, 0x6755, 0x3800, 0x500E,
0x1212, 0x0222, 0x1848, 0x59B8,
0x3840, 0x77E2, 0x7625, 0x0A93
};
int attack;
int decay;
bool gate;
int release;
int sustain;
public byte envelopeCounter;
public bool envelopeProcessEnabled;
public int exponentialCounter;
public int exponentialCounterPeriod;
public bool freeze;
public int lfsr;
public int rate;
public EnvelopeState state;
public EnvelopeGenerator()
{
Reset();
}
public int Attack
{
get
{
return attack;
}
set
{
attack = value;
if (state == EnvelopeState.Attack)
rate = adsrTable[attack];
}
}
public void Clock()
{
if (envelopeProcessEnabled)
{
envelopeProcessEnabled = false;
envelopeCounter--;
UpdateExponentialCounter();
}
if (lfsr != rate)
{
int feedback = ((lfsr >> 14) ^ (lfsr >> 13)) & 0x01;
lfsr = ((lfsr << 1) & 0x7FFF) | feedback;
return;
}
lfsr = 0x7FFF;
if ((state == EnvelopeState.Attack) || (++exponentialCounter == exponentialCounterPeriod))
{
exponentialCounter = 0;
if (!freeze)
{
switch (state)
{
case EnvelopeState.Attack:
++envelopeCounter;
if (envelopeCounter == 0xFF)
{
state = EnvelopeState.Decay;
rate = adsrTable[decay];
}
break;
case EnvelopeState.Decay:
if (envelopeCounter == ((sustain << 4) | sustain))
{
return;
}
if (exponentialCounterPeriod != 1)
{
envelopeProcessEnabled = true;
return;
}
envelopeCounter--;
break;
case EnvelopeState.Release:
if (exponentialCounterPeriod != 1)
{
envelopeProcessEnabled = true;
return;
}
envelopeCounter--;
break;
}
UpdateExponentialCounter();
}
}
}
public int Decay
{
get
{
return decay;
}
set
{
decay = value;
if (state == EnvelopeState.Decay)
rate = adsrTable[decay];
}
}
public bool Gate
{
get
{
return gate;
}
set
{
bool gateThis = value;
if (!gate && gateThis)
{
state = EnvelopeState.Attack;
rate = adsrTable[attack];
freeze = false;
envelopeProcessEnabled = false;
}
else if (gate && !gateThis)
{
state = EnvelopeState.Release;
rate = adsrTable[release];
}
gate = gateThis;
}
}
public short Output
{
get
{
return envelopeCounter;
}
}
public int Release
{
get
{
return release;
}
set
{
release = value;
if (state == EnvelopeState.Release)
rate = adsrTable[release];
}
}
public void Reset()
{
attack = 0;
decay = 0;
sustain = 0;
release = 0;
gate = false;
envelopeCounter = 0;
envelopeProcessEnabled = false;
exponentialCounter = 0;
exponentialCounterPeriod = 1;
lfsr = 0x7FFF;
state = EnvelopeState.Release;
rate = adsrTable[release];
freeze = true;
}
public void SetState(int stateAtk, int stateDcy, int stateSus, int stateRls, bool stateGate, EnvelopeState stateState)
{
attack = stateAtk;
decay = stateDcy;
sustain = stateSus;
release = stateRls;
gate = stateGate;
state = stateState;
}
public int Sustain
{
get
{
return sustain;
}
set
{
sustain = value;
}
}
private void UpdateExponentialCounter()
{
switch (envelopeCounter)
{
case 0x00:
exponentialCounterPeriod = 1;
freeze = true;
break;
case 0x06:
exponentialCounterPeriod = 30;
break;
case 0x0E:
exponentialCounterPeriod = 16;
break;
case 0x1A:
exponentialCounterPeriod = 8;
break;
case 0x36:
exponentialCounterPeriod = 4;
break;
case 0x5D:
exponentialCounterPeriod = 2;
break;
case 0xFF:
exponentialCounterPeriod = 1;
break;
}
}
}
}

View File

@ -1,143 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class Sid : ISoundProvider
{
private short[] sampleBuffer;
private int sampleBufferCapacity;
private int sampleBufferCount;
private int sampleBufferIndex;
private int sampleBufferReadIndex;
private int sampleCounter;
public void DiscardSamples()
{
sampleBuffer = new short[sampleBufferCapacity];
ResetBuffer();
}
public short[] GetAllSamples()
{
if (sampleBufferCount > 0)
{
short[] samples = new short[sampleBufferCount];
GetSamples(samples);
return samples;
}
else
{
return new short[] { };
}
}
public void GetSamples(short[] samples)
{
int count = samples.Length;
int copied = 0;
while (copied < count)
{
samples[copied] = sampleBuffer[sampleBufferReadIndex];
if (sampleBufferIndex != sampleBufferReadIndex)
sampleBufferReadIndex++;
copied++;
if (sampleBufferReadIndex == sampleBufferCapacity)
sampleBufferReadIndex = 0;
}
// catch buffer up
sampleBufferReadIndex = sampleBufferIndex;
sampleBufferCount = 0;
}
private void InitSound(int initSampleRate)
{
sampleBufferCapacity = initSampleRate;
DiscardSamples();
}
public int MaxVolume
{
get
{
return 0;
}
set
{
}
}
private void ResetBuffer()
{
sampleBufferReadIndex = 0;
sampleBufferIndex = 0;
}
private void SubmitSample()
{
if (sampleCounter == 0)
{
int mixer;
mixer = voices[0].Output();
mixer += voices[1].Output();
if (!regs.D3 || !regs.FILT[2])
mixer += voices[2].Output();
// apply volume
mixer *= regs.VOL;
mixer >>= 4;
// apply filter
// (todo)
// the mixer is very loud at this point, let's make it quieter
mixer /= 4;
if (mixer > 32767)
mixer = 326767;
else if (mixer < -32768)
mixer = -32768;
short output = (short)mixer;
// run twice since the buffer expects stereo sound (I THINK)
for (int i = 0; i < 2; i++)
{
sampleBufferIndex++;
sampleBufferCount++;
if (sampleBufferIndex == sampleBufferCapacity)
sampleBufferIndex = 0;
sampleBuffer[sampleBufferIndex] = output;
}
sampleCounter = cyclesPerSample;
}
sampleCounter--;
}
}
public class SidSyncSoundProvider : ISyncSoundProvider
{
private Sid sid;
public SidSyncSoundProvider(Sid source)
{
sid = source;
}
public void DiscardSamples()
{
sid.DiscardSamples();
}
public void GetSamples(out short[] samples, out int nsamp)
{
samples = sid.GetAllSamples();
nsamp = samples.Length / 2;
}
}
}

View File

@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class Sid : ISoundProvider
{
public void SyncState(Serializer ser)
{
// voices
for (int i = 0; i < 3; i++)
{
string iTag = i.ToString();
ser.Sync("GENACCUM" + iTag, ref regs.Voices[i].Generator.accumulator);
ser.Sync("GENFOTTL" + iTag, ref regs.Voices[i].Generator.floatingOutputTtl);
ser.Sync("GENMSBRISING" + iTag, ref regs.Voices[i].Generator.msbRising);
ser.Sync("GENNOISEOUT" + iTag, ref regs.Voices[i].Generator.noiseOutput);
ser.Sync("GENPULSEOUT" + iTag, ref regs.Voices[i].Generator.pulseOutput);
ser.Sync("GENSR" + iTag, ref regs.Voices[i].Generator.shiftRegister);
ser.Sync("GENSRDELAY" + iTag, ref regs.Voices[i].Generator.shiftRegisterDelay);
ser.Sync("GENSRRESETDELAY" + iTag, ref regs.Voices[i].Generator.shiftRegisterResetDelay);
ser.Sync("GENWAVEFORMOUT" + iTag, ref regs.Voices[i].Generator.waveformOutput);
ser.Sync("ENVCOUNTER" + iTag, ref regs.Voices[i].Envelope.envelopeCounter);
ser.Sync("ENVENABLE" + iTag, ref regs.Voices[i].Envelope.envelopeProcessEnabled);
ser.Sync("ENVEXPCOUNTER" + iTag, ref regs.Voices[i].Envelope.exponentialCounter);
ser.Sync("ENVEXPCOUNTERPERIOD" + iTag, ref regs.Voices[i].Envelope.exponentialCounterPeriod);
ser.Sync("ENVFREEZE" + iTag, ref regs.Voices[i].Envelope.freeze);
ser.Sync("ENVLFSR" + iTag, ref regs.Voices[i].Envelope.lfsr);
ser.Sync("ENVRATE" + iTag, ref regs.Voices[i].Envelope.rate);
byte control = regs.Voices[i].Generator.Control;
int freq = regs.Voices[i].Generator.Frequency;
int pw = regs.Voices[i].Generator.PulseWidth;
int attack = regs.Voices[i].Envelope.Attack;
int decay = regs.Voices[i].Envelope.Decay;
int sustain = regs.Voices[i].Envelope.Sustain;
int release = regs.Voices[i].Envelope.Release;
bool gate = regs.Voices[i].Envelope.Gate;
int state = (int)regs.Voices[i].Envelope.state;
ser.Sync("GENCONTROL" + iTag, ref control);
ser.Sync("GENFREQ" + iTag, ref freq);
ser.Sync("GENPW" + iTag, ref pw);
ser.Sync("ENVATTACK" + iTag, ref attack);
ser.Sync("ENVDECAY" + iTag, ref decay);
ser.Sync("ENVSUSTAIN" + iTag, ref sustain);
ser.Sync("ENVRELEASE" + iTag, ref release);
ser.Sync("ENVGATE" + iTag, ref gate);
ser.Sync("ENVSTATE" + iTag, ref state);
if (ser.IsReader)
{
regs.Voices[i].Generator.SetState(control, freq, pw);
regs.Voices[i].Envelope.SetState(attack, decay, sustain, release, gate, (EnvelopeGenerator.EnvelopeState)state);
}
}
// regs
ser.Sync("BP", ref regs.BP);
ser.Sync("D3", ref regs.D3);
ser.Sync("FC", ref regs.FC);
ser.Sync("FILT0", ref regs.FILT[0]);
ser.Sync("FILT1", ref regs.FILT[1]);
ser.Sync("FILT2", ref regs.FILT[2]);
ser.Sync("FILTEX", ref regs.FILTEX);
ser.Sync("HP", ref regs.HP);
ser.Sync("LP", ref regs.LP);
ser.Sync("POTX", ref regs.POTX);
ser.Sync("POTY", ref regs.POTY);
ser.Sync("RES", ref regs.RES);
ser.Sync("VOL", ref regs.VOL);
// vars
ser.Sync("CLOCK", ref clock);
ser.Sync("CYCLESPERSAMPLE", ref cyclesPerSample);
ser.Sync("OUTPUT", ref output);
}
}
}

View File

@ -1,255 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
// constants for the WaveformGenerator and calculation
// methods come from the libsidplayfp residfp library.
public partial class WaveformGenerator
{
// internal
private byte control;
private int freq;
private int pw;
public int accumulator;
public int floatingOutputTtl;
public bool msbRising;
public int noiseOutput;
public int pulseOutput;
public int ringMsbMask;
public int shiftRegister;
public int shiftRegisterDelay;
public int shiftRegisterResetDelay;
public bool sync;
public bool test;
private short[] wave;
public int waveform;
public int waveformOutput;
// these are temp values used to speed up calculation
private int noNoise;
private int noNoiseOrNoiseOutput;
private int noPulse;
public WaveformGenerator()
{
Reset();
}
public void Clock()
{
if (test)
{
pulseOutput = 0xFFF;
if (shiftRegisterResetDelay != 0 && --shiftRegisterResetDelay == 0)
{
ResetShiftRegister();
}
}
else
{
int accumulatorNext = (accumulator + freq) & 0xFFFFFF;
int accumulatorBitsSet = ~accumulator & accumulatorNext;
accumulator = accumulatorNext;
msbRising = (accumulatorBitsSet & 0x800000) != 0;
if ((accumulatorBitsSet & 0x080000) != 0)
{
shiftRegisterDelay = 2;
}
else if (shiftRegisterDelay != 0 && --shiftRegisterDelay == 0)
{
ClockShiftRegister();
}
}
}
private void ClockShiftRegister()
{
int bit0 = ((shiftRegister >> 22) ^ (shiftRegister >> 17)) & 0x1;
shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF;
UpdateNoiseOutput();
}
public byte Control
{
get
{
return control;
}
set
{
control = value;
int waveformPrev = waveform;
bool testPrev = test;
waveform = (control >> 4) & 0x0F;
test = (control & 0x08) != 0;
sync = (control & 0x02) != 0;
wave = WaveformSamples[waveform & 0x7];
ringMsbMask = ((~control >> 5) & (control >> 2) & 0x1) << 23;
noNoise = (waveform & 0x8) != 0 ? 0x000 : 0xFFF;
noNoiseOrNoiseOutput = noNoise | noiseOutput;
noPulse = (waveform & 0x4) != 0 ? 0x000 : 0xFFF;
if (!testPrev && test)
{
accumulator = 0;
shiftRegisterDelay = 0;
shiftRegisterResetDelay = 0x8000;
}
else if (testPrev && !test)
{
int bit0 = (~shiftRegister >> 17) & 0x1;
shiftRegister = ((shiftRegister << 1) | bit0) & 0x7FFFFF;
UpdateNoiseOutput();
}
if (waveform == 0 && waveformPrev != 0)
{
floatingOutputTtl = 0x28000;
}
}
}
public int Frequency
{
get
{
return freq;
}
set
{
freq = value;
}
}
public short Output(WaveformGenerator ringModulator)
{
if (waveform != 0)
{
int ix = (accumulator ^ (ringModulator.accumulator & ringMsbMask)) >> 12;
waveformOutput = wave[ix] & (noPulse | pulseOutput) & noNoiseOrNoiseOutput;
if (waveform > 0x8)
{
WriteShiftRegister();
}
}
else
{
if (floatingOutputTtl != 0 && --floatingOutputTtl == 0)
{
waveformOutput = 0;
}
}
pulseOutput = ((accumulator >> 12) >= pw) ? 0xFFF : 0x000;
return (short)waveformOutput;
}
public int PulseWidth
{
get
{
return pw;
}
set
{
pw = value;
}
}
public void Reset()
{
control = 0;
waveform = 0;
freq = 0;
pw = 0;
accumulator = 0;
test = false;
sync = false;
msbRising = false;
wave = WaveformSamples[0];
ringMsbMask = 0;
noNoise = 0xFFF;
noPulse = 0xFFF;
pulseOutput = 0xFFF;
ResetShiftRegister();
shiftRegisterDelay = 0;
waveformOutput = 0;
floatingOutputTtl = 0;
}
private void ResetShiftRegister()
{
shiftRegister = 0x7FFFFF;
shiftRegisterResetDelay = 0;
UpdateNoiseOutput();
}
public void SetState(byte stateControl, int stateFreq, int statePulseWidth)
{
pw = statePulseWidth;
freq = stateFreq;
control = stateControl;
noNoise = (waveform & 0x8) != 0 ? 0x000 : 0xFFF;
noNoiseOrNoiseOutput = noNoise | noiseOutput;
noPulse = (waveform & 0x4) != 0 ? 0x000 : 0xFFF;
ringMsbMask = ((~control >> 5) & (control >> 2) & 0x1) << 23;
waveform = (control >> 4) & 0x0F;
test = (control & 0x08) != 0;
sync = (control & 0x02) != 0;
wave = WaveformSamples[waveform & 0x7];
}
public void Synchronize(WaveformGenerator syncDest, WaveformGenerator syncSource)
{
if (msbRising && syncDest.sync && !(sync && syncSource.msbRising))
{
syncDest.accumulator = 0;
}
}
private void UpdateNoiseOutput()
{
noiseOutput =
((shiftRegister & 0x100000) >> 9) |
((shiftRegister & 0x040000) >> 8) |
((shiftRegister & 0x004000) >> 5) |
((shiftRegister & 0x000800) >> 3) |
((shiftRegister & 0x000200) >> 2) |
((shiftRegister & 0x000020) << 1) |
((shiftRegister & 0x000004) << 3) |
((shiftRegister & 0x000001) << 4);
noNoiseOrNoiseOutput = noNoise | noiseOutput;
}
private void WriteShiftRegister()
{
shiftRegister &=
~((1 << 20) | (1 << 18) | (1 << 14) | (1 << 11) |
(1 << 9) | (1 << 5) | (1 << 2) | (1 << 0)) |
((waveformOutput & 0x800) << 9) |
((waveformOutput & 0x400) << 8) |
((waveformOutput & 0x200) << 5) |
((waveformOutput & 0x100) << 3) |
((waveformOutput & 0x080) << 2) |
((waveformOutput & 0x040) >> 1) |
((waveformOutput & 0x020) >> 3) |
((waveformOutput & 0x010) >> 4);
noiseOutput &= waveformOutput;
noNoiseOrNoiseOutput = noNoise | noiseOutput;
}
}
}

View File

@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public class Timing
{
public int crystalFreq;
public uint timer;
public Timing(Region timingRegion)
{
switch (timingRegion)
{
case Region.NTSC:
crystalFreq = 14318181;
break;
case Region.PAL:
crystalFreq = 17734472;
break;
}
}
public void Advance()
{
// need an unchecked block here since the timer will wrap
unchecked
{
timer++;
}
}
public bool IsCycle(int divisor)
{
return (timer % divisor) == 0;
}
}
}

View File

@ -1,420 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
// MOS Technologies VIA 6522
// register count: 16
// IO port count: 2
public class ViaRegs
{
public int[] CACONTROL = new int[2];
public int[] CBCONTROL = new int[2];
public bool[] EICA = new bool[2];
public bool[] EICB = new bool[2];
public bool EISR;
public bool[] EIT = new bool[2];
public bool[] ICA = new bool[2];
public bool[] ICB = new bool[2];
public bool IRQ;
public bool ISR;
public bool[] IT = new bool[2];
public bool PALE;
public bool PBLE;
public int SR;
public int SRCONTROL;
public int[] TC = new int[2];
public int[] TCONTROL = new int[2];
public int[] TL = new int[2];
private DataPortConnector[] connectors;
public ViaRegs()
{
// power on state
connectors = new DataPortConnector[2];
connectors[0] = new DataPortConnector();
connectors[1] = new DataPortConnector();
}
public byte this[int addr]
{
get
{
int result = 0xFF;
addr &= 0xF;
switch (addr)
{
case 0x0: // port B data
result = connectors[1].Data;
break;
case 0x1: // port A data
case 0xF: // port A data without handshake
result = connectors[0].Data;
break;
case 0x2: // port B direction
result = connectors[1].Direction;
break;
case 0x3: // port A direction
result = connectors[0].Direction;
break;
case 0x4: // timer 0 lo
result = TC[0] & 0xFF;
break;
case 0x5: // timer 0 hi
result = (TC[0] & 0xFF00) >> 8;
break;
case 0x6: // timer 0 latch lo
result = TL[0] & 0xFF;
break;
case 0x7: // timer 0 latch hi
result = (TL[0] & 0xFF00) >> 8;
break;
case 0x8: // timer 1 lo
result = TC[1] & 0xFF;
break;
case 0x9: // timer 1 hi
result = (TC[1] & 0xFF00) >> 8;
break;
case 0xA: // shift register
result = SR;
break;
case 0xB: // peripheral control register
result = (CACONTROL[0] & 0x01);
result |= (CACONTROL[1] & 0x07) << 1;
result |= (CBCONTROL[0] & 0x01) << 4;
result |= (CBCONTROL[1] & 0x07) << 5;
break;
case 0xC: // auxilary control register
result = (PALE) ? 0x01 : 0x00;
result |= (PBLE) ? 0x02 : 0x00;
result |= (SRCONTROL & 0x7) << 2;
result |= (TCONTROL[0] & 0x1) << 5;
result |= (TCONTROL[1] & 0x3) << 6;
break;
case 0xD: // interrupt status register
result = ICA[1] ? 0x01 : 0x00;
result |= ICA[0] ? 0x02 : 0x00;
result |= ISR ? 0x04 : 0x00;
result |= ICB[1] ? 0x08 : 0x00;
result |= ICB[0] ? 0x10 : 0x00;
result |= IT[1] ? 0x20 : 0x00;
result |= IT[0] ? 0x40 : 0x00;
result |= IRQ ? 0x80 : 0x00;
break;
case 0xE: // interrupt control register
result = EICA[1] ? 0x01 : 0x00;
result |= EICA[0] ? 0x02 : 0x00;
result |= EISR ? 0x04 : 0x00;
result |= EICB[1] ? 0x08 : 0x00;
result |= EICB[0] ? 0x10 : 0x00;
result |= EIT[1] ? 0x20 : 0x00;
result |= EIT[0] ? 0x40 : 0x00;
result |= 0x80; // TODO: check if this is needed
break;
}
return (byte)result;
}
set
{
byte val = value;
addr &= 0xF;
switch (addr)
{
case 0x0: // port B data
connectors[1].Data = val;
break;
case 0x1: // port A data
case 0xF: // port A data without handshake
connectors[0].Data = val;
break;
case 0x2: // port B direction
connectors[1].Direction = val;
break;
case 0x3: // port A direction
connectors[0].Direction = val;
break;
case 0x4: // timer 0 lo
TC[0] &= 0xFF00;
TC[0] |= val;
break;
case 0x5: // timer 0 hi
TC[0] &= 0x00FF;
TC[0] |= (int)val << 8;
break;
case 0x6: // timer 0 latch lo
TL[0] &= 0xFF00;
TL[0] |= val;
break;
case 0x7: // timer 0 latch hi
TL[0] &= 0x00FF;
TL[0] |= (int)val << 8;
break;
case 0x8: // timer 1 lo
TC[1] &= 0xFF00;
TC[1] |= val;
break;
case 0x9: // timer 1 hi
TC[1] &= 0x00FF;
TC[1] |= (int)val << 8;
break;
case 0xA: // shift register
SR = val;
break;
case 0xB: // peripheral control register
CACONTROL[0] = (val & 0x1);
CACONTROL[1] = ((val >> 1) & 0x7);
CBCONTROL[0] = ((val >> 4) & 0x1);
CBCONTROL[1] = ((val >> 5) & 0x7);
break;
case 0xC: // auxilary control register
PALE = ((val & 0x01) != 0);
PBLE = ((val & 0x02) != 0);
SRCONTROL = (val >> 2) & 0x7;
TCONTROL[0] = (val >> 5) & 0x1;
TCONTROL[1] = (val >> 6) & 0x3;
break;
case 0xD: // interrupt status register
ICA[1] = ((val & 0x01) != 0);
ICA[0] = ((val & 0x02) != 0);
ISR = ((val & 0x04) != 0);
ICB[1] = ((val & 0x08) != 0);
ICB[0] = ((val & 0x10) != 0);
IT[1] = ((val & 0x20) != 0);
IT[0] = ((val & 0x40) != 0);
IRQ = ((val & 0x80) != 0);
break;
case 0xE: // interrupt control register
EICA[1] = ((val & 0x01) != 0);
EICA[0] = ((val & 0x02) != 0);
EISR = ((val & 0x04) != 0);
EICB[1] = ((val & 0x08) != 0);
EICB[0] = ((val & 0x10) != 0);
EIT[1] = ((val & 0x20) != 0);
EIT[0] = ((val & 0x40) != 0);
break;
}
}
}
public void Connect(DataPortConnector connector, int index)
{
connectors[index] = connector;
}
public bool PB6
{
get
{
return ((connectors[1].Latch & 0x40) != 0);
}
set
{
connectors[1].Data = (byte)((connectors[1].Latch & 0xBF) | (value ? 0x40 : 0x00));
}
}
public bool PB7
{
get
{
return ((connectors[1].Latch & 0x80) != 0);
}
set
{
connectors[1].Data = (byte)((connectors[1].Latch & 0x7F) | (value ? 0x80 : 0x00));
}
}
}
// 0x0: port B
// 0x1: port A
// 0x2: port B data direction
// 0x3: port A data direction
// 0x4: timer lo
// 0x5: timer hi
// 0x6: timer latch lo
// 0x7: timer latch hi
// 0x8: unused
// 0x9: unused
// 0xA: unused
// 0xB: timer control
// 0xC: auxilary control
// 0xD: interrupt status
// 0xE: interrupt control
// 0xF: unused
public class Via
{
private ViaRegs regs;
public Via()
{
HardReset();
}
public void Connect(DataPortConnector connector)
{
regs.Connect(connector, 1);
}
public void HardReset()
{
regs = new ViaRegs();
}
public bool IRQ
{
get
{
return regs.IRQ;
}
}
public byte Peek(int addr)
{
addr &= 0xF;
return regs[addr];
}
public void PerformCycle()
{
Tick0();
Tick1();
UpdateInterrupts();
}
public void Poke(int addr, byte val)
{
addr &= 0xF;
regs[addr] = val;
}
public byte Read(ushort addr)
{
byte result;
addr &= 0xF;
switch (addr)
{
case 0x4:
result = regs[0x4];
regs.IT[0] = false;
break;
case 0x8:
result = (byte)(regs.TC[1] & 0xFF);
regs.IT[1] = false;
break;
case 0x9:
result = (byte)(regs.TC[1] >> 8);
regs.IT[1] = false;
break;
case 0xD:
// reading this clears it
result = regs[addr];
regs[addr] = 0x00;
break;
default:
result = regs[addr];
break;
}
return result;
}
private void Tick0()
{
bool underflow = false;
switch (regs.TCONTROL[0] & 0x1)
{
case 0:
if (regs.TC[0] > 0)
{
if (--regs.TC[0] <= 0)
{
regs.IT[0] = true;
underflow = true;
}
}
break;
case 1:
if (--regs.TC[0] <= 0)
{
regs.IT[0] = true;
regs.TC[0] = regs.TL[0];
underflow = true;
}
break;
}
if (underflow)
{
if ((regs.TCONTROL[0] & 0x2) != 0)
{
regs.PB7 = !regs.PB7;
}
}
}
private void Tick1()
{
switch (regs.TCONTROL[1])
{
case 0:
break;
case 1:
break;
}
}
private void UpdateInterrupts()
{
regs.IRQ =
(regs.ICA[0] & regs.EICA[0]) |
(regs.ICA[1] & regs.EICA[1]) |
(regs.ICB[0] & regs.EICB[0]) |
(regs.ICB[1] & regs.EICB[1]) |
(regs.IT[0] & regs.EIT[0]) |
(regs.IT[1] & regs.EIT[1]) |
(regs.ISR & regs.EISR);
}
public void Write(ushort addr, byte val)
{
addr &= 0xF;
switch (addr)
{
case 0x4: // write low counter
regs[0x6] = val;
break;
case 0x5: // write high counter
regs[0x4] = regs[0x06];
regs[0x5] = val;
regs[0x7] = val;
regs.IT[0] = false;
break;
case 0x7:
regs[0x7] = val;
regs.IT[0] = false;
break;
case 0x8:
regs.TL[1] = val;
break;
case 0x9:
regs.TC[1] = ((int)val << 8) | regs.TL[1];
regs.IT[1] = false;
break;
default:
regs[addr] = val;
break;
}
}
}
}

View File

@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class VicII : IVideoProvider
{
public Memory mem;
public Region region;
public ChipSignals signal;
public VicII(ChipSignals newSignal, Region newRegion)
{
region = newRegion;
signal = newSignal;
InitPipeline(newRegion);
HardReset();
}
public int CyclesPerFrame
{
get
{
return pipelineLength * rasterLines;
}
}
public double FramesPerSecond
{
get
{
switch (region)
{
case Region.NTSC:
return (14318181d / 14d) / (double)CyclesPerFrame;
case Region.PAL:
return (17734472d / 18d) / (double)CyclesPerFrame;
}
return 0;
}
}
public void HardReset()
{
InitRegs();
InitVideoBuffer();
cycle = 0;
}
public bool Interrupt
{
get
{
return IRQ;
}
}
public void PerformCycle()
{
ExecutePipeline();
UpdateInterrupts();
signal.VicIRQ = IRQ;
}
}
}

View File

@ -1,670 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class VicII : IVideoProvider
{
private int baCount;
private int cycle;
private uint[][] pipeline;
private bool pipelineGAccess;
private int pipelineLength;
private void ExecutePipeline()
{
pipelineGAccess = false;
advanceX = true;
baCount = 0;
uint tableX = pipeline[0][cycle];
uint tableFetch = pipeline[1][cycle];
uint tableBA = pipeline[2][cycle];
uint tableOps = pipeline[3][cycle];
#region Pipeline Cycle Init
{
//rasterX = (int)tableX;
if (cycle == 0)
{
if (!rasterInterruptTriggered && RASTER == rasterInterruptLine && RASTER > 0)
{
IRST = true;
rasterInterruptTriggered = true;
}
}
else if (cycle == 1)
{
if (!rasterInterruptTriggered && RASTER == 0 && rasterInterruptLine == 0)
{
IRST = true;
rasterInterruptTriggered = true;
}
}
if (RASTER == 0x030)
displayEnabled = (displayEnabled | DEN);
if (RASTER >= 0x030 && RASTER < 0x0F8)
badline = ((YSCROLL == (RASTER & 0x07)) && displayEnabled);
else
badline = false;
if (badline)
idle = false;
for (int i = 0; i < 8; i++)
if (!sprites[i].MxYE)
sprites[i].MxYEToggle = true;
}
#endregion
#region Pipeline Fetch
{
switch (tableFetch)
{
case 0x00: PipelineFetchSpriteP(0); break;
case 0x01: PipelineFetchSpriteP(1); break;
case 0x02: PipelineFetchSpriteP(2); break;
case 0x03: PipelineFetchSpriteP(3); break;
case 0x04: PipelineFetchSpriteP(4); break;
case 0x05: PipelineFetchSpriteP(5); break;
case 0x06: PipelineFetchSpriteP(6); break;
case 0x07: PipelineFetchSpriteP(7); break;
case 0x08: PipelineFetchSpriteS(0); break;
case 0x09: PipelineFetchSpriteS(1); break;
case 0x0A: PipelineFetchSpriteS(2); break;
case 0x0B: PipelineFetchSpriteS(3); break;
case 0x0C: PipelineFetchSpriteS(4); break;
case 0x0D: PipelineFetchSpriteS(5); break;
case 0x0E: PipelineFetchSpriteS(6); break;
case 0x0F: PipelineFetchSpriteS(7); break;
case 0x10:
mem.VicRead(ECM ? (ushort)0x39FF : (ushort)0x3FFF);
break;
case 0x11:
mem.VicRead((ushort)refreshAddress);
refreshAddress = (refreshAddress - 1) & 0xFF;
refreshAddress |= 0x3F00;
break;
case 0x12:
PipelineFetchC();
break;
}
}
#endregion
#region BA
{
uint baSprite0 = tableBA & 0xF;
uint baSprite1 = (tableBA >> 4) & 0xF;
uint baSprite2 = (tableBA >> 8) & 0xF;
bool baFetch = ((tableBA >> 12) & 0x1) != 0;
if ((baSprite0 < 8 && sprites[baSprite0].MDMA) || (baSprite1 < 8 && sprites[baSprite1].MDMA) || (baSprite2 < 8 && sprites[baSprite2].MDMA) || (baFetch && badline))
baCount++;
}
#endregion
#region Operations
{
//if ((tableOps & OpChkBrdL0) != 0)
//{
//}
//if ((tableOps & OpChkBrdL1) != 0)
//{
//}
//if ((tableOps & OpChkBrdR0) != 0)
//{
//}
//if ((tableOps & OpChkBrdR1) != 0)
//{
//}
//if ((tableOps & OpChkSprCrunch) != 0)
//{
//}
if ((tableOps & OpChkSprDisp) != 0)
{
for (int i = 0; i < 8; i++)
{
VicIISprite sprite = sprites[i];
sprite.MC = sprite.MCBASE;
if (sprite.MDMA && sprite.MxY == (RASTER & 0xFF))
{
sprite.MxXEToggle = false;
}
}
}
if ((tableOps & OpChkSprDma) != 0)
{
for (int i = 0; i < 8; i++)
{
VicIISprite sprite = sprites[i];
sprite.MD = false;
if (sprite.MxE == true && sprite.MxY == (RASTER & 0xFF) && sprite.MDMA == false)
{
sprite.MDMA = true;
sprite.MCBASE = 0;
if (sprite.MxYE)
sprite.MxYEToggle = false;
}
sprite.MxXEToggle = false;
}
}
if ((tableOps & OpChkSprExp) != 0)
{
for (int i = 0; i < 8; i++)
if (sprites[i].MxYE)
sprites[i].MxYEToggle = !sprites[i].MxYEToggle;
}
if ((tableOps & OpUpdateMcBase) != 0)
{
for (int i = 0; i < 8; i++)
{
VicIISprite sprite = sprites[i];
if (sprite.MxYEToggle)
{
sprite.MCBASE += 3;
if (sprite.MxYEToggle && sprite.MCBASE == 63)
{
sprite.MDMA = false;
}
}
}
}
if ((tableOps & OpUpdateRc) != 0)
{
if (RC == 7)
{
idle = true;
VCBASE = VC;
}
if (!idle)
{
RC = (RC + 1) & 0x7;
}
}
if ((tableOps & OpUpdateVc) != 0)
{
VC = VCBASE;
VMLI = 0;
bitmapColumn = 0;
if (badline)
{
RC = 0;
}
bitmapData = 0;
colorData = 0;
characterData = 0;
}
}
#endregion
#region Render
{
for (int i = 0; i < 8; i++)
{
int pixel;
if ((pipelineGAccess) && XSCROLL == i)
{
#region Fetch G
{
int gAddress;
bitmapColumn = 0;
if (idle || VMLI >= 40 || !displayEnabled)
{
mem.VicRead(ECM ? (ushort)0x39FF : (ushort)0x3FFF);
characterData = 0;
colorData = 0;
}
else
{
characterData = characterDataBus;
colorData = colorDataBus;
}
switch (graphicsMode)
{
case 0: // 000
case 1: // 001
gAddress = (CB << 11) | (characterData << 3) | RC;
bitmapData = mem.VicRead((ushort)gAddress);
break;
case 2: // 010
case 3: // 011
gAddress = ((CB & 0x4) << 11) | (VC << 3) | RC;
bitmapData = mem.VicRead((ushort)gAddress);
break;
case 4: // 100
case 5: // 101
gAddress = (CB << 11) | ((characterData & 0x3F) << 3) | RC;
bitmapData = mem.VicRead((ushort)gAddress);
break;
case 6: // 110
case 7: // 111
gAddress = ((CB & 0x4) << 11) | ((VC & 0x33F) << 3) | RC;
bitmapData = mem.VicRead((ushort)gAddress);
break;
}
if (!idle)
{
VC++;
VMLI++;
}
}
#endregion
}
if (rasterX == borderRight)
borderOnMain = true;
if (rasterX == borderLeft)
{
if (RASTER == borderBottom)
borderOnVertical = true;
if ((RASTER == borderTop) && DEN)
borderOnVertical = false;
if (!borderOnVertical)
borderOnMain = false;
}
#region Plotter
switch (graphicsMode)
{
case 0x00:
if ((bitmapData & 0x80) != 0x00)
{
plotterData = 0x03;
plotterPixel = colorData;
}
else
{
plotterData = 0x00;
plotterPixel = BxC[0];
}
bitmapData <<= 1;
break;
case 0x01:
if ((colorData & 0x08) != 0x00)
{
if ((bitmapColumn & 0x01) == 0x00)
{
plotterData = (bitmapData >> 6) & 0x03;
bitmapData <<= 2;
}
switch (plotterData)
{
case 0x00:
plotterPixel = BxC[0];
break;
case 0x01:
plotterPixel = BxC[1];
break;
case 0x02:
plotterPixel = BxC[2];
break;
case 0x03:
plotterPixel = colorData & 0x7;
break;
}
}
else
{
if ((bitmapData & 0x80) != 0x00)
{
plotterData = 0x03;
plotterPixel = colorData;
}
else
{
plotterData = 0x00;
plotterPixel = BxC[0];
}
bitmapData <<= 1;
}
break;
case 0x02:
if ((bitmapData & 0x80) != 0x00)
{
plotterData = 0x03;
plotterPixel = characterData >> 4;
}
else
{
plotterData = 0x00;
plotterPixel = characterData & 0xF;
}
bitmapData <<= 1;
break;
case 0x03:
if ((bitmapColumn & 0x01) == 0x00)
{
plotterData = (bitmapData >> 6) & 0x03;
bitmapData <<= 2;
}
switch (plotterData)
{
case 0x00:
plotterPixel = BxC[0];
break;
case 0x01:
plotterPixel = characterData >> 4;
break;
case 0x02:
plotterPixel = characterData & 0xF;
break;
case 0x03:
plotterPixel = colorData & 0xF;
break;
}
break;
case 0x04:
if ((bitmapData & 0x80) != 0x00)
{
plotterData = 0x03;
plotterPixel = colorData;
}
else
{
plotterData = 0x00;
plotterPixel = BxC[characterData >> 6];
}
bitmapData <<= 1;
break;
case 0x05:
if ((colorData & 0x08) != 0x00)
{
if ((bitmapColumn & 0x01) == 0x00)
{
plotterData = bitmapData >> 6;
plotterPixel = 0;
bitmapData <<= 2;
}
}
else
{
plotterData = bitmapData >> 7;
plotterPixel = 0;
bitmapData <<= 1;
}
break;
case 0x06:
if ((bitmapData & 0x80) != 0x00)
{
plotterData = 0x03;
plotterPixel = 0;
}
else
{
plotterData = 0x00;
plotterPixel = 0;
}
bitmapData <<= 1;
break;
case 0x07:
if ((bitmapColumn & 0x01) == 0x00)
{
plotterData = bitmapData >> 6;
bitmapData <<= 2;
}
plotterPixel = 0;
break;
}
#endregion
#region Sprites
{
int pixelOwner = -1;
int sData = 0;
int sPixel = 0;
spriteData = 0;
spritePixel = 0;
spritePriority = false;
for (int j = 0; j < 8; j++)
{
VicIISprite sprite = sprites[j];
if (sprite.MSR == 0)
{
sprite.MD = false;
}
else if ((!sprite.MD) && (sprite.MxX == rasterX))
{
sprite.MD = true;
}
if (sprite.MD)
{
if (sprite.MxMC)
{
sData = ((sprite.MSR >> 22) & 0x3);
if ((rasterX & 0x1) != (sprite.MxX & 0x1))
{
if (!sprite.MxXE || sprite.MxXEToggle)
{
sprite.MSR <<= 2;
}
sprite.MxXEToggle = !sprite.MxXEToggle;
}
}
else
{
sData = ((sprite.MSR >> 22) & 0x2);
if (!sprite.MxXE || sprite.MxXEToggle)
{
sprite.MSR <<= 1;
}
sprite.MxXEToggle = !sprite.MxXEToggle;
}
if (!borderOnVertical)
{
if (sData != 0)
{
if (pixelOwner >= 0)
{
sprite.MxM = true;
sprites[pixelOwner].MxM = true;
}
else
{
switch (sData)
{
case 1:
sPixel = MMx[0];
break;
case 2:
sPixel = sprite.MxC;
break;
case 3:
sPixel = MMx[1];
break;
}
spritePriority = sprite.MxDP;
spritePixel = sPixel;
spriteData = sData;
pixelOwner = j;
}
if (plotterDataBuffer[plotterBufferIndex] >= 0x2)
{
sprite.MxD = true;
IMBC = true;
}
}
}
}
}
}
#endregion
#region Pixelbuffer Write
{
if (borderOnMain || borderOnVertical)
pixel = EC;
else
{
if ((spriteData == 0) || (spritePriority == true && plotterDataBuffer[plotterBufferIndex] >= 0x2))
{
pixel = plotterPixelBuffer[plotterBufferIndex];
}
else
{
pixel = spritePixel;
}
}
// write pixel to buffer
videoBuffer[videoBufferIndex++] = palette[pixel & 0xF];
if (videoBufferIndex == videoBufferSize)
videoBufferIndex = 0;
plotterPixelBuffer[plotterBufferIndex] = plotterPixel;
plotterDataBuffer[plotterBufferIndex] = plotterData;
plotterBufferIndex++;
if (plotterBufferIndex == plotterDelay)
plotterBufferIndex = 0;
bitmapColumn++;
if (advanceX)
{
rasterX++;
if (rasterX >= rasterWidth)
rasterX -= rasterWidth;
}
}
#endregion
}
}
#endregion
cycle++;
if (cycle >= pipelineLength)
{
cycle = 0;
rasterInterruptTriggered = false;
RASTER++;
if (RASTER == rasterLines)
{
RASTER = 0;
VCBASE = 0;
displayEnabled = false;
rasterX = rasterLeft;
}
badline = false;
}
signal.VicBA = (baCount > 0);
PipelineBA(signal.VicBA);
if (baCount > 0)
{
if (fetchCounter > 0)
fetchCounter--;
signal.VicAEC = (fetchCounter != 0);
}
else
{
fetchCounter = 0;
signal.VicAEC = true;
}
}
private void InitPipeline(Region region)
{
switch (region)
{
case Region.NTSC:
plotterDelay = 12;
rasterLines = 263;
rasterLeft = 0x19C;
pipeline = cycleTabNTSC;
break;
case Region.PAL:
plotterDelay = 4;
rasterLines = 312;
rasterLeft = 0x194;
pipeline = cycleTabPAL;
break;
}
pipelineLength = pipeline[0].Length;
}
private void PipelineBA(bool val)
{
if (val)
{
if (signal.VicAEC == true && fetchCounter == 0)
fetchCounter = 4;
}
else
{
fetchCounter = 0;
}
}
private void PipelineBorderCheck()
{
if ((RASTER == borderTop) && (DEN))
borderOnVertical = false;
if (RASTER == borderBottom)
borderOnVertical = true;
}
private void PipelineFetchC()
{
pipelineGAccess = true;
if (idle || VMLI >= 40)
{
characterDataBus = 0;
colorDataBus = 0;
}
else
{
if (badline)
{
int cAddress = (VM << 10) | VC;
characterDataBus = mem.VicRead((ushort)cAddress);
colorDataBus = mem.colorRam[VC];
}
else
{
characterDataBus = characterMemory[VMLI];
colorDataBus = colorMemory[VMLI];
return;
}
colorMemory[VMLI] = colorDataBus;
characterMemory[VMLI] = characterDataBus;
}
}
private void PipelineFetchSpriteP(int index)
{
VicIISprite spr = sprites[index];
ushort pointerOffset = (ushort)((VM << 10) | 0x3F8 | index);
spr.MPTR = mem.VicRead(pointerOffset);
if (spr.MDMA)
{
spr.MSR = mem.VicRead((ushort)((spr.MPTR << 6) | (spr.MC)));
spr.MC++;
}
}
private void PipelineFetchSpriteS(int index)
{
VicIISprite spr = sprites[index];
if (spr.MDMA)
{
for (int i = 0; i < 2; i++)
{
spr.MSR <<= 8;
spr.MSR |= mem.VicRead((ushort)((spr.MPTR << 6) | (spr.MC)));
spr.MC++;
}
}
}
}
}

View File

@ -1,165 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class VicII
{
private const uint OpNone = 0x000;
private const uint OpUpdateVc = 0x001;
private const uint OpChkSprCrunch = 0x002;
private const uint OpUpdateMcBase = 0x004;
private const uint OpChkBrdL1 = 0x008;
private const uint OpChkBrdL0 = 0x010;
private const uint OpChkBrdR0 = 0x020;
private const uint OpChkBrdR1 = 0x040;
private const uint OpChkSprDma = 0x080;
private const uint OpChkSprExp = 0x100;
private const uint OpUpdateRc = 0x200;
private const uint OpChkSprDisp = 0x400;
private static uint[][] cycleTabNTSC = new uint[][]
{
new uint[] // x
{
0x19C, 0x1A4, 0x1AC, 0x1B4, 0x1BC,
0x1C4, 0x1CC, 0x1D4, 0x1DC, 0x1E4,
0x1EC, 0x1F4, 0x1FC, 0x004, 0x00C,
0x014, 0x01C, 0x024, 0x02C, 0x034,
0x03C, 0x044, 0x04C, 0x054, 0x05C,
0x064, 0x06C, 0x074, 0x07C, 0x084,
0x08C, 0x094, 0x09C, 0x0A4, 0x0AC,
0x0B4, 0x0BC, 0x0C4, 0x0CC, 0x0D4,
0x0DC, 0x0E4, 0x0EC, 0x0F4, 0x0FC,
0x104, 0x10C, 0x114, 0x11C, 0x124,
0x12C, 0x134, 0x13C, 0x144, 0x14C,
0x154, 0x15C, 0x164, 0x16C, 0x174,
0x17C, 0x184, 0x184, 0x18C, 0x194
},
new uint[] // fetch (0-7=P 8-F=S 10=I 11=R 12=G/C)
{
0x0B, 0x04, 0x0C, 0x05, 0x0D,
0x06, 0x0E, 0x07, 0x0F, 0x10,
0x11, 0x11, 0x11, 0x11, 0x11,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x10, 0x10, 0x10, 0x00, 0x08,
0x01, 0x09, 0x02, 0x0A, 0x03
},
new uint[] // ba (flg/spr/spr/spr 8=none)
{
0x0845, 0x0885, 0x0856, 0x0886, 0x0867,
0x0887, 0x0887, 0x0888, 0x0888, 0x0888,
0x0888, 0x0888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x0880, 0x0880, 0x0801, 0x0881, 0x0812,
0x0882, 0x0823, 0x0883, 0x0834, 0x0884
},
new uint[] // operations
{
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpUpdateVc, OpChkSprCrunch,
OpUpdateMcBase,OpChkBrdL1, OpChkBrdL0, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpChkSprDma|OpChkBrdR0|OpChkSprExp,
OpChkSprDma|OpChkBrdR1,
OpUpdateRc,
OpChkSprDisp,
OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone
}
};
private static uint[][] cycleTabPAL = new uint[][]
{
new uint[] // x
{
0x194, 0x19C, 0x1A4, 0x1AC, 0x1B4,
0x1BC, 0x1C4, 0x1CC, 0x1D4, 0x1DC,
0x1E4, 0x1EC, 0x1F4, 0x004, 0x00C,
0x014, 0x01C, 0x024, 0x02C, 0x034,
0x03C, 0x044, 0x04C, 0x054, 0x05C,
0x064, 0x06C, 0x074, 0x07C, 0x084,
0x08C, 0x094, 0x09C, 0x0A4, 0x0AC,
0x0B4, 0x0BC, 0x0C4, 0x0CC, 0x0D4,
0x0DC, 0x0E4, 0x0EC, 0x0F4, 0x0FC,
0x104, 0x10C, 0x114, 0x11C, 0x124,
0x12C, 0x134, 0x13C, 0x144, 0x14C,
0x154, 0x15C, 0x164, 0x16C, 0x174,
0x17C, 0x184, 0x18C
},
new uint[] // fetch (0-7=P 8-F=S 10=I 11=R 12=G/C)
{
0x03, 0x0B, 0x04, 0x0C, 0x05,
0x0D, 0x06, 0x0E, 0x07, 0x0F,
0x11, 0x11, 0x11, 0x11, 0x11,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12,
0x10, 0x10, 0x00, 0x08, 0x01,
0x09, 0x02, 0x0A
},
new uint[] // ba (flg/spr/spr/spr 8=none)
{
0x0884, 0x0845, 0x0885, 0x0856, 0x0886,
0x0867, 0x0887, 0x0887, 0x0888, 0x0888,
0x0888, 0x0888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1888,
0x1888, 0x1888, 0x1888, 0x1888, 0x1880,
0x0880, 0x0801, 0x0881, 0x0812, 0x0882,
0x0823, 0x0883, 0x0834
},
new uint[] // operations
{
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpUpdateVc, OpChkSprCrunch,
OpUpdateMcBase,OpChkBrdL1, OpChkBrdL0, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpNone,
OpNone, OpNone, OpNone, OpNone, OpChkSprDma,
OpChkSprDma|OpChkBrdR0|OpChkSprExp,
OpChkBrdR1,
OpUpdateRc|OpChkSprDisp,
OpNone, OpNone, OpNone, OpNone, OpNone
}
};
}
}

View File

@ -1,614 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class VicII : IVideoProvider
{
private class VicIISprite
{
// internal regs
public int MC;
public int MCBASE;
public bool MD;
public bool MDMA;
public int MPTR;
public int MSR;
public bool MxXEToggle;
public bool MxYEToggle;
// external regs
public int MxC; // sprite color
public bool MxD; // sprite-data collision
public bool MxDP; // sprite priority
public bool MxE; // sprite enabled
public bool MxM; // sprite-sprite collision
public bool MxMC; // sprite multicolor
public int MxX; // sprite X coordinate
public bool MxXE; // sprite X expansion
public int MxY; // sprite Y coordinate
public bool MxYE; // sprite Y expansion
}
// internal regs
private int RC;
private int VC;
private int VCBASE;
private int VMLI;
// external regs
private bool BMM; // bitmap mode
private int[] BxC = new int[4]; // background colors
private int CB; // character bitmap offset
private bool CSEL; // column select
private bool DEN; // display enabled
private int EC; // border color
private bool ECM; // extra color mode
private bool ELP; // enable lightpen interrupt
private bool EMBC; // enable sprite-data interrupt
private bool EMMC; // enable sprite-sprite interrupt
private bool ERST; // enable raster line interrupt
private bool ILP; // light pen interrupt active
private bool IMBC; // sprite-data interrupt active
private bool IMMC; // sprite-sprite interrupt active
private bool IRQ; // interrupt was triggered
private bool IRST; // raster line interrupt active
private int LPX; // lightpen X coordinate
private int LPY; // lightpen Y coordinate
private bool MCM; // multicolor mode
private int[] MMx = new int[2]; // sprite extra color
private int RASTER; // current raster line
private bool RES; // reset bit (does nothing in this version of the VIC)
private bool RSEL; // row select
private int VM; // video memory offset
private int XSCROLL; // X scroll position
private int YSCROLL; // Y scroll position
private int spriteData;
private int spritePixel;
private bool spritePriority;
private VicIISprite[] sprites;
private bool advanceX;
private bool badline;
private int bitmapColumn;
private byte bitmapData;
private int borderBottom;
private int borderLeft;
private bool borderOnMain;
private bool borderOnVertical;
private int borderRight;
private int borderTop;
private bool centerEnabled;
private byte characterData;
private byte characterDataBus;
private byte[] characterMemory;
private byte colorData;
private byte colorDataBus;
private byte[] colorMemory;
private bool displayEnabled;
private int fetchCounter;
private int graphicsMode;
private bool idle;
private int plotterBufferIndex;
private int plotterData;
private int[] plotterDataBuffer;
private int plotterDelay;
private int plotterPixel;
private int[] plotterPixelBuffer;
private int rasterInterruptLine;
private bool rasterInterruptTriggered;
private int rasterLeft;
private int rasterLines;
private int rasterWidth;
private int rasterX;
private int refreshAddress;
private void InitRegs()
{
// init sprites
sprites = new VicIISprite[8];
for (int i = 0; i < 8; i++)
sprites[i] = new VicIISprite();
// init buffers
plotterDataBuffer = new int[plotterDelay];
plotterPixelBuffer = new int[plotterDelay];
characterMemory = new byte[40];
colorMemory = new byte[40];
// init raster data
rasterX = rasterLeft;
rasterWidth = pipelineLength * 8;
// reset regs
for (int i = 0; i < 0x40; i++)
this[i] = 0x00;
// power on state
this[0x16] = 0xC0;
this[0x18] = 0x01;
this[0x19] = 0x71;
this[0x1A] = 0xF0;
RC = 7;
refreshAddress = 0x3FFF;
idle = true;
}
private 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 = sprites[addr >> 1].MxX;
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0x09:
case 0x0B:
case 0x0D:
case 0x0F:
result = sprites[addr >> 1].MxY;
break;
case 0x10:
result = ((sprites[0].MxX & 0x100) != 0) ? 0x01 : 0x00;
result |= ((sprites[1].MxX & 0x100) != 0) ? 0x02 : 0x00;
result |= ((sprites[2].MxX & 0x100) != 0) ? 0x04 : 0x00;
result |= ((sprites[3].MxX & 0x100) != 0) ? 0x08 : 0x00;
result |= ((sprites[4].MxX & 0x100) != 0) ? 0x10 : 0x00;
result |= ((sprites[5].MxX & 0x100) != 0) ? 0x20 : 0x00;
result |= ((sprites[6].MxX & 0x100) != 0) ? 0x40 : 0x00;
result |= ((sprites[7].MxX & 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 = (sprites[0].MxE ? 0x01 : 0x00);
result |= (sprites[1].MxE ? 0x02 : 0x00);
result |= (sprites[2].MxE ? 0x04 : 0x00);
result |= (sprites[3].MxE ? 0x08 : 0x00);
result |= (sprites[4].MxE ? 0x10 : 0x00);
result |= (sprites[5].MxE ? 0x20 : 0x00);
result |= (sprites[6].MxE ? 0x40 : 0x00);
result |= (sprites[7].MxE ? 0x80 : 0x00);
break;
case 0x16:
result &= 0xC0;
result |= XSCROLL & 0x07;
result |= (CSEL ? 0x08 : 0x00);
result |= (MCM ? 0x10 : 0x00);
result |= (RES ? 0x20 : 0x00);
break;
case 0x17:
result = (sprites[0].MxYE ? 0x01 : 0x00);
result |= (sprites[1].MxYE ? 0x02 : 0x00);
result |= (sprites[2].MxYE ? 0x04 : 0x00);
result |= (sprites[3].MxYE ? 0x08 : 0x00);
result |= (sprites[4].MxYE ? 0x10 : 0x00);
result |= (sprites[5].MxYE ? 0x20 : 0x00);
result |= (sprites[6].MxYE ? 0x40 : 0x00);
result |= (sprites[7].MxYE ? 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 = (sprites[0].MxDP ? 0x01 : 0x00);
result |= (sprites[1].MxDP ? 0x02 : 0x00);
result |= (sprites[2].MxDP ? 0x04 : 0x00);
result |= (sprites[3].MxDP ? 0x08 : 0x00);
result |= (sprites[4].MxDP ? 0x10 : 0x00);
result |= (sprites[5].MxDP ? 0x20 : 0x00);
result |= (sprites[6].MxDP ? 0x40 : 0x00);
result |= (sprites[7].MxDP ? 0x80 : 0x00);
break;
case 0x1C:
result = (sprites[0].MxMC ? 0x01 : 0x00);
result |= (sprites[1].MxMC ? 0x02 : 0x00);
result |= (sprites[2].MxMC ? 0x04 : 0x00);
result |= (sprites[3].MxMC ? 0x08 : 0x00);
result |= (sprites[4].MxMC ? 0x10 : 0x00);
result |= (sprites[5].MxMC ? 0x20 : 0x00);
result |= (sprites[6].MxMC ? 0x40 : 0x00);
result |= (sprites[7].MxMC ? 0x80 : 0x00);
break;
case 0x1D:
result = (sprites[0].MxXE ? 0x01 : 0x00);
result |= (sprites[1].MxXE ? 0x02 : 0x00);
result |= (sprites[2].MxXE ? 0x04 : 0x00);
result |= (sprites[3].MxXE ? 0x08 : 0x00);
result |= (sprites[4].MxXE ? 0x10 : 0x00);
result |= (sprites[5].MxXE ? 0x20 : 0x00);
result |= (sprites[6].MxXE ? 0x40 : 0x00);
result |= (sprites[7].MxXE ? 0x80 : 0x00);
break;
case 0x1E:
result = (sprites[0].MxM ? 0x01 : 0x00);
result |= (sprites[1].MxM ? 0x02 : 0x00);
result |= (sprites[2].MxM ? 0x04 : 0x00);
result |= (sprites[3].MxM ? 0x08 : 0x00);
result |= (sprites[4].MxM ? 0x10 : 0x00);
result |= (sprites[5].MxM ? 0x20 : 0x00);
result |= (sprites[6].MxM ? 0x40 : 0x00);
result |= (sprites[7].MxM ? 0x80 : 0x00);
break;
case 0x1F:
result = (sprites[0].MxD ? 0x01 : 0x00);
result |= (sprites[1].MxD ? 0x02 : 0x00);
result |= (sprites[2].MxD ? 0x04 : 0x00);
result |= (sprites[3].MxD ? 0x08 : 0x00);
result |= (sprites[4].MxD ? 0x10 : 0x00);
result |= (sprites[5].MxD ? 0x20 : 0x00);
result |= (sprites[6].MxD ? 0x40 : 0x00);
result |= (sprites[7].MxD ? 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 |= sprites[addr - 0x27].MxC & 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;
sprites[index].MxX &= 0x100;
sprites[index].MxX |= (val & 0xFF);
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0x09:
case 0x0B:
case 0x0D:
case 0x0F:
index = addr >> 1;
sprites[index].MxY &= 0x100;
sprites[index].MxY |= (val & 0xFF);
break;
case 0x10:
sprites[0].MxX = (sprites[0].MxX & 0xFF) | ((val & 0x01) << 8);
sprites[1].MxX = (sprites[1].MxX & 0xFF) | ((val & 0x02) << 7);
sprites[2].MxX = (sprites[2].MxX & 0xFF) | ((val & 0x04) << 6);
sprites[3].MxX = (sprites[3].MxX & 0xFF) | ((val & 0x08) << 5);
sprites[4].MxX = (sprites[4].MxX & 0xFF) | ((val & 0x10) << 4);
sprites[5].MxX = (sprites[5].MxX & 0xFF) | ((val & 0x20) << 3);
sprites[6].MxX = (sprites[6].MxX & 0xFF) | ((val & 0x40) << 2);
sprites[7].MxX = (sprites[7].MxX & 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:
sprites[0].MxE = ((val & 0x01) != 0x00);
sprites[1].MxE = ((val & 0x02) != 0x00);
sprites[2].MxE = ((val & 0x04) != 0x00);
sprites[3].MxE = ((val & 0x08) != 0x00);
sprites[4].MxE = ((val & 0x10) != 0x00);
sprites[5].MxE = ((val & 0x20) != 0x00);
sprites[6].MxE = ((val & 0x40) != 0x00);
sprites[7].MxE = ((val & 0x80) != 0x00);
break;
case 0x16:
XSCROLL = (val & 0x07);
CSEL = ((val & 0x08) != 0x00);
MCM = ((val & 0x10) != 0x00);
RES = ((val & 0x20) != 0x00);
break;
case 0x17:
sprites[0].MxYE = ((val & 0x01) != 0x00);
sprites[1].MxYE = ((val & 0x02) != 0x00);
sprites[2].MxYE = ((val & 0x04) != 0x00);
sprites[3].MxYE = ((val & 0x08) != 0x00);
sprites[4].MxYE = ((val & 0x10) != 0x00);
sprites[5].MxYE = ((val & 0x20) != 0x00);
sprites[6].MxYE = ((val & 0x40) != 0x00);
sprites[7].MxYE = ((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);
break;
case 0x1A:
ERST = ((val & 0x01) != 0x00);
EMBC = ((val & 0x02) != 0x00);
EMMC = ((val & 0x04) != 0x00);
ELP = ((val & 0x08) != 0x00);
break;
case 0x1B:
sprites[0].MxDP = ((val & 0x01) != 0x00);
sprites[1].MxDP = ((val & 0x02) != 0x00);
sprites[2].MxDP = ((val & 0x04) != 0x00);
sprites[3].MxDP = ((val & 0x08) != 0x00);
sprites[4].MxDP = ((val & 0x10) != 0x00);
sprites[5].MxDP = ((val & 0x20) != 0x00);
sprites[6].MxDP = ((val & 0x40) != 0x00);
sprites[7].MxDP = ((val & 0x80) != 0x00);
break;
case 0x1C:
sprites[0].MxMC = ((val & 0x01) != 0x00);
sprites[1].MxMC = ((val & 0x02) != 0x00);
sprites[2].MxMC = ((val & 0x04) != 0x00);
sprites[3].MxMC = ((val & 0x08) != 0x00);
sprites[4].MxMC = ((val & 0x10) != 0x00);
sprites[5].MxMC = ((val & 0x20) != 0x00);
sprites[6].MxMC = ((val & 0x40) != 0x00);
sprites[7].MxMC = ((val & 0x80) != 0x00);
break;
case 0x1D:
sprites[0].MxXE = ((val & 0x01) != 0x00);
sprites[1].MxXE = ((val & 0x02) != 0x00);
sprites[2].MxXE = ((val & 0x04) != 0x00);
sprites[3].MxXE = ((val & 0x08) != 0x00);
sprites[4].MxXE = ((val & 0x10) != 0x00);
sprites[5].MxXE = ((val & 0x20) != 0x00);
sprites[6].MxXE = ((val & 0x40) != 0x00);
sprites[7].MxXE = ((val & 0x80) != 0x00);
break;
case 0x1E:
sprites[0].MxM = ((val & 0x01) != 0x00);
sprites[1].MxM = ((val & 0x02) != 0x00);
sprites[2].MxM = ((val & 0x04) != 0x00);
sprites[3].MxM = ((val & 0x08) != 0x00);
sprites[4].MxM = ((val & 0x10) != 0x00);
sprites[5].MxM = ((val & 0x20) != 0x00);
sprites[6].MxM = ((val & 0x40) != 0x00);
sprites[7].MxM = ((val & 0x80) != 0x00);
break;
case 0x1F:
sprites[0].MxD = ((val & 0x01) != 0x00);
sprites[1].MxD = ((val & 0x02) != 0x00);
sprites[2].MxD = ((val & 0x04) != 0x00);
sprites[3].MxD = ((val & 0x08) != 0x00);
sprites[4].MxD = ((val & 0x10) != 0x00);
sprites[5].MxD = ((val & 0x20) != 0x00);
sprites[6].MxD = ((val & 0x40) != 0x00);
sprites[7].MxD = ((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:
sprites[addr - 0x27].MxC = val & 0x0F;
break;
}
}
}
public byte Peek(int addr)
{
return this[addr & 0x3F];
}
public void Poke(int addr, byte val)
{
this[addr & 0x3F] = val;
}
public byte Read(ushort addr)
{
byte result = 0;
addr &= 0x3F;
switch (addr)
{
case 0x1E:
// clear after read
result = this[addr];
this[addr] = 0x00;
IMMC = false;
UpdateInterrupts();
break;
case 0x1F:
// clear after read
result = this[addr];
this[addr] = 0x00;
IMBC = false;
UpdateInterrupts();
break;
default:
result = this[addr];
break;
}
return result;
}
private void UpdateBorder()
{
borderTop = RSEL ? 0x033 : 0x037;
borderBottom = RSEL ? 0x0FB : 0x0F7;
borderLeft = CSEL ? 0x018 : 0x01F;
borderRight = CSEL ? 0x158 : 0x14F;
}
private void UpdateInterrupts()
{
IRQ = ((IRST & ERST) || (IMMC & EMMC) || (IMBC & EMBC) || (ILP & ELP));
}
private void UpdatePlotter()
{
graphicsMode = (ECM ? 0x04 : 0x00) | (BMM ? 0x02 : 0x00) | (MCM ? 0x01 : 0x00);
}
public void Write(ushort addr, byte val)
{
addr &= 0x3F;
switch (addr)
{
case 0x11:
rasterInterruptTriggered = false;
rasterInterruptLine &= 0xFF;
rasterInterruptLine |= (val & 0x80) << 1;
// raster upper bit can't be changed, save and restore the value
val &= 0x7F;
val |= (byte)(this[addr] & 0x80);
this[addr] = val;
UpdateBorder();
UpdatePlotter();
break;
case 0x12:
// raster interrupt lower 8 bits
rasterInterruptTriggered = false;
rasterInterruptLine &= 0x100;
rasterInterruptLine |= (val & 0xFF);
break;
case 0x16:
this[addr] = val;
UpdateBorder();
UpdatePlotter();
break;
case 0x19:
// only allow clearing of these flags
if ((val & 0x01) != 0x00)
IRST = false;
if ((val & 0x02) != 0x00)
IMBC = false;
if ((val & 0x04) != 0x00)
IMMC = false;
if ((val & 0x08) != 0x00)
ILP = false;
UpdateInterrupts();
break;
case 0x1E:
case 0x1F:
// can't write to these regs
break;
default:
this[addr] = val;
break;
}
}
}
}

View File

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class VicII : IVideoProvider
{
private int[] videoBuffer;
private int videoBufferHeight;
private int videoBufferIndex;
private int videoBufferSize;
private int videoBufferWidth;
// palette
private static int[] palette =
{
Colors.ARGB(0x00, 0x00, 0x00),
Colors.ARGB(0xFF, 0xFF, 0xFF),
Colors.ARGB(0x68, 0x37, 0x2B),
Colors.ARGB(0x70, 0xA4, 0xB2),
Colors.ARGB(0x6F, 0x3D, 0x86),
Colors.ARGB(0x58, 0x8D, 0x43),
Colors.ARGB(0x35, 0x28, 0x79),
Colors.ARGB(0xB8, 0xC7, 0x6F),
Colors.ARGB(0x6F, 0x4F, 0x25),
Colors.ARGB(0x43, 0x39, 0x00),
Colors.ARGB(0x9A, 0x67, 0x59),
Colors.ARGB(0x44, 0x44, 0x44),
Colors.ARGB(0x6C, 0x6C, 0x6C),
Colors.ARGB(0x9A, 0xD2, 0x84),
Colors.ARGB(0x6C, 0x5E, 0xB5),
Colors.ARGB(0x95, 0x95, 0x95)
};
public int BackgroundColor
{
get { return -16777216; } //FF000000
}
public int BufferHeight
{
get { return videoBufferHeight; }
}
public int BufferWidth
{
get { return videoBufferWidth; }
}
public int[] GetVideoBuffer()
{
return videoBuffer;
}
private void InitVideoBuffer()
{
videoBufferIndex = 0;
videoBufferWidth = pipelineLength * 8;
videoBufferHeight = rasterLines;
videoBufferSize = videoBufferWidth * videoBufferHeight;
videoBuffer = new int[videoBufferSize];
}
public int VirtualWidth
{
get { return videoBufferWidth; }
}
}
}

View File

@ -1,110 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class VicII : IVideoProvider
{
public void SyncState(Serializer ser)
{
// internal
ser.Sync("RC", ref RC);
ser.Sync("VC", ref VC);
ser.Sync("VCBASE", ref VCBASE);
ser.Sync("VMLI", ref VMLI);
// external
ser.Sync("BMM", ref BMM);
ser.Sync("BxC", ref BxC, false);
ser.Sync("CB", ref CB);
ser.Sync("CSEL", ref CSEL);
ser.Sync("DEN", ref DEN);
ser.Sync("EC", ref EC);
ser.Sync("ECM", ref ECM);
ser.Sync("ELP", ref ELP);
ser.Sync("EMBC", ref EMBC);
ser.Sync("EMMC", ref EMMC);
ser.Sync("ERST", ref ERST);
ser.Sync("ILP", ref ILP);
ser.Sync("IMBC", ref IMBC);
ser.Sync("IMMC", ref IMMC);
ser.Sync("IRQ", ref IRQ);
ser.Sync("IRST", ref IRST);
ser.Sync("LPX", ref LPX);
ser.Sync("LPY", ref LPY);
ser.Sync("MCM", ref MCM);
ser.Sync("MMx", ref MMx, false);
ser.Sync("RASTER", ref RASTER);
ser.Sync("RES", ref RES);
ser.Sync("RSEL", ref RSEL);
ser.Sync("VM", ref VM);
ser.Sync("XSCROLL", ref XSCROLL);
ser.Sync("YSCROLL", ref YSCROLL);
// state
ser.Sync("ADVANCEX", ref advanceX);
ser.Sync("BADLINE", ref badline);
ser.Sync("BITMAPCOLUMN", ref bitmapColumn);
ser.Sync("BITMAPDATA", ref bitmapData);
ser.Sync("BORDERONMAIN", ref borderOnMain);
ser.Sync("BORDERONVERTICAL", ref borderOnVertical);
ser.Sync("CENTERENABLED", ref centerEnabled);
ser.Sync("CHARACTERDATA", ref characterData);
ser.Sync("CHARACTERDATABUS", ref characterDataBus);
ser.Sync("CHARMEM", ref characterMemory, false);
ser.Sync("COLORDATA", ref colorData);
ser.Sync("COLORDATABUS", ref colorDataBus);
ser.Sync("COLORMEM", ref colorMemory, false);
ser.Sync("DISPLAYENABLED", ref displayEnabled);
ser.Sync("FETCHCOUNTER", ref fetchCounter);
ser.Sync("IDLE", ref idle);
ser.Sync("PLOTTERBUFFERINDEX", ref plotterBufferIndex);
ser.Sync("PLOTTERDATA", ref plotterData);
ser.Sync("PLOTTERDATABUFFER", ref plotterDataBuffer, false);
ser.Sync("PLOTTERDELAY", ref plotterDelay);
ser.Sync("PLOTTERPIXEL", ref plotterPixel);
ser.Sync("PLOTTERPIXELBUFFER", ref plotterPixelBuffer, false);
ser.Sync("RASTERINTERRUPTLINE", ref rasterInterruptLine);
ser.Sync("RASTERINTERRUPTTRIGGERED", ref rasterInterruptTriggered);
ser.Sync("RASTERX", ref rasterX);
ser.Sync("REFRESHADDRESS", ref refreshAddress);
// pipeline
ser.Sync("CYCLE", ref cycle);
ser.Sync("PIPELINEGACCESS", ref pipelineGAccess);
// sprites
for (int i = 0; i < 8; i++)
{
string iTag = i.ToString();
ser.Sync("MC" + iTag, ref sprites[i].MC);
ser.Sync("MCBASE" + iTag, ref sprites[i].MCBASE);
ser.Sync("MD" + iTag, ref sprites[i].MD);
ser.Sync("MDMA" + iTag, ref sprites[i].MDMA);
ser.Sync("MPTR" + iTag, ref sprites[i].MPTR);
ser.Sync("MSR" + iTag, ref sprites[i].MSR);
ser.Sync("MxXEToggle" + iTag, ref sprites[i].MxXEToggle);
ser.Sync("MxYEToggle" + iTag, ref sprites[i].MxYEToggle);
ser.Sync("MxC" + iTag, ref sprites[i].MxC);
ser.Sync("MxD" + iTag, ref sprites[i].MxD);
ser.Sync("MxDP" + iTag, ref sprites[i].MxDP);
ser.Sync("MxE" + iTag, ref sprites[i].MxE);
ser.Sync("MxM" + iTag, ref sprites[i].MxM);
ser.Sync("MxMC" + iTag, ref sprites[i].MxMC);
ser.Sync("MxX" + iTag, ref sprites[i].MxX);
ser.Sync("MxXE" + iTag, ref sprites[i].MxXE);
ser.Sync("MxY" + iTag, ref sprites[i].MxY);
ser.Sync("MxYE" + iTag, ref sprites[i].MxYE);
}
if (ser.IsReader)
{
UpdateBorder();
UpdatePlotter();
}
}
}
}