partial jagcd support (doesn't seem to completely work here)
fix some issues with vjaguar cleanup add mem/trace callbacks and get/set reg support
This commit is contained in:
parent
d50454b37a
commit
6113f3c17b
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.M68000;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
||||
{
|
||||
public partial class JaguarDisassembler : VerifiedDisassembler
|
||||
{
|
||||
private readonly MC68000 _disassembler = new();
|
||||
|
||||
public override string PCRegisterName => "PC";
|
||||
|
||||
public override IEnumerable<string> AvailableCpus => new[] { "M68000" };
|
||||
|
||||
public override string Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
_disassembler.ReadByte = a => (sbyte)m.PeekByte(a);
|
||||
_disassembler.ReadWord = a => (short)m.PeekUshort(a, true);
|
||||
_disassembler.ReadLong = a => (int)m.PeekUint(a, true);
|
||||
var info = _disassembler.Disassemble((int)addr);
|
||||
length = info.Length;
|
||||
return $"{info.RawBytes.Substring(0, 4):X4} {info.Mnemonic,-7} {info.Args}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,34 +8,6 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
|||
{
|
||||
public abstract class LibVirtualJaguar : LibWaterboxCore
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Settings
|
||||
{
|
||||
public bool NTSC;
|
||||
public bool UseBIOS;
|
||||
public bool UseFastBlitter;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public new class FrameInfo : LibWaterboxCore.FrameInfo
|
||||
{
|
||||
public Buttons Player1;
|
||||
public Buttons Player2;
|
||||
public bool Reset;
|
||||
}
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool Init(ref Settings s, IntPtr bios, IntPtr rom, int romsize);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool SaveRamIsDirty();
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void GetSaveRam(byte[] dst);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void PutSaveRam(byte[] src);
|
||||
|
||||
[Flags]
|
||||
public enum Buttons : uint
|
||||
{
|
||||
|
@ -61,5 +33,99 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
|||
Option = 1 << 19,
|
||||
Pause = 1 << 20,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Settings
|
||||
{
|
||||
public bool NTSC;
|
||||
public bool UseBIOS;
|
||||
public bool UseFastBlitter;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public new class FrameInfo : LibWaterboxCore.FrameInfo
|
||||
{
|
||||
public Buttons Player1;
|
||||
public Buttons Player2;
|
||||
public bool Reset;
|
||||
}
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool Init(ref Settings s, IntPtr bios, IntPtr rom, int romsize);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TOC
|
||||
{
|
||||
public byte Padding0;
|
||||
public byte Padding1;
|
||||
public byte NumSessions;
|
||||
public byte MinTrack;
|
||||
public byte MaxTrack;
|
||||
public byte LastLeadOutMins;
|
||||
public byte LastLeadOutSecs;
|
||||
public byte LastLeadOutFrames;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Track
|
||||
{
|
||||
public byte TrackNum;
|
||||
public byte StartMins;
|
||||
public byte StartSecs;
|
||||
public byte StartFrames;
|
||||
public byte SessionNum;
|
||||
public byte DurMins;
|
||||
public byte DurSecs;
|
||||
public byte DurFrames;
|
||||
}
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 127)]
|
||||
public Track[] Tracks;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void CDTOCCallback(IntPtr dst);
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void CDReadCallback(int lba, IntPtr dst);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetCdCallbacks(CDTOCCallback cdtc, CDReadCallback cdrc);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void InitWithCd(ref Settings s, IntPtr bios);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract bool SaveRamIsDirty();
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void GetSaveRam(byte[] dst);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void PutSaveRam(byte[] src);
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void MemoryCallback(uint addr);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetMemoryCallback(int which, MemoryCallback callback);
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void TraceCallback(IntPtr regs);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetTraceCallback(TraceCallback callback);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void GetRegisters(uint[] regs);
|
||||
|
||||
public enum M68KRegisters : uint
|
||||
{
|
||||
D0, D1, D2, D3, D4, D5, D6, D7,
|
||||
A0, A1, A2, A3, A4, A5, A6, A7,
|
||||
PC, SR,
|
||||
}
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetRegister(M68KRegisters which, int val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
||||
{
|
||||
partial class VirtualJaguar : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
uint[] regs = new uint[18];
|
||||
_core.GetRegisters(regs);
|
||||
|
||||
var ret = new Dictionary<string, RegisterValue>();
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
ret[$"D{i}"] = regs[i];
|
||||
ret[$"A{i}"] = regs[8 + i];
|
||||
}
|
||||
ret["PC"] = regs[16];
|
||||
ret["SR"] = regs[17];
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
=> _core.SetRegister((LibVirtualJaguar.M68KRegisters)Enum.Parse(typeof(LibVirtualJaguar.M68KRegisters), register.ToUpperInvariant()), value);
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
=> false;
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public long TotalExecutedCycles
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks => _memoryCallbacks;
|
||||
|
||||
private readonly MemoryCallbackSystem _memoryCallbacks = new(new[] { "System Bus" });
|
||||
|
||||
private LibVirtualJaguar.MemoryCallback _readCallback;
|
||||
private LibVirtualJaguar.MemoryCallback _writeCallback;
|
||||
private LibVirtualJaguar.MemoryCallback _execCallback;
|
||||
|
||||
private void InitMemoryCallbacks()
|
||||
{
|
||||
LibVirtualJaguar.MemoryCallback CreateCallback(MemoryCallbackFlags flags, Func<bool> getHasCBOfType)
|
||||
{
|
||||
var rawFlags = (uint)flags;
|
||||
return address =>
|
||||
{
|
||||
if (getHasCBOfType())
|
||||
{
|
||||
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "System Bus");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_readCallback = CreateCallback(MemoryCallbackFlags.AccessRead, () => MemoryCallbacks.HasReads);
|
||||
_writeCallback = CreateCallback(MemoryCallbackFlags.AccessWrite, () => MemoryCallbacks.HasWrites);
|
||||
_execCallback = CreateCallback(MemoryCallbackFlags.AccessExecute, () => MemoryCallbacks.HasExecutes);
|
||||
|
||||
_memoryCallbacks.ActiveChanged += SetMemoryCallbacks;
|
||||
}
|
||||
|
||||
private void SetMemoryCallbacks()
|
||||
{
|
||||
_core.SetMemoryCallback(0, MemoryCallbacks.HasReads ? _readCallback : null);
|
||||
_core.SetMemoryCallback(1, MemoryCallbacks.HasWrites ? _writeCallback : null);
|
||||
_core.SetMemoryCallback(2, MemoryCallbacks.HasExecutes ? _execCallback : null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
||||
{
|
||||
public partial class VirtualJaguar
|
||||
{
|
||||
private ITraceable Tracer { get; }
|
||||
private readonly LibVirtualJaguar.TraceCallback _traceCallback;
|
||||
|
||||
private unsafe void MakeTrace(IntPtr r)
|
||||
{
|
||||
uint* regs = (uint*)r;
|
||||
var pc = regs[16] & 0xFFFFFF;
|
||||
var disasm = _disassembler.Disassemble(this.AsMemoryDomains().SystemBus, pc, out _);
|
||||
var regInfo = string.Empty;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
regInfo += $"D{i}:{regs[i]:X8} ";
|
||||
}
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
regInfo += $"A{i}:{regs[i + 8]:X8} ";
|
||||
}
|
||||
regInfo += $"SR:{regs[17]:X8} ";
|
||||
var sr = regs[17];
|
||||
regInfo += string.Concat(
|
||||
(sr & 16) > 0 ? "X" : "x",
|
||||
(sr & 8) > 0 ? "N" : "n",
|
||||
(sr & 4) > 0 ? "Z" : "z",
|
||||
(sr & 2) > 0 ? "V" : "v",
|
||||
(sr & 1) > 0 ? "C" : "c");
|
||||
|
||||
Tracer.Put(new(disassembly: $"{pc:X6}: {disasm}".PadRight(50), registerInfo: regInfo));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Common.CollectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using BizHawk.Emulation.DiscSystem;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
||||
{
|
||||
[PortedCore(CoreNames.VirtualJaguar, "Niels Wagenaar, Carwin Jones, Adam Green, James L. Hammons", "2.1.3", "https://icculus.org/virtualjaguar/", isReleased: false)]
|
||||
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
|
||||
public partial class VirtualJaguar : WaterboxCore, IRegionable
|
||||
public partial class VirtualJaguar : WaterboxCore, IRegionable, IDriveLight
|
||||
{
|
||||
private readonly LibVirtualJaguar _core;
|
||||
private readonly JaguarDisassembler _disassembler;
|
||||
|
||||
[CoreConstructor(VSystemID.Raw.JAG)]
|
||||
public VirtualJaguar(CoreLoadParameters<object, VirtualJaguarSyncSettings> lp)
|
||||
|
@ -34,6 +37,11 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
|||
Region = _syncSettings.NTSC ? DisplayType.NTSC : DisplayType.PAL;
|
||||
VsyncNumerator = _syncSettings.NTSC ? 60 : 50;
|
||||
|
||||
InitMemoryCallbacks();
|
||||
_traceCallback = MakeTrace;
|
||||
_cdTocCallback = CDTOCCallback;
|
||||
_cdReadCallback = CDReadCallback;
|
||||
|
||||
_core = PreInit<LibVirtualJaguar>(new WaterboxOptions
|
||||
{
|
||||
Filename = "virtualjaguar.wbx",
|
||||
|
@ -44,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
|||
MmapHeapSizeKB = 64 * 1024,
|
||||
SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
|
||||
SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
|
||||
});
|
||||
}, new Delegate[] { _readCallback, _writeCallback, _execCallback, _traceCallback, _cdTocCallback, _cdReadCallback, });
|
||||
|
||||
var bios = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("Jaguar", "Bios"));
|
||||
if (bios.Length != 0x20000)
|
||||
|
@ -59,19 +67,59 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
|||
UseFastBlitter = _syncSettings.UseFastBlitter,
|
||||
};
|
||||
|
||||
var rom = lp.Roms[0].FileData;
|
||||
unsafe
|
||||
if (lp.Discs.Count > 0)
|
||||
{
|
||||
fixed (byte* rp = rom, bp = bios)
|
||||
#if false
|
||||
_cd = lp.Discs[0].DiscData;
|
||||
_cdReader = new(_cd);
|
||||
#else
|
||||
_cd = new Disc[lp.Discs.Count];
|
||||
_cdReader = new DiscSectorReader[lp.Discs.Count];
|
||||
for (int i = 0; i < lp.Discs.Count; i++)
|
||||
{
|
||||
if (!_core.Init(ref settings, (IntPtr)bp, (IntPtr)rp, rom.Length))
|
||||
_cd[i] = lp.Discs[i].DiscData;
|
||||
_cdReader[i] = new(lp.Discs[i].DiscData);
|
||||
}
|
||||
#endif
|
||||
_core.SetCdCallbacks(_cdTocCallback, _cdReadCallback);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* bp = bios)
|
||||
{
|
||||
throw new Exception("Core rejected the rom!");
|
||||
_core.InitWithCd(ref settings, (IntPtr)bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_cdTocCallback = null;
|
||||
_cdReadCallback = null;
|
||||
var rom = lp.Roms[0].FileData;
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* rp = rom, bp = bios)
|
||||
{
|
||||
if (!_core.Init(ref settings, (IntPtr)bp, (IntPtr)rp, rom.Length))
|
||||
{
|
||||
throw new Exception("Core rejected the rom!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_core.SetCdCallbacks(null, null);
|
||||
|
||||
PostInit();
|
||||
|
||||
_core.SetCdCallbacks(_cdTocCallback, _cdReadCallback);
|
||||
|
||||
_disassembler = new();
|
||||
_serviceProvider.Register<IDisassemblable>(_disassembler);
|
||||
|
||||
const string TRACE_HEADER = "M68K: PC, machine code, mnemonic, operands, registers (D0-D7, A0-A7, SR), flags (XNZVC)";
|
||||
Tracer = new TraceBuffer(TRACE_HEADER);
|
||||
_serviceProvider.Register(Tracer);
|
||||
}
|
||||
|
||||
private static readonly IReadOnlyList<string> JaguarButtonsOrdered = new[]
|
||||
|
@ -150,6 +198,9 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
|||
|
||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
_core.SetTraceCallback(Tracer.IsEnabled() ? _traceCallback : null);
|
||||
DriveLightOn = false;
|
||||
|
||||
return new LibVirtualJaguar.FrameInfo()
|
||||
{
|
||||
Player1 = GetButtons(controller, 1),
|
||||
|
@ -158,6 +209,143 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar
|
|||
};
|
||||
}
|
||||
|
||||
protected override void LoadStateBinaryInternal(BinaryReader reader)
|
||||
{
|
||||
SetMemoryCallbacks();
|
||||
_core.SetCdCallbacks(_cdTocCallback, _cdReadCallback);
|
||||
}
|
||||
|
||||
public DisplayType Region { get; }
|
||||
|
||||
public bool IsJaguarCD => _cd != null;
|
||||
public bool DriveLightEnabled => IsJaguarCD;
|
||||
public bool DriveLightOn { get; private set; }
|
||||
|
||||
private readonly LibVirtualJaguar.CDTOCCallback _cdTocCallback;
|
||||
private readonly LibVirtualJaguar.CDReadCallback _cdReadCallback;
|
||||
|
||||
#if false // uh oh, we don't actually have multisession disc support, so...
|
||||
private readonly Disc _cd;
|
||||
private readonly DiscSectorReader _cdReader;
|
||||
|
||||
private void CDTOCCallback(IntPtr dst)
|
||||
{
|
||||
var lastLeadOutTs = new Timestamp(_cd.TOC.LeadoutLBA + 150);
|
||||
|
||||
var toc = new LibVirtualJaguar.TOC
|
||||
{
|
||||
Padding0 = 0,
|
||||
Padding1 = 0,
|
||||
NumSessions = (byte)(_cd.Structure.Sessions.Count - 1),
|
||||
MinTrack = (byte)_cd.TOC.FirstRecordedTrackNumber,
|
||||
MaxTrack = (byte)_cd.TOC.LastRecordedTrackNumber,
|
||||
LastLeadOutMins = lastLeadOutTs.MIN,
|
||||
LastLeadOutSecs = lastLeadOutTs.SEC,
|
||||
LastLeadOutFrames = lastLeadOutTs.FRAC,
|
||||
Tracks = new LibVirtualJaguar.TOC.Track[127],
|
||||
};
|
||||
|
||||
var trackNum = 0;
|
||||
for (int i = 1; i < _cd.Structure.Sessions.Count; i++)
|
||||
{
|
||||
var session = _cd.Structure.Sessions[i];
|
||||
for (int j = 1; j < session.InformationTrackCount; j++)
|
||||
{
|
||||
var track = session.Tracks[trackNum];
|
||||
toc.Tracks[i].TrackNum = (byte)track.Number;
|
||||
var ts = new Timestamp(track.LBA + 150);
|
||||
toc.Tracks[i].StartMins = ts.MIN;
|
||||
toc.Tracks[i].StartSecs = ts.SEC;
|
||||
toc.Tracks[i].StartFrames = ts.FRAC;
|
||||
toc.Tracks[i].SessionNum = (byte)(i - 1);
|
||||
var durTs = new Timestamp(track.NextTrack.LBA - track.LBA);
|
||||
toc.Tracks[i].DurMins = durTs.MIN;
|
||||
toc.Tracks[i].DurSecs = durTs.SEC;
|
||||
toc.Tracks[i].DurFrames = durTs.FRAC;
|
||||
trackNum++;
|
||||
}
|
||||
}
|
||||
|
||||
Marshal.StructureToPtr(toc, dst, false);
|
||||
}
|
||||
|
||||
private void CDReadCallback(int lba, IntPtr dst)
|
||||
{
|
||||
var buf = new byte[2352];
|
||||
_cdReader.ReadLBA_2352(lba, buf, 0);
|
||||
Marshal.Copy(buf, 0, dst, 2352);
|
||||
DriveLightOn = true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
private readonly Disc[] _cd;
|
||||
private readonly DiscSectorReader[] _cdReader;
|
||||
private int[] _cdLbaOffsets;
|
||||
|
||||
private void CDTOCCallback(IntPtr dst)
|
||||
{
|
||||
var lastLeadOutTs = new Timestamp(_cd.Sum(c => c.TOC.LeadoutLBA) + _cd.Length * 150);
|
||||
|
||||
var toc = new LibVirtualJaguar.TOC
|
||||
{
|
||||
Padding0 = 0,
|
||||
Padding1 = 0,
|
||||
NumSessions = (byte)_cd.Length,
|
||||
MinTrack = (byte)_cd[0].TOC.FirstRecordedTrackNumber,
|
||||
MaxTrack = (byte)(_cd[0].TOC.FirstRecordedTrackNumber + _cd.Sum(c => c.Session1.InformationTrackCount - c.TOC.FirstRecordedTrackNumber)),
|
||||
LastLeadOutMins = lastLeadOutTs.MIN,
|
||||
LastLeadOutSecs = lastLeadOutTs.SEC,
|
||||
LastLeadOutFrames = lastLeadOutTs.FRAC,
|
||||
Tracks = new LibVirtualJaguar.TOC.Track[127],
|
||||
};
|
||||
|
||||
var trackNum = 0;
|
||||
var lbaOffset = 0;
|
||||
var trackOffset = 0;
|
||||
_cdLbaOffsets = new int[_cd.Length];
|
||||
for (int i = 0; i < _cd.Length; i++)
|
||||
{
|
||||
var session = _cd[i].Session1;
|
||||
for (int j = 0; j < session.InformationTrackCount; j++)
|
||||
{
|
||||
var track = session.Tracks[j + 1];
|
||||
toc.Tracks[trackNum].TrackNum = (byte)(trackOffset + track.Number);
|
||||
var ts = new Timestamp(lbaOffset + track.LBA + 150);
|
||||
toc.Tracks[trackNum].StartMins = ts.MIN;
|
||||
toc.Tracks[trackNum].StartSecs = ts.SEC;
|
||||
toc.Tracks[trackNum].StartFrames = ts.FRAC;
|
||||
toc.Tracks[trackNum].SessionNum = (byte)i;
|
||||
var durTs = new Timestamp(track.NextTrack.LBA - track.LBA);
|
||||
toc.Tracks[trackNum].DurMins = durTs.MIN;
|
||||
toc.Tracks[trackNum].DurSecs = durTs.SEC;
|
||||
toc.Tracks[trackNum].DurFrames = durTs.FRAC;
|
||||
trackNum++;
|
||||
}
|
||||
|
||||
trackOffset += session.InformationTrackCount;
|
||||
lbaOffset += session.LeadoutTrack.LBA - session.FirstInformationTrack.LBA + 150;
|
||||
_cdLbaOffsets[i] = lbaOffset;
|
||||
}
|
||||
|
||||
Marshal.StructureToPtr(toc, dst, false);
|
||||
}
|
||||
|
||||
private void CDReadCallback(int lba, IntPtr dst)
|
||||
{
|
||||
var buf = new byte[2352];
|
||||
for (int i = 0; i < _cdReader.Length; i++)
|
||||
{
|
||||
if (lba < _cdLbaOffsets[i])
|
||||
{
|
||||
_cdReader[i].ReadLBA_2352(lba - (i == 0 ? 0 : _cdLbaOffsets[i - 1]), buf, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Marshal.Copy(buf, 0, dst, 2352);
|
||||
DriveLightOn = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "memory.h"
|
||||
#include "tom.h"
|
||||
#include "joystick.h"
|
||||
#include "m68000/m68kinterface.h"
|
||||
|
||||
#include "blip_buf.h"
|
||||
|
||||
#include <emulibc.h>
|
||||
|
@ -36,7 +38,7 @@ static blip_t* blipL;
|
|||
static blip_t* blipR;
|
||||
static s16 latchL, latchR;
|
||||
|
||||
EXPORT bool Init(BizSettings* bizSettings, u8* boot, u8* rom, u32 sz)
|
||||
static void InitCommon(BizSettings* bizSettings)
|
||||
{
|
||||
vjs.hardwareTypeNTSC = bizSettings->hardwareTypeNTSC;
|
||||
vjs.useJaguarBIOS = bizSettings->useJaguarBIOS;
|
||||
|
@ -46,8 +48,12 @@ EXPORT bool Init(BizSettings* bizSettings, u8* boot, u8* rom, u32 sz)
|
|||
blipR = blip_new(1024);
|
||||
blip_set_rates(blipL, 48000, 44100);
|
||||
blip_set_rates(blipR, 48000, 44100);
|
||||
|
||||
JaguarInit();
|
||||
}
|
||||
|
||||
EXPORT bool Init(BizSettings* bizSettings, u8* boot, u8* rom, u32 sz)
|
||||
{
|
||||
InitCommon(bizSettings);
|
||||
|
||||
if (!JaguarLoadFile(rom, sz))
|
||||
{
|
||||
|
@ -71,6 +77,26 @@ EXPORT bool Init(BizSettings* bizSettings, u8* boot, u8* rom, u32 sz)
|
|||
return true;
|
||||
}
|
||||
|
||||
void (*cd_toc_callback)(void * dest);
|
||||
void (*cd_read_callback)(int32_t lba, void * dest);
|
||||
|
||||
EXPORT void SetCdCallbacks(void (*ctc)(void * dest), void (*cdrc)(int32_t lba, void * dest))
|
||||
{
|
||||
cd_toc_callback = ctc;
|
||||
cd_read_callback = cdrc;
|
||||
}
|
||||
|
||||
EXPORT void InitWithCd(BizSettings* bizSettings, u8* boot)
|
||||
{
|
||||
InitCommon(bizSettings);
|
||||
vjs.hardwareTypeAlpine = false;
|
||||
|
||||
SET32(jaguarMainRAM, 0, 0x00200000);
|
||||
memcpy(jagMemSpace + 0xE00000, boot, 0x20000);
|
||||
|
||||
JaguarReset();
|
||||
}
|
||||
|
||||
extern uint16_t eeprom_ram[64];
|
||||
extern bool eeprom_dirty;
|
||||
|
||||
|
@ -96,42 +122,42 @@ EXPORT void GetMemoryAreas(MemoryArea* m)
|
|||
m[0].Data = jaguarMainRAM;
|
||||
m[0].Name = "Main RAM";
|
||||
m[0].Size = 0x200000;
|
||||
m[0].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY;
|
||||
m[0].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_PRIMARY;
|
||||
|
||||
m[1].Data = eeprom_ram;
|
||||
m[1].Name = "EEPROM";
|
||||
m[1].Size = sizeof(eeprom_ram);
|
||||
m[1].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE;
|
||||
m[1].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SAVERAMMABLE;
|
||||
|
||||
m[2].Data = gpuRAM;
|
||||
m[2].Name = "GPU RAM";
|
||||
m[2].Size = 0x18000;
|
||||
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE;
|
||||
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN;
|
||||
|
||||
m[3].Data = dspRAM;
|
||||
m[3].Name = "DSP RAM";
|
||||
m[3].Size = 0x5000;
|
||||
m[3].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE;
|
||||
m[3].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN;
|
||||
|
||||
m[4].Data = TOMGetRamPointer();
|
||||
m[4].Name = "TOM RAM";
|
||||
m[4].Size = 0x4000;
|
||||
m[4].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE;
|
||||
m[4].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN;
|
||||
|
||||
m[5].Data = jaguarMainROM;
|
||||
m[5].Name = "ROM";
|
||||
m[5].Size = jaguarROMSize;
|
||||
m[5].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE;
|
||||
m[5].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN;
|
||||
|
||||
m[6].Data = jagMemSpace + 0xE00000;
|
||||
m[6].Name = "BIOS";
|
||||
m[6].Size = 0x20000;
|
||||
m[6].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE;
|
||||
m[6].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN;
|
||||
|
||||
m[7].Data = jagMemSpace;
|
||||
m[7].Name = "System Bus";
|
||||
m[7].Size = 0xF20000;
|
||||
m[7].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE;
|
||||
m[7].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN;
|
||||
}
|
||||
|
||||
struct MyFrameInfo : public FrameInfo
|
||||
|
@ -141,7 +167,6 @@ struct MyFrameInfo : public FrameInfo
|
|||
};
|
||||
|
||||
bool lagged;
|
||||
void (*inputcb)() = 0;
|
||||
|
||||
EXPORT void FrameAdvance(MyFrameInfo* f)
|
||||
{
|
||||
|
@ -195,7 +220,43 @@ EXPORT void FrameAdvance(MyFrameInfo* f)
|
|||
blip_read_samples(blipR, f->SoundBuffer + 1, f->Samples, 1);
|
||||
}
|
||||
|
||||
void (*InputCallback)() = 0;
|
||||
|
||||
EXPORT void SetInputCallback(void (*callback)())
|
||||
{
|
||||
inputcb = callback;
|
||||
InputCallback = callback;
|
||||
}
|
||||
|
||||
void (*ReadCallback)(u32) = 0;
|
||||
void (*WriteCallback)(u32) = 0;
|
||||
void (*ExecuteCallback)(u32) = 0;
|
||||
|
||||
EXPORT void SetMemoryCallback(u32 which, void (*callback)(u32))
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case 0: ReadCallback = callback; break;
|
||||
case 1: WriteCallback = callback; break;
|
||||
case 2: ExecuteCallback = callback; break;
|
||||
}
|
||||
}
|
||||
|
||||
void (*TraceCallback)(u32*) = 0;
|
||||
|
||||
EXPORT void SetTraceCallback(void (*callback)(u32*))
|
||||
{
|
||||
TraceCallback = callback;
|
||||
}
|
||||
|
||||
EXPORT void GetRegisters(u32* regs)
|
||||
{
|
||||
for (u32 i = 0; i < 18; i++)
|
||||
{
|
||||
regs[i] = m68k_get_reg(NULL, (m68k_register_t)i);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT void SetRegister(u32 which, u32 val)
|
||||
{
|
||||
m68k_set_reg((m68k_register_t)which, val);
|
||||
}
|
||||
|
|
|
@ -642,6 +642,11 @@ void blitter_generic(uint32_t cmd)
|
|||
uint32_t pixelSize = (size - 1) << 16;
|
||||
a2_x = (a2_x + pixelSize) & ~pixelSize;
|
||||
}
|
||||
|
||||
a1_x += a1_step_x;
|
||||
a1_y += a1_step_y;
|
||||
a2_x += a2_step_x;
|
||||
a2_y += a2_step_y;
|
||||
}
|
||||
|
||||
WREG(A1_PIXEL, (a1_y & 0xFFFF0000) | ((a1_x >> 16) & 0xFFFF));
|
||||
|
@ -1670,20 +1675,20 @@ void BlitterMidsummer2(void)
|
|||
ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y);
|
||||
ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y);
|
||||
|
||||
if (a1addx == 3)
|
||||
{
|
||||
a1_frac_x = addq_x, a1_frac_y = addq_y;
|
||||
if (a1addx == 3)
|
||||
{
|
||||
a1_frac_x = addq_x, a1_frac_y = addq_y;
|
||||
|
||||
addasel = 2, addbsel = 0, a1fracldi = false;
|
||||
ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y,
|
||||
a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y);
|
||||
ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y);
|
||||
ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y);
|
||||
addasel = 2, addbsel = 0, a1fracldi = false;
|
||||
ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y,
|
||||
a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y);
|
||||
ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y);
|
||||
ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y);
|
||||
|
||||
a1_x = addq_x, a1_y = addq_y;
|
||||
}
|
||||
else
|
||||
a1_x = addq_x, a1_y = addq_y;
|
||||
a1_x = addq_x, a1_y = addq_y;
|
||||
}
|
||||
else
|
||||
a1_x = addq_x, a1_y = addq_y;
|
||||
}
|
||||
|
||||
if (a2_add)
|
||||
|
@ -2054,7 +2059,7 @@ void DATA(uint64_t &wdata, uint8_t &dcomp, uint8_t &zcomp, bool &nowrite,
|
|||
uint8_t dech38el[2][8] = { { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
|
||||
|
||||
int en = (dend & 0x3F ? 1 : 0);
|
||||
int en = (dend & 0x3F ? 1 : 0);
|
||||
uint8_t e_coarse = decl38e[en][(dend & 0x38) >> 3];
|
||||
uint8_t e_fine = decl38e[(e_coarse & 0x01) ^ 0x01][dend & 0x07];
|
||||
e_fine &= 0xFE;
|
||||
|
|
|
@ -0,0 +1,427 @@
|
|||
#include "cdhle.h"
|
||||
#include "gpu.h"
|
||||
#include "memory.h"
|
||||
#include "jaguar.h"
|
||||
#include "event.h"
|
||||
#include "m68000/m68kinterface.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SET_ERR() jaguarMainRAM[0x3E00] = -1
|
||||
#define NO_ERR() jaguarMainRAM[0x3E00] = 0
|
||||
|
||||
#define TOC_BASE_ADDR 0x2C00
|
||||
|
||||
static bool cd_setup;
|
||||
static bool cd_initm;
|
||||
static bool cd_muted;
|
||||
static bool cd_paused;
|
||||
static uint8_t cd_mode;
|
||||
static uint8_t cd_osamp;
|
||||
|
||||
static bool cd_is_reading;
|
||||
static uint32_t cd_read_addr_start;
|
||||
static uint32_t cd_read_addr_end;
|
||||
static int32_t cd_read_lba;
|
||||
static uint8_t cd_buf2352[2352 * 4]; // also 64 * 147
|
||||
static uint32_t cd_buf_block_num;
|
||||
|
||||
extern void (*cd_toc_callback)(void * dest);
|
||||
extern void (*cd_read_callback)(int32_t lba, void * dest);
|
||||
extern bool jaguarCdInserted;
|
||||
|
||||
struct Track {
|
||||
uint8_t track_num;
|
||||
uint8_t start_mins;
|
||||
uint8_t start_secs;
|
||||
uint8_t start_frames;
|
||||
uint8_t session_num;
|
||||
uint8_t dur_mins;
|
||||
uint8_t dur_secs;
|
||||
uint8_t dur_frames;
|
||||
};
|
||||
|
||||
struct TOC {
|
||||
uint8_t padding_0;
|
||||
uint8_t padding_1;
|
||||
uint8_t num_sessions;
|
||||
uint8_t min_track_num;
|
||||
uint8_t max_track_num;
|
||||
uint8_t last_lead_out_mins;
|
||||
uint8_t last_lead_out_secs;
|
||||
uint8_t last_lead_out_frames;
|
||||
Track tracks[127];
|
||||
};
|
||||
|
||||
static_assert(sizeof(TOC) == 1024);
|
||||
|
||||
static TOC toc;
|
||||
static uint32_t cd_boot_addr;
|
||||
static uint32_t cd_boot_len;
|
||||
static int32_t cd_boot_lba;
|
||||
static uint32_t cd_boot_off;
|
||||
|
||||
void CDHLEInit(void)
|
||||
{
|
||||
if (cd_toc_callback && cd_read_callback)
|
||||
{
|
||||
jaguarCdInserted = true;
|
||||
cd_toc_callback(&toc);
|
||||
assert(toc.num_sessions >= 2); // need at least 2 sessions
|
||||
int32_t bootTrackNum = 0;
|
||||
for (uint32_t i = 0; i < 127; i++)
|
||||
{
|
||||
if (toc.tracks[i].session_num == 1)
|
||||
{
|
||||
bootTrackNum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(bootTrackNum != 0);
|
||||
Track& bootTrack = toc.tracks[bootTrackNum];
|
||||
int32_t startLba = bootTrack.start_mins * 4500 + bootTrack.start_secs * 75 + bootTrack.start_frames - 150;
|
||||
fprintf(stderr, "timecode: %02d:%02d:%02d, startLba %04X\n", bootTrack.start_mins, bootTrack.start_secs, bootTrack.start_frames, startLba);
|
||||
int32_t numLbas = bootTrack.dur_mins * 4500 + bootTrack.dur_secs * 75 + bootTrack.dur_frames;
|
||||
uint8_t buf2352[2352];
|
||||
bool foundHeader = false;
|
||||
for (int32_t i = 0; i < numLbas; i++)
|
||||
{
|
||||
cd_read_callback(startLba + i, buf2352);
|
||||
static const char* atariHeader = "ATARI APPROVED DATA HEADER ATRI\x20";
|
||||
|
||||
for (uint32_t j = 0; j < (2352 - 32 - 4 - 4); j += 2)
|
||||
{
|
||||
if (!memcmp(&buf2352[j], atariHeader, 32))
|
||||
{
|
||||
fprintf(stderr, "startLba + i %04X\n", startLba + i);
|
||||
cd_boot_addr = GET32(buf2352, j + 32);
|
||||
cd_boot_len = GET32(buf2352, j + 32 + 4);
|
||||
cd_boot_lba = startLba + i;
|
||||
cd_boot_off = j + 32 + 4 + 4;
|
||||
foundHeader = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundHeader) break;
|
||||
}
|
||||
assert(foundHeader);
|
||||
}
|
||||
|
||||
CDHLEReset();
|
||||
}
|
||||
|
||||
void CDHLEReset(void)
|
||||
{
|
||||
cd_setup = false;
|
||||
cd_initm = false;
|
||||
cd_muted = false;
|
||||
cd_paused = false;
|
||||
cd_mode = 0;
|
||||
cd_osamp = 0;
|
||||
|
||||
if (cd_read_callback)
|
||||
{
|
||||
// copy TOC to RAM
|
||||
memcpy(&jaguarMainRAM[TOC_BASE_ADDR], &toc, sizeof(TOC));
|
||||
|
||||
// copy bootcode to RAM
|
||||
// maximum of 64KiB is allowed
|
||||
uint32_t dstStart = cd_boot_addr;
|
||||
uint32_t dstEnd = cd_boot_addr + (cd_boot_len > 0x10000 ? 0x10000 : cd_boot_len);
|
||||
int32_t lba = cd_boot_lba;
|
||||
uint8_t buf2352[2352];
|
||||
|
||||
cd_read_callback(lba++, buf2352);
|
||||
for (uint32_t i = cd_boot_off; i < 2352 && dstStart < dstEnd;)
|
||||
{
|
||||
uint32_t end = (i + 64) > 2352 ? 2352 : (i + 64);
|
||||
for (; i < end; i++, dstStart++)
|
||||
{
|
||||
JaguarWriteByte(dstStart, buf2352[i], GPU);
|
||||
}
|
||||
}
|
||||
|
||||
while (dstStart < dstEnd)
|
||||
{
|
||||
cd_read_callback(lba++, buf2352);
|
||||
for (uint32_t i = 0; i < 2352 && dstStart < dstEnd;)
|
||||
{
|
||||
uint32_t end = (i + 64) > 2352 ? 2352 : (i + 64);
|
||||
for (; i < end; i++, dstStart++)
|
||||
{
|
||||
JaguarWriteByte(dstStart, buf2352[i], GPU);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cd_read_addr_start = dstStart;
|
||||
|
||||
SET32(jaguarMainRAM, 4, cd_boot_addr);
|
||||
SET16(jaguarMainRAM, 0x3004, 0x0403); // BIOS VER
|
||||
}
|
||||
}
|
||||
|
||||
void CDHLEDone(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void CDSendBlock(void)
|
||||
{
|
||||
if (cd_buf_block_num == 0)
|
||||
{
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
{
|
||||
cd_read_callback(cd_read_lba + i, &cd_buf2352[2352 * i]);
|
||||
}
|
||||
|
||||
cd_read_lba += 4;
|
||||
}
|
||||
|
||||
// send one block of data
|
||||
for (uint32_t i = 0; i < 64; i++)
|
||||
{
|
||||
JaguarWriteByte(cd_read_addr_start + i, cd_buf2352[i + 64 * cd_buf_block_num], GPU);
|
||||
}
|
||||
|
||||
cd_read_addr_start += 64;
|
||||
cd_buf_block_num = (cd_buf_block_num + 1) % 147;
|
||||
|
||||
if (cd_read_addr_start >= cd_read_addr_end)
|
||||
{
|
||||
cd_is_reading = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void CDHLECallback(void)
|
||||
{
|
||||
RemoveCallback(CDHLECallback);
|
||||
if (cd_is_reading)
|
||||
{
|
||||
if (!cd_paused)
|
||||
{
|
||||
CDSendBlock();
|
||||
}
|
||||
SetCallbackTime(CDHLECallback, 180 >> (cd_mode & 1));
|
||||
}
|
||||
}
|
||||
|
||||
static void CD_init(void);
|
||||
static void CD_mode(void);
|
||||
static void CD_ack(void);
|
||||
static void CD_jeri(void);
|
||||
static void CD_spin(void);
|
||||
static void CD_stop(void);
|
||||
static void CD_mute(void);
|
||||
static void CD_umute(void);
|
||||
static void CD_paus(void);
|
||||
static void CD_upaus(void);
|
||||
static void CD_read(void);
|
||||
static void CD_uread(void);
|
||||
static void CD_setup(void);
|
||||
static void CD_ptr(void);
|
||||
static void CD_osamp(void);
|
||||
static void CD_getoc(void);
|
||||
static void CD_initm(void);
|
||||
static void CD_initf(void);
|
||||
static void CD_switch(void);
|
||||
|
||||
static void (* CD_functions[19])() =
|
||||
{
|
||||
CD_init, CD_mode, CD_ack, CD_jeri,
|
||||
CD_spin, CD_stop, CD_mute, CD_umute,
|
||||
CD_paus, CD_upaus, CD_read, CD_uread,
|
||||
CD_setup, CD_ptr, CD_osamp, CD_getoc,
|
||||
CD_initm, CD_initf, CD_switch,
|
||||
};
|
||||
|
||||
static const char * cd_func_strs[19] = {
|
||||
"CD_init", "CD_mode", "CD_ack", "CD_jeri",
|
||||
"CD_spin", "CD_stop", "CD_mute", "CD_umute",
|
||||
"CD_paus", "CD_upaus", "CD_read", "CD_uread",
|
||||
"CD_setup", "CD_ptr", "CD_osamp", "CD_getoc",
|
||||
"CD_initm", "CD_initf", "CD_switch",
|
||||
};
|
||||
|
||||
void CDHLEHook(uint32_t which)
|
||||
{
|
||||
//fprintf(stderr, "CD HLE Hook %s\n", cd_func_strs[which]);
|
||||
CD_functions[which]();
|
||||
}
|
||||
|
||||
static void CD_init(void)
|
||||
{
|
||||
fprintf(stderr, "do CD_init");
|
||||
cd_initm = false;
|
||||
}
|
||||
|
||||
static void CD_mode(void)
|
||||
{
|
||||
// bit 0 = speed (0 = single, 1 = double)
|
||||
// bit 1 = mode (0 = audio, 1 = data)
|
||||
cd_mode = m68k_get_reg(NULL, M68K_REG_D0) & 3;
|
||||
fprintf(stderr, "CD_mode mode = %d, speed = %d\n", cd_mode >> 1, cd_mode & 1);
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_ack(void)
|
||||
{
|
||||
if (!cd_paused)
|
||||
{
|
||||
while (cd_is_reading)
|
||||
{
|
||||
CDSendBlock();
|
||||
}
|
||||
}
|
||||
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_jeri(void)
|
||||
{
|
||||
fprintf(stderr, "CD_jeri called %d!!!\n", m68k_get_reg(NULL, M68K_REG_D0) & 1);
|
||||
}
|
||||
|
||||
static void CD_spin(void)
|
||||
{
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_stop(void)
|
||||
{
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_mute(void)
|
||||
{
|
||||
if (!(cd_mode & 2))
|
||||
{
|
||||
cd_muted = true;
|
||||
NO_ERR();
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_ERR();
|
||||
}
|
||||
}
|
||||
|
||||
static void CD_umute(void)
|
||||
{
|
||||
if (!(cd_mode & 2))
|
||||
{
|
||||
cd_muted = false;
|
||||
NO_ERR();
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_ERR();
|
||||
}
|
||||
}
|
||||
|
||||
static void CD_paus(void)
|
||||
{
|
||||
cd_paused = true;
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_upaus(void)
|
||||
{
|
||||
cd_paused = false;
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_read(void)
|
||||
{
|
||||
uint32_t dstStart = m68k_get_reg(NULL, M68K_REG_A0);
|
||||
uint32_t dstEnd = m68k_get_reg(NULL, M68K_REG_A1);
|
||||
|
||||
fprintf(stderr, "CD READ: dstStart %08X, dstEnd %08X\n", dstStart, dstEnd);
|
||||
|
||||
if (dstEnd <= dstStart)
|
||||
{
|
||||
fprintf(stderr, "CD READ ERROR: dstEnd < dstStart\n");
|
||||
SET_ERR();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t timecode = m68k_get_reg(NULL, M68K_REG_D0);
|
||||
|
||||
uint32_t frames = timecode & 0xFF;
|
||||
uint32_t seconds = (timecode >> 8) & 0xFF;
|
||||
uint32_t minutes = (timecode >> 16) & 0xFF;
|
||||
|
||||
fprintf(stderr, "CD READ: is seeking %d, mins %02d, secs %02d, frames %02d\n", !!(timecode & 0x80000000), minutes, seconds, frames);
|
||||
|
||||
if (frames >= 75 || seconds >= 60 || minutes >= 73)
|
||||
{
|
||||
fprintf(stderr, "CD READ ERROR: timecode too large\n");
|
||||
SET_ERR();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(timecode & 0x80000000))
|
||||
{
|
||||
cd_is_reading = true;
|
||||
cd_read_addr_start = dstStart;
|
||||
cd_read_addr_end = dstEnd;
|
||||
cd_read_lba = (minutes * 60 + seconds) * 75 + frames - 150;
|
||||
cd_buf_block_num = 0;
|
||||
RemoveCallback(CDHLECallback);
|
||||
SetCallbackTime(CDHLECallback, 180 >> (cd_mode & 1));
|
||||
}
|
||||
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_uread(void)
|
||||
{
|
||||
if (cd_is_reading)
|
||||
{
|
||||
cd_is_reading = false;
|
||||
NO_ERR();
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_ERR();
|
||||
}
|
||||
}
|
||||
|
||||
static void CD_setup(void)
|
||||
{
|
||||
// probaby don't really care about this
|
||||
cd_setup = true;
|
||||
}
|
||||
|
||||
static void CD_ptr(void)
|
||||
{
|
||||
m68k_set_reg(M68K_REG_A0, cd_read_addr_start);
|
||||
m68k_set_reg(M68K_REG_A1, 0);
|
||||
}
|
||||
|
||||
static void CD_osamp(void)
|
||||
{
|
||||
cd_osamp = m68k_get_reg(NULL, M68K_REG_D0) & 3;
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
static void CD_getoc(void)
|
||||
{
|
||||
// this is for debugging only, retail games will not call this
|
||||
}
|
||||
|
||||
static void CD_initm(void)
|
||||
{
|
||||
cd_initm = true;
|
||||
}
|
||||
|
||||
static void CD_initf(void)
|
||||
{
|
||||
cd_initm = false;
|
||||
}
|
||||
|
||||
static void CD_switch(void)
|
||||
{
|
||||
// not supporting CD switching, so
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef __CDHLE_H__
|
||||
#define __CDHLE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void CDHLEInit(void);
|
||||
void CDHLEReset(void);
|
||||
void CDHLEDone(void);
|
||||
|
||||
void CDHLEHook(uint32_t which);
|
||||
|
||||
#endif // __CDHLE_H__
|
|
@ -219,14 +219,6 @@ static uint8_t dsp_ram_8[0x2000];
|
|||
|
||||
#define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
|
||||
|
||||
static uint32_t dsp_in_exec = 0;
|
||||
static uint32_t dsp_releaseTimeSlice_flag = 0;
|
||||
|
||||
void DSPReleaseTimeslice(void)
|
||||
{
|
||||
dsp_releaseTimeSlice_flag = 1;
|
||||
}
|
||||
|
||||
void dsp_build_branch_condition_table(void)
|
||||
{
|
||||
for(int i=0; i<65536; i++)
|
||||
|
@ -457,7 +449,6 @@ void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who)
|
|||
if (JERRYIRQEnabled(IRQ2_DSP))
|
||||
{
|
||||
JERRYSetPendingIRQ(IRQ2_DSP);
|
||||
DSPReleaseTimeslice();
|
||||
m68k_set_irq(2);
|
||||
}
|
||||
data &= ~CPUINT;
|
||||
|
@ -466,7 +457,6 @@ void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who)
|
|||
if (data & DSPINT0)
|
||||
{
|
||||
m68k_end_timeslice();
|
||||
DSPReleaseTimeslice();
|
||||
DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
|
||||
data &= ~DSPINT0;
|
||||
}
|
||||
|
@ -478,8 +468,6 @@ void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who)
|
|||
{
|
||||
if (who == M68K)
|
||||
m68k_end_timeslice();
|
||||
else if (who == DSP)
|
||||
DSPReleaseTimeslice();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -505,7 +493,7 @@ void DSPUpdateRegisterBanks(void)
|
|||
int bank = (dsp_flags & REGPAGE);
|
||||
|
||||
if (dsp_flags & IMASK)
|
||||
bank = 0; // IMASK forces main bank to be bank 0
|
||||
bank = 0;
|
||||
|
||||
if (bank)
|
||||
dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
|
||||
|
@ -593,7 +581,6 @@ void DSPReset(void)
|
|||
dsp_data_organization = 0xFFFFFFFF;
|
||||
dsp_control = 0x00002000;
|
||||
dsp_div_control = 0x00000000;
|
||||
dsp_in_exec = 0;
|
||||
|
||||
dsp_reg = dsp_reg_bank_0;
|
||||
dsp_alternate_reg = dsp_reg_bank_1;
|
||||
|
@ -617,9 +604,6 @@ void DSPDone(void)
|
|||
//
|
||||
void DSPExec(int32_t cycles)
|
||||
{
|
||||
dsp_releaseTimeSlice_flag = 0;
|
||||
dsp_in_exec++;
|
||||
|
||||
while (cycles > 0 && DSP_RUNNING)
|
||||
{
|
||||
if (IMASKCleared)
|
||||
|
@ -636,8 +620,6 @@ void DSPExec(int32_t cycles)
|
|||
dsp_opcode[index]();
|
||||
cycles -= dsp_opcode_cycles[index];
|
||||
}
|
||||
|
||||
dsp_in_exec--;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -959,7 +941,7 @@ static void dsp_opcode_normi(void)
|
|||
static void dsp_opcode_mmult(void)
|
||||
{
|
||||
int count = dsp_matrix_control&0x0f;
|
||||
uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
|
||||
uint32_t addr = dsp_pointer_to_matrix;
|
||||
int64_t accum = 0;
|
||||
uint32_t res;
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ uint32_t DSPReadLong(uint32_t offset, uint32_t who = UNKNOWN);
|
|||
void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who = UNKNOWN);
|
||||
void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who = UNKNOWN);
|
||||
void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who = UNKNOWN);
|
||||
void DSPReleaseTimeslice(void);
|
||||
bool DSPIsRunning(void);
|
||||
|
||||
// Exported vars
|
||||
|
|
|
@ -295,7 +295,7 @@ uint16_t GPUReadWord(uint32_t offset, uint32_t who)
|
|||
|
||||
uint32_t data = GPUReadLong(offset & 0xFFFFFFFC, who);
|
||||
|
||||
if (offset & 0x02) // Cases 0 & 2...
|
||||
if (offset & 0x02)
|
||||
return data & 0xFFFF;
|
||||
else
|
||||
return data >> 16;
|
||||
|
@ -436,12 +436,13 @@ void GPUWriteWord(uint32_t offset, uint16_t data, uint32_t who)
|
|||
//
|
||||
// GPU dword access (write)
|
||||
//
|
||||
void GPUWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
|
||||
void GPUWriteLong(uint32_t offset, uint32_t data, uint32_t who)
|
||||
{
|
||||
if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFC))
|
||||
{
|
||||
offset &= 0xFFF;
|
||||
SET32(gpu_ram_8, offset, data);
|
||||
return;
|
||||
}
|
||||
else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1C))
|
||||
{
|
||||
|
@ -465,7 +466,6 @@ void GPUWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
|
|||
gpu_matrix_control = data;
|
||||
break;
|
||||
case 0x08:
|
||||
// This can only point to long aligned addresses
|
||||
gpu_pointer_to_matrix = data & 0xFFFFFFFC;
|
||||
break;
|
||||
case 0x0C:
|
||||
|
@ -492,7 +492,6 @@ void GPUWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
|
|||
{
|
||||
GPUSetIRQLine(0, ASSERT_LINE);
|
||||
m68k_end_timeslice();
|
||||
DSPReleaseTimeslice();
|
||||
data &= ~0x04;
|
||||
}
|
||||
|
||||
|
@ -509,7 +508,11 @@ void GPUWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
|
|||
gpu_div_control = data;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
JaguarWriteLong(offset, data, who);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -851,9 +854,9 @@ static void gpu_opcode_pack(void)
|
|||
{
|
||||
uint32_t val = RN;
|
||||
|
||||
if (IMM_1 == 0) // Pack
|
||||
if (IMM_1 == 0)
|
||||
RN = ((val >> 10) & 0x0000F000) | ((val >> 5) & 0x00000F00) | (val & 0x000000FF);
|
||||
else // Unpack
|
||||
else
|
||||
RN = ((val & 0x0000F000) << 10) | ((val & 0x00000F00) << 5) | (val & 0x000000FF);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "blitter.h"
|
||||
#include "cdhle.h"
|
||||
#include "cdrom.h"
|
||||
#include "dac.h"
|
||||
#include "dsp.h"
|
||||
|
@ -50,10 +51,34 @@ extern uint8_t jagMemSpace[];
|
|||
uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
|
||||
bool jaguarCartInserted = false;
|
||||
bool lowerField = false;
|
||||
bool jaguarCdInserted = false;
|
||||
|
||||
void M68KInstructionHook(void)
|
||||
{
|
||||
// TODO: Trace/Exec callback
|
||||
if (jaguarCdInserted)
|
||||
{
|
||||
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
|
||||
if (pc >= 0x3000 && pc <= 0x306C)
|
||||
{
|
||||
CDHLEHook((pc - 0x3000) / 6);
|
||||
// return
|
||||
uint32_t sp = m68k_get_reg(NULL, M68K_REG_SP);
|
||||
m68k_set_reg(M68K_REG_PC, m68k_read_memory_32(sp));
|
||||
m68k_set_reg(M68K_REG_SP, sp + 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (__builtin_expect(!!TraceCallback, false))
|
||||
{
|
||||
uint32_t regs[18];
|
||||
for (uint32_t i = 0; i < 18; i++)
|
||||
{
|
||||
regs[i] = m68k_get_reg(NULL, (m68k_register_t)i);
|
||||
}
|
||||
TraceCallback(regs);
|
||||
}
|
||||
|
||||
MAYBE_CALLBACK(ExecuteCallback, m68k_get_reg(NULL, M68K_REG_PC));
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -73,6 +98,8 @@ int irq_ack_handler(int level)
|
|||
|
||||
unsigned int m68k_read_memory_8(unsigned int address)
|
||||
{
|
||||
MAYBE_CALLBACK(ReadCallback, address);
|
||||
|
||||
address &= 0x00FFFFFF;
|
||||
|
||||
unsigned int retVal = 0;
|
||||
|
@ -97,6 +124,8 @@ unsigned int m68k_read_memory_8(unsigned int address)
|
|||
|
||||
unsigned int m68k_read_memory_16(unsigned int address)
|
||||
{
|
||||
MAYBE_CALLBACK(ReadCallback, address);
|
||||
|
||||
address &= 0x00FFFFFF;
|
||||
|
||||
unsigned int retVal = 0;
|
||||
|
@ -129,6 +158,8 @@ unsigned int m68k_read_memory_16(unsigned int address)
|
|||
|
||||
unsigned int m68k_read_memory_32(unsigned int address)
|
||||
{
|
||||
MAYBE_CALLBACK(ReadCallback, address);
|
||||
|
||||
address &= 0x00FFFFFF;
|
||||
|
||||
uint32_t retVal = 0;
|
||||
|
@ -148,6 +179,8 @@ unsigned int m68k_read_memory_32(unsigned int address)
|
|||
|
||||
void m68k_write_memory_8(unsigned int address, unsigned int value)
|
||||
{
|
||||
MAYBE_CALLBACK(WriteCallback, address);
|
||||
|
||||
address &= 0x00FFFFFF;
|
||||
|
||||
if ((address >= 0x000000) && (address <= 0x1FFFFF))
|
||||
|
@ -164,6 +197,8 @@ void m68k_write_memory_8(unsigned int address, unsigned int value)
|
|||
|
||||
void m68k_write_memory_16(unsigned int address, unsigned int value)
|
||||
{
|
||||
MAYBE_CALLBACK(WriteCallback, address);
|
||||
|
||||
address &= 0x00FFFFFF;
|
||||
|
||||
if ((address >= 0x000000) && (address <= 0x1FFFFE))
|
||||
|
@ -388,6 +423,7 @@ void JaguarInit(void)
|
|||
TOMInit();
|
||||
JERRYInit();
|
||||
CDROMInit();
|
||||
CDHLEInit();
|
||||
}
|
||||
|
||||
void HalflineCallback(void);
|
||||
|
@ -410,7 +446,8 @@ void JaguarReset(void)
|
|||
GPUReset();
|
||||
DSPReset();
|
||||
CDROMReset();
|
||||
m68k_pulse_reset();
|
||||
CDHLEReset();
|
||||
m68k_pulse_reset();
|
||||
|
||||
lowerField = false;
|
||||
SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
|
||||
|
@ -418,6 +455,7 @@ void JaguarReset(void)
|
|||
|
||||
void JaguarDone(void)
|
||||
{
|
||||
CDHLEDone();
|
||||
CDROMDone();
|
||||
GPUDone();
|
||||
DSPDone();
|
||||
|
|
|
@ -36,4 +36,16 @@ extern bool jaguarCartInserted;
|
|||
#define ASSERT_LINE 1
|
||||
#define CLEAR_LINE 0
|
||||
|
||||
// Callbacks
|
||||
|
||||
extern void (*InputCallback)();
|
||||
|
||||
extern void (*ReadCallback)(uint32_t);
|
||||
extern void (*WriteCallback)(uint32_t);
|
||||
extern void (*ExecuteCallback)(uint32_t);
|
||||
|
||||
extern void (*TraceCallback)(uint32_t*);
|
||||
|
||||
#define MAYBE_CALLBACK(callback, ...) do { if (__builtin_expect(!!callback, false)) callback(__VA_ARGS__); } while (0)
|
||||
|
||||
#endif // __JAGUAR_H__
|
||||
|
|
|
@ -27,7 +27,6 @@ uint8_t joypad1Buttons[21];
|
|||
static bool joysticksEnabled;
|
||||
|
||||
extern bool lagged;
|
||||
extern void (*inputcb)();
|
||||
|
||||
void JoystickInit(void)
|
||||
{
|
||||
|
@ -53,8 +52,7 @@ void JoystickDone(void)
|
|||
uint16_t JoystickReadWord(uint32_t offset)
|
||||
{
|
||||
lagged = false;
|
||||
if (__builtin_expect(!!inputcb, false))
|
||||
inputcb();
|
||||
MAYBE_CALLBACK(InputCallback);
|
||||
|
||||
uint8_t joypad0Offset[16] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0xFF, 0xFF, 0xFF, 0x08, 0xFF, 0x04, 0x00, 0xFF
|
||||
|
|
|
@ -53,7 +53,7 @@ static uint8_t op_blend_cr[0x10000];
|
|||
|
||||
static uint32_t op_pointer;
|
||||
|
||||
int32_t phraseWidthToPixels[8] = { 64, 32, 16, 8, 4, 2, 0, 0 };
|
||||
static const int32_t phraseWidthToPixels[8] = { 64, 32, 16, 8, 4, 2, 0, 0 };
|
||||
|
||||
//
|
||||
// Object Processor initialization
|
||||
|
|
Loading…
Reference in New Issue