diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index e245a6da57..c8de8c4e79 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -78,6 +78,11 @@
+
+
+
+
+
diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs
index bde26b7f3b..a082a39812 100644
--- a/BizHawk.Emulation/Computers/Commodore64/C64.core.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/C64.core.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Text;
using BizHawk.Emulation.CPUs.M6502;
@@ -8,25 +9,76 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
public partial class C64 : IEmulator
{
- public byte[] rom;
+ // source
+ public Cartridge cart;
+ public bool cartInserted;
+ public byte[] inputFile;
+
+ // chipset
+ public Cia cia1;
+ public Cia cia2;
public MOS6502X cpu;
+ public MemoryBus mem;
+ public Sid sid;
+ public VicII vic;
+ public VicSignals vicSignal;
private void HardReset()
{
cpu = new MOS6502X();
cpu.ReadMemory = ReadMemory;
cpu.WriteMemory = WriteMemory;
- cpu.DummyReadMemory = ReadMemory;
+ cpu.DummyReadMemory = PeekMemory;
+
+ // initialize cia timers
+ cia1 = new Cia();
+ cia2 = new Cia();
+
+ // initialize vic
+ vicSignal = new VicSignals();
+ vic = new VicII(vicSignal, VicIIMode.NTSC);
+
+ // initialize sid
+ sid = new Sid();
+
+ // initialize memory (this must be done AFTER all other chips are initialized)
+ string romPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "C64Kernal");
+ mem = new MemoryBus(romPath, vic, sid, cia1, cia2);
+
+ // initialize media
+ Cartridge cart = new Cartridge(inputFile);
+ if (cart.valid)
+ {
+ mem.ApplyCartridge(cart);
+ }
+
+ // initialize cpu (hard reset vector)
+ cpu.PC = (ushort)(ReadMemory(0xFFFC) + (ReadMemory(0xFFFD) << 8));
}
+ public byte PeekMemory(ushort addr)
+ {
+ return mem.Peek(addr);
+ }
+
+ public byte PeekMemoryInt(int addr)
+ {
+ return mem.Peek((ushort)(addr & 0xFFFF));
+ }
+
+ public void PokeMemoryInt(int addr, byte val)
+ {
+ // todo
+ }
+
public byte ReadMemory(ushort addr)
{
- return 0;
+ return mem.Read(addr);
}
public void WriteMemory(ushort addr, byte value)
{
- //TODO
+ mem.Write(addr, value);
}
}
}
diff --git a/BizHawk.Emulation/Computers/Commodore64/C64.cs b/BizHawk.Emulation/Computers/Commodore64/C64.cs
index 3abaf0881a..f1571fc4e1 100644
--- a/BizHawk.Emulation/Computers/Commodore64/C64.cs
+++ b/BizHawk.Emulation/Computers/Commodore64/C64.cs
@@ -11,11 +11,12 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
public C64(GameInfo game, byte[] rom, string romextension)
{
- videoProvider = new MyVideoProvider(this);
- SetupMemoryDomains();
- CoreOutputComm = new CoreOutputComm();
- CoreInputComm = new CoreInputComm();
- HardReset();
+ inputFile = rom;
+ SetupMemoryDomains();
+ CoreOutputComm = new CoreOutputComm();
+ CoreInputComm = new CoreInputComm();
+ HardReset();
+ videoProvider = new MyVideoProvider(vic);
}
public string SystemId { get { return "C64"; } }
@@ -45,7 +46,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
/*TODO*/
- public int[] frameBuffer = new int[256 * 192]; //TODO
public ISyncSoundProvider SyncSoundProvider { get { return null; } } //TODO
public bool StartAsyncSound() { return true; } //TODO
public void EndAsyncSound() { } //TODO
@@ -58,12 +58,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
public IController Controller { get; set; }
public static readonly ControllerDefinition Atari7800ControllerDefinition = new ControllerDefinition
{
- Name = "Atari 7800 Basic Controller", //TODO
+ Name = "Commodore 64 Controller", //TODO
BoolButtons =
{
- "P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button",
- "P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button",
- "Reset", "Select"
+ "P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button",
+ "P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button"
}
};
@@ -89,8 +88,23 @@ namespace BizHawk.Emulation.Computers.Commodore64
_frame++;
_islag = true;
- //TODO
- //Do stuff here
+ int cyclesPerSecond = (14318181 / 14 / 60);
+
+ for (int i = 0; i < cyclesPerSecond; i++)
+ {
+ if (vicSignal.Interrupt)
+ {
+ cpu.IRQ = true;
+ }
+ if (vicSignal.AllowCpu)
+ {
+ cpu.ExecuteOne();
+ }
+ vic.PerformCycle();
+ sid.PerformCycle();
+ cia1.PerformCycle();
+ cia2.PerformCycle();
+ }
if (_islag)
{
@@ -104,27 +118,31 @@ namespace BizHawk.Emulation.Computers.Commodore64
private MySoundProvider soundProvider;
private MyVideoProvider videoProvider;
+
class MyVideoProvider : IVideoProvider
{
- public int top = 0; //TODO
- public int bottom = 262; //TODO
- public int left = 0; //TODO
- public int right = 320; //TODO
+ public int top;
+ public int bottom;
+ public int left;
+ public int right;
- C64 emu;
- public MyVideoProvider(C64 emu)
+ VicII vic;
+ public MyVideoProvider(VicII vic)
{
- this.emu = emu;
+ this.vic = vic;
+
+ buffer = new int[vic.rasterWidth * vic.rasterTotalLines];
+ top = 0;
+ bottom = vic.rasterTotalLines-1;
+ left = 0;
+ right = vic.rasterWidth-1;
}
- int[] buffer = new int[262 * 320];
+ int[] buffer;
public void FillFrameBuffer()
{
- for (int i = 0; i < buffer.Length; i++)
- {
- buffer[i] = 0; //TODO
- }
+ Array.Copy(vic.buffer, buffer, buffer.Length);
}
public int[] GetVideoBuffer()
@@ -141,7 +159,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
private void SetupMemoryDomains()
{
var domains = new List(1);
- domains.Add(new MemoryDomain("Main RAM", 1, Endian.Little, addr => 0xFF, null)); //TODO
+ domains.Add(new MemoryDomain("RAM", 0x10000, Endian.Little, new Func(PeekMemoryInt), new Action(PokeMemoryInt))); //TODO
memoryDomains = domains.AsReadOnly();
}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Cartridge.cs b/BizHawk.Emulation/Computers/Commodore64/Cartridge.cs
new file mode 100644
index 0000000000..f96df5a218
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/Cartridge.cs
@@ -0,0 +1,140 @@
+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 class Cartridge
+ {
+ public List chips;
+ public bool exRomPin;
+ public bool gamePin;
+ public int type;
+ public bool valid;
+ public int version;
+
+ public Cartridge(byte[] rom)
+ {
+ chips = new List();
+
+ 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();
+
+ 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);
+ }
+ }
+ }
+
+ public byte Read(ushort addr)
+ {
+ CartridgeChip currentChip = chips[0];
+ return currentChip.data[addr & currentChip.romMask];
+ }
+
+ public void Write(ushort addr, byte val)
+ {
+ // can't write to rom but we can process DE00/DF00 here
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Cia.cs b/BizHawk.Emulation/Computers/Commodore64/Cia.cs
new file mode 100644
index 0000000000..7139809590
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/Cia.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64
+{
+ public class Cia
+ {
+ public int cycles;
+ public byte[] regs;
+
+ public Cia()
+ {
+ regs = new byte[0x10];
+ }
+
+ public void PerformCycle()
+ {
+ unchecked
+ {
+ cycles++;
+ }
+ }
+
+ public byte Read(ushort addr)
+ {
+ byte result = 0;
+
+ switch (addr & 0x0F)
+ {
+ case 0x00:
+ break;
+ case 0x01:
+ break;
+ case 0x02:
+ break;
+ case 0x03:
+ break;
+ case 0x04:
+ break;
+ case 0x05:
+ break;
+ case 0x06:
+ break;
+ case 0x07:
+ break;
+ case 0x08:
+ break;
+ case 0x09:
+ break;
+ case 0x0A:
+ break;
+ case 0x0B:
+ break;
+ case 0x0C:
+ break;
+ case 0x0D:
+ break;
+ case 0x0E:
+ break;
+ case 0x0F:
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ public void Write(ushort addr, byte val)
+ {
+ switch (addr & 0x0F)
+ {
+ case 0x00:
+ break;
+ case 0x01:
+ break;
+ case 0x02:
+ break;
+ case 0x03:
+ break;
+ case 0x04:
+ break;
+ case 0x05:
+ break;
+ case 0x06:
+ break;
+ case 0x07:
+ break;
+ case 0x08:
+ break;
+ case 0x09:
+ break;
+ case 0x0A:
+ break;
+ case 0x0B:
+ break;
+ case 0x0C:
+ break;
+ case 0x0D:
+ break;
+ case 0x0E:
+ break;
+ case 0x0F:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/MemBus.cs b/BizHawk.Emulation/Computers/Commodore64/MemBus.cs
new file mode 100644
index 0000000000..b8d02d6501
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/MemBus.cs
@@ -0,0 +1,451 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64
+{
+ public enum MemoryBusDesignation
+ {
+ Disabled,
+ RAM,
+ Basic,
+ Kernal,
+ IO,
+ Character,
+ ROMLo,
+ ROMHi,
+ Vic,
+ Sid,
+ ColorRam,
+ Cia1,
+ Cia2,
+ Expansion1,
+ Expansion2
+ }
+
+ public class MemoryBusLayout
+ {
+ public MemoryBusDesignation Mem1000 = MemoryBusDesignation.RAM;
+ public MemoryBusDesignation Mem8000 = MemoryBusDesignation.RAM;
+ public MemoryBusDesignation MemA000 = MemoryBusDesignation.RAM;
+ public MemoryBusDesignation MemC000 = MemoryBusDesignation.RAM;
+ public MemoryBusDesignation MemD000 = MemoryBusDesignation.RAM;
+ public MemoryBusDesignation MemE000 = MemoryBusDesignation.RAM;
+ }
+
+ public class MemoryBus
+ {
+ // chips
+ public Cia cia1;
+ public Cia cia2;
+ public VicII vic;
+ public Sid sid;
+
+ // storage
+ public Cartridge cart;
+ public bool cartInserted = false;
+
+ // roms
+ public byte[] basicRom;
+ public byte[] charRom;
+ public bool exRomPin = true;
+ public bool gamePin = true;
+ public byte[] kernalRom;
+ public MemoryBusLayout layout;
+
+ // ram
+ public byte[] colorRam;
+ public byte[] ram;
+
+ // registers
+ public byte busData;
+ public byte cpu00; // register $00
+ public byte cpu01; // register $01
+ public bool readTrigger = true;
+ public bool writeTrigger = true;
+
+ public MemoryBus(string sourceFolder, VicII newVic, Sid newSid, Cia newCia1, Cia newCia2)
+ {
+ ram = new byte[0x10000];
+ WipeMemory();
+
+ string basicFile = "basic";
+ string charFile = "chargen";
+ string kernalFile = "kernal";
+
+ basicRom = File.ReadAllBytes(Path.Combine(sourceFolder, basicFile));
+ charRom = File.ReadAllBytes(Path.Combine(sourceFolder, charFile));
+ kernalRom = File.ReadAllBytes(Path.Combine(sourceFolder, kernalFile));
+ colorRam = new byte[0x1000];
+
+ vic = newVic;
+ sid = newSid;
+ cia1 = newCia1;
+ cia2 = newCia2;
+ cpu00 = 0x2F;
+ cpu01 = 0x37;
+
+ layout = new MemoryBusLayout();
+ UpdateLayout();
+ }
+
+ public void ApplyCartridge(Cartridge newCart)
+ {
+ cart = newCart;
+ cartInserted = true;
+ exRomPin = cart.exRomPin;
+ gamePin = cart.gamePin;
+ UpdateLayout();
+ }
+
+ public MemoryBusDesignation GetDesignation(ushort addr)
+ {
+ MemoryBusDesignation result;
+
+ if (addr < 0x1000)
+ {
+ result = MemoryBusDesignation.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 == MemoryBusDesignation.IO)
+ {
+ addr &= 0x0FFF;
+ if (addr < 0x0400)
+ {
+ result = MemoryBusDesignation.Vic;
+ }
+ else if (addr < 0x0800)
+ {
+ result = MemoryBusDesignation.Sid;
+ }
+ else if (addr < 0x0C00)
+ {
+ result = MemoryBusDesignation.ColorRam;
+ }
+ else if (addr < 0x0D00)
+ {
+ result = MemoryBusDesignation.Cia1;
+ }
+ else if (addr < 0x0E00)
+ {
+ result = MemoryBusDesignation.Cia2;
+ }
+ else if (addr < 0x0F00)
+ {
+ result = MemoryBusDesignation.Expansion1;
+ }
+ else
+ {
+ result = MemoryBusDesignation.Expansion2;
+ }
+ }
+
+ return result;
+ }
+
+ public byte Peek(ushort addr)
+ {
+ byte result;
+
+ if (addr == 0x0000)
+ {
+ result = cpu00;
+ }
+ else if (addr == 0x0001)
+ {
+ result = cpu01;
+ }
+ else
+ {
+ MemoryBusDesignation des = GetDesignation(addr);
+
+ switch (des)
+ {
+ case MemoryBusDesignation.Basic:
+ result = basicRom[addr & 0x1FFF];
+ break;
+ case MemoryBusDesignation.Character:
+ result = charRom[addr & 0x0FFF];
+ break;
+ case MemoryBusDesignation.Vic:
+ result = vic.regs[addr & 0x3F];
+ break;
+ case MemoryBusDesignation.Sid:
+ result = sid.regs[addr & 0x1F];
+ break;
+ case MemoryBusDesignation.ColorRam:
+ result = colorRam[addr & 0x03FF];
+ break;
+ case MemoryBusDesignation.Cia1:
+ result = cia1.regs[addr & 0x0F];
+ break;
+ case MemoryBusDesignation.Cia2:
+ result = cia2.regs[addr & 0x0F];
+ break;
+ case MemoryBusDesignation.Expansion1:
+ result = 0;
+ break;
+ case MemoryBusDesignation.Expansion2:
+ result = 0;
+ break;
+ case MemoryBusDesignation.Kernal:
+ result = kernalRom[addr & 0x1FFF];
+ break;
+ case MemoryBusDesignation.RAM:
+ result = ram[addr];
+ break;
+ case MemoryBusDesignation.ROMHi:
+ result = cart.chips[0].data[addr & cart.chips[0].romMask];
+ break;
+ case MemoryBusDesignation.ROMLo:
+ result = cart.chips[0].data[addr & cart.chips[0].romMask];
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ busData = result;
+ return result;
+ }
+
+ public byte Read(ushort addr)
+ {
+ byte result;
+
+ if (addr == 0x0000)
+ {
+ result = cpu00;
+ }
+ else if (addr == 0x0001)
+ {
+ result = cpu01;
+ }
+ else
+ {
+ MemoryBusDesignation des = GetDesignation(addr);
+
+ switch (des)
+ {
+ case MemoryBusDesignation.Basic:
+ result = basicRom[addr & 0x1FFF];
+ break;
+ case MemoryBusDesignation.Character:
+ result = charRom[addr & 0x0FFF];
+ break;
+ case MemoryBusDesignation.Vic:
+ result = vic.Read(addr);
+ break;
+ case MemoryBusDesignation.Sid:
+ result = sid.Read(addr);
+ break;
+ case MemoryBusDesignation.ColorRam:
+ result = (byte)((busData & 0xF0) | (colorRam[addr & 0x03FF]));
+ break;
+ case MemoryBusDesignation.Cia1:
+ result = cia1.Read(addr);
+ break;
+ case MemoryBusDesignation.Cia2:
+ result = cia2.Read(addr);
+ break;
+ case MemoryBusDesignation.Expansion1:
+ result = 0;
+ break;
+ case MemoryBusDesignation.Expansion2:
+ result = 0;
+ break;
+ case MemoryBusDesignation.Kernal:
+ result = kernalRom[addr & 0x1FFF];
+ break;
+ case MemoryBusDesignation.RAM:
+ result = ram[addr];
+ break;
+ case MemoryBusDesignation.ROMHi:
+ result = cart.Read(addr);
+ break;
+ case MemoryBusDesignation.ROMLo:
+ result = cart.Read(addr);
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ busData = result;
+ return result;
+ }
+
+ public void UpdateLayout()
+ {
+ bool loRom = ((cpu01 & 0x01) != 0);
+ bool hiRom = ((cpu01 & 0x02) != 0);
+ bool ioEnable = ((cpu01 & 0x04) != 0);
+
+ if (loRom && hiRom && exRomPin && gamePin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.RAM;
+ layout.MemA000 = MemoryBusDesignation.Basic;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = ioEnable ? MemoryBusDesignation.IO : MemoryBusDesignation.Character;
+ layout.MemE000 = MemoryBusDesignation.Kernal;
+ }
+ else if (loRom && !hiRom && exRomPin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.RAM;
+ layout.MemA000 = MemoryBusDesignation.RAM;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = ioEnable ? MemoryBusDesignation.IO : MemoryBusDesignation.Character;
+ layout.MemE000 = MemoryBusDesignation.RAM;
+ }
+ else if (loRom && !hiRom && !exRomPin && !gamePin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.RAM;
+ layout.MemA000 = MemoryBusDesignation.RAM;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = ioEnable ? MemoryBusDesignation.IO : MemoryBusDesignation.RAM;
+ layout.MemE000 = MemoryBusDesignation.RAM;
+ }
+ else if ((!loRom && hiRom && gamePin) || (!loRom && !hiRom && !exRomPin))
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.RAM;
+ layout.MemA000 = MemoryBusDesignation.RAM;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = ioEnable ? MemoryBusDesignation.IO : MemoryBusDesignation.Character;
+ layout.MemE000 = MemoryBusDesignation.Kernal;
+ }
+ else if (!loRom && !hiRom && gamePin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.RAM;
+ layout.MemA000 = MemoryBusDesignation.RAM;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = MemoryBusDesignation.RAM;
+ layout.MemE000 = MemoryBusDesignation.RAM;
+ }
+ else if (loRom && hiRom && gamePin && !exRomPin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.ROMLo;
+ layout.MemA000 = MemoryBusDesignation.Basic;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = ioEnable ? MemoryBusDesignation.IO : MemoryBusDesignation.Character;
+ layout.MemE000 = MemoryBusDesignation.Kernal;
+ }
+ else if (!loRom && hiRom && !gamePin && !exRomPin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.RAM;
+ layout.MemA000 = MemoryBusDesignation.ROMHi;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = ioEnable ? MemoryBusDesignation.IO : MemoryBusDesignation.Character;
+ layout.MemE000 = MemoryBusDesignation.Kernal;
+ }
+ else if (loRom && hiRom && !gamePin && !exRomPin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.RAM;
+ layout.Mem8000 = MemoryBusDesignation.ROMLo;
+ layout.MemA000 = MemoryBusDesignation.ROMHi;
+ layout.MemC000 = MemoryBusDesignation.RAM;
+ layout.MemD000 = ioEnable ? MemoryBusDesignation.IO : MemoryBusDesignation.Character;
+ layout.MemE000 = MemoryBusDesignation.Kernal;
+ }
+ else if (!gamePin && exRomPin)
+ {
+ layout.Mem1000 = MemoryBusDesignation.Disabled;
+ layout.Mem8000 = MemoryBusDesignation.ROMLo;
+ layout.MemA000 = MemoryBusDesignation.Disabled;
+ layout.MemC000 = MemoryBusDesignation.Disabled;
+ layout.MemD000 = MemoryBusDesignation.IO;
+ layout.MemE000 = MemoryBusDesignation.ROMHi;
+ }
+ }
+
+ public void WipeMemory()
+ {
+ 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;
+ }
+ }
+
+ public void Write(ushort addr, byte val)
+ {
+ if (addr == 0x0000)
+ {
+ cpu00 = val;
+ }
+ else if (addr == 0x0001)
+ {
+ cpu01 &= (byte)(~cpu00);
+ cpu01 |= (byte)(cpu00 & val);
+ UpdateLayout();
+ }
+ else
+ {
+ MemoryBusDesignation des = GetDesignation(addr);
+
+ switch (des)
+ {
+ case MemoryBusDesignation.Vic:
+ vic.Write(addr, val);
+ break;
+ case MemoryBusDesignation.Sid:
+ sid.Write(addr, val);
+ break;
+ case MemoryBusDesignation.ColorRam:
+ colorRam[addr & 0x03FF] = (byte)(val & 0x0F);
+ break;
+ case MemoryBusDesignation.Cia1:
+ cia1.Write(addr, val);
+ break;
+ case MemoryBusDesignation.Cia2:
+ cia2.Write(addr, val);
+ break;
+ case MemoryBusDesignation.Expansion1:
+ break;
+ case MemoryBusDesignation.Expansion2:
+ break;
+ case MemoryBusDesignation.RAM:
+ ram[addr] = val;
+ break;
+ default:
+ break;
+ }
+ }
+ busData = val;
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/Sid.cs b/BizHawk.Emulation/Computers/Commodore64/Sid.cs
new file mode 100644
index 0000000000..b8ddad567c
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/Sid.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64
+{
+ public enum SidMode
+ {
+ Sid6581,
+ Sid8580
+ }
+
+ public class Sid
+ {
+ public byte[] regs;
+
+ public Sid()
+ {
+ regs = new byte[0x20];
+ }
+
+ public void PerformCycle()
+ {
+ }
+
+ public byte Read(ushort addr)
+ {
+ switch (addr & 0x1F)
+ {
+ default:
+ return 0;
+ }
+ }
+
+ public void Write(ushort addr, byte val)
+ {
+ switch (addr & 0x1F)
+ {
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Computers/Commodore64/VicII.cs b/BizHawk.Emulation/Computers/Commodore64/VicII.cs
new file mode 100644
index 0000000000..ac41cf1228
--- /dev/null
+++ b/BizHawk.Emulation/Computers/Commodore64/VicII.cs
@@ -0,0 +1,446 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Computers.Commodore64
+{
+ public enum VicIIMode
+ {
+ NTSC,
+ PAL
+ }
+
+ public class VicII
+ {
+ // buffer
+ public int[] buffer;
+ public int bufferSize;
+
+ // palette
+ public 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)
+ };
+
+ // interrupts
+ public bool interrupt;
+ public bool lightPenInterrupt;
+ public bool lightPenInterruptEnabled;
+ public bool rasterInterrupt;
+ public bool rasterInterruptEnabled;
+ public bool spriteBackgroundInterrupt;
+ public bool spriteBackgroundInterruptEnabled;
+ public bool spriteSpriteInterrupt;
+ public bool spriteSpriteInterruptEnabled;
+
+ // memory
+ public int characterMemoryOffset;
+ public int screenMemoryOffset;
+
+ // lightpen
+ public int lightPenX;
+ public int lightPenY;
+
+ // raster
+ public int[] backgroundColor;
+ public bool backgroundMode;
+ public bool bitmapMode;
+ public int borderColor;
+ public bool borderOn;
+ public byte[] charBuffer;
+ public bool extendHeight;
+ public bool extendWidth;
+ public int horizontalScroll;
+ public bool multiColorMode;
+ public int rasterInterruptLine;
+ public int rasterOffset;
+ public int rasterOffsetX;
+ public int rasterOffsetY;
+ public int rasterTotalLines;
+ public int rasterWidth;
+ public bool screenEnabled;
+ public int verticalScroll;
+ public int visibleHeight;
+ public int visibleWidth;
+
+ // sprites
+ public bool[] spriteBackgroundCollision;
+ public bool[] spriteCollision;
+ public int[] spriteColor;
+ public bool[] spriteEnabled;
+ public int[] spriteExtraColor;
+ public bool[] spriteMultiColor;
+ public bool[] spritePriority;
+ public bool[] spriteStretchHorizontal;
+ public bool[] spriteStretchVertical;
+ public int[] spriteX;
+ public int[] spriteY;
+
+ public VicSignals cpuSignal;
+ public byte[] regs;
+
+ public VicII(VicSignals signals, VicIIMode videoMode)
+ {
+ cpuSignal = signals;
+
+ switch (videoMode)
+ {
+ case VicIIMode.NTSC:
+ rasterWidth = 512;
+ rasterTotalLines = 263;
+ visibleWidth = 368;
+ visibleHeight = 235;
+ break;
+ case VicIIMode.PAL:
+ break;
+ default:
+ break;
+ }
+
+ // initialize raster
+ backgroundColor = new int[4];
+ charBuffer = new byte[40];
+
+ // initialize sprites
+ spriteBackgroundCollision = new bool[8];
+ spriteCollision = new bool[8];
+ spriteColor = new int[8];
+ spriteEnabled = new bool[8];
+ spriteExtraColor = new int[2];
+ spriteMultiColor = new bool[8];
+ spritePriority = new bool[8];
+ spriteStretchHorizontal = new bool[8];
+ spriteStretchVertical = new bool[8];
+ spriteX = new int[8];
+ spriteY = new int[8];
+
+ // initialize buffer
+ buffer = new int[rasterWidth * rasterTotalLines];
+ bufferSize = buffer.Length;
+
+ // initialize registers
+ regs = new byte[0x40];
+ for (int i = 0x2F; i <= 0x3F; i++)
+ regs[i] = 0xFF;
+ UpdateRegs();
+ }
+
+ public void LockBus()
+ {
+ cpuSignal.Lock();
+ }
+
+ public void PerformCycle()
+ {
+ for (int i = 0; i < 8; i++)
+ WritePixel(borderColor);
+
+ if (rasterInterruptEnabled && (rasterOffsetY == rasterInterruptLine) && (rasterOffsetX == 0))
+ {
+ // removed for now
+ //rasterInterrupt = true;
+ }
+
+ interrupt =
+ (rasterInterrupt & rasterInterruptEnabled) |
+ (spriteSpriteInterrupt & spriteSpriteInterruptEnabled) |
+ (spriteBackgroundInterrupt & spriteBackgroundInterruptEnabled) |
+ (lightPenInterrupt & lightPenInterruptEnabled);
+
+ cpuSignal.Interrupt = interrupt;
+ UpdateRegs();
+ }
+
+ public byte Read(ushort addr)
+ {
+ return regs[addr & 0x3F];
+ }
+
+ public void UnlockBus()
+ {
+ cpuSignal.Unlock();
+ }
+
+ public void UpdateRegs()
+ {
+ // these registers update on their own
+
+ regs[0x11] = (byte)
+ ((verticalScroll & 0x07) |
+ (extendHeight ? 0x08 : 0x00) |
+ (screenEnabled ? 0x10 : 0x00) |
+ (bitmapMode ? 0x20 : 0x00) |
+ (backgroundMode ? 0x40 : 0x00) |
+ ((rasterOffsetY & 0x100) >> 1));
+ regs[0x12] = (byte)(rasterOffsetY & 0xFF);
+ regs[0x13] = (byte)(lightPenX >> 1);
+ regs[0x14] = (byte)(lightPenY);
+ regs[0x19] = (byte)
+ ((rasterInterrupt ? 0x01 : 0x00) |
+ (spriteBackgroundInterrupt ? 0x02 : 0x00) |
+ (spriteSpriteInterrupt ? 0x04 : 0x00) |
+ (lightPenInterrupt ? 0x08 : 0x00) |
+ (interrupt ? 0x80 : 0x00));
+ }
+
+ public void Write(ushort addr, byte val)
+ {
+ int index = 0;
+ bool allowWrite = true;
+ addr &= 0x3F;
+
+ switch (addr & 0x3F)
+ {
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0x08:
+ case 0x0A:
+ case 0x0C:
+ case 0x0E:
+ index = addr >> 1;
+ spriteX[index] &= 0xFF;
+ spriteX[index] |= val;
+ break;
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ case 0x0B:
+ case 0x0D:
+ case 0x0F:
+ index = addr >> 1;
+ spriteY[index] &= 0xFF;
+ spriteY[index] |= val;
+ break;
+ case 0x10:
+ spriteX[0] = (spriteX[0] & 0xFF) | ((val & 0x01) << 8);
+ spriteX[1] = (spriteX[1] & 0xFF) | ((val & 0x02) << 8);
+ spriteX[2] = (spriteX[2] & 0xFF) | ((val & 0x04) << 8);
+ spriteX[3] = (spriteX[3] & 0xFF) | ((val & 0x08) << 8);
+ spriteX[4] = (spriteX[4] & 0xFF) | ((val & 0x10) << 8);
+ spriteX[5] = (spriteX[5] & 0xFF) | ((val & 0x20) << 8);
+ spriteX[6] = (spriteX[6] & 0xFF) | ((val & 0x40) << 8);
+ spriteX[7] = (spriteX[7] & 0xFF) | ((val & 0x80) << 8);
+ break;
+ case 0x11:
+ verticalScroll = val & 0x07;
+ extendHeight = ((val & 0x08) != 0x00);
+ screenEnabled = ((val & 0x10) != 0x00);
+ bitmapMode = ((val & 0x20) != 0x00);
+ backgroundMode = ((val & 0x40) != 0x00);
+ rasterInterruptLine = (rasterInterruptLine & 0xFF) | ((val & 0x80) << 1);
+ val = (byte)((val & 0x7F) | ((rasterOffsetY & 0x100) >> 1));
+ break;
+ case 0x12:
+ rasterInterruptLine = (rasterInterruptLine & 0x100) | val;
+ allowWrite = false;
+ break;
+ case 0x15:
+ spriteEnabled[0] = ((val & 0x01) != 0x00);
+ spriteEnabled[1] = ((val & 0x02) != 0x00);
+ spriteEnabled[2] = ((val & 0x04) != 0x00);
+ spriteEnabled[3] = ((val & 0x08) != 0x00);
+ spriteEnabled[4] = ((val & 0x10) != 0x00);
+ spriteEnabled[5] = ((val & 0x20) != 0x00);
+ spriteEnabled[6] = ((val & 0x40) != 0x00);
+ spriteEnabled[7] = ((val & 0x80) != 0x00);
+ break;
+ case 0x16:
+ horizontalScroll = val & 0x07;
+ extendWidth = ((val & 0x08) != 0x00);
+ multiColorMode = ((val & 0x10) != 0x00);
+ bitmapMode = ((val & 0x20) != 0x00);
+ val |= 0xC0;
+ break;
+ case 0x17:
+ spriteStretchVertical[0] = ((val & 0x01) != 0x00);
+ spriteStretchVertical[1] = ((val & 0x02) != 0x00);
+ spriteStretchVertical[2] = ((val & 0x04) != 0x00);
+ spriteStretchVertical[3] = ((val & 0x08) != 0x00);
+ spriteStretchVertical[4] = ((val & 0x10) != 0x00);
+ spriteStretchVertical[5] = ((val & 0x20) != 0x00);
+ spriteStretchVertical[6] = ((val & 0x40) != 0x00);
+ spriteStretchVertical[7] = ((val & 0x80) != 0x00);
+ break;
+ case 0x18:
+ characterMemoryOffset = (int)(val & 0x0E) << 10;
+ screenMemoryOffset = (int)(val & 0xF0) << 6;
+ break;
+ case 0x19:
+ rasterInterrupt = ((val & 0x01) != 0);
+ spriteSpriteInterrupt = ((val & 0x02) != 0);
+ spriteBackgroundInterrupt = ((val & 0x04) != 0);
+ lightPenInterrupt = ((val & 0x08) != 0);
+ allowWrite = false;
+ break;
+ case 0x1A:
+ rasterInterruptEnabled = ((val & 0x01) != 0);
+ spriteSpriteInterruptEnabled = ((val & 0x02) != 0);
+ spriteBackgroundInterruptEnabled = ((val & 0x04) != 0);
+ lightPenInterruptEnabled = ((val & 0x08) != 0);
+ break;
+ case 0x1B:
+ spritePriority[0] = ((val & 0x01) != 0x00);
+ spritePriority[1] = ((val & 0x02) != 0x00);
+ spritePriority[2] = ((val & 0x04) != 0x00);
+ spritePriority[3] = ((val & 0x08) != 0x00);
+ spritePriority[4] = ((val & 0x10) != 0x00);
+ spritePriority[5] = ((val & 0x20) != 0x00);
+ spritePriority[6] = ((val & 0x40) != 0x00);
+ spritePriority[7] = ((val & 0x80) != 0x00);
+ break;
+ case 0x1C:
+ spriteMultiColor[0] = ((val & 0x01) != 0x00);
+ spriteMultiColor[1] = ((val & 0x02) != 0x00);
+ spriteMultiColor[2] = ((val & 0x04) != 0x00);
+ spriteMultiColor[3] = ((val & 0x08) != 0x00);
+ spriteMultiColor[4] = ((val & 0x10) != 0x00);
+ spriteMultiColor[5] = ((val & 0x20) != 0x00);
+ spriteMultiColor[6] = ((val & 0x40) != 0x00);
+ spriteMultiColor[7] = ((val & 0x80) != 0x00);
+ break;
+ case 0x1D:
+ spriteStretchHorizontal[0] = ((val & 0x01) != 0x00);
+ spriteStretchHorizontal[1] = ((val & 0x02) != 0x00);
+ spriteStretchHorizontal[2] = ((val & 0x04) != 0x00);
+ spriteStretchHorizontal[3] = ((val & 0x08) != 0x00);
+ spriteStretchHorizontal[4] = ((val & 0x10) != 0x00);
+ spriteStretchHorizontal[5] = ((val & 0x20) != 0x00);
+ spriteStretchHorizontal[6] = ((val & 0x40) != 0x00);
+ spriteStretchHorizontal[7] = ((val & 0x80) != 0x00);
+ break;
+ case 0x1E:
+ spriteCollision[0] = ((val & 0x01) != 0x00);
+ spriteCollision[1] = ((val & 0x02) != 0x00);
+ spriteCollision[2] = ((val & 0x04) != 0x00);
+ spriteCollision[3] = ((val & 0x08) != 0x00);
+ spriteCollision[4] = ((val & 0x10) != 0x00);
+ spriteCollision[5] = ((val & 0x20) != 0x00);
+ spriteCollision[6] = ((val & 0x40) != 0x00);
+ spriteCollision[7] = ((val & 0x80) != 0x00);
+ break;
+ case 0x1F:
+ spriteBackgroundCollision[0] = ((val & 0x01) != 0x00);
+ spriteBackgroundCollision[1] = ((val & 0x02) != 0x00);
+ spriteBackgroundCollision[2] = ((val & 0x04) != 0x00);
+ spriteBackgroundCollision[3] = ((val & 0x08) != 0x00);
+ spriteBackgroundCollision[4] = ((val & 0x10) != 0x00);
+ spriteBackgroundCollision[5] = ((val & 0x20) != 0x00);
+ spriteBackgroundCollision[6] = ((val & 0x40) != 0x00);
+ spriteBackgroundCollision[7] = ((val & 0x80) != 0x00);
+ break;
+ case 0x20:
+ borderColor = val;
+ break;
+ case 0x21:
+ backgroundColor[0] = val;
+ break;
+ case 0x22:
+ backgroundColor[1] = val;
+ break;
+ case 0x23:
+ backgroundColor[2] = val;
+ break;
+ case 0x24:
+ backgroundColor[3] = val;
+ break;
+ case 0x25:
+ spriteExtraColor[0] = val;
+ break;
+ case 0x26:
+ spriteExtraColor[1] = val;
+ break;
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ index = addr - 0x27;
+ spriteColor[index] = val;
+ break;
+ default:
+ allowWrite = false;
+ break;
+ }
+
+ if (allowWrite)
+ regs[addr] = val;
+ }
+
+ private void WritePixel(int value)
+ {
+ buffer[rasterOffset] = palette[value];
+ rasterOffset++;
+ if (rasterOffset >= bufferSize)
+ rasterOffset = 0;
+
+ rasterOffsetX = (rasterOffset & 0x1FF);
+ rasterOffsetY = (rasterOffset >> 9);
+ }
+ }
+
+ public class VicSignals
+ {
+ public bool AllowCpu;
+ public bool Interrupt;
+ public int LockCounter;
+
+ public VicSignals()
+ {
+ AllowCpu = true;
+ Interrupt = false;
+ LockCounter = 0;
+ }
+
+ public void Lock()
+ {
+ if (AllowCpu)
+ {
+ LockCounter = 4;
+ }
+ }
+
+ public void PerformCycle()
+ {
+ if (AllowCpu)
+ {
+ if (LockCounter > 0)
+ {
+ LockCounter--;
+ if (LockCounter == 0)
+ {
+ AllowCpu = false;
+ }
+ }
+ }
+ }
+
+ public void Unlock()
+ {
+ AllowCpu = true;
+ }
+
+ }
+}