diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 4c85a02848..0703028e19 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -112,6 +112,8 @@ + + diff --git a/BizHawk.Emulation/CPUs/HuC6280/Execute.cs b/BizHawk.Emulation/CPUs/HuC6280/Execute.cs index a314c04818..8f81b4f7d2 100644 --- a/BizHawk.Emulation/CPUs/HuC6280/Execute.cs +++ b/BizHawk.Emulation/CPUs/HuC6280/Execute.cs @@ -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))); diff --git a/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs b/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs index 47b54ab6af..aa8570d994 100644 --- a/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs +++ b/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs @@ -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; diff --git a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs index d3a2dd75d7..d5550b6453 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs @@ -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); diff --git a/BizHawk.Emulation/Consoles/PC Engine/ScsiCD.cs b/BizHawk.Emulation/Consoles/PC Engine/ScsiCD.cs new file mode 100644 index 0000000000..bc16e2888d --- /dev/null +++ b/BizHawk.Emulation/Consoles/PC Engine/ScsiCD.cs @@ -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 + ============================================================================== + + */ + + } +} diff --git a/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs b/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs index f9c562e823..a902c71c9b 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs @@ -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); + } } } diff --git a/BizHawk.MultiClient/output/gamedb.txt b/BizHawk.MultiClient/output/gamedb.txt index aeb2f4c38c..adaafdbeed 100644 --- a/BizHawk.MultiClient/output/gamedb.txt +++ b/BizHawk.MultiClient/output/gamedb.txt @@ -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