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:
CasualPokePlayer 2022-09-23 01:05:41 -07:00
parent d50454b37a
commit 6113f3c17b
17 changed files with 1026 additions and 94 deletions

Binary file not shown.

View File

@ -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}";
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}
}

View File

@ -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
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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
}

View File

@ -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__

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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();

View File

@ -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__

View File

@ -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

View File

@ -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