diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 492263d848..62ee186e36 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -114,6 +114,7 @@ + diff --git a/BizHawk.Emulation/CPUs/CP1610/CP1610.cs b/BizHawk.Emulation/CPUs/CP1610/CP1610.cs index e647723e13..14aa393b4b 100644 --- a/BizHawk.Emulation/CPUs/CP1610/CP1610.cs +++ b/BizHawk.Emulation/CPUs/CP1610/CP1610.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.CPUs.CP1610 public int PendingCycles; public Func ReadMemory; - public Action WriteMemory; + public Func WriteMemory; private static bool logging = true; private static StreamWriter log; diff --git a/BizHawk.Emulation/Consoles/Intellivision/Cartridge.cs b/BizHawk.Emulation/Consoles/Intellivision/Cartridge.cs new file mode 100644 index 0000000000..bb33de0fb8 --- /dev/null +++ b/BizHawk.Emulation/Consoles/Intellivision/Cartridge.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Consoles.Intellivision +{ + public sealed class Cartridge : ICart + { + private ushort[] Data = new ushort[56320]; + + public int Parse(byte[] Rom) + { + // TODO: Actually parse the ROM. + return 1; + } + + public ushort? Read(ushort addr) + { + // TODO: Check if address is RAM / ROM. + switch (addr & 0xF000) + { + case 0x0000: + if (addr <= 0x03FF) + break; + if (addr <= 0x04FF) + // OK on all but Intellivision 2. + return Data[addr & 0x00FF]; + else if (addr <= 0x06FF) + return Data[addr & 0x02FF]; + else if (addr <= 0x0CFF) + // OK if no Intellivoice. + return Data[addr & 0x08FF]; + else + return Data[addr & 0x0BFF]; + case 0x2000: + // OK if no ECS. + return Data[(addr & 0x0FFF) + 0x0C00]; + case 0x4000: + if (addr <= 0x47FF) + // OK if no ECS. + return Data[(addr & 0x07FF) + 0x1C00]; + else if (addr == 0x4800) + return Data[0x2400]; + else + return Data[(addr & 0x0FFF) + 0x1C00]; + case 0x5000: + case 0x6000: + if (addr <= 0x5014) + return Data[(addr & 0x0014) + 0x2C00]; + else + return Data[(addr & 0x1FFF) + 0x2C00]; + case 0x7000: + if (addr == 0x7000) + // OK if no ECS. + return Data[0x04C00]; + else if (addr <= 0x77FF) + // OK if no ECS. + return Data[(addr & 0x07FF) + 0x4C00]; + else + // OK if no ECS. + return Data[(addr & 0x0FFF) + 0x4C00]; + case 0x8000: + // OK. Avoid STIC alias at $8000-$803F. + return Data[(addr & 0x0FFF) + 0x5C00]; + case 0x9000: + case 0xA000: + case 0xB000: + if (addr <= 0xB7FF) + return Data[(addr & 0x27FF) + 0x6C00]; + else + return Data[(addr & 0x2FFF) + 0x6C00]; + case 0xC000: + // OK. Avoid STIC alias at $C000-$C03F. + return Data[(addr & 0x0FFF) + 0x9C00]; + case 0xD000: + return Data[(addr & 0x0FFF) + 0xAC00]; + case 0xE000: + // OK if no ECS. + return Data[(addr & 0x0FFF) + 0xBC00]; + case 0xF000: + if (addr <= 0xF7FF) + return Data[(addr & 0x07FF) + 0xCC00]; + else + return Data[(addr & 0x0FFF) + 0xCC00]; + } + return null; + } + + public bool Write(ushort addr, ushort value) + { + // TODO: Check if address is RAM / ROM. + switch (addr & 0xF000) + { + case 0x0000: + if (addr <= 0x03FF) + break; + if (addr <= 0x04FF) + { + // OK on all but Intellivision 2. + Data[addr & 0x00FF] = value; + return true; + } + else if (addr <= 0x06FF) + { + Data[addr & 0x02FF] = value; + return true; + } + else if (addr <= 0x0CFF) + { + // OK if no Intellivoice. + Data[addr & 0x08FF] = value; + return true; + } + else + { + Data[addr & 0x0BFF] = value; + return true; + } + case 0x2000: + // OK if no ECS. + Data[(addr & 0x0FFF) + 0x0C00] = value; + return true; + case 0x4000: + if (addr <= 0x47FF) + { + // OK if no ECS. + Data[(addr & 0x07FF) + 0x1C00] = value; + return true; + } + else if (addr == 0x4800) + { + // OK only if boot ROM at $7000. + Data[0x2400] = value; + return true; + } + else + { + Data[(addr & 0x0FFF) + 0x1C00] = value; + return true; + } + case 0x5000: + case 0x6000: + if (addr <= 0x5014) + { + // OK only if boot ROM at $4800 or $7000. + Data[(addr & 0x0014) + 0x2C00] = value; + return true; + } + else + { + Data[(addr & 0x1FFF) + 0x2C00] = value; + return true; + } + case 0x7000: + if (addr == 0x7000) + { + // RAM at $7000 confuses EXEC boot sequence. + Data[0x04C00] = value; + return true; + } + else if (addr <= 0x77FF) + { + // OK if no ECS. + Data[(addr & 0x07FF) + 0x4C00] = value; + return true; + } + else + { + // Do not map RAM here due to GRAM alias. + Data[(addr & 0x0FFF) + 0x4C00] = value; + return true; + } + case 0x8000: + // OK. Avoid STIC alias at $8000-$803F. + Data[(addr & 0x0FFF) + 0x5C00] = value; + return true; + case 0x9000: + case 0xA000: + case 0xB000: + if (addr <= 0xB7FF) + { + Data[(addr & 0x27FF) + 0x6C00] = value; + return true; + } + else + { + // Do not map RAM here due to GRAM alias. + Data[(addr & 0x2FFF) + 0x6C00] = value; + return true; + } + case 0xC000: + // OK. Avoid STIC alias at $C000-$C03F. + Data[(addr & 0x0FFF) + 0x9C00] = value; + return true; + case 0xD000: + Data[(addr & 0x0FFF) + 0xAC00] = value; + return true; + case 0xE000: + // OK if no ECS. + Data[(addr & 0x0FFF) + 0xBC00] = value; + return true; + case 0xF000: + if (addr <= 0xF7FF) + { + Data[(addr & 0x07FF) + 0xCC00] = value; + return true; + } + else + { + // Do not map RAM here due to GRAM alias. + Data[(addr & 0x0FFF) + 0xCC00] = value; + return true; + } + } + return false; + } + } +} diff --git a/BizHawk.Emulation/Consoles/Intellivision/Intellicart.cs b/BizHawk.Emulation/Consoles/Intellivision/Intellicart.cs index 50d6e109fd..b3d7d8c005 100644 --- a/BizHawk.Emulation/Consoles/Intellivision/Intellicart.cs +++ b/BizHawk.Emulation/Consoles/Intellivision/Intellicart.cs @@ -5,9 +5,9 @@ using System.Text; namespace BizHawk.Emulation.Consoles.Intellivision { - public sealed partial class Intellivision : ICart + public sealed class Intellicart : ICart { - private ushort[] Intellicart = new ushort[65536]; + private ushort[] Data = new ushort[65536]; private bool[][] MemoryAttributes = new bool[32][]; private ushort[][] FineAddresses = new ushort[32][]; @@ -52,12 +52,12 @@ namespace BizHawk.Emulation.Consoles.Intellivision return (ushort)((crc << 8) ^ CRC16_table[(crc >> 8) ^ data]); } - public int Parse() + public int Parse(byte[] Rom) { int offset = 0; // Check to see if the header is valid. if (Rom[offset++] != 0xA8 || Rom[offset++] != (0xFF ^ Rom[offset++])) - throw new ArgumentException(); + return -1; ushort crc, expected; // Parse for data segments. for (int segment = 0; segment < Rom[1]; segment++) @@ -69,9 +69,8 @@ namespace BizHawk.Emulation.Consoles.Intellivision crc = UpdateCRC16(crc, upper_end); ushort start = (ushort)(upper_start << 8); ushort end = (ushort)((upper_end << 8) | 0xFF); - // This range is invalid if it starts at a higher range than it ends. if (end < start) - throw new ArgumentException(); + throw new ArgumentException("Ranges can't start higher than they end."); for (int addr = start; addr <= end; addr++) { ushort data; @@ -80,12 +79,11 @@ namespace BizHawk.Emulation.Consoles.Intellivision crc = UpdateCRC16(crc, high); crc = UpdateCRC16(crc, low); data = (ushort)((high << 8) | low); - Intellicart[addr] = data; + Data[addr] = data; } expected = (ushort)((Rom[offset++] << 8) | Rom[offset++]); - // Check if there is an invalid CRC. if (expected != crc) - throw new ArgumentException(); + throw new ArgumentException("Invalid CRC."); } // Parse for memory attributes. for (int range = 0; range < 32; range++) @@ -117,9 +115,8 @@ namespace BizHawk.Emulation.Consoles.Intellivision int range_start = range * 2048; ushort start = (ushort)((((Rom[index] >> 4) & 0x07) << 8) + range_start); ushort end = (ushort)((((Rom[index]) & 0x07) << 8) + 0xFF + range_start); - // This range is invalid if it starts at a higher range than it ends. if (end < start) - throw new ArgumentException(); + throw new ArgumentException("Ranges can't start higher than they end."); FineAddresses[range] = new ushort[2]; FineAddresses[range][0] = start; FineAddresses[range][1] = end; @@ -130,20 +127,20 @@ namespace BizHawk.Emulation.Consoles.Intellivision expected = (ushort)((Rom[offset++] << 8) | (Rom[offset++] & 0xFF)); // Check if there is an invalid CRC for the memory attributes / fine addresses. if (expected != crc) - throw new ArgumentException(); + throw new ArgumentException("Invalid CRC."); return offset; } - public ushort? ReadCart(ushort addr) + public ushort? Read(ushort addr) { int range = addr / 2048; bool[] attributes = MemoryAttributes[range]; if (attributes[0] && addr >= FineAddresses[range][0] && addr <= FineAddresses[range][1]) - return Intellicart[addr]; + return Data[addr]; return null; } - public bool WriteCart(ushort addr, ushort value) + public bool Write(ushort addr, ushort value) { int range = addr / 2048; bool[] attributes = MemoryAttributes[range]; @@ -154,7 +151,7 @@ namespace BizHawk.Emulation.Consoles.Intellivision value &= 0xFF; if (attributes[3]) throw new NotImplementedException("Bank-switched memory attribute not implemented."); - Intellicart[addr] = value; + Data[addr] = value; return true; } return false; diff --git a/BizHawk.Emulation/Consoles/Intellivision/Intellivision.cs b/BizHawk.Emulation/Consoles/Intellivision/Intellivision.cs index b3a2b74c18..cec93f67de 100644 --- a/BizHawk.Emulation/Consoles/Intellivision/Intellivision.cs +++ b/BizHawk.Emulation/Consoles/Intellivision/Intellivision.cs @@ -11,6 +11,7 @@ namespace BizHawk.Emulation.Consoles.Intellivision GameInfo Game; CP1610 Cpu; + ICart Cart; public void LoadExecutive_ROM() { @@ -42,7 +43,12 @@ namespace BizHawk.Emulation.Consoles.Intellivision Game = game; LoadExecutive_ROM(); LoadGraphics_ROM(); - Parse(); + Cart = new Intellicart(); + if (Cart.Parse(Rom) == -1) + { + Cart = new Cartridge(); + Cart.Parse(Rom); + } Cpu = new CP1610(); Cpu.ReadMemory = ReadMemory; diff --git a/BizHawk.Emulation/Consoles/Intellivision/MemoryMap.cs b/BizHawk.Emulation/Consoles/Intellivision/MemoryMap.cs index 1319293351..da988a3d50 100644 --- a/BizHawk.Emulation/Consoles/Intellivision/MemoryMap.cs +++ b/BizHawk.Emulation/Consoles/Intellivision/MemoryMap.cs @@ -8,17 +8,6 @@ namespace BizHawk.Emulation.Consoles.Intellivision public sealed partial class Intellivision { private const string INVALID = "Invalid memory address."; - private const string UNOCCUPIED = "Unoccupied memory address."; - private const string UNOCCUPIED_CART_READ = "Unoccupied memory address available to cartridge not mapped as" - + " readable."; - private const string UNOCCUPIED_CART_WRITE = "Unoccupied memory address available to cartridge not mapped as" - + " writable."; - private const string READ_ONLY_STIC = "This STIC Register alias is read-only."; - private const string READ_ONLY_EXEC = "Executive ROM is read-only."; - private const string READ_ONLY_GROM = "Graphics ROM is read-only."; - private const string WRITE_ONLY_STIC = "This STIC Register alias is write-only."; - private const string GARBAGE = "Memory address contains a garbage value, perhaps only in the Intellivision II."; - private const string INTV2_EXEC = "Additional EXEC ROM, Intellivision II only."; private ushort[] STIC_Registers = new ushort[64]; private ushort[] Scratchpad_RAM = new ushort[240]; @@ -27,12 +16,11 @@ namespace BizHawk.Emulation.Consoles.Intellivision private ushort[] Executive_ROM = new ushort[4096]; // TODO: Intellivision II support? private ushort[] Graphics_ROM = new ushort[2048]; private ushort[] Graphics_RAM = new ushort[512]; - private ushort[] Cartridge = new ushort[56320]; // TODO: Resize as cartridge mapping grows. public ushort ReadMemory(ushort addr) { - ushort? cart = ReadCart(addr); - ushort core; + ushort? cart = Cart.Read(addr); + ushort? core = null; switch (addr & 0xF000) { case 0x0000: @@ -43,7 +31,8 @@ namespace BizHawk.Emulation.Consoles.Intellivision // TODO: OK only during VBlank Period 2. core = STIC_Registers[addr & 0x003F]; else if (addr <= 0x00FF) - throw new ArgumentException(UNOCCUPIED); + // Unoccupied. + break; else if (addr <= 0x01EF) core = Scratchpad_RAM[addr & 0x00EF]; else if (addr <= 0x01FF) @@ -51,44 +40,15 @@ namespace BizHawk.Emulation.Consoles.Intellivision else if (addr <= 0x035F) core = System_RAM[addr & 0x015F]; else if (addr <= 0x03FF) - // TODO: Intellivision II support? - throw new ArgumentException(GARBAGE); + // TODO: Garbage values for Intellivision II. + break; else if (addr <= 0x04FF) - // TODO: Actually map cartridge (on all but Intellivision II) RAM / ROM to decide which path to take. - if (false) - // TODO: Intellivision II support? - throw new ArgumentException(INTV2_EXEC); - else - core = Cartridge[addr & 0x00FF]; - else if (addr <= 0x06FF) - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[addr & 0x02FF]; - else if (addr <= 0x0CFF) - // TODO: Actually map cartridge (only if no Intellivoice) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[addr & 0x08FF]; - else - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[addr & 0x0BFF]; + // TODO: Additional EXEC ROM for Intellivision II. + break; break; case 0x1000: core = Executive_ROM[addr & 0x0FFF]; break; - case 0x2000: - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0x0C00]; - break; case 0x3000: if (addr <= 0x37FF) // TODO: OK only during VBlank Period 2. @@ -109,667 +69,269 @@ namespace BizHawk.Emulation.Consoles.Intellivision case 0x4000: if (addr <= 0x403F) { - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (true) - { + if (addr == 0x4021) // TODO: OK only during VBlank Period 1. - if (addr == 0x4021) - // TODO: Switch into Color Stack mode. - core = STIC_Registers[0x0021]; - else - throw new ArgumentException(WRITE_ONLY_STIC); - } - else - core = Cartridge[(addr & 0x003F) + 0x1C00]; - } - else if (addr <= 0x47FF) - { - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x07FF) + 0x1C00]; - } - else if (addr == 0x4800) - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[0x2400]; - } - else - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0x1C00]; - } - break; - case 0x5000: - case 0x6000: - if (addr <= 0x5014) - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0014) + 0x2C00]; - } - else - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x1FFF) + 0x2C00]; + // TODO: Switch into Color Stack mode. + core = STIC_Registers[0x0021]; } break; case 0x7000: - if (addr == 0x7000) - { - /* - TODO: Actually map cartridge (only if no ECS) RAM (confuses EXEC boot sequence) / ROM to decide - which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[0x04C00]; - } - else if (addr <= 0x77FF) - { - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x07FF) + 0x4C00]; - } + if (addr <= 0x77FF) + // Available to cartridges. + break; else if (addr <= 0x79FF) - { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x09FF) + 0x4C00]; - } + // Write-only Graphics RAM. + break; else if (addr <= 0x7BFF) - { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0BFF) + 0x4C00]; - } + // Write-only Graphics RAM. + break; else if (addr <= 0x7DFF) - { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0DFF) + 0x4C00]; - } + // Write-only Graphics RAM. + break; else - { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0x4C00]; - } - break; + // Write-only Graphics RAM. + break; case 0x8000: if (addr <= 0x803F) { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (true) - { + if (addr == 0x8021) // TODO: OK only during VBlank Period 1. - if (addr == 0x8021) - // TODO: Switch into Color Stack mode. - core = STIC_Registers[0x0021]; - else - throw new ArgumentException(WRITE_ONLY_STIC); - } - else - core = Cartridge[(addr & 0x003F) + 0x5C00]; - } - else - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0x5C00]; + // TODO: Switch into Color Stack mode. + core = STIC_Registers[0x0021]; } break; - case 0x9000: - case 0xA000: case 0xB000: if (addr <= 0xB7FF) - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x27FF) + 0x6C00]; - } + // Available to cartridges. + break; else if (addr <= 0xB9FF) - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x29FF) + 0x6C00]; - } + // Write-only Graphics RAM. + break; else if (addr <= 0xBBFF) - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x2BFF) + 0x6C00]; - } + // Write-only Graphics RAM. + break; else if (addr <= 0xBDFF) - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x2DFF) + 0x6C00]; - } + // Write-only Graphics RAM. + break; else - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x2FFF) + 0x6C00]; - } - break; + // Write-only Graphics RAM. + break; case 0xC000: if (addr <= 0xC03F) { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (true) - { + if (addr == 0xC021) // TODO: OK only during VBlank Period 1. - if (addr == 0xC021) - // TODO: Switch into Color Stack mode. - core = STIC_Registers[0x0021]; - else - throw new ArgumentException(WRITE_ONLY_STIC); - } - else - core = Cartridge[(addr & 0x003F) + 0x9C00]; + // TODO: Switch into Color Stack mode. + core = STIC_Registers[0x0021]; } - else - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0x9C00]; - } - break; - case 0xD000: - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0xAC00]; - break; - case 0xE000: - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0xBC00]; break; case 0xF000: if (addr <= 0xF7FF) - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x07FF) + 0xCC00]; - } + // Available to cartridges. + break; else if (addr <= 0xF9FF) - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x09FF) + 0xCC00]; - } + // Write-only Graphics RAM. + break; else if (addr <= 0xFBFF) - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0BFF) + 0xCC00]; - } + // Write-only Graphics RAM. + break; else if (addr <= 0xFDFF) - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0DFF) + 0xCC00]; - } + // Write-only Graphics RAM. + break; else - { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_READ); - else - core = Cartridge[(addr & 0x0FFF) + 0xCC00]; - } - break; - default: - throw new ArgumentException(INVALID); + // Write-only Graphics RAM. + break; } - /* - TODO: Fix Intellicart hook. if (cart != null) return (ushort)cart; - */ - return core; + else if (core == null) + throw new ArgumentException(INVALID); + return (ushort)core; } - public void WriteMemory(ushort addr, ushort value) + public bool WriteMemory(ushort addr, ushort value) { - WriteCart(addr, value); + bool cart = Cart.Write(addr, value); switch (addr & 0xF000) { case 0x0000: if (addr <= 0x003F) + { + // TODO: OK only during VBlank Period 1. STIC_Registers[addr] = value; + return true; + } else if (addr <= 0x007F) - throw new ArgumentException(READ_ONLY_STIC); + // Read-only STIC. + break; else if (addr <= 0x00FF) - throw new ArgumentException(UNOCCUPIED); + // Unoccupied. + break; else if (addr <= 0x01EF) + { Scratchpad_RAM[addr & 0x00EF] = value; + return true; + } else if (addr <= 0x01FF) + { PSG_Registers[addr & 0x000F] = value; + return true; + } else if (addr <= 0x035F) + { System_RAM[addr & 0x015F] = value; + return true; + } else if (addr <= 0x03FF) - // TODO: Intellivision II support? - throw new ArgumentException(GARBAGE); + // Read-only garbage values for Intellivision II. + break; else if (addr <= 0x04FF) - // TODO: Actually map cartridge (on all but Intellivision II) RAM / ROM to decide which path to take. - if (false) - // TODO: Intellivision II support? - throw new ArgumentException(INTV2_EXEC); - else - Cartridge[addr & 0x00FF] = value; - else if (addr <= 0x06FF) - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[addr & 0x02FF] = value; - else if (addr <= 0x0CFF) - // TODO: Actually map cartridge (only if no Intellivoice) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[addr & 0x08FF] = value; - else - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[addr & 0x0BFF] = value; + // Read-only additional EXEC ROM for Intellivision II. + break; break; case 0x1000: - throw new ArgumentException(READ_ONLY_EXEC); - case 0x2000: - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x0FFF) + 0x0C00] = value; + // Read-only Executive ROM. break; case 0x3000: if (addr <= 0x37FF) - throw new ArgumentException(READ_ONLY_GROM); + // Read-only Graphics ROM. + break; else if (addr <= 0x39FF) + { // TODO: OK only during VBlank Period 2. Graphics_RAM[addr & 0x01FF] = value; + return true; + } else if (addr <= 0x3BFF) + { // TODO: OK only during VBlank Period 2. Graphics_RAM[addr & 0x01FF] = value; + return true; + } else if (addr <= 0x3DFF) + { // TODO: OK only during VBlank Period 2. Graphics_RAM[addr & 0x01FF] = value; + return true; + } else + { // TODO: OK only during VBlank Period 2. Graphics_RAM[addr & 0x01FF] = value; - break; + return true; + } case 0x4000: if (addr <= 0x403F) { - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (true) - // TODO: OK only during VBlank Period 1. - STIC_Registers[addr & 0x003F] = value; - else - Cartridge[(addr & 0x003F) + 0x1C00] = value; - } - else if (addr <= 0x47FF) - { - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x07FF) + 0x1C00] = value; - } - else if (addr == 0x4800) - { - // TODO: Actually map cartridge (only if boot ROM at $7000) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[0x2400] = value; - } - else - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x0FFF) + 0x1C00] = value; - } - break; - case 0x5000: - case 0x6000: - if (addr <= 0x5014) - { - /* - TODO: Actually map (only if boot ROM at $4800 or $7000) cartridge RAM / ROM to decide which path to - take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x0014) + 0x2C00] = value; - } - else - { - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x1FFF) + 0x2C00] = value; + // TODO: OK only during VBlank Period 1. + STIC_Registers[addr & 0x003F] = value; + return true; } break; case 0x7000: - if (addr == 0x7000) - { - /* - TODO: Actually map cartridge (only if no ECS) RAM (confuses EXEC boot sequence) / ROM to decide - which path to take. - */ - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[0x04C00] = value; - } - else if (addr <= 0x77FF) - { - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x07FF) + 0x4C00] = value; - } + if (addr <= 0x77FF) + // Available to cartridges. + break; else if (addr <= 0x79FF) { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x09FF) + 0x4C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else if (addr <= 0x7BFF) { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x0BFF) + 0x4C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else if (addr <= 0x7DFF) { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x0DFF) + 0x4C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else { - /* - TODO: Actually map cartridge (only if no ECS) RAM (Do not because of GRAM alias) / ROM to decide - which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x0FFF) + 0x4C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } - break; case 0x8000: if (addr <= 0x803F) { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (true) - // TODO: OK only during VBlank Period 1. - STIC_Registers[addr & 0x003F] = value; - else - Cartridge[(addr & 0x003F) + 0x5C00] = value; - } - else - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x0FFF) + 0x5C00] = value; + // TODO: OK only during VBlank Period 1. + STIC_Registers[addr & 0x003F] = value; + return true; } break; case 0x9000: case 0xA000: case 0xB000: if (addr <= 0xB7FF) - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x27FF) + 0x6C00] = value; - } + // Available to cartridges. + break; else if (addr <= 0xB9FF) { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x29FF) + 0x6C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else if (addr <= 0xBBFF) { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x2BFF) + 0x6C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else if (addr <= 0xBDFF) { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x2DFF) + 0x6C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x2FFF) + 0x6C00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } - break; case 0xC000: if (addr <= 0x803F) { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (true) - // TODO: OK only during VBlank Period 1. - STIC_Registers[addr & 0x003F] = value; - else - Cartridge[(addr & 0x003F) + 0x9C00] = value; + // TODO: OK only during VBlank Period 1. + STIC_Registers[addr & 0x003F] = value; + return true; } - else - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x0FFF) + 0x9C00] = value; - } - break; - case 0xD000: - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x0FFF) + 0xAC00] = value; - break; - case 0xE000: - // TODO: Actually map cartridge (only if no ECS) RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x0FFF) + 0xBC00] = value; break; case 0xF000: if (addr <= 0xF7FF) - { - // TODO: Actually map cartridge RAM / ROM to decide which path to take. - if (false) - throw new ArgumentException(UNOCCUPIED_CART_WRITE); - else - Cartridge[(addr & 0x07FF) + 0xCC00] = value; - } + // Available to cartridges. + break; else if (addr <= 0xF9FF) { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x09FF) + 0xCC00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else if (addr <= 0xFBFF) { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x0BFF) + 0xCC00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else if (addr <= 0xFDFF) { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x0DFF) + 0xCC00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } else { - /* - TODO: Actually map cartridge RAM (Do not because of GRAM alias) / ROM to decide which path to take. - */ - if (true) - // TODO: OK only during VBlank Period 2. - Graphics_RAM[addr & 0x01FF] = value; - else - Cartridge[(addr & 0x0FFF) + 0xCC00] = value; + // TODO: OK only during VBlank Period 2. + Graphics_RAM[addr & 0x01FF] = value; + return true; } - break; - default: - throw new ArgumentException(INVALID); } + return cart; } } } diff --git a/BizHawk.Emulation/Interfaces/ICart.cs b/BizHawk.Emulation/Interfaces/ICart.cs index ab26cdaf10..6389742a35 100644 --- a/BizHawk.Emulation/Interfaces/ICart.cs +++ b/BizHawk.Emulation/Interfaces/ICart.cs @@ -7,7 +7,8 @@ namespace BizHawk { public interface ICart { - ushort? ReadCart(ushort addr); - bool WriteCart(ushort addr, ushort value); + int Parse(byte[] Rom); + ushort? Read(ushort addr); + bool Write(ushort addr, ushort value); } }