Everything works great now. Phantasy Star loads and plays
This commit is contained in:
@@ -43,19 +43,16 @@ namespace Core.Io
|
|||||||
{
|
{
|
||||||
byte lowerPort = (byte)(port & 0xFF);
|
byte lowerPort = (byte)(port & 0xFF);
|
||||||
|
|
||||||
// Audio Ports
|
|
||||||
if (lowerPort == 0x7E || lowerPort == 0x7F)
|
if (lowerPort == 0x7E || lowerPort == 0x7F)
|
||||||
{
|
{
|
||||||
AudioProcessor.WritePort7F(value);
|
AudioProcessor.WritePort7F(value);
|
||||||
}
|
}
|
||||||
// Video Ports
|
// THE FIX: Video Ports are mirrored across the entire 0x80 to 0xBF range!
|
||||||
else if (lowerPort == 0xBE)
|
else if (lowerPort >= 0x80 && lowerPort <= 0xBF)
|
||||||
{
|
{
|
||||||
VideoProcessor.WriteDataPort(value);
|
// Even ports are Data, Odd ports are Control
|
||||||
}
|
if ((lowerPort & 0x01) == 0) VideoProcessor.WriteDataPort(value);
|
||||||
else if (lowerPort == 0xBF)
|
else VideoProcessor.WriteControlPort(value);
|
||||||
{
|
|
||||||
VideoProcessor.WriteControlPort(value);
|
|
||||||
}
|
}
|
||||||
else if (lowerPort <= 0x3F)
|
else if (lowerPort <= 0x3F)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ namespace Core.Memory
|
|||||||
private int _romBank1 = 1;
|
private int _romBank1 = 1;
|
||||||
private int _romBank2 = 2;
|
private int _romBank2 = 2;
|
||||||
|
|
||||||
|
// --- NEW: Cartridge RAM ---
|
||||||
|
private byte _mapperControl = 0; // 0xFFFC
|
||||||
|
private byte[] _cartridgeRam = new byte[0x8000]; // 32KB Max Cart RAM
|
||||||
|
|
||||||
// A flag to handle cartridges that don't use paging (like early 32KB games)
|
// A flag to handle cartridges that don't use paging (like early 32KB games)
|
||||||
private bool _isCartridgeLoaded = false;
|
private bool _isCartridgeLoaded = false;
|
||||||
|
|
||||||
@@ -39,7 +43,6 @@ namespace Core.Memory
|
|||||||
if (address < 0x4000) // ROM Slot 0 (0x0000 - 0x3FFF)
|
if (address < 0x4000) // ROM Slot 0 (0x0000 - 0x3FFF)
|
||||||
{
|
{
|
||||||
// SMS Hardware Quirk: The first 1KB (0x0000 - 0x03FF) is NEVER paged.
|
// SMS Hardware Quirk: The first 1KB (0x0000 - 0x03FF) is NEVER paged.
|
||||||
// It is hardwired to Bank 0 so the interrupt handlers don't crash.
|
|
||||||
if (address < 0x0400) return ReadFromCartridge(0, address);
|
if (address < 0x0400) return ReadFromCartridge(0, address);
|
||||||
|
|
||||||
return ReadFromCartridge(_romBank0, address);
|
return ReadFromCartridge(_romBank0, address);
|
||||||
@@ -50,18 +53,98 @@ namespace Core.Memory
|
|||||||
}
|
}
|
||||||
if (address < 0xC000) // ROM Slot 2 (0x8000 - 0xBFFF)
|
if (address < 0xC000) // ROM Slot 2 (0x8000 - 0xBFFF)
|
||||||
{
|
{
|
||||||
|
// --- THE MISSING LINK: Read from Save RAM if enabled! ---
|
||||||
|
if ((_mapperControl & 0x08) != 0)
|
||||||
|
{
|
||||||
|
int ramBank = (_mapperControl & 0x04) != 0 ? 1 : 0;
|
||||||
|
int ramOffset = (ramBank * 0x4000) + (address & 0x3FFF);
|
||||||
|
return _cartridgeRam[ramOffset];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, read from the ROM as usual
|
||||||
return ReadFromCartridge(_romBank2, address & 0x3FFF);
|
return ReadFromCartridge(_romBank2, address & 0x3FFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are here, we are in System RAM (0xC000 - 0xFFFF)
|
// System RAM (0xC000 - 0xFFFF)
|
||||||
// The & 0x1FFF handles the 8KB mirroring automatically!
|
|
||||||
return _workRam[address & 0x1FFF];
|
return _workRam[address & 0x1FFF];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//public byte Read(ushort address)
|
||||||
|
//{
|
||||||
|
// if (address < 0x4000) // ROM Slot 0 (0x0000 - 0x3FFF)
|
||||||
|
// {
|
||||||
|
// // SMS Hardware Quirk: The first 1KB (0x0000 - 0x03FF) is NEVER paged.
|
||||||
|
// // It is hardwired to Bank 0 so the interrupt handlers don't crash.
|
||||||
|
// if (address < 0x0400) return ReadFromCartridge(0, address);
|
||||||
|
|
||||||
|
// return ReadFromCartridge(_romBank0, address);
|
||||||
|
// }
|
||||||
|
// if (address < 0x8000) // ROM Slot 1 (0x4000 - 0x7FFF)
|
||||||
|
// {
|
||||||
|
// return ReadFromCartridge(_romBank1, address & 0x3FFF);
|
||||||
|
// }
|
||||||
|
// if (address < 0xC000) // ROM Slot 2 (0x8000 - 0xBFFF)
|
||||||
|
// {
|
||||||
|
// // Check if Cartridge RAM is enabled (Bit 3 of Mapper Control)
|
||||||
|
// if ((_mapperControl & 0x08) != 0)
|
||||||
|
// {
|
||||||
|
// // Bit 2 decides if we read the first 16KB half or the second 16KB half of the RAM chip
|
||||||
|
// int ramBank = (_mapperControl & 0x04) != 0 ? 1 : 0;
|
||||||
|
// int ramOffset = (ramBank * 0x4000) + (address & 0x3FFF);
|
||||||
|
// return _cartridgeRam[ramOffset];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return ReadFromCartridge(_romBank2, address & 0x3FFF);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // If we are here, we are in System RAM (0xC000 - 0xFFFF)
|
||||||
|
// // The & 0x1FFF handles the 8KB mirroring automatically!
|
||||||
|
// return _workRam[address & 0x1FFF];
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public void Write(ushort address, byte value)
|
||||||
|
//{
|
||||||
|
// // --- 1. CARTRIDGE RAM (Save Data) ---
|
||||||
|
// if (address < 0xC000)
|
||||||
|
// {
|
||||||
|
// if (address >= 0x8000 && (_mapperControl & 0x08) != 0)
|
||||||
|
// {
|
||||||
|
// int ramBank = (_mapperControl & 0x04) != 0 ? 1 : 0;
|
||||||
|
// int ramOffset = (ramBank * 0x4000) + (address & 0x3FFF);
|
||||||
|
// _cartridgeRam[ramOffset] = value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // You cannot write to a ROM cartridge!
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // --- 2. SYSTEM RAM ---
|
||||||
|
// _workRam[address & 0x1FFF] = value;
|
||||||
|
|
||||||
|
// // --- 3. SEGA MAPPER (With Hardware Mirroring!) ---
|
||||||
|
// // By checking the masked address (address & 0x1FFF), we perfectly
|
||||||
|
// // catch writes to 0xFFFC-0xFFFF *and* their 0xDFFC-0xDFFF mirrors!
|
||||||
|
// int mapperAddress = address & 0x1FFF;
|
||||||
|
|
||||||
|
// if (mapperAddress == 0x1FFC) _mapperControl = value;
|
||||||
|
// else if (mapperAddress == 0x1FFD) _romBank0 = value;
|
||||||
|
// else if (mapperAddress == 0x1FFE) _romBank1 = value;
|
||||||
|
// else if (mapperAddress == 0x1FFF) _romBank2 = value;
|
||||||
|
//}
|
||||||
|
|
||||||
public void Write(ushort address, byte value)
|
public void Write(ushort address, byte value)
|
||||||
{
|
{
|
||||||
if (address < 0xC000)
|
if (address < 0xC000)
|
||||||
{
|
{
|
||||||
|
// Bypass the lock if they are trying to save their game!
|
||||||
|
if (address >= 0x8000 && (_mapperControl & 0x08) != 0)
|
||||||
|
{
|
||||||
|
int ramBank = (_mapperControl & 0x04) != 0 ? 1 : 0;
|
||||||
|
int ramOffset = (ramBank * 0x4000) + (address & 0x3FFF);
|
||||||
|
_cartridgeRam[ramOffset] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// You cannot write to a ROM cartridge!
|
// You cannot write to a ROM cartridge!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -69,6 +152,19 @@ namespace Core.Memory
|
|||||||
// Write to System RAM
|
// Write to System RAM
|
||||||
_workRam[address & 0x1FFF] = value;
|
_workRam[address & 0x1FFF] = value;
|
||||||
|
|
||||||
|
// --- THE SEGA MAPPER ---
|
||||||
|
if (address == 0xFFFC) // <-- ADD THIS
|
||||||
|
{
|
||||||
|
_mapperControl = value;
|
||||||
|
}
|
||||||
|
else if (address == 0xFFFD)
|
||||||
|
{
|
||||||
|
_romBank0 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write to System RAM
|
||||||
|
_workRam[address & 0x1FFF] = value;
|
||||||
|
|
||||||
// --- THE SEGA MAPPER ---
|
// --- THE SEGA MAPPER ---
|
||||||
// If the CPU wrote to the very top of memory, it is commanding a bank swap!
|
// If the CPU wrote to the very top of memory, it is commanding a bank swap!
|
||||||
if (address == 0xFFFD)
|
if (address == 0xFFFD)
|
||||||
@@ -104,6 +200,7 @@ namespace Core.Memory
|
|||||||
public void CleanRAMData()
|
public void CleanRAMData()
|
||||||
{
|
{
|
||||||
Array.Clear(_workRam, 0, _workRam.Length);
|
Array.Clear(_workRam, 0, _workRam.Length);
|
||||||
|
Array.Clear(_cartridgeRam, 0, _cartridgeRam.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user