Extremely preliminary TurboCD support
This commit is contained in:
parent
cfccc65672
commit
0a5157d9a6
|
@ -112,8 +112,9 @@
|
|||
<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.TurboCD.cs" />
|
||||
<Compile Include="Consoles\PC Engine\MemoryMap.Populous.cs" />
|
||||
<Compile Include="Consoles\PC Engine\ScsiCD.cs" />
|
||||
<Compile Include="Consoles\PC Engine\ScsiCDBus.cs" />
|
||||
<Compile Include="Consoles\PC Engine\TurboCD.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\MemoryMap.CodeMasters.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\MemoryMap.Sega.cs" />
|
||||
|
@ -222,6 +223,7 @@
|
|||
<Compile Include="Interfaces\Base Implementations\NullEmulator.cs" />
|
||||
<Compile Include="Interfaces\CoreComms.cs" />
|
||||
<Compile Include="QuickCollections.cs" />
|
||||
<Compile Include="Sound\CDAudio.cs" />
|
||||
<Compile Include="Sound\Utilities\BufferedAsync.cs" />
|
||||
<Compile Include="Sound\Utilities\Metaspu.cs" />
|
||||
<Compile Include="Interfaces\IController.cs" />
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace BizHawk.Emulation.CPUs.H6280
|
|||
public bool TimerAssert;
|
||||
public byte IRQControlByte, IRQNextControlByte;
|
||||
|
||||
public int TotalExecutedCycles;
|
||||
public long TotalExecutedCycles;
|
||||
public int PendingCycles;
|
||||
public bool LowSpeed;
|
||||
|
||||
|
@ -124,7 +124,7 @@ namespace BizHawk.Emulation.CPUs.H6280
|
|||
else if (args[0] == "IRQNextControlByte")
|
||||
IRQNextControlByte = byte.Parse(args[1], NumberStyles.HexNumber);
|
||||
else if (args[0] == "ExecutedCycles")
|
||||
TotalExecutedCycles = int.Parse(args[1]);
|
||||
TotalExecutedCycles = long.Parse(args[1]);
|
||||
else if (args[0] == "PendingCycles")
|
||||
PendingCycles = int.Parse(args[1]);
|
||||
else if (args[0] == "LowSpeed")
|
||||
|
@ -194,7 +194,7 @@ namespace BizHawk.Emulation.CPUs.H6280
|
|||
TimerAssert = reader.ReadBoolean();
|
||||
IRQControlByte = reader.ReadByte();
|
||||
IRQNextControlByte = reader.ReadByte();
|
||||
TotalExecutedCycles = reader.ReadInt32();
|
||||
TotalExecutedCycles = reader.ReadInt64();
|
||||
PendingCycles = reader.ReadInt32();
|
||||
LowSpeed = reader.ReadBoolean();
|
||||
|
||||
|
|
|
@ -63,8 +63,8 @@
|
|||
|
||||
if (Region == "Japan") value |= 0x40;
|
||||
|
||||
/*if (Type != NecSystemType.TurboCD)
|
||||
value |= 0x80;*/
|
||||
if (Type != NecSystemType.TurboCD && BramEnabled == false)
|
||||
value |= 0x80;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
namespace BizHawk.Emulation.Consoles.TurboGrafx
|
||||
{
|
||||
public partial class PCEngine
|
||||
{
|
||||
private byte ReadMemoryCD(int addr)
|
||||
{
|
||||
if (addr < 0xD0000) // read ROM
|
||||
return RomData[addr % RomLength];
|
||||
|
||||
if (addr >= 0x1F0000 && addr < 0x1F8000) // read RAM
|
||||
return Ram[addr & 0x1FFF];
|
||||
|
||||
if (addr >= 0x100000 && addr < 0x110000) // read CD RAM
|
||||
return CDRam[addr & 0xFFFF];
|
||||
|
||||
if (addr >= 0xD0000 && addr < 0x100000 && SuperRam != null) // Super SysCard RAM
|
||||
return SuperRam[addr - 0xD0000];
|
||||
|
||||
if (addr >= 0x1FE000) // hardware page.
|
||||
{
|
||||
if (addr < 0x1FE400) return VDC1.ReadVDC(addr);
|
||||
if (addr < 0x1FE800) { Cpu.PendingCycles--; return VCE.ReadVCE(addr); }
|
||||
if (addr < 0x1FEC00) return IOBuffer;
|
||||
if (addr < 0x1FF000) { IOBuffer = (byte)(Cpu.ReadTimerValue() | (IOBuffer & 0x80)); return IOBuffer; }
|
||||
if (addr >= 0x1FF000 &&
|
||||
addr < 0x1FF400) { IOBuffer = ReadInput(); return IOBuffer; }
|
||||
if ((addr & ~1) == 0x1FF400) return IOBuffer;
|
||||
if (addr == 0x1FF402) { IOBuffer = (byte)(Cpu.IRQControlByte | (IOBuffer & 0xF8)); return IOBuffer; }
|
||||
if (addr == 0x1FF403) { IOBuffer = (byte)(Cpu.ReadIrqStatus() | (IOBuffer & 0xF8)); return IOBuffer; }
|
||||
if (addr >= 0x1FF800) return ReadCD(addr);
|
||||
}
|
||||
|
||||
if (addr >= 0x1EE000 && addr <= 0x1EE7FF) // BRAM
|
||||
{
|
||||
if (BramEnabled && BramLocked == false)
|
||||
return BRAM[addr & 0x7FF];
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
Log.Error("MEM", "UNHANDLED READ: {0:X6}", addr);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
private void WriteMemoryCD(int addr, byte value)
|
||||
{
|
||||
if (addr >= 0x1F0000 && addr < 0x1F8000) // write RAM.
|
||||
Ram[addr & 0x1FFF] = value;
|
||||
|
||||
else if (addr >= 0x100000 && addr < 0x110000) // write CD-RAM
|
||||
CDRam[addr & 0xFFFF] = value;
|
||||
|
||||
else if (addr >= 0xD0000 && addr < 0x100000 && SuperRam != null) // Super SysCard RAM
|
||||
SuperRam[addr - 0xD0000] = value;
|
||||
|
||||
else if (addr >= 0x1FE000) // hardware page.
|
||||
{
|
||||
if (addr < 0x1FE400) VDC1.WriteVDC(addr, value);
|
||||
else if (addr < 0x1FE800) { Cpu.PendingCycles--; VCE.WriteVCE(addr, value); }
|
||||
else if (addr < 0x1FEC00) { IOBuffer = value; PSG.WritePSG((byte)addr, value, Cpu.TotalExecutedCycles); }
|
||||
else if (addr == 0x1FEC00) { IOBuffer = value; Cpu.WriteTimer(value); }
|
||||
else if (addr == 0x1FEC01) { IOBuffer = value; Cpu.WriteTimerEnable(value); }
|
||||
else if (addr >= 0x1FF000 &&
|
||||
addr < 0x1FF400) { IOBuffer = value; WriteInput(value); }
|
||||
else if (addr == 0x1FF402) { IOBuffer = value; Cpu.WriteIrqControl(value); }
|
||||
else if (addr == 0x1FF403) { IOBuffer = value; Cpu.WriteIrqStatus(); }
|
||||
else if (addr >= 0x1FF800) { WriteCD(addr, value); }
|
||||
else Log.Error("MEM", "unhandled hardware write [{0:X6}] : {1:X2}", addr, value);
|
||||
}
|
||||
|
||||
else if (addr >= 0x1EE000 && addr <= 0x1EE7FF) // BRAM
|
||||
{
|
||||
if (BramEnabled && BramLocked == false)
|
||||
{
|
||||
BRAM[addr & 0x7FF] = value;
|
||||
SaveRamModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
Log.Error("MEM", "UNHANDLED WRITE: {0:X6}:{1:X2}", addr, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,11 +29,7 @@
|
|||
if (addr >= 0x1EE000 && addr <= 0x1EE7FF) // BRAM
|
||||
{
|
||||
if (BramEnabled && BramLocked == false)
|
||||
{
|
||||
System.Console.WriteLine("READ BRAM[{0}] ; ret {1:X2}", addr & 0x7FF, BRAM[addr & 0x7FF]);
|
||||
return BRAM[addr & 0x7FF];
|
||||
}
|
||||
System.Console.WriteLine("attemped BRAM read while locked");
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
@ -44,11 +40,7 @@
|
|||
private void WriteMemory(int addr, byte value)
|
||||
{
|
||||
if (addr >= 0x1F0000 && addr < 0x1F8000) // write RAM.
|
||||
{
|
||||
//if (Cpu.debug)
|
||||
//Log.Note("MEM", "*Mem* Changed {0:X4} from {1:X2} to {2:X2}", addr & 0x1FFF, Ram[addr & 0x1FFF], value);
|
||||
Ram[addr & 0x1FFF] = value;
|
||||
}
|
||||
|
||||
else if (addr >= 0x1FE000) // hardware page.
|
||||
{
|
||||
|
@ -69,11 +61,9 @@
|
|||
{
|
||||
if (BramEnabled && BramLocked == false)
|
||||
{
|
||||
System.Console.WriteLine("WRITE BRAM[{0}] : {1:X2}", addr & 0x7FF, value);
|
||||
BRAM[addr & 0x7FF] = value;
|
||||
SaveRamModified = true;
|
||||
}
|
||||
else System.Console.WriteLine("attemped BRAM write while locked!");
|
||||
}
|
||||
|
||||
else
|
||||
|
|
|
@ -27,8 +27,14 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
public HuC6280 Cpu;
|
||||
public VDC VDC1, VDC2;
|
||||
public VCE VCE;
|
||||
public HuC6280PSG PSG;
|
||||
public VPC VPC;
|
||||
public ScsiCDBus SCSI;
|
||||
|
||||
public HuC6280PSG PSG;
|
||||
public CDAudio CDAudio;
|
||||
// TODO ADPCM
|
||||
public SoundMixer SoundMixer;
|
||||
public MetaspuSoundProvider SoundSynchronizer;
|
||||
|
||||
private bool TurboGrafx { get { return Type == NecSystemType.TurboGrafx; } }
|
||||
private bool SuperGrafx { get { return Type == NecSystemType.SuperGrafx; } }
|
||||
|
@ -40,15 +46,18 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
private byte[] BRAM;
|
||||
|
||||
// Memory system
|
||||
public byte[] Ram;
|
||||
public byte[] Ram; // PCE= 8K base ram, SGX= 64k base ram
|
||||
public byte[] CDRam; // TurboCD extra 64k of ram
|
||||
public byte[] SuperRam; // Super System Card 192K of additional RAM
|
||||
public byte[] ArcadeRam; // Arcade Card 2048K of additional RAM
|
||||
|
||||
// PC Engine timings:
|
||||
// 21,477,270 Machine clocks / sec
|
||||
// 7,159,090 Cpu cycles / sec
|
||||
|
||||
public PCEngine(GameInfo game, byte[] rom)
|
||||
{
|
||||
CoreOutputComm = new CoreOutputComm();
|
||||
|
||||
switch (game.System)
|
||||
{
|
||||
case "PCE": Type = NecSystemType.TurboGrafx; break;
|
||||
|
@ -72,16 +81,19 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
VCE = new VCE();
|
||||
VDC1 = new VDC(Cpu, VCE);
|
||||
PSG = new HuC6280PSG();
|
||||
InitScsiBus();
|
||||
|
||||
if (TurboGrafx || TurboCD)
|
||||
if (TurboGrafx)
|
||||
{
|
||||
Ram = new byte[0x2000];
|
||||
Cpu.ReadMemory21 = ReadMemory;
|
||||
Cpu.WriteMemory21 = WriteMemory;
|
||||
Cpu.WriteVDC = VDC1.WriteVDC;
|
||||
soundProvider = PSG;
|
||||
CDAudio = new CDAudio(null, 0);
|
||||
}
|
||||
|
||||
if (SuperGrafx)
|
||||
else if (SuperGrafx)
|
||||
{
|
||||
VDC2 = new VDC(Cpu, VCE);
|
||||
VPC = new VPC(VDC1, VDC2, VCE, Cpu);
|
||||
|
@ -89,6 +101,23 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
Cpu.ReadMemory21 = ReadMemorySGX;
|
||||
Cpu.WriteMemory21 = WriteMemorySGX;
|
||||
Cpu.WriteVDC = VDC1.WriteVDC;
|
||||
soundProvider = PSG;
|
||||
CDAudio = new CDAudio(null, 0);
|
||||
}
|
||||
|
||||
else if (TurboCD)
|
||||
{
|
||||
Ram = new byte[0x2000];
|
||||
CDRam = new byte[0x10000];
|
||||
Cpu.ReadMemory21 = ReadMemoryCD;
|
||||
Cpu.WriteMemory21 = WriteMemoryCD;
|
||||
Cpu.WriteVDC = VDC1.WriteVDC;
|
||||
CDAudio = new CDAudio(disc, short.MaxValue);
|
||||
// TODO ADPCM
|
||||
SoundMixer = new SoundMixer(PSG, CDAudio);
|
||||
SoundSynchronizer = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V);
|
||||
soundProvider = SoundSynchronizer;
|
||||
VDC1.MidScanlineThink = () => SCSI.Think();
|
||||
}
|
||||
|
||||
if (rom.Length == 0x60000)
|
||||
|
@ -114,7 +143,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
RomLength = RomData.Length;
|
||||
}
|
||||
|
||||
if (game["BRAM"])
|
||||
if (game["BRAM"] || Type == NecSystemType.TurboCD)
|
||||
{
|
||||
BramEnabled = true;
|
||||
BRAM = new byte[2048];
|
||||
|
@ -125,6 +154,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
BRAM[4] = 0x00; BRAM[5] = 0x88; BRAM[6] = 0x10; BRAM[7] = 0x80;
|
||||
}
|
||||
|
||||
if (game["SuperSysCard"])
|
||||
SuperRam = new byte[0x30000];
|
||||
|
||||
if (game["ArcadeCard"])
|
||||
ArcadeRam = new byte[0x200000];
|
||||
|
||||
if (game["PopulousSRAM"])
|
||||
{
|
||||
PopulousRAM = new byte[0x8000];
|
||||
|
@ -188,6 +223,9 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
VDC1.ExecFrame(render);
|
||||
|
||||
PSG.EndFrame(Cpu.TotalExecutedCycles);
|
||||
if (TurboCD)
|
||||
SoundSynchronizer.PullSamples(SoundMixer);
|
||||
|
||||
if (lagged)
|
||||
{
|
||||
_lagcount++;
|
||||
|
@ -205,9 +243,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
get { return (IVideoProvider) VPC ?? VDC1; }
|
||||
}
|
||||
|
||||
private ISoundProvider soundProvider;
|
||||
public ISoundProvider SoundProvider
|
||||
{
|
||||
get { return PSG; }
|
||||
get { return soundProvider; }
|
||||
}
|
||||
|
||||
public string SystemId { get { return "PCE"; } }
|
||||
|
@ -254,6 +293,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
VDC1.SaveStateText(writer, 1);
|
||||
PSG.SaveStateText(writer);
|
||||
}
|
||||
if (TurboCD)
|
||||
{
|
||||
CDAudio.SaveStateText(writer);
|
||||
}
|
||||
writer.WriteLine("[/PCEngine]");
|
||||
}
|
||||
|
||||
|
@ -289,6 +332,8 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
VDC1.LoadStateText(reader, 1);
|
||||
else if (args[0] == "[VDC2]")
|
||||
VDC2.LoadStateText(reader, 2);
|
||||
else if (args[0] == "[CDAudio]")
|
||||
CDAudio.LoadStateText(reader);
|
||||
else
|
||||
Console.WriteLine("Skipping unrecognized identifier " + args[0]);
|
||||
}
|
||||
|
@ -299,8 +344,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
if (SuperGrafx == false)
|
||||
{
|
||||
writer.Write(Ram);
|
||||
if (BRAM != null)
|
||||
writer.Write(BRAM);
|
||||
if (PopulousRAM != null)
|
||||
writer.Write(PopulousRAM);
|
||||
if (SuperRam != null)
|
||||
writer.Write(SuperRam);
|
||||
writer.Write(Frame);
|
||||
writer.Write(_lagcount);
|
||||
writer.Write(SF2MapperLatch);
|
||||
|
@ -309,6 +358,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
VCE.SaveStateBinary(writer);
|
||||
VDC1.SaveStateBinary(writer);
|
||||
PSG.SaveStateBinary(writer);
|
||||
if (TurboCD)
|
||||
{
|
||||
CDAudio.SaveStateBinary(writer);
|
||||
}
|
||||
} else {
|
||||
writer.Write(Ram);
|
||||
writer.Write(Frame);
|
||||
|
@ -328,8 +381,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
if (SuperGrafx == false)
|
||||
{
|
||||
Ram = reader.ReadBytes(0x2000);
|
||||
if (BRAM != null)
|
||||
BRAM = reader.ReadBytes(0x800);
|
||||
if (PopulousRAM != null)
|
||||
PopulousRAM = reader.ReadBytes(0x8000);
|
||||
if (SuperRam != null)
|
||||
SuperRam = reader.ReadBytes(0x30000);
|
||||
Frame = reader.ReadInt32();
|
||||
_lagcount = reader.ReadInt32();
|
||||
SF2MapperLatch = reader.ReadByte();
|
||||
|
@ -338,6 +395,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
VCE.LoadStateBinary(reader);
|
||||
VDC1.LoadStateBinary(reader);
|
||||
PSG.LoadStateBinary(reader);
|
||||
if (TurboCD)
|
||||
{
|
||||
CDAudio.LoadStateBinary(reader);
|
||||
}
|
||||
} else {
|
||||
Ram = reader.ReadBytes(0x8000);
|
||||
Frame = reader.ReadInt32();
|
||||
|
@ -354,16 +415,19 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
int buflen = 75866;
|
||||
int buflen = 75870;
|
||||
if (SuperGrafx) buflen += 90698;
|
||||
if (BramEnabled) buflen += 2048;
|
||||
if (PopulousRAM != null) buflen += 0x8000;
|
||||
if (SuperRam != null) buflen += 0x30000;
|
||||
if (TurboCD) buflen += 26;
|
||||
//Console.WriteLine("LENGTH1 " + buflen);
|
||||
|
||||
var buf = new byte[buflen];
|
||||
var stream = new MemoryStream(buf);
|
||||
var writer = new BinaryWriter(stream);
|
||||
SaveStateBinary(writer);
|
||||
//Console.WriteLine("LENGTH " + stream.Position);
|
||||
//Console.WriteLine("LENGTH2 " + stream.Position);
|
||||
writer.Close();
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
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
|
||||
==============================================================================
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,652 @@
|
|||
using System;
|
||||
using BizHawk.DiscSystem;
|
||||
using BizHawk.Emulation.Sound;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.TurboGrafx
|
||||
{
|
||||
public sealed class ScsiCDBus
|
||||
{
|
||||
private const int STATUS_GOOD = 0;
|
||||
private const int STATUS_CHECK_CONDITION = 1;
|
||||
private const int STATUS_CONDITION_MET = 2;
|
||||
private const int STATUS_BUSY = 4;
|
||||
private const int STATUS_INTERMEDIATE = 8;
|
||||
|
||||
private const int SCSI_TEST_UNIT_READY = 0x00;
|
||||
private const int SCSI_REQUEST_SENSE = 0x03;
|
||||
private const int SCSI_READ = 0x08;
|
||||
private const int SCSI_AUDIO_START_POS = 0xD8;
|
||||
private const int SCSI_AUDIO_END_POS = 0xD9;
|
||||
private const int SCSI_PAUSE = 0xDA;
|
||||
private const int SCSI_READ_SUBCODE_Q = 0xDD;
|
||||
private const int SCSI_READ_TOC = 0xDE;
|
||||
|
||||
private bool bsy, sel, cd, io, msg, req, ack, atn, rst;
|
||||
private bool signalsChanged;
|
||||
|
||||
public bool BSY
|
||||
{
|
||||
get { return bsy; }
|
||||
set {
|
||||
if (value != BSY) signalsChanged = true;
|
||||
bsy = value;
|
||||
}
|
||||
}
|
||||
public bool SEL
|
||||
{
|
||||
get { return sel; }
|
||||
set
|
||||
{
|
||||
if (value != SEL) signalsChanged = true;
|
||||
sel = value;
|
||||
}
|
||||
}
|
||||
public bool CD // CONTROL = true, DATA = false
|
||||
{
|
||||
get { return cd; }
|
||||
set
|
||||
{
|
||||
if (value != CD) signalsChanged = true;
|
||||
cd = value;
|
||||
}
|
||||
}
|
||||
public bool IO // INPUT = true, OUTPUT = false
|
||||
{
|
||||
get { return io; }
|
||||
set
|
||||
{
|
||||
if (value != IO) signalsChanged = true;
|
||||
io = value;
|
||||
}
|
||||
}
|
||||
public bool MSG
|
||||
{
|
||||
get { return msg; }
|
||||
set
|
||||
{
|
||||
if (value != MSG) signalsChanged = true;
|
||||
msg = value;
|
||||
}
|
||||
}
|
||||
public bool REQ
|
||||
{
|
||||
get { return req; }
|
||||
set
|
||||
{
|
||||
if (value != REQ) signalsChanged = true;
|
||||
req = value;
|
||||
}
|
||||
}
|
||||
public bool ACK
|
||||
{
|
||||
get { return ack; }
|
||||
set
|
||||
{
|
||||
if (value != ACK) signalsChanged = true;
|
||||
ack = value;
|
||||
}
|
||||
}
|
||||
public bool ATN
|
||||
{
|
||||
get { return atn; }
|
||||
set
|
||||
{
|
||||
if (value != ATN) signalsChanged = true;
|
||||
atn = value;
|
||||
}
|
||||
}
|
||||
public bool RST
|
||||
{
|
||||
get { return rst; }
|
||||
set
|
||||
{
|
||||
if (value != RST) signalsChanged = true;
|
||||
rst = value;
|
||||
}
|
||||
}
|
||||
public byte DataBits { get; set; } // data bits
|
||||
|
||||
private enum BusPhase
|
||||
{
|
||||
BusFree,
|
||||
Command,
|
||||
DataIn,
|
||||
DataOut,
|
||||
MessageIn,
|
||||
MessageOut,
|
||||
Status
|
||||
}
|
||||
|
||||
private bool busPhaseChanged;
|
||||
private BusPhase Phase = BusPhase.BusFree;
|
||||
|
||||
private bool MessageCompleted;
|
||||
private bool StatusCompleted;
|
||||
private byte MessageValue;
|
||||
|
||||
private QuickList<byte> CommandBuffer = new QuickList<byte>(10); // 10 = biggest command
|
||||
public QuickQueue<byte> DataIn = new QuickQueue<byte>(2048); // proper size
|
||||
|
||||
// ******** Data Transfer / READ command support ********
|
||||
private long DataReadWaitTimer;
|
||||
private bool DataReadInProgress;
|
||||
private bool DataTransferWasDone;
|
||||
private int CurrentReadingSector;
|
||||
private int SectorsLeftToRead;
|
||||
|
||||
// ******** Resources ********
|
||||
|
||||
private PCEngine pce;
|
||||
public Disc disc;
|
||||
|
||||
// ******** Events ********
|
||||
|
||||
public Action<bool> DataTransferReady;
|
||||
public Action<bool> DataTransferComplete;
|
||||
|
||||
public ScsiCDBus(PCEngine pce, Disc disc)
|
||||
{
|
||||
this.pce = pce;
|
||||
this.disc = disc;
|
||||
}
|
||||
|
||||
public void Think()
|
||||
{
|
||||
if (RST)
|
||||
{
|
||||
ResetDevice();
|
||||
return;
|
||||
}
|
||||
|
||||
if (DataReadInProgress && pce.Cpu.TotalExecutedCycles > DataReadWaitTimer)
|
||||
{
|
||||
if (DataIn.Count == 0)
|
||||
{
|
||||
Console.WriteLine("Sector available to read!!!");
|
||||
// read in a sector and shove it in the queue
|
||||
disc.ReadLBA_2048(CurrentReadingSector, DataIn.GetBuffer(), 0);
|
||||
DataIn.SignalBufferFilled(2048);
|
||||
CurrentReadingSector++;
|
||||
SectorsLeftToRead--;
|
||||
|
||||
DataTransferReady(true);
|
||||
|
||||
// If more sectors, should set the next think-clock to however long it takes to read 1 sector
|
||||
// but I dont. I dont think transfers actually happen sector by sector
|
||||
// like this, they probably become available as the bits come off the disc.
|
||||
// but lets get some basic functionality before we go crazy.
|
||||
// Idunno, maybe they do come in a sector at a time.
|
||||
if (SectorsLeftToRead == 0)
|
||||
{
|
||||
DataReadInProgress = false;
|
||||
DataTransferWasDone = true;
|
||||
}
|
||||
SetPhase(BusPhase.DataIn);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
signalsChanged = false;
|
||||
busPhaseChanged = false;
|
||||
|
||||
if (SEL && !BSY)
|
||||
{
|
||||
SetPhase(BusPhase.Command);
|
||||
}
|
||||
else if (ATN && !REQ && !ACK)
|
||||
{
|
||||
SetPhase(BusPhase.MessageOut);
|
||||
}
|
||||
else switch (Phase)
|
||||
{
|
||||
case BusPhase.Command: ThinkCommandPhase(); break;
|
||||
case BusPhase.DataIn: ThinkDataInPhase(); break;
|
||||
case BusPhase.DataOut: ThinkDataOutPhase(); break;
|
||||
case BusPhase.MessageIn: ThinkMessageInPhase(); break;
|
||||
case BusPhase.MessageOut: ThinkMessageOutPhase(); break;
|
||||
case BusPhase.Status: ThinkStatusPhase(); break;
|
||||
default: break;
|
||||
}
|
||||
} while (signalsChanged || busPhaseChanged);
|
||||
}
|
||||
|
||||
private void ResetDevice()
|
||||
{
|
||||
CD = false;
|
||||
IO = false;
|
||||
MSG = false;
|
||||
REQ = false;
|
||||
ACK = false;
|
||||
ATN = false;
|
||||
DataBits = 0;
|
||||
Phase = BusPhase.BusFree;
|
||||
|
||||
CommandBuffer.Clear();
|
||||
DataIn.Clear();
|
||||
DataReadInProgress = false;
|
||||
pce.CDAudio.Stop();
|
||||
}
|
||||
|
||||
private void ThinkCommandPhase()
|
||||
{
|
||||
if (REQ && ACK)
|
||||
{
|
||||
CommandBuffer.Add(DataBits);
|
||||
REQ = false;
|
||||
}
|
||||
|
||||
if (!REQ && !ACK && CommandBuffer.Count > 0)
|
||||
{
|
||||
bool complete = CheckCommandBuffer();
|
||||
|
||||
if (complete)
|
||||
{
|
||||
CommandBuffer.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
REQ = true; // needs more data!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ThinkDataInPhase()
|
||||
{
|
||||
if (REQ && ACK)
|
||||
{
|
||||
REQ = false;
|
||||
}
|
||||
else if (!REQ && !ACK)
|
||||
{
|
||||
if (DataIn.Count > 0)
|
||||
{
|
||||
DataBits = DataIn.Dequeue();
|
||||
REQ = true;
|
||||
} else {
|
||||
// data transfer is finished
|
||||
|
||||
DataTransferReady(false);
|
||||
if (DataTransferWasDone)
|
||||
{
|
||||
Console.WriteLine("DATA TRANSFER FINISHED!");
|
||||
DataTransferWasDone = false;
|
||||
DataTransferComplete(true);
|
||||
}
|
||||
SetStatusMessage(STATUS_GOOD, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ThinkDataOutPhase()
|
||||
{
|
||||
Console.WriteLine("*********** DATA OUT PHASE, DOES THIS HAPPEN? ****************");
|
||||
SetPhase(BusPhase.BusFree);
|
||||
}
|
||||
|
||||
private void ThinkMessageInPhase()
|
||||
{
|
||||
if (REQ && ACK)
|
||||
{
|
||||
REQ = false;
|
||||
MessageCompleted = true;
|
||||
}
|
||||
|
||||
if (!REQ && !ACK && MessageCompleted)
|
||||
{
|
||||
MessageCompleted = false;
|
||||
SetPhase(BusPhase.BusFree);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThinkMessageOutPhase()
|
||||
{
|
||||
Console.WriteLine("******* IN MESSAGE OUT PHASE. DOES THIS EVER HAPPEN? ********");
|
||||
SetPhase(BusPhase.BusFree);
|
||||
}
|
||||
|
||||
private void ThinkStatusPhase()
|
||||
{
|
||||
if (REQ && ACK)
|
||||
{
|
||||
REQ = false;
|
||||
StatusCompleted = true;
|
||||
}
|
||||
if (!REQ && !ACK && StatusCompleted)
|
||||
{
|
||||
StatusCompleted = false;
|
||||
DataBits = MessageValue;
|
||||
SetPhase(BusPhase.MessageIn);
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if command completed, false if more data bytes needed
|
||||
private bool CheckCommandBuffer()
|
||||
{
|
||||
switch (CommandBuffer[0])
|
||||
{
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
if (CommandBuffer.Count < 6) return false;
|
||||
Log.Note("CD", "Execute TEST_UNIT_READY");
|
||||
SetStatusMessage(STATUS_GOOD, 0);
|
||||
return true;
|
||||
|
||||
case SCSI_READ:
|
||||
if (CommandBuffer.Count < 6) return false;
|
||||
CommandRead();
|
||||
return true;
|
||||
|
||||
case SCSI_AUDIO_START_POS:
|
||||
if (CommandBuffer.Count < 10) return false;
|
||||
CommandAudioStartPos();
|
||||
return true;
|
||||
|
||||
case SCSI_AUDIO_END_POS:
|
||||
if (CommandBuffer.Count < 10) return false;
|
||||
CommandAudioEndPos();
|
||||
return true;
|
||||
|
||||
case SCSI_PAUSE:
|
||||
if (CommandBuffer.Count < 10) return false;
|
||||
CommandPause();
|
||||
return true;
|
||||
|
||||
case SCSI_READ_SUBCODE_Q:
|
||||
if (CommandBuffer.Count < 10) return false;
|
||||
CommandReadSubcodeQ();
|
||||
return true;
|
||||
|
||||
case SCSI_READ_TOC:
|
||||
if (CommandBuffer.Count < 10) return false;
|
||||
CommandReadTOC();
|
||||
return true;
|
||||
|
||||
default:
|
||||
Console.WriteLine("UNRECOGNIZED SCSI COMMAND! {0:X2}", CommandBuffer[0]);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CommandRead()
|
||||
{
|
||||
int sector = (CommandBuffer[1] & 0x1f) << 16;
|
||||
sector |= CommandBuffer[2] << 8;
|
||||
sector |= CommandBuffer[3];
|
||||
sector += 150; // BLEH
|
||||
|
||||
if (CommandBuffer[4] == 0)
|
||||
throw new Exception("requesting 0 sectors read.............................");
|
||||
|
||||
DataReadInProgress = true;
|
||||
CurrentReadingSector = sector;
|
||||
SectorsLeftToRead = CommandBuffer[4];
|
||||
|
||||
Console.WriteLine("STARTED READ: {0} SECTORS FROM {1}",SectorsLeftToRead, CurrentReadingSector);
|
||||
DataReadWaitTimer = pce.Cpu.TotalExecutedCycles + 5000; // figure out proper read delay later
|
||||
pce.CDAudio.Stop();
|
||||
}
|
||||
|
||||
private int audioStartLBA;
|
||||
private int audioEndLBA;
|
||||
|
||||
private void CommandAudioStartPos()
|
||||
{
|
||||
switch (CommandBuffer[9] & 0xC0)
|
||||
{
|
||||
case 0x00: // Set start offset in LBA units
|
||||
audioStartLBA = (CommandBuffer[3] << 16) | (CommandBuffer[4] << 8) | CommandBuffer[5];
|
||||
Console.WriteLine("Set Start LBA: "+audioStartLBA);
|
||||
break;
|
||||
|
||||
case 0x40: // Set start offset in MSF units
|
||||
byte m = CommandBuffer[2].BCDtoBin();
|
||||
byte s = CommandBuffer[3].BCDtoBin();
|
||||
byte f = CommandBuffer[4].BCDtoBin();
|
||||
audioStartLBA = Disc.ConvertMSFtoLBA(m, s, f);
|
||||
Console.WriteLine("Set Start MSF: {0} {1} {2} lba={3}",m,s,f,audioStartLBA);
|
||||
break;
|
||||
|
||||
case 0x80: // Set start offset in track units
|
||||
byte trackNo = CommandBuffer[2].BCDtoBin();
|
||||
audioStartLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].lba;
|
||||
Console.WriteLine("Set Start track: {0} lba={1}", trackNo, audioStartLBA);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CommandBuffer[1] == 0)
|
||||
{
|
||||
pce.CDAudio.Pause();
|
||||
// silent?
|
||||
} else {
|
||||
pce.CDAudio.PlayStartingAtLba(audioStartLBA);
|
||||
}
|
||||
|
||||
// TODO there are some flags in command[1]
|
||||
// wat we do if audio is already playing
|
||||
// wat we do if audio paused
|
||||
|
||||
SetStatusMessage(STATUS_GOOD, 0);
|
||||
// irq callback?
|
||||
}
|
||||
|
||||
private void CommandAudioEndPos()
|
||||
{
|
||||
switch (CommandBuffer[9] & 0xC0)
|
||||
{
|
||||
case 0x00: // Set end offset in LBA units
|
||||
audioEndLBA = (CommandBuffer[3] << 16) | (CommandBuffer[4] << 8) | CommandBuffer[5];
|
||||
Console.WriteLine("Set End LBA: " + audioEndLBA);
|
||||
break;
|
||||
|
||||
case 0x40: // Set end offset in MSF units
|
||||
byte m = CommandBuffer[2].BCDtoBin();
|
||||
byte s = CommandBuffer[3].BCDtoBin();
|
||||
byte f = CommandBuffer[4].BCDtoBin();
|
||||
audioEndLBA = Disc.ConvertMSFtoLBA(m, s, f);
|
||||
Console.WriteLine("Set End MSF: {0} {1} {2} lba={3}", m, s, f, audioEndLBA);
|
||||
break;
|
||||
|
||||
case 0x80: // Set end offset in track units
|
||||
byte trackNo = CommandBuffer[2].BCDtoBin();
|
||||
audioEndLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].lba;
|
||||
Console.WriteLine("Set End track: {0} lba={1}", trackNo, audioEndLBA);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (CommandBuffer[1])
|
||||
{
|
||||
case 0: // end immediately
|
||||
pce.CDAudio.Stop();
|
||||
break;
|
||||
case 1: // play in loop mode. I guess this constitues A-B looping
|
||||
Console.WriteLine("DOING A-B LOOP. NOT SURE IF RIGHT.");
|
||||
pce.CDAudio.PlayStartingAtLba(audioStartLBA);
|
||||
pce.CDAudio.EndLBA = audioEndLBA;
|
||||
pce.CDAudio.PlayMode = CDAudio.PlaybackMode.LoopOnCompletion;
|
||||
break;
|
||||
case 2: // Play audio, fire IRQ2 when end position reached
|
||||
Console.WriteLine("STOP MODE 2 ENGAGED, BUT NOTE. IRQ WILL NOT FIRE YET.");
|
||||
pce.CDAudio.PlayStartingAtLba(audioStartLBA);
|
||||
pce.CDAudio.EndLBA = audioEndLBA;
|
||||
pce.CDAudio.PlayMode = CDAudio.PlaybackMode.IRQOnCompletion;
|
||||
break;
|
||||
case 3: // Play normal
|
||||
Console.WriteLine("*** SET END POS, IN PLAY NORMAL MODE? STARTING AT _START_ POS. IS THAT RIGHT?");
|
||||
pce.CDAudio.PlayStartingAtLba(audioStartLBA);
|
||||
pce.CDAudio.EndLBA = audioEndLBA;
|
||||
pce.CDAudio.PlayMode = CDAudio.PlaybackMode.StopOnCompletion;
|
||||
break;
|
||||
}
|
||||
SetStatusMessage(STATUS_GOOD, 0);
|
||||
}
|
||||
|
||||
private void CommandPause()
|
||||
{
|
||||
// apparently pause means stop? I guess? Idunno.
|
||||
pce.CDAudio.Stop();
|
||||
SetStatusMessage(STATUS_GOOD, 0);
|
||||
// TODO send error if already stopped.. or paused... or something.
|
||||
}
|
||||
|
||||
private void CommandReadSubcodeQ()
|
||||
{
|
||||
DataIn.Clear();
|
||||
|
||||
switch (pce.CDAudio.Mode)
|
||||
{
|
||||
case CDAudio.CDAudioMode.Playing: DataIn.Enqueue(0); break;
|
||||
case CDAudio.CDAudioMode.Paused: DataIn.Enqueue(2); break;
|
||||
case CDAudio.CDAudioMode.Stopped: DataIn.Enqueue(3); break;
|
||||
}
|
||||
DataIn.Enqueue(0); // unused?
|
||||
DataIn.Enqueue((byte)pce.CDAudio.PlayingTrack); // track
|
||||
DataIn.Enqueue(1); // index
|
||||
DataIn.Enqueue(1); // M(rel)
|
||||
DataIn.Enqueue(1); // S(rel)
|
||||
DataIn.Enqueue(1); // F(rel)
|
||||
DataIn.Enqueue(1); // M(abs)
|
||||
DataIn.Enqueue(1); // S(abs)
|
||||
DataIn.Enqueue(1); // F(abs)
|
||||
SetPhase(BusPhase.DataIn);
|
||||
}
|
||||
|
||||
private void CommandReadTOC()
|
||||
{
|
||||
switch (CommandBuffer[1])
|
||||
{
|
||||
case 0: // return number of tracks
|
||||
{
|
||||
Log.Error("CD","Execute READ_TOC : num of tracks");
|
||||
DataIn.Clear();
|
||||
DataIn.Enqueue(0x01);
|
||||
DataIn.Enqueue(((byte) disc.TOC.Sessions[0].Tracks.Count).BinToBCD());
|
||||
SetPhase(BusPhase.DataIn);
|
||||
break;
|
||||
}
|
||||
case 1: // return total disc length in minutes/seconds/frames
|
||||
{
|
||||
int totalLbaLength = disc.LBACount;
|
||||
|
||||
byte m, s, f;
|
||||
Disc.ConvertLBAtoMSF(totalLbaLength, out m, out s, out f);
|
||||
|
||||
DataIn.Clear();
|
||||
DataIn.Enqueue(m.BinToBCD());
|
||||
DataIn.Enqueue(s.BinToBCD());
|
||||
DataIn.Enqueue(f.BinToBCD());
|
||||
SetPhase(BusPhase.DataIn);
|
||||
|
||||
Log.Error("CD","EXECUTE READ_TOC : length of disc, LBA {0}, m:{1},s:{2},f:{3}",
|
||||
totalLbaLength, m, s, f);
|
||||
break;
|
||||
}
|
||||
case 2: // Return starting position of specified track in MSF format
|
||||
{
|
||||
int track = CommandBuffer[2].BCDtoBin();
|
||||
if (CommandBuffer[2] > 0x99)
|
||||
throw new Exception("invalid track number BCD request... is something I need to handle?");
|
||||
if (track == 0) track = 1;
|
||||
track--;
|
||||
if (track > disc.TOC.Sessions[0].Tracks.Count)
|
||||
throw new Exception("Request more tracks than exist.... need to do error handling");
|
||||
// I error handled your mom last night
|
||||
|
||||
int lbaPos = disc.TOC.Sessions[0].Tracks[track].Indexes[1].lba;
|
||||
byte m, s, f;
|
||||
Disc.ConvertLBAtoMSF(lbaPos, out m, out s, out f);
|
||||
|
||||
DataIn.Clear();
|
||||
DataIn.Enqueue(m.BinToBCD());
|
||||
DataIn.Enqueue(s.BinToBCD());
|
||||
DataIn.Enqueue(f.BinToBCD());
|
||||
if (disc.TOC.Sessions[0].Tracks[track].TrackType == ETrackType.Audio)
|
||||
DataIn.Enqueue(0);
|
||||
else
|
||||
DataIn.Enqueue(4);
|
||||
SetPhase(BusPhase.DataIn);
|
||||
|
||||
Log.Error("CD", "EXECUTE READ_TOC : start pos of TRACK {4}, LBA {0}, m:{1},s:{2},f:{3}",
|
||||
lbaPos, m, s, f, track);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Console.WriteLine("unimplemented READ TOC command argument!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetStatusMessage(byte status, byte message)
|
||||
{
|
||||
MessageValue = message;
|
||||
StatusCompleted = false;
|
||||
MessageCompleted = false;
|
||||
DataBits = status == STATUS_GOOD ? (byte) 0x00 : (byte) 0x01;
|
||||
SetPhase(BusPhase.Status);
|
||||
}
|
||||
|
||||
private void SetPhase(BusPhase phase)
|
||||
{
|
||||
if (Phase == phase)
|
||||
return;
|
||||
|
||||
Phase = phase;
|
||||
busPhaseChanged = true;
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
case BusPhase.BusFree:
|
||||
BSY = false;
|
||||
MSG = false;
|
||||
CD = false;
|
||||
IO = false;
|
||||
REQ = false;
|
||||
DataTransferComplete(false);
|
||||
break;
|
||||
case BusPhase.Command:
|
||||
BSY = true;
|
||||
MSG = false;
|
||||
CD = true;
|
||||
IO = false;
|
||||
REQ = true;
|
||||
break;
|
||||
case BusPhase.DataIn:
|
||||
BSY = true;
|
||||
MSG = false;
|
||||
CD = false;
|
||||
IO = true;
|
||||
REQ = false;
|
||||
break;
|
||||
case BusPhase.DataOut:
|
||||
BSY = true;
|
||||
MSG = false;
|
||||
CD = false;
|
||||
IO = false;
|
||||
REQ = true;
|
||||
break;
|
||||
case BusPhase.MessageIn:
|
||||
BSY = true;
|
||||
MSG = true;
|
||||
CD = true;
|
||||
IO = true;
|
||||
REQ = true;
|
||||
break;
|
||||
case BusPhase.MessageOut:
|
||||
BSY = true;
|
||||
MSG = true;
|
||||
CD = true;
|
||||
IO = false;
|
||||
REQ = true;
|
||||
break;
|
||||
case BusPhase.Status:
|
||||
BSY = true;
|
||||
MSG = false;
|
||||
CD = true;
|
||||
IO = true;
|
||||
REQ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,144 +2,213 @@
|
|||
|
||||
namespace BizHawk.Emulation.Consoles.TurboGrafx
|
||||
{
|
||||
public partial class PCEngine
|
||||
{
|
||||
private byte[] CdIoPorts = new byte[16];
|
||||
private ScsiCD scsi = new ScsiCD();
|
||||
public partial class PCEngine
|
||||
{
|
||||
private byte[] CdIoPorts = new byte[16];
|
||||
|
||||
private void WriteCD(int addr, byte value)
|
||||
{
|
||||
Console.WriteLine("Write to reg[{0:X4}] {1:X2}", addr & 0x1FFF, value);
|
||||
switch (addr & 0x1FFF)
|
||||
{
|
||||
case 0x1800: // SCSI Drive Control Line
|
||||
CdIoPorts[0] = value;
|
||||
// Console.WriteLine("Write to CDC Status [0] {0:X2}", value);
|
||||
private void InitScsiBus()
|
||||
{
|
||||
SCSI = new ScsiCDBus(this, disc);
|
||||
// this is kind of stupid
|
||||
SCSI.DataTransferReady = yes =>
|
||||
{
|
||||
// set or clear Ready Bit
|
||||
if (yes)
|
||||
CdIoPorts[3] |= 0x40;
|
||||
else
|
||||
CdIoPorts[3] &= 0xBF;
|
||||
};
|
||||
SCSI.DataTransferComplete = yes =>
|
||||
{
|
||||
if (yes)
|
||||
CdIoPorts[3] |= 0x20; // Set "Complete"
|
||||
else
|
||||
{
|
||||
CdIoPorts[3] &= 0xBF; // Clear "ready"
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
scsi.SEL = true;
|
||||
scsi.Think();
|
||||
scsi.SEL = false;
|
||||
scsi.Think();
|
||||
private void WriteCD(int addr, byte value)
|
||||
{
|
||||
//Log.Note("CD","Write: {0:X4} {1:X2} (PC={2:X4})", addr & 0x1FFF, value, Cpu.PC);
|
||||
switch (addr & 0x1FFF)
|
||||
{
|
||||
case 0x1800: // SCSI Drive Control Line
|
||||
CdIoPorts[0] = value;
|
||||
// Console.WriteLine("Write to CDC Status [0] {0:X2}", value);
|
||||
|
||||
// this probably does some things
|
||||
// possibly clear irq line or trigger or who knows
|
||||
break;
|
||||
SCSI.SEL = true;
|
||||
SCSI.Think();
|
||||
SCSI.SEL = false;
|
||||
SCSI.Think();
|
||||
|
||||
case 0x1801: // CDC Command
|
||||
CdIoPorts[1] = value;
|
||||
scsi.DB = value;
|
||||
scsi.Think();
|
||||
// Console.WriteLine("Write to CDC Command [1] {0:X2}", value);
|
||||
break;
|
||||
// this probably does some things
|
||||
// possibly clear irq line or trigger or who knows
|
||||
break;
|
||||
|
||||
case 0x1802: // ACK and Interrupt Control
|
||||
CdIoPorts[2] = value;
|
||||
scsi.ACK = ((value & 0x80) != 0);
|
||||
scsi.Think();
|
||||
RefreshIRQ2();
|
||||
break;
|
||||
case 0x1801: // CDC Command
|
||||
CdIoPorts[1] = value;
|
||||
SCSI.DataBits = value;
|
||||
SCSI.Think();
|
||||
// Console.WriteLine("Write to CDC Command [1] {0:X2}", value);
|
||||
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 0x1802: // ACK and Interrupt Control
|
||||
CdIoPorts[2] = value;
|
||||
SCSI.ACK = ((value & 0x80) != 0);
|
||||
|
||||
case 0x1807: // BRAM Unlock
|
||||
if (BramEnabled && (value & 0x80) != 0)
|
||||
{
|
||||
Console.WriteLine("UNLOCK BRAM!");
|
||||
BramLocked = false;
|
||||
}
|
||||
break;
|
||||
if ((CdIoPorts[2] & 0x04) != 0) Log.Note("CD", "INTAEN enable");
|
||||
if ((CdIoPorts[2] & 0x08) != 0) Log.Note("CD", "INTSTOPEN enable");
|
||||
if ((CdIoPorts[2] & 0x10) != 0) Log.Note("CD", "INTSUBEN enable");
|
||||
if ((CdIoPorts[2] & 0x20) != 0) Log.Note("CD", "INTMEN enable");
|
||||
if ((CdIoPorts[2] & 0x40) != 0) Log.Note("CD", "INTDEN enable");
|
||||
if ((Cpu.IRQControlByte & 0x01) != 0) Log.Note("CD", "BTW, IRQ2 is not masked");
|
||||
|
||||
case 0x180B: // ADPCM DMA Control
|
||||
CdIoPorts[0x0B] = value;
|
||||
// Console.WriteLine("Write to ADPCM DMA Control [B]");
|
||||
// TODO... there is DMA to be done
|
||||
break;
|
||||
SCSI.Think();
|
||||
RefreshIRQ2();
|
||||
break;
|
||||
|
||||
case 0x180D: // ADPCM Address Control
|
||||
CdIoPorts[0x0D] = value;
|
||||
// Console.WriteLine("Write to ADPCM Address Control [D]");
|
||||
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 0x180E: // ADPCM Playback Rate
|
||||
CdIoPorts[0x0E] = value;
|
||||
// Console.WriteLine("Write to ADPCM Address Control [E]");
|
||||
break;
|
||||
case 0x1805:
|
||||
case 0x1806:
|
||||
// Latch CDDA data... no action needed for us
|
||||
break;
|
||||
|
||||
case 0x180F: // Audio Fade Timer
|
||||
CdIoPorts[0x0F] = value;
|
||||
// Console.WriteLine("Write to CD Audio fade timer [F]");
|
||||
// TODO: hook this up to audio system);
|
||||
break;
|
||||
case 0x1807: // BRAM Unlock
|
||||
if (BramEnabled && (value & 0x80) != 0)
|
||||
{
|
||||
//Console.WriteLine("UNLOCK BRAM!");
|
||||
BramLocked = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine("unknown write to {0:X4}:{1:X2}", addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 0x180B: // ADPCM DMA Control
|
||||
CdIoPorts[0x0B] = value;
|
||||
Console.WriteLine("Write to ADPCM DMA Control [B]");
|
||||
// TODO... there is DMA to be done
|
||||
break;
|
||||
|
||||
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 0x180D: // ADPCM Address Control
|
||||
CdIoPorts[0x0D] = value;
|
||||
Console.WriteLine("Write to ADPCM Address Control [D]");
|
||||
break;
|
||||
|
||||
case 0x1802: // ADPCM / CD Control
|
||||
Console.WriteLine("Read 1802 {0:X2}", CdIoPorts[2]);
|
||||
return CdIoPorts[2];
|
||||
case 0x180E: // ADPCM Playback Rate
|
||||
CdIoPorts[0x0E] = value;
|
||||
Console.WriteLine("Write to ADPCM Address Control [E]");
|
||||
break;
|
||||
|
||||
case 0x1803: // BRAM Lock
|
||||
if (BramEnabled)
|
||||
{
|
||||
Console.WriteLine("LOCKED BRAM! (read 1803)");
|
||||
BramLocked = true;
|
||||
}
|
||||
return CdIoPorts[3];
|
||||
case 0x180F: // Audio Fade Timer
|
||||
CdIoPorts[0x0F] = value;
|
||||
Console.WriteLine("Write to CD Audio fade timer [F]");
|
||||
// TODO: hook this up to audio system. and to your mother
|
||||
break;
|
||||
|
||||
case 0x1804: // CD Reset
|
||||
Console.WriteLine("Read 1804 {0:X2}", CdIoPorts[4]);
|
||||
return CdIoPorts[4];
|
||||
default:
|
||||
Console.WriteLine("unknown write to {0:X4}:{1:X2}",addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case 0x180F: // Audio Fade Timer
|
||||
Console.WriteLine("Read 180F {0:X2}", CdIoPorts[0xF]);
|
||||
return CdIoPorts[0x0F];
|
||||
public byte ReadCD(int addr)
|
||||
{
|
||||
byte returnValue = 0;
|
||||
short sample;
|
||||
|
||||
// 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;
|
||||
switch (addr & 0x1FFF)
|
||||
{
|
||||
case 0x1800: // SCSI Drive Control Line
|
||||
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;
|
||||
//Log.Note("CD", "Read: 1800 {0:X2} (PC={1:X4})", returnValue, Cpu.PC);
|
||||
return returnValue;
|
||||
|
||||
default:
|
||||
Console.WriteLine("unknown read to {0:X4}", addr);
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
case 0x1801: // Read data bus
|
||||
//Log.Note("CD", "Read: 1801 {0:X2} (PC={1:X4})", SCSI.DataBits, Cpu.PC);
|
||||
return SCSI.DataBits;
|
||||
|
||||
private void RefreshIRQ2()
|
||||
{
|
||||
int mask = CdIoPorts[2] & CdIoPorts[3] & 0x7C;
|
||||
Cpu.IRQ2Assert = (mask != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
case 0x1802: // ADPCM / CD Control
|
||||
//Log.Note("CD", "Read: 1802 {0:X2} (PC={1:X4})", CdIoPorts[2], Cpu.PC);
|
||||
return CdIoPorts[2];
|
||||
|
||||
case 0x1803: // BRAM Lock
|
||||
if (BramEnabled)
|
||||
{
|
||||
Log.Note("CD", "Read: 1803 {0:X2} (PC={1:X4})", CdIoPorts[3], Cpu.PC);
|
||||
BramLocked = true;
|
||||
|
||||
}
|
||||
returnValue = CdIoPorts[3];
|
||||
CdIoPorts[3] ^= 2;
|
||||
return returnValue;
|
||||
|
||||
case 0x1804: // CD Reset
|
||||
//Log.Note("CD", "Read: 1804 {0:X2} (PC={1:X4})", CdIoPorts[4], Cpu.PC);
|
||||
return CdIoPorts[4];
|
||||
|
||||
case 0x1805: // CD audio data Low
|
||||
if ((CdIoPorts[0x3] & 0x2) == 0)
|
||||
sample = CDAudio.VolumeLeft;
|
||||
else
|
||||
sample = CDAudio.VolumeRight;
|
||||
return (byte) sample;
|
||||
|
||||
case 0x1806: // CD audio data High
|
||||
if ((CdIoPorts[0x3] & 0x2) == 0)
|
||||
sample = CDAudio.VolumeLeft;
|
||||
else
|
||||
sample = CDAudio.VolumeRight;
|
||||
return (byte) (sample >> 8);
|
||||
|
||||
case 0x1808: // "auto handshake data input"
|
||||
byte ret = SCSI.DataBits;
|
||||
//Console.WriteLine("read 1808 {0:X2} remain: {1}", ret, SCSI.DataIn.Count);
|
||||
if (SCSI.REQ && SCSI.IO && !SCSI.CD)
|
||||
{
|
||||
SCSI.ACK = false;
|
||||
SCSI.REQ = false;
|
||||
SCSI.Think();
|
||||
}
|
||||
return ret;
|
||||
|
||||
case 0x180F: // Audio Fade Timer
|
||||
Log.Note("CD", "Read: 180F {0:X2} (PC={1:X4})", CdIoPorts[0xF], Cpu.PC);
|
||||
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:
|
||||
Log.Note("CD", "unknown read to {0:X4}", addr);
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshIRQ2()
|
||||
{
|
||||
int mask = CdIoPorts[2] & CdIoPorts[3] & 0x7C;
|
||||
Cpu.IRQ2Assert = (mask != 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -86,7 +86,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
if ((StatusByte & (StatusVerticalBlanking | StatusVramSatDmaComplete)) != 0)
|
||||
cpu.IRQ1Assert = true;
|
||||
|
||||
cpu.Execute(455 - HBlankCycles - 2);
|
||||
cpu.Execute(50);
|
||||
MidScanlineThink();
|
||||
|
||||
cpu.Execute(455 - HBlankCycles - 52);
|
||||
|
||||
if (InActiveDisplay == false && DmaRequested)
|
||||
RunDmaForScanline();
|
||||
|
@ -130,9 +133,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
int yTile = (vertLine / 8);
|
||||
int yOfs = vertLine % 8;
|
||||
|
||||
// TODO: x-scrolling is done super quick and shitty here and slow.
|
||||
// Ergo, make it better later.
|
||||
|
||||
// This is not optimized. But it seems likely to remain that way.
|
||||
int xScroll = Registers[BXR] & 0x3FF;
|
||||
for (int x = 0; x < FrameWidth; x++)
|
||||
{
|
||||
|
|
|
@ -84,9 +84,10 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx
|
|||
public const byte StatusSprite0Collision = 0x01;
|
||||
|
||||
private const int VramSize = 0x8000;
|
||||
|
||||
|
||||
private HuC6280 cpu;
|
||||
private VCE vce;
|
||||
public Action MidScanlineThink = () => { };
|
||||
|
||||
public int MultiResHack = 0;
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@ namespace BizHawk
|
|||
{
|
||||
// You can set current desired logging settings here.
|
||||
// Production builds should be done with all logging disabled.
|
||||
//LogToConsole = true;
|
||||
LogToConsole = true;
|
||||
//LogToFile = true;
|
||||
//LogFilename = "d:/bizhawk.log";
|
||||
//EnableDomain("CD");
|
||||
//EnableDomain("CPU");
|
||||
//EnableDomain("VDC");
|
||||
//EnableDomain("VDC");
|
||||
//EnableDomain("MEM");
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace BizHawk
|
|||
buffer = new T[capacity];
|
||||
}
|
||||
|
||||
public int Count { get { return tail - head; } }
|
||||
public int Count { get { return size; } }
|
||||
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
|
@ -83,6 +83,18 @@ namespace BizHawk
|
|||
size = 0;
|
||||
}
|
||||
|
||||
public T[] GetBuffer()
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void SignalBufferFilled(int count)
|
||||
{
|
||||
head = 0;
|
||||
tail = count;
|
||||
size = count;
|
||||
}
|
||||
|
||||
// TODO serialization functions
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace BizHawk.Emulation.Sound
|
|||
private byte WaveTableWriteOffset;
|
||||
|
||||
private Queue<QueuedCommand> commands = new Queue<QueuedCommand>(256);
|
||||
private int frameStartTime, frameStopTime;
|
||||
private long frameStartTime, frameStopTime;
|
||||
|
||||
private const int SampleRate = 44100;
|
||||
private const int PsgBase = 3580000;
|
||||
|
@ -47,7 +47,7 @@ namespace BizHawk.Emulation.Sound
|
|||
Channels[i] = new PSGChannel();
|
||||
}
|
||||
|
||||
public void BeginFrame(int cycles)
|
||||
public void BeginFrame(long cycles)
|
||||
{
|
||||
while (commands.Count > 0)
|
||||
{
|
||||
|
@ -57,12 +57,12 @@ namespace BizHawk.Emulation.Sound
|
|||
frameStartTime = cycles;
|
||||
}
|
||||
|
||||
public void EndFrame(int cycles)
|
||||
public void EndFrame(long cycles)
|
||||
{
|
||||
frameStopTime = cycles;
|
||||
}
|
||||
|
||||
public void WritePSG(byte register, byte value, int cycles)
|
||||
public void WritePSG(byte register, byte value, long cycles)
|
||||
{
|
||||
commands.Enqueue(new QueuedCommand { Register = register, Value = value, Time = cycles-frameStartTime });
|
||||
}
|
||||
|
@ -132,12 +132,12 @@ namespace BizHawk.Emulation.Sound
|
|||
public void DiscardSamples() { /*TBD*/ }
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
int elapsedCycles = frameStopTime - frameStartTime;
|
||||
int elapsedCycles = (int) (frameStopTime - frameStartTime);
|
||||
int start = 0;
|
||||
while (commands.Count > 0)
|
||||
{
|
||||
var cmd = commands.Dequeue();
|
||||
int pos = ((cmd.Time * samples.Length) / elapsedCycles) & ~1;
|
||||
int pos = (int) ((cmd.Time * samples.Length) / elapsedCycles) & ~1;
|
||||
MixSamples(samples, start, pos - start);
|
||||
start = pos;
|
||||
WritePSGImmediate(cmd.Register, cmd.Value);
|
||||
|
@ -348,7 +348,7 @@ namespace BizHawk.Emulation.Sound
|
|||
{
|
||||
public byte Register;
|
||||
public byte Value;
|
||||
public int Time;
|
||||
public long Time;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,15 +10,24 @@ namespace BizHawk.Emulation.Sound
|
|||
{
|
||||
buffer = Metaspu.metaspu_construct(method);
|
||||
}
|
||||
public MetaspuSoundProvider()
|
||||
: this(ESynchMethod.ESynchMethod_Z)
|
||||
|
||||
public MetaspuSoundProvider() : this(ESynchMethod.ESynchMethod_V)
|
||||
{
|
||||
}
|
||||
|
||||
private short[] pullBuffer = new short[1470];
|
||||
public void PullSamples(ISoundProvider source)
|
||||
{
|
||||
Array.Clear(pullBuffer, 0, 1470);
|
||||
source.GetSamples(pullBuffer);
|
||||
buffer.enqueue_samples(pullBuffer, 735);
|
||||
}
|
||||
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
buffer.output_samples(samples, samples.Length / 2);
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
buffer.clear();
|
||||
|
@ -573,16 +582,13 @@ namespace BizHawk.Emulation.Sound
|
|||
|
||||
public void enqueue_samples(short[] buf, int samples_provided)
|
||||
{
|
||||
throw new Exception("bluh");
|
||||
int samplesToEnqueue = samples_provided;
|
||||
if (samples_provided + buffer.Count > MaxExcessSamples)
|
||||
samplesToEnqueue = MaxExcessSamples - buffer.Count;
|
||||
|
||||
//for (int i = 0; i < samplesToEnqueue; i++)
|
||||
//buffer.Enqueue(buf[i]);
|
||||
|
||||
Console.WriteLine("enqueue {0} samples, buffer at {1}/4096 max capacity, {2} excess samples",
|
||||
samplesToEnqueue, buffer.Count, buffer.Count - SamplesInOneFrame);
|
||||
int ctr = 0;
|
||||
for (int i = 0; i < samples_provided; i++)
|
||||
{
|
||||
short left = buf[ctr++];
|
||||
short right = buf[ctr++];
|
||||
enqueue_sample(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
public void enqueue_sample(short left, short right)
|
||||
|
@ -597,7 +603,6 @@ namespace BizHawk.Emulation.Sound
|
|||
|
||||
public void clear()
|
||||
{
|
||||
Console.WriteLine("clear requested... but why! it makes me sad :'(");
|
||||
buffer.Clear();
|
||||
}
|
||||
|
||||
|
@ -611,11 +616,6 @@ namespace BizHawk.Emulation.Sound
|
|||
// if we're within 75% of target, then I guess we suck it up and resample.
|
||||
// we sample in a goofy way, we could probably do it a bit smarter, if we cared more.
|
||||
|
||||
Console.WriteLine("REASONABLE UNDERFLOW, RESAMPLING.");
|
||||
|
||||
if (samples_requested > 2730)
|
||||
throw new Exception("something rather bad has happened");
|
||||
|
||||
int samples_available = buffer.Count;
|
||||
for (int i = 0; buffer.Count > 0; i++)
|
||||
resampleBuffer[i] = buffer.Dequeue();
|
||||
|
@ -627,17 +627,15 @@ namespace BizHawk.Emulation.Sound
|
|||
buf[index++] = sample.left;
|
||||
buf[index++] = sample.right;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// we're outside of a "reasonable" underflow. Give up and output silence.
|
||||
Console.WriteLine("EXCESSIVE UNDERFLOW. GIVE UP AND MAKE A POP");
|
||||
// Do nothing. The whole frame will be excess buffer.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal operation
|
||||
Console.WriteLine("samples in buffer {0}, requested {1}", buffer.Count, samples_requested);
|
||||
//Console.WriteLine("samples in buffer {0}, requested {1}", buffer.Count, samples_requested);
|
||||
int index = 0;
|
||||
for (int i = 0; i < samples_requested && buffer.Count > 0; i++)
|
||||
{
|
||||
|
|
|
@ -579,9 +579,6 @@
|
|||
<ItemGroup>
|
||||
<None Include="config\ControllerImages\GBController.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="config\ControllerImages\220px-TurboGrafx-16-Controller.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="config\ControllerImages\PCEngineController.png" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -55,14 +55,14 @@
|
|||
public string PathSMSScreenshots = ".\\Screenshots";
|
||||
public string PathSMSCheats = ".\\Cheats";
|
||||
|
||||
public string BaseGG = ".\\GG";
|
||||
public string BaseGG = ".\\Game Gear";
|
||||
public string PathGGROMs = ".";
|
||||
public string PathGGSavestates = ".\\State";
|
||||
public string PathGGSaveRAM = ".\\SaveRAM";
|
||||
public string PathGGScreenshots = ".\\Screenshots";
|
||||
public string PathGGCheats = ".\\Cheats";
|
||||
|
||||
public string BaseSG = ".\\GG";
|
||||
public string BaseSG = ".\\SG-1000";
|
||||
public string PathSGROMs = ".";
|
||||
public string PathSGSavestates = ".\\State";
|
||||
public string PathSGSaveRAM = ".\\SaveRAM";
|
||||
|
@ -76,7 +76,7 @@
|
|||
public string PathGenesisScreenshots = ".\\Screenshots";
|
||||
public string PathGenesisCheats = ".\\Cheats";
|
||||
|
||||
public string BasePCE = ".\\PCE";
|
||||
public string BasePCE = ".\\PC Engine";
|
||||
public string PathPCEROMs = ".";
|
||||
public string PathPCESavestates = ".\\State";
|
||||
public string PathPCESaveRAM = ".\\SaveRAM";
|
||||
|
|
|
@ -945,7 +945,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
game = new GameInfo();
|
||||
game.System = "PCE";
|
||||
game.Name = file.Name;
|
||||
game.Name = Path.GetFileNameWithoutExtension(file.Name);
|
||||
}
|
||||
|
||||
switch (game.System)
|
||||
|
@ -953,10 +953,14 @@ namespace BizHawk.MultiClient
|
|||
case "PCE":
|
||||
if (File.Exists(Global.Config.PathPCEBios) == false)
|
||||
{
|
||||
MessageBox.Show("PCE-CD System Card not found. Please check the BIOS path in Config->Paths.");
|
||||
MessageBox.Show("PCE-CD System Card not found. Please check the BIOS path in Config->Paths->PC Engine.");
|
||||
return false;
|
||||
}
|
||||
rom = new RomGame(new HawkFile(Global.Config.PathPCEBios));
|
||||
if (rom.GameInfo["SuperSysCard"])
|
||||
game.AddOption("SuperSysCard");
|
||||
if ((game["NeedSuperSysCard"]) && game["SuperSysCard"] == false)
|
||||
MessageBox.Show("This game requires a version 3.0 System card and won't run with the system card you've selected. Try selecting a 3.0 System Card in Config->Paths->PC Engine.");
|
||||
nextEmulator = new PCEngine(game, disc, rom.RomData);
|
||||
break;
|
||||
}
|
||||
|
@ -2033,8 +2037,8 @@ namespace BizHawk.MultiClient
|
|||
ofd.InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId);
|
||||
//"Rom Files|*.NES;*.SMS;*.GG;*.SG;*.PCE;*.SGX;*.GB;*.BIN;*.SMD;*.ROM;*.ZIP;*.7z|NES (*.NES)|*.NES|Master System|*.SMS;*.GG;*.SG;*.ZIP;*.7z|PC Engine|*.PCE;*.SGX;*.ZIP;*.7z|Gameboy|*.GB;*.ZIP;*.7z|TI-83|*.rom|Archive Files|*.zip;*.7z|Savestate|*.state|All Files|*.*";
|
||||
ofd.Filter = FormatFilter(
|
||||
"Rom Files", "*.nes;*.sms;*.gg;*.sg;*.pce;*.sgx;*.gb;*.bin;*.smd;*.rom;*.iso;%ARCH%",
|
||||
"Disc Images", "*.iso",
|
||||
"Rom Files", "*.nes;*.sms;*.gg;*.sg;*.pce;*.sgx;*.gb;*.bin;*.smd;*.rom;*.cue;%ARCH%",
|
||||
"Disc Images", "*.cue",
|
||||
"NES", "*.nes;%ARCH%",
|
||||
"Master System", "*.sms;*.gg;*.sg;%ARCH%",
|
||||
"PC Engine", "*.pce;*.sgx;%ARCH%",
|
||||
|
|
|
@ -1 +1,80 @@
|
|||
067CB059A300BD731E7620803CAE044E Bomberman '94 Special Version PCE
|
||||
3E9ED52416C4642096EC78B16AFA3956 Alzadick PCE
|
||||
3770A9888388B41A10C28841F9EFD15B Black Hole Assault PCE NeedSuperSysCard
|
||||
147F46AA1E72C204488035ABB6E8DD37 Blood Gear PCE NeedSuperSysCard
|
||||
067CB059A300BD731E7620803CAE044E Bomberman '94 Special Version PCE NeedSuperSysCard
|
||||
F4BCF27A1407EDD8AAF51C34E3EAF0C3 Bonk 3 PCE NeedSuperSysCard
|
||||
491B7FAB01C8A4017221270EFBDBFF37 Brandish PCE NeedSuperSysCard;ArcadeCard
|
||||
5835601EC3879D4E5161DE2BC30BDF44 Cardangels PCE NeedSuperSysCard
|
||||
60AAF2DA21D2AA0BADFCFC0EDE4006D5 Cosmic Fantasy II (U) PCE
|
||||
EDD630721F0719F1648A2E00621AD7B7 Cotton (U) PCE NeedSuperSysCard
|
||||
78009190135209BE042D8355B647BE35 Dracula X - Rondo of Blood PCE NeedSuperSysCard
|
||||
F6869EBAB1F3F5927B92F59DCF34D512 Double Dragon 2 - The Revenge PCE NeedSuperSysCard
|
||||
DBF82B69AB6AE97E7E16F64FC9267253 Download II PCE
|
||||
0C260D7C5758E786D80D75ED60E135B8 Dragon Slayer (U) PCE NeedSuperSysCard
|
||||
00C357F33118BCD033F98952370126A8 Dungeon Explorer II (U) PCE NeedSuperSysCard
|
||||
65069522E26B5A41F457ADAF97474889 Dungeon Master - Theron's Quest (U) PCE NeedSuperSysCard
|
||||
3CCA1F2CEFC009906EDC19BD5AD30138 Emerald Dragon PCE NeedSuperSysCard
|
||||
E5C69B9D84AEA0641041FB355F66B33A Exile (U) PCE
|
||||
6DCB244E33963B5F82B0B96B1BA4A4A5 Exile II - Wicked Phenomenon (U) PCE NeedSuperSysCard
|
||||
A067C38F8D5E3AB35FA0EB238C141B81 Fantasy Star Soldeier PCE NeedSuperSysCard
|
||||
68C794604F210B82D21C5B9DCFAB4596 Final Zone II (U) PCE
|
||||
71CB34D94D36C19901EA67B6355CDC98 Flash Hiders PCE NeedSuperSysCard
|
||||
579CFB162AF2B56BB5D178CE32AEC328 Forgotten Worlds (U) PCE NeedSuperSysCard
|
||||
E7C724F744BE836B955D212160F5475E Gain Ground SX PCE NeedSuperSysCard
|
||||
5D4E8379FDA5160C4400D926ADEA0F92 Gates Of Thunder (U) PCE NeedSuperSysCard
|
||||
619424C78C17F4D759994810B3253048 God Panic PCE NeedSuperSysCard
|
||||
5B969960E0B1DA41BCF1A2352724EB63 Golden Axe PCE
|
||||
7F83141788B5A94A339689FD5F4A0840 Gradius II PCE NeedSuperSysCard
|
||||
C96792AA34C6EA050DEBD1EDA5944046 Hellfire S PCE
|
||||
9808305827B37767FA8F0A201E8ADD43 Image Fight II PCE NeedSuperSysCard
|
||||
692AC5B78CB31DD880E652E8CBDF0AFC Jim Power - In Mutant Planet PCE NeedSuperSysCard
|
||||
83A2F0661448457DF7AF2B39FCFEFA26 Kaze Kiri Ninja Action PCE NeedSuperSysCard
|
||||
23E7D0D4E468A6F2A801049BA5D36D41 Kiaidan 00 PCE NeedSuperSysCard
|
||||
6A556ED91862FA957866661E47F35320 Langrisser - Hikari no Matseui PCE NeedSuperSysCard
|
||||
33D4467131049E22E34A02DBA43D3F3D Last Alert PCE
|
||||
0CF51518CCE1F807D5CF92ACBB6BEE33 Legion PCE
|
||||
26873893BAE98A25DF06118228B2B470 Lemmings PCE NeedSuperSysCard
|
||||
8C26362AB1C7FA22AE981431500E40DF Loom (U) PCE NeedSuperSysCard
|
||||
4EA3DA589C2A40D7E114B316FEA353A4 Lords of Thunder PCE NeedSuperSysCard
|
||||
FD8166D038239F1AEF641B14AF0F6BC4 Macross 2036 PCE
|
||||
F3C6E4A5BF25C1D0A6219FCCF8933046 Mad Stalker - Full Metal Force PCE NeedSuperSysCard;ArcadeCard
|
||||
52CA7465F10DDA85DC2D17B96A508621 Magical Fantasy Adventure - Popful Mail PCE NeedSuperSysCard;ArcadeCard;
|
||||
A82FA56B18356FA2553E445B92FD0317 Metamor Jupiter PCE NeedSuperSysCard
|
||||
A9B7FE6A879DBC47BA83579ECBE8FE2A Might and Magic III - Isles of Terra (U) PCE NeedSuperSysCard
|
||||
BFB522337FB86B6A029894442DEE2647 Monster Lair (U) PCE
|
||||
CF7EBAE2FEAC0F968F2C7D7C815F53F3 Motoroader MC PCE NeedSuperSysCard
|
||||
A52AB896E603673E6EA30C1769449DF4 Mystic Formula PCE NeedSuperSysCard
|
||||
8C793F868A30A176EBB02CADE64F7F57 Nexzr PCE NeedSuperSysCard
|
||||
C80A4ACE402AB5D7D72D2CA643A108A6 Prince of Persia (U) PCE NeedSuperSysCard
|
||||
F338D84D2B3E77DD81D611964C0D460F Psychic Storm PCE NeedSuperSysCard
|
||||
B16C8BC632CBDEC676B9874E39975DDD Puyo Puyo CD PCE NeedSuperSysCard
|
||||
9398887DB9C2771F1FBB3D4FEF561A14 Rayxanber II PCE
|
||||
7FEC58BDB95CBF1F3AE553933DB5F60B Rayxanber III PCE NeedSuperSysCard
|
||||
EFF6C174835503B034CF6A4079627DBD Road Spirits PCE
|
||||
FBC374F66ED4228120B74D327DE81298 R-Type Complete CD PCE NeedSuperSysCard
|
||||
5D16FE7D452DC9B46CAA7A436F45468D Sapphire PCE NeedSuperSysCard;ArcadeCard
|
||||
D67A425615770ECE13CF5157CA32EF61 Shubibinman III PCE
|
||||
E6CB40FD1E315B84D09100915DCABF9C Shadow of the Beast(U) PCE NeedSuperSysCard
|
||||
C8559632FE3EA3B4FBABBEF80865B36C Shape Shifter (U) PCE NeedSuperSysCard
|
||||
B2FEE487FBE1CB5A81F1FAAA5C49AF0A Sim Earth PCE NeedSuperSysCard
|
||||
C0DD9A7A52ACF8D98F0BA36F907C486A Snatcher PCE NeedSuperSysCard
|
||||
8E352778CD8A5530761DFD4127D1BBE2 Splash Lake (U) PCE
|
||||
25607EDD1F77B2C993185A8C2DBD785E Spriggan PCE
|
||||
506B41BDEEB6EA6BD4AFA89C9C594BEE Spriggan Mark II PCE NeedSuperSysCard
|
||||
DEF4EAE3C3565FAA7C1CADCAB61C89A3 Strider Hiryu PCE NeedSuperSysCard;ArcadeCard
|
||||
23484EC2987B58B93285E1EC827BE839 Super Air Zonk (U) PCE NeedSuperSysCard
|
||||
6BB02DEEA591C30A71CA201EA6A84197 Super Darius II PCE NeedSuperSysCard
|
||||
AE912784A40DEE31133F33ABFAB9522C Super Raiden PCE NeedSuperSysCard
|
||||
ECFD4A849AF8C7C88B8DAD3A9CFD804E Super Schwartzschild PCE NeedSuperSysCard
|
||||
3355BDD8F966E413E31A50412B18A282 Super Schwartzschild II PCE NeedSuperSysCard
|
||||
065F306DD079E506F953251FDCCE2444 Syd Mead's Terraforming PCE
|
||||
9E9BA0A787C06167919857AAC3505E11 Sylphia PCE NeedSuperSysCard
|
||||
BCB0530021FE2E2EAAA258D3C61EF2E4 Valis PCE NeedSuperSysCard
|
||||
05A0213934814E08EC6E7D4112200BD6 Valis II (U) PCE
|
||||
187AF2A604CC66A9790B547D04745BF8 Valis III (U) PCE
|
||||
8BA20724E08300C69E2F67DA76E1F0D2 Valis IV PCE
|
||||
FB571B290600A18B90E1BBF1D18FC8AA World Heroes II PCE NeedSuperSysCard;ArcadeCard
|
||||
BA451E33D76FD6C644F46309708BABF2 Ys Book I & II (U) PCE
|
||||
725BF9524040917AC8D5DD1765483527 Ys III - Wanderers from Ys (U) PCE
|
||||
844E0E4D40BE2EBD5550429AE53EAFB2 Ys IV - The Dawn of Ys PCE NeedSuperSysCard
|
||||
1F91B1245003DB964C35AFE6A165964E Zero Wing PCE
|
|
@ -1143,11 +1143,11 @@ B915FC01C039C1B0003436432CB73AA0 V Tatsujin (J) [b3] PCE
|
|||
EEA13EF4FE8DE1686D0BBDD877579E31 Tatsujin Sounds PCE
|
||||
8F458B72EC050504A1B68C49DCD6942C Ten no Koe Memory Bank (J) [o1] PCE
|
||||
E0047B06DC84CB242CCED8C5FA7EFAFE Ten no Koe Memory Bank (J) PCE
|
||||
B724F9514E1F44AA3BCB4C678C06D51D V Tenseiryuu - Saint Dragon (J) [b1] PCE
|
||||
C0E0C5C42ACF339155E11293FF2629EE V Tenseiryuu - Saint Dragon (J) [b1][o1] PCE
|
||||
B9BD4CE494C2DFD4663D3E366E41422C V Tenseiryuu - Saint Dragon (J) [b2][o1] PCE
|
||||
BFEE45769C69CBF4AE7761F650F06E99 Tenseiryuu - Saint Dragon (J) [o1] PCE
|
||||
92857243D4E985F1A58BEC9CB2E16D58 Tenseiryuu - Saint Dragon (J) PCE
|
||||
B724F9514E1F44AA3BCB4C678C06D51D V Tenseiryuu - Saint Dragon (J) [b1] PCE HBlankPeriod=83
|
||||
C0E0C5C42ACF339155E11293FF2629EE V Tenseiryuu - Saint Dragon (J) [b1][o1] PCE HBlankPeriod=83
|
||||
B9BD4CE494C2DFD4663D3E366E41422C V Tenseiryuu - Saint Dragon (J) [b2][o1] PCE HBlankPeriod=83
|
||||
BFEE45769C69CBF4AE7761F650F06E99 Tenseiryuu - Saint Dragon (J) [o1] PCE HBlankPeriod=83
|
||||
92857243D4E985F1A58BEC9CB2E16D58 Tenseiryuu - Saint Dragon (J) PCE HBlankPeriod=83
|
||||
7C7A752CB98A2E2AC8F9BD3D6B2EC581 Tenseiryuu - Saint Dragon Sounds PCE
|
||||
64716E1013C5230E25F0249D8E641D5B Terra Cresta II - Mandrer no Gyakushuu (J) PCE
|
||||
F914D101D22CB30D8CE5CAA5775E00F8 Terra Cresta II - Mandrer no Gyakushuu Sounds PCE
|
||||
|
@ -1592,10 +1592,10 @@ FFD159AF6240051B15867476B6A9B808 I CD-ROM System V2.01 (U) PCE BRAM
|
|||
F544FEE6DCD0162A40C2C612DF360B2D H CD-ROM System V2.10 (J) (reports V1) [h1] PCE BRAM
|
||||
34C93E053615758218FAC19A3900723E V CD-ROM System V2.10 (J) [b1] PCE BRAM
|
||||
3CDD6614A918616BFC41C862E889DD79 I CD-ROM System V2.10 (J) PCE BRAM
|
||||
FC3D75364EF8CCCB4FA6B633E4BD5258 V Super CD-ROM2 System V3.00 (J) [o1] PCE BRAM
|
||||
CB65B86FAABF0F4717CF8C84230B187C V Super CD-ROM2 System V3.00 (J) [o2] PCE BRAM
|
||||
0FD6A4CFD78F2242025370D39AA3F287 V Super CD-ROM2 System V3.00 (J) [o3] PCE BRAM
|
||||
D3A12A001E22EFB1436EC509D453A10F V Super CD-ROM2 System V3.00 (J) [o4] PCE BRAM
|
||||
38179DF8F4AC870017DB21EBCBF53114 I Super CD-ROM2 System V3.00 (J) PCE BRAM
|
||||
0754F903B52E3B3342202BDAFB13EFA5 I Super CD-ROM2 System V3.00 (U) PCE BRAM
|
||||
98D43A097A165B03DF170FD5C2AD2C2F I Super CD-ROM2 System V3.01 (U) PCE BRAM
|
||||
FC3D75364EF8CCCB4FA6B633E4BD5258 V Super CD-ROM2 System V3.00 (J) [o1] PCE BRAM;SuperSysCard
|
||||
CB65B86FAABF0F4717CF8C84230B187C V Super CD-ROM2 System V3.00 (J) [o2] PCE BRAM;SuperSysCard
|
||||
0FD6A4CFD78F2242025370D39AA3F287 V Super CD-ROM2 System V3.00 (J) [o3] PCE BRAM;SuperSysCard
|
||||
D3A12A001E22EFB1436EC509D453A10F V Super CD-ROM2 System V3.00 (J) [o4] PCE BRAM;SuperSysCard
|
||||
38179DF8F4AC870017DB21EBCBF53114 I Super CD-ROM2 System V3.00 (J) PCE BRAM;SuperSysCard
|
||||
0754F903B52E3B3342202BDAFB13EFA5 I Super CD-ROM2 System V3.00 (U) PCE BRAM;SuperSysCard
|
||||
98D43A097A165B03DF170FD5C2AD2C2F I Super CD-ROM2 System V3.01 (U) PCE BRAM;SuperSysCard
|
Loading…
Reference in New Issue