Fix PCE Populous by supporting its custom SaveRAM.

+ Unsubstantial TurboCD progress.
This commit is contained in:
beirich 2011-07-15 02:08:18 +00:00
parent 4b892cdfea
commit 3f27ac0b2a
7 changed files with 318 additions and 17 deletions

View File

@ -112,6 +112,8 @@
<Compile Include="Consoles\Nintendo\NES\PPU.cs" />
<Compile Include="Consoles\Nintendo\NES\PPU.regs.cs" />
<Compile Include="Consoles\Nintendo\NES\PPU.run.cs" />
<Compile Include="Consoles\PC Engine\MemoryMap.Populous.cs" />
<Compile Include="Consoles\PC Engine\ScsiCD.cs" />
<Compile Include="Consoles\PC Engine\TurboCD.cs" />
<Compile Include="Consoles\Sega\SMS\MemoryMap.CodeMasters.cs" />
<Compile Include="Consoles\Sega\SMS\MemoryMap.Sega.cs" />

View File

@ -44,14 +44,37 @@ namespace BizHawk.Emulation.CPUs.H6280
PendingCycles -= 8;
}
if (IRQ2Assert && FlagI == false && LagIFlag == false && (IRQControlByte & IRQ2Selector) == 0)
{
Console.WriteLine("ENTERING IRQ2 INTERRUPT");
WriteMemory((ushort)(S-- + 0x2100), (byte)(PC >> 8));
WriteMemory((ushort)(S-- + 0x2100), (byte)PC);
WriteMemory((ushort)(S-- + 0x2100), (byte)(P & (~0x10)));
FlagD = false;
FlagI = true;
PC = ReadWord(IRQ2Vector);
PendingCycles -= 8;
}
IRQControlByte = IRQNextControlByte;
LagIFlag = FlagI;
//Console.WriteLine(State());
byte opcode = ReadMemory(PC++);
switch (opcode)
{
case 0x00: // BRK
throw new Exception("break");
Console.WriteLine("EXEC BRK"); // TODO CpuCoreGenerator needs updated, but I dont even know if this works yet
PC++;
WriteMemory((ushort)(S-- + 0x2100), (byte)(PC >> 8));
WriteMemory((ushort)(S-- + 0x2100), (byte)PC);
WriteMemory((ushort)(S-- + 0x2100), (byte)(P & (~0x10)));
FlagT = false;
FlagB = true;
FlagD = false;
FlagI = true;
PC = ReadWord(IRQ2Vector);
PendingCycles -= 8;
break;
case 0x01: // ORA (addr,X)
value8 = ReadMemory(ReadWordPageWrap((ushort)((byte)(ReadMemory(PC++)+X)+0x2000)));

View File

@ -43,6 +43,7 @@ namespace BizHawk.Emulation.CPUs.H6280
public bool LagIFlag;
public bool IRQ1Assert;
public bool IRQ2Assert;
public bool TimerAssert;
public byte IRQControlByte, IRQNextControlByte;
@ -191,9 +192,6 @@ namespace BizHawk.Emulation.CPUs.H6280
public void WriteIrqControl(byte value)
{
// There is a single-instruction delay before writes to the IRQ Control Byte take effect.
// After Burner requires this to function, as it ACKs the timer interrupt AFTER un-masking
// the interrupt.
value &= 7;
IRQNextControlByte = value;
}
@ -206,7 +204,7 @@ namespace BizHawk.Emulation.CPUs.H6280
public byte ReadIrqStatus()
{
byte status = 0;
//if (IRQ2Assert) status |= 1;
if (IRQ2Assert) status |= 1;
if (IRQ1Assert) status |= 2;
if (TimerAssert) status |= 4;
return status;
@ -232,6 +230,8 @@ namespace BizHawk.Emulation.CPUs.H6280
{
if (TimerTickCounter + 5 > 1024)
{
// There exists a slight delay between when the timer counter is decremented and when
// the interrupt fires; games can detect it, so we hack it this way.
return (byte) ((TimerValue - 1) & 0x7F);
}
return TimerValue;

View File

@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using BizHawk.Emulation.CPUs.H6280;
using BizHawk.Emulation.Sound;
using BizHawk.Disc;
namespace BizHawk.Emulation.Consoles.TurboGrafx
{
@ -40,6 +41,9 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
// Memory system
public byte[] Ram;
// Disc
//private Disc.Disc disc = Disc.Disc.FromCuePath("d:/lib/roms/Turbo CD/Cosmic Fantasy II/Cosmic Fantasy II [U][CD][WTG990301][Telenet Japan][1992][PCE][thx-1138-darkwater].cue");
// PC Engine timings:
// 21,477,270 Machine clocks / sec
// 7,159,090 Cpu cycles / sec
@ -109,6 +113,13 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
BRAM[4] = 0x00; BRAM[5] = 0x88; BRAM[6] = 0x10; BRAM[7] = 0x80;
}
if (game.GetOptions().Contains("PopulousSRAM"))
{
PopulousRAM = new byte[0x8000];
Cpu.ReadMemory21 = ReadMemoryPopulous;
Cpu.WriteMemory21 = WriteMemoryPopulous;
}
Cpu.ResetPC();
SetupMemoryDomains();
}
@ -171,6 +182,11 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
writer.WriteLine("[PCEngine]");
writer.Write("RAM ");
Ram.SaveAsHex(writer);
if (PopulousRAM != null)
{
writer.Write("PopulousRAM ");
PopulousRAM.SaveAsHex(writer);
}
writer.WriteLine("Frame " + Frame);
writer.WriteLine("Lag " + _lagcount);
if (Cpu.ReadMemory21 == ReadMemorySF2)
@ -215,6 +231,8 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
IOBuffer = byte.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "RAM")
Ram.ReadFromHex(args[1]);
else if (args[0] == "PopulousRAM" && PopulousRAM != null)
PopulousRAM.ReadFromHex(args[1]);
else if (args[0] == "[HuC6280]")
Cpu.LoadStateText(reader);
else if (args[0] == "[PSG]")
@ -237,8 +255,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if (SuperGrafx == false)
{
writer.Write(Ram);
if (PopulousRAM != null)
writer.Write(PopulousRAM);
writer.Write(Frame);
// writer.Write(_lagcount); //TODO: why does this fail?
writer.Write(_lagcount);
writer.Write(SF2MapperLatch);
writer.Write(IOBuffer);
Cpu.SaveStateBinary(writer);
@ -248,7 +268,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
} else {
writer.Write(Ram);
writer.Write(Frame);
// writer.Write(_lagcount);
writer.Write(_lagcount);
writer.Write(IOBuffer);
Cpu.SaveStateBinary(writer);
VCE.SaveStateBinary(writer);
@ -264,8 +284,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
if (SuperGrafx == false)
{
Ram = reader.ReadBytes(0x2000);
if (PopulousRAM != null)
PopulousRAM = reader.ReadBytes(0x8000);
Frame = reader.ReadInt32();
// _lagcount = reader.ReadInt32();
_lagcount = reader.ReadInt32();
SF2MapperLatch = reader.ReadByte();
IOBuffer = reader.ReadByte();
Cpu.LoadStateBinary(reader);
@ -275,7 +297,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
} else {
Ram = reader.ReadBytes(0x8000);
Frame = reader.ReadInt32();
// _lagcount = reader.ReadInt32();
_lagcount = reader.ReadInt32();
IOBuffer = reader.ReadByte();
Cpu.LoadStateBinary(reader);
VCE.LoadStateBinary(reader);
@ -288,8 +310,9 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
public byte[] SaveStateBinary()
{
int buflen = SuperGrafx ? 166552 : 75854;
int buflen = SuperGrafx ? 166556 : 75858;
if (BramEnabled) buflen += 2048;
if (PopulousRAM != null) buflen += 0x8000;
var buf = new byte[buflen];
var stream = new MemoryStream(buf);

View File

@ -0,0 +1,192 @@
using System;
namespace BizHawk.Emulation
{
public sealed class ScsiCD
{
private bool bsy, sel, cd, io, msg, req, ack, atn, rst;
private bool lagBSY, lagSEL, lagCD, lagIO, lagMSG, lagREQ, lagACK, lagATN, lagRST;
public bool BSY {
get { return bsy; }
set {
if (value != lagBSY) signalsChanged = true;
lagBSY = bsy;
bsy = value;
}
}
public bool SEL
{
get { return sel; }
set
{
if (value != lagSEL) signalsChanged = true;
lagSEL = sel;
sel = value;
}
}
public bool CD // false=data, true=control
{
get { return cd; }
set
{
if (value != lagCD) signalsChanged = true;
lagCD = cd;
cd = value;
}
}
public bool IO
{
get { return io; }
set
{
if (value != lagIO) signalsChanged = true;
lagIO = io;
io = value;
}
}
public bool MSG
{
get { return msg; }
set
{
if (value != lagMSG) signalsChanged = true;
lagMSG = msg;
msg = value;
}
}
public bool REQ
{
get { return req; }
set
{
if (value != lagREQ) signalsChanged = true;
lagREQ = req;
req = value;
}
}
public bool ACK
{
get { return ack; }
set
{
if (value != lagACK) signalsChanged = true;
lagACK = ack;
ack = value;
}
}
public bool ATN
{
get { return atn; }
set
{
if (value != lagATN) signalsChanged = true;
lagATN = atn;
atn = value;
}
}
public bool RST
{
get { return rst; }
set
{
if (value != lagRST) signalsChanged = true;
lagRST = rst;
rst = value;
}
}
public byte DB { get; set; } // data bits
private bool signalsChanged;
private bool driveSelected;
public void Think()
{
if (BSY == false && SEL == false)
{
Console.WriteLine("BUS FREE!");
// zap the rest of the signals
CD = false;
IO = false;
MSG = false;
REQ = false;
ACK = false;
ATN = false;
DB = 0;
}
if (SEL && lagSEL == false)
{
driveSelected = true;
CD = true;
BSY = true;
MSG = false;
IO = false;
REQ = true;
}
if (RST && lagRST == false)
{
// reset buffers and CDDA and stuff.
CD = false;
IO = false;
MSG = false;
REQ = false;
ACK = false;
ATN = false;
DB = 0;
}
}
/* SCSI BUS SIGNALS
BSY (BUSY). An "OR-tied" signal that indicates that the bus is being used.
SEL (SELECT). A signal used by an initiator to select a target or by a target
to reselect an initiator.
C/D (CONTROL/DATA). A signal driven by a target that indicates whether
CONTROL or DATA information is on the DATA BUS. True indicates CONTROL.
I/O (INPUT/OUTPUT). A signal driven by a target that controls the direction
of data movement on the DATA BUS with respect to an initiator. True indicates
input to the initiator. This signal is also used to distinguish between
SELECTION and RESELECTION phases.
MSG (MESSAGE). A signal driven by a target during the MESSAGE phase.
REQ (REQUEST). A signal driven by a target to indicate a request for a
REQ/ACK data transfer handshake.
ACK (ACKNOWLEDGE). A signal driven by an initiator to indicate an
acknowledgment for a REQ/ACK data transfer handshake.
ATN (ATTENTION). A signal driven by an initiator to indicate the ATTENTION
condition.
RST (RESET). An "OR-tied" signal that indicates the RESET condition.
Plus 8 data bits (DB7-0) and parity (P).
==============================================================================
Signals
----------------------------------------------------------
C/D, I/O,
Bus Phase BSY SEL MSG, REQ ACK/ATN DB(7-0,P)
------------------------------------------------------------------------------
BUS FREE None None None None None
ARBITRATION All Winner None None SCSI ID
SELECTION I&T Initiator None Initiator Initiator
RESELECTION I&T Target Target Initiator Target
COMMAND Target None Target Initiator Initiator
DATA IN Target None Target Initiator Target
DATA OUT Target None Target Initiator Initiator
STATUS Target None Target Initiator Target
MESSAGE IN Target None Target Initiator Target
MESSAGE OUT Target None Target Initiator Initiator
==============================================================================
*/
}
}

View File

@ -5,17 +5,49 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
public partial class PCEngine
{
private byte[] CdIoPorts = new byte[16];
private ScsiCD scsi = new ScsiCD();
private void WriteCD(int addr, byte value)
{
Console.WriteLine("Write to reg[{0:X4}] {1:X2}", addr&0x1FFF, value);
switch (addr & 0x1FFF)
{
case 0x1802: // ADPCM / CD Control
case 0x1800: // SCSI Drive Control Line
CdIoPorts[0] = value;
// Console.WriteLine("Write to CDC Status [0] {0:X2}", value);
scsi.SEL = true;
scsi.Think();
scsi.SEL = false;
scsi.Think();
// this probably does some things
// possibly clear irq line or trigger or who knows
break;
case 0x1801: // CDC Command
CdIoPorts[1] = value;
scsi.DB = value;
scsi.Think();
// Console.WriteLine("Write to CDC Command [1] {0:X2}", value);
break;
case 0x1802: // ACK and Interrupt Control
CdIoPorts[2] = value;
scsi.ACK = ((value & 0x80) != 0);
scsi.Think();
RefreshIRQ2();
break;
case 0x1804: // CD Reset Command
CdIoPorts[4] = value;
scsi.RST = ((value & 0x02) != 0);
scsi.Think();
if (scsi.RST)
{
CdIoPorts[3] &= 0x8F; // Clear interrupt control bits
RefreshIRQ2();
}
break;
case 0x1807: // BRAM Unlock
@ -28,23 +60,23 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
case 0x180B: // ADPCM DMA Control
CdIoPorts[0x0B] = value;
Console.WriteLine("Write to ADPCM DMA Control [B]");
// Console.WriteLine("Write to ADPCM DMA Control [B]");
// TODO... there is DMA to be done
break;
case 0x180D: // ADPCM Address Control
CdIoPorts[0x0D] = value;
Console.WriteLine("Write to ADPCM Address Control [D]");
// Console.WriteLine("Write to ADPCM Address Control [D]");
break;
case 0x180E: // ADPCM Playback Rate
CdIoPorts[0x0E] = value;
Console.WriteLine("Write to ADPCM Address Control [E]");
// Console.WriteLine("Write to ADPCM Address Control [E]");
break;
case 0x180F: // Audio Fade Timer
CdIoPorts[0x0F] = value;
Console.WriteLine("Write to CD Audio fade timer [F]");
// Console.WriteLine("Write to CD Audio fade timer [F]");
// TODO: hook this up to audio system);
break;
@ -56,29 +88,58 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
public byte ReadCD(int addr)
{
byte returnValue = 0;
switch (addr & 0x1FFF)
{
case 0x1800: // SCSI Drive Control Line
scsi.Think();
if (scsi.IO) returnValue |= 0x08;
if (scsi.CD) returnValue |= 0x10;
if (scsi.MSG) returnValue |= 0x20;
if (scsi.REQ) returnValue |= 0x40;
if (scsi.BSY) returnValue |= 0x80;
//if (returnValue != 0) returnValue = 0x40;
Console.WriteLine("Read SCSI Drive Control Line [0]: {0:X2} btw, pc={1:X4} ", returnValue,this.Cpu.PC);
return returnValue;
case 0x1802: // ADPCM / CD Control
Console.WriteLine("Read 1802 {0:X2}", CdIoPorts[2]);
return CdIoPorts[2];
case 0x1803: // BRAM Lock
if (BramEnabled)
{
Console.WriteLine("LOCKED BRAM!");
Console.WriteLine("LOCKED BRAM! (read 1803)");
BramLocked = true;
}
return CdIoPorts[3];
case 0x1804: // CD Reset
Console.WriteLine("Read 1804 {0:X2}", CdIoPorts[4]);
return CdIoPorts[4];
case 0x180F: // Audio Fade Timer
Console.WriteLine("Read 180F {0:X2}", CdIoPorts[0xF]);
return CdIoPorts[0x0F];
// These are some retarded version check
case 0x18C1: return 0xAA;
case 0x18C2: return 0x55;
case 0x18C3: return 0x00;
case 0x18C5: return 0xAA;
case 0x18C6: return 0x55;
case 0x18C7: return 0x03;
default:
Console.WriteLine("unknown read to {0:X4}", addr);
return 0xFF;
}
}
private void RefreshIRQ2()
{
int mask = CdIoPorts[2] & CdIoPorts[3] & 0x7C;
Cpu.IRQ2Assert = (mask != 0);
}
}
}

View File

@ -2174,7 +2174,7 @@ BB4429B6 Paranoia PCE
E6458212 Parasol Stars PCE
647718F9 Parodius PCE
740491C2 PC Denjin - Punkic Cyborgs PCE
4938B8BB Populous PCE BRAM
4938B8BB Populous PCE BRAM;PopulousSRAM
25E0F6E9 Power Drift PCE
BE8B6E3B Power Gate PCE
04A85769 Power League PCE