remove all meteor and garbo stuff completely. These two GBA cores were never up to par, really.
This commit is contained in:
parent
cc5ff74689
commit
72808f01bb
|
@ -413,7 +413,7 @@
|
|||
<Compile Include="Consoles\Intellivision\ICart.cs" />
|
||||
<Compile Include="Consoles\Intellivision\Intellicart.cs" />
|
||||
<Compile Include="Consoles\Intellivision\Intellivision.IInputPollable.cs">
|
||||
<DependentUpon>Intellivision.cs</DependentUpon>
|
||||
<DependentUpon>Intellivision.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Intellivision\Intellivision.ISettable.cs">
|
||||
<DependentUpon>Intellivision.cs</DependentUpon>
|
||||
|
@ -491,26 +491,10 @@
|
|||
<Compile Include="Consoles\Nintendo\Gameboy\GBDisassembler.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\ArmV4Disassembler.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\GBA.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\IGBAGPUViewable.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\LibMeteor.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\LibmGBA.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\LibVBANext.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\Meteor.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\Meteor.IGBAGPUViewable.cs">
|
||||
<DependentUpon>Meteor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\Meteor.IMemoryDomains.cs">
|
||||
<DependentUpon>Meteor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\Meteor.ISaveRam.cs">
|
||||
<DependentUpon>Meteor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\Meteor.IStatable.cs">
|
||||
<DependentUpon>Meteor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\Meteor.IVideoProvider.cs">
|
||||
<DependentUpon>Meteor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\VBANext.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\VBANext.IDebuggable.cs">
|
||||
|
|
|
@ -1,294 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
/// <summary>
|
||||
/// bindings into libmeteor.dll
|
||||
/// </summary>
|
||||
public static class LibMeteor
|
||||
{
|
||||
/// <summary>
|
||||
/// power cycle the emulation core
|
||||
/// </summary>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_hardreset();
|
||||
|
||||
/// <summary>
|
||||
/// signal that you are removing data from the sound buffer.
|
||||
/// the next time frameadvance() is called, writing will start from the beginning
|
||||
/// </summary>
|
||||
/// <returns>the valid length of the buffer, in bytes</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern uint libmeteor_emptysound();
|
||||
|
||||
/// <summary>
|
||||
/// set up buffers for libmeteor to dump data to. these must be valid before every frameadvance
|
||||
/// </summary>
|
||||
/// <param name="vid">buffer to hold video data as BGRA32</param>
|
||||
/// <param name="vidlen">length in bytes. must be at least 240 * 160 * 4</param>
|
||||
/// <param name="aud">buffer to hold audio data as stereo s16le</param>
|
||||
/// <param name="audlen">length in bytes. must be 0 mod 4 (hold a full stereo sample set)</param>
|
||||
/// <returns>false if some problem. buffers will not be valid in this case</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_setbuffers(IntPtr vid, uint vidlen, IntPtr aud, uint audlen);
|
||||
|
||||
/// <summary>
|
||||
/// initialize the library
|
||||
/// </summary>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_init();
|
||||
|
||||
/// <summary>
|
||||
/// run emulation for one frame, updating sound and video along the way
|
||||
/// </summary>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_frameadvance();
|
||||
|
||||
/// <summary>
|
||||
/// load a rom image
|
||||
/// </summary>
|
||||
/// <param name="data">raw rom data. need not persist past this call</param>
|
||||
/// <param name="datalen">length of data in bytes</param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_loadrom(byte[] data, uint datalen);
|
||||
|
||||
/// <summary>
|
||||
/// load a bios image
|
||||
/// </summary>
|
||||
/// <param name="data">raw bios data. need not persist past this call</param>
|
||||
/// <param name="datalen">length of data in bytes</param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_loadbios(byte[] data, uint datalen);
|
||||
|
||||
/// <summary>
|
||||
/// core callback to print meaningful (or meaningless) log messages
|
||||
/// </summary>
|
||||
/// <param name="msg">message to be printed</param>
|
||||
/// <param name="abort">true if emulation should be aborted</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void MessageCallback(string msg, bool abort);
|
||||
|
||||
/// <summary>
|
||||
/// set callback for log messages. this can (and should) be called first
|
||||
/// </summary>
|
||||
/// <param name="cb"></param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_setmessagecallback(MessageCallback cb);
|
||||
|
||||
/// <summary>
|
||||
/// combination of button flags used by the key callback
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Buttons : ushort
|
||||
{
|
||||
BTN_A = 0x001,
|
||||
BTN_B = 0x002,
|
||||
BTN_SELECT = 0x004,
|
||||
BTN_START = 0x008,
|
||||
BTN_RIGHT = 0x010,
|
||||
BTN_LEFT = 0x020,
|
||||
BTN_UP = 0x040,
|
||||
BTN_DOWN = 0x080,
|
||||
BTN_R = 0x100,
|
||||
BTN_L = 0x200
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// core callback to get input state
|
||||
/// </summary>
|
||||
/// <returns>buttons pressed bitfield</returns>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate Buttons InputCallback();
|
||||
|
||||
/// <summary>
|
||||
/// set callback for whenever input is requested
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_setkeycallback(InputCallback callback);
|
||||
|
||||
/// <summary>
|
||||
/// parameter to libmeteor_getmemoryarea
|
||||
/// </summary>
|
||||
public enum MemoryArea
|
||||
{
|
||||
/// <summary>
|
||||
/// BIOS, may be invalid if bios not loaded. valid size: 16K. system bus: @00000000h
|
||||
/// </summary>
|
||||
bios = 0,
|
||||
/// <summary>
|
||||
/// external workram. valid size: 256K. system bus: @02000000h
|
||||
/// </summary>
|
||||
ewram = 1,
|
||||
/// <summary>
|
||||
/// internal workram. valid size: 32K. system bus: @03000000h
|
||||
/// </summary>
|
||||
iwram = 2,
|
||||
/// <summary>
|
||||
/// palettes. valid size: 1K. system bus: @05000000h
|
||||
/// </summary>
|
||||
palram = 3,
|
||||
/// <summary>
|
||||
/// video ram. valid size: 96K. system bus: @06000000h
|
||||
/// </summary>
|
||||
vram = 4,
|
||||
/// <summary>
|
||||
/// sprite attribute ram. valid size: 1K. system bus: @07000000h
|
||||
/// </summary>
|
||||
oam = 5,
|
||||
/// <summary>
|
||||
/// rom. always valid to full size, even if no rom or small rom loaded. valid size: 32M. system bus: @08000000h, others
|
||||
/// </summary>
|
||||
rom = 6,
|
||||
/// <summary>
|
||||
/// direct access to cached io port values. this should NEVER be modified! valid size: 4K. system bus: @04000000h (sort of)
|
||||
/// </summary>
|
||||
io = 7
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return a pointer to a memory area
|
||||
/// </summary>
|
||||
/// <param name="which"></param>
|
||||
/// <returns>IntPtr.Zero if which is unrecognized</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr libmeteor_getmemoryarea(MemoryArea which);
|
||||
|
||||
/// <summary>
|
||||
/// core callback for tracelogging
|
||||
/// </summary>
|
||||
/// <param name="msg">disassembly of an instruction about to be run</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void TraceCallback(string msg);
|
||||
|
||||
/// <summary>
|
||||
/// set callback to run before each instruction is executed
|
||||
/// </summary>
|
||||
/// <param name="callback">null to clear</param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_settracecallback(TraceCallback callback);
|
||||
|
||||
/// <summary>
|
||||
/// load saveram from a byte buffer
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns>success</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_loadsaveram(byte[] data, uint size);
|
||||
|
||||
/// <summary>
|
||||
/// save saveram to a byte buffer
|
||||
/// </summary>
|
||||
/// <param name="data">buffer generated by core. copy from, but do not modify</param>
|
||||
/// <param name="size">length of buffer</param>
|
||||
/// <returns>success</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_savesaveram(ref IntPtr data, ref uint size);
|
||||
|
||||
/// <summary>
|
||||
/// destroy a buffer previously returned by libmeteor_savesaveram() to avoid leakage
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_savesaveram_destroy(IntPtr data);
|
||||
|
||||
/// <summary>
|
||||
/// return true if there is saveram installed on currently loaded cart
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_hassaveram();
|
||||
|
||||
/// <summary>
|
||||
/// resets the current cart's saveram
|
||||
/// </summary>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_clearsaveram();
|
||||
|
||||
/// <summary>
|
||||
/// serialize state
|
||||
/// </summary>
|
||||
/// <param name="data">buffer generated by core</param>
|
||||
/// <param name="size">size of buffer</param>
|
||||
/// <returns>success</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_savestate(ref IntPtr data, ref uint size);
|
||||
|
||||
/// <summary>
|
||||
/// destroy a buffer previously returned by libmeteor_savestate() to avoid leakage
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_savestate_destroy(IntPtr data);
|
||||
|
||||
/// <summary>
|
||||
/// unserialize state
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns>success</returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool libmeteor_loadstate(byte[] data, uint size);
|
||||
|
||||
/// <summary>
|
||||
/// read a byte off the system bus. guaranteed to have no side effects
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern byte libmeteor_peekbus(uint addr);
|
||||
|
||||
/// <summary>
|
||||
/// write a byte to the system bus.
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="val"></param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_writebus(uint addr, byte val);
|
||||
|
||||
/// <summary>
|
||||
/// type of the scanline callback
|
||||
/// </summary>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ScanlineCallback();
|
||||
|
||||
/// <summary>
|
||||
/// set a callback to coincide with vcount interrupts
|
||||
/// </summary>
|
||||
/// <param name="callback">null to clear</param>
|
||||
/// <param name="scanline">0-227, 160 occurring first in a frame</param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_setscanlinecallback(ScanlineCallback callback, int scanline);
|
||||
|
||||
/// <summary>
|
||||
/// get current cpu regs
|
||||
/// </summary>
|
||||
/// <param name="dest">length 18 please</param>
|
||||
[DllImport("libmeteor.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void libmeteor_getregs(int[] dest);
|
||||
|
||||
public static readonly string[] regnames = new string[]
|
||||
{
|
||||
"r0",
|
||||
"r1",
|
||||
"r2",
|
||||
"r3",
|
||||
"r4",
|
||||
"r5",
|
||||
"r6",
|
||||
"r7",
|
||||
"r8",
|
||||
"r9",
|
||||
"r10",
|
||||
"r11",
|
||||
"r12",
|
||||
"r13",
|
||||
"r14",
|
||||
"r15",
|
||||
"cpsr",
|
||||
"spsr"
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class GBA : IGBAGPUViewable
|
||||
{
|
||||
public GBAGPUMemoryAreas GetMemoryAreas()
|
||||
{
|
||||
IntPtr _vram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.vram);
|
||||
IntPtr _palram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.palram);
|
||||
IntPtr _oam = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.oam);
|
||||
IntPtr _mmio = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.io);
|
||||
|
||||
if (_vram == IntPtr.Zero || _palram == IntPtr.Zero || _oam == IntPtr.Zero || _mmio == IntPtr.Zero)
|
||||
throw new Exception("libmeteor_getmemoryarea() failed!");
|
||||
|
||||
return new GBAGPUMemoryAreas
|
||||
{
|
||||
vram = _vram,
|
||||
palram = _palram,
|
||||
oam = _oam,
|
||||
mmio = _mmio
|
||||
};
|
||||
}
|
||||
|
||||
public void SetScanlineCallback(Action callback, int scanline)
|
||||
{
|
||||
if (scanline < 0 || scanline > 227)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(scanline), "Scanline must be in [0, 227]!");
|
||||
}
|
||||
|
||||
if (callback == null)
|
||||
{
|
||||
scanlinecb = null;
|
||||
LibMeteor.libmeteor_setscanlinecallback(null, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
scanlinecb = new LibMeteor.ScanlineCallback(callback);
|
||||
LibMeteor.libmeteor_setscanlinecallback(scanlinecb, scanline);
|
||||
}
|
||||
}
|
||||
|
||||
private LibMeteor.ScanlineCallback scanlinecb = null;
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class GBA
|
||||
{
|
||||
private List<MemoryDomain> _domainList = new List<MemoryDomain>();
|
||||
private IMemoryDomains _memoryDomains;
|
||||
|
||||
private void AddMemoryDomain(LibMeteor.MemoryArea which, int size, string name)
|
||||
{
|
||||
IntPtr data = LibMeteor.libmeteor_getmemoryarea(which);
|
||||
if (data == IntPtr.Zero)
|
||||
throw new Exception("libmeteor_getmemoryarea() returned NULL??");
|
||||
|
||||
MemoryDomain md = MemoryDomain.FromIntPtr(name, size, MemoryDomain.Endian.Little, data);
|
||||
_domainList.Add(md);
|
||||
}
|
||||
|
||||
private void SetUpMemoryDomains()
|
||||
{
|
||||
_domainList.Clear();
|
||||
// this must be first to coincide with "main memory"
|
||||
// note that ewram could also be considered main memory depending on which hairs you split
|
||||
AddMemoryDomain(LibMeteor.MemoryArea.iwram, 32 * 1024, "IWRAM");
|
||||
AddMemoryDomain(LibMeteor.MemoryArea.ewram, 256 * 1024, "EWRAM");
|
||||
AddMemoryDomain(LibMeteor.MemoryArea.bios, 16 * 1024, "BIOS");
|
||||
AddMemoryDomain(LibMeteor.MemoryArea.palram, 1024, "PALRAM");
|
||||
AddMemoryDomain(LibMeteor.MemoryArea.vram, 96 * 1024, "VRAM");
|
||||
AddMemoryDomain(LibMeteor.MemoryArea.oam, 1024, "OAM");
|
||||
// even if the rom is less than 32MB, the whole is still valid in meteor
|
||||
AddMemoryDomain(LibMeteor.MemoryArea.rom, 32 * 1024 * 1024, "ROM");
|
||||
// special domain for system bus
|
||||
{
|
||||
MemoryDomain sb = new MemoryDomainDelegate("System Bus", 1 << 28, MemoryDomain.Endian.Little,
|
||||
delegate(long addr)
|
||||
{
|
||||
if (addr < 0 || addr >= 0x10000000)
|
||||
throw new IndexOutOfRangeException();
|
||||
return LibMeteor.libmeteor_peekbus((uint)addr);
|
||||
},
|
||||
delegate(long addr, byte val)
|
||||
{
|
||||
if (addr < 0 || addr >= 0x10000000)
|
||||
throw new IndexOutOfRangeException();
|
||||
LibMeteor.libmeteor_writebus((uint)addr, val);
|
||||
}, 4);
|
||||
_domainList.Add(sb);
|
||||
}
|
||||
// special combined ram memory domain
|
||||
{
|
||||
var ew = _domainList[1];
|
||||
var iw = _domainList[0];
|
||||
MemoryDomain cr = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, MemoryDomain.Endian.Little,
|
||||
delegate(long addr)
|
||||
{
|
||||
if (addr < 0 || addr >= (256 + 32) * 1024)
|
||||
throw new IndexOutOfRangeException();
|
||||
if (addr >= 256 * 1024)
|
||||
return iw.PeekByte(addr & 32767);
|
||||
else
|
||||
return ew.PeekByte(addr);
|
||||
},
|
||||
delegate(long addr, byte val)
|
||||
{
|
||||
if (addr < 0 || addr >= (256 + 32) * 1024)
|
||||
throw new IndexOutOfRangeException();
|
||||
if (addr >= 256 * 1024)
|
||||
iw.PokeByte(addr & 32767, val);
|
||||
else
|
||||
ew.PokeByte(addr, val);
|
||||
}, 4);
|
||||
_domainList.Add(cr);
|
||||
}
|
||||
|
||||
_memoryDomains = new MemoryDomainList(_domainList);
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(_memoryDomains);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class GBA : ISaveRam
|
||||
{
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException(this.GetType().ToString());
|
||||
return LibMeteor.libmeteor_hassaveram();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
throw new Exception("This needs to be fixed to match the VBANext Core!");
|
||||
#if false
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException(this.GetType().ToString());
|
||||
if (!LibMeteor.libmeteor_hassaveram())
|
||||
return null;
|
||||
IntPtr data = IntPtr.Zero;
|
||||
uint size = 0;
|
||||
if (!LibMeteor.libmeteor_savesaveram(ref data, ref size))
|
||||
throw new Exception("libmeteor_savesaveram() returned false!");
|
||||
byte[] ret = new byte[size];
|
||||
Marshal.Copy(data, ret, 0, (int)size);
|
||||
LibMeteor.libmeteor_savesaveram_destroy(data);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
throw new Exception("This needs to be fixed to match the VBANext Core!");
|
||||
#if false
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException(this.GetType().ToString());
|
||||
if (!LibMeteor.libmeteor_loadsaveram(data, (uint)data.Length))
|
||||
throw new Exception("libmeteor_loadsaveram() returned false!");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class GBA : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred { get { return true; } }
|
||||
|
||||
public void SaveStateText(System.IO.TextWriter writer)
|
||||
{
|
||||
var temp = SaveStateBinary();
|
||||
temp.SaveAsHex(writer);
|
||||
// write extra copy of stuff we don't use
|
||||
writer.WriteLine("Frame {0}", Frame);
|
||||
}
|
||||
|
||||
public void LoadStateText(System.IO.TextReader reader)
|
||||
{
|
||||
string hex = reader.ReadLine();
|
||||
byte[] state = new byte[hex.Length / 2];
|
||||
state.ReadFromHex(hex);
|
||||
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||
}
|
||||
|
||||
public void SaveStateBinary(System.IO.BinaryWriter writer)
|
||||
{
|
||||
byte[] data = SaveCoreBinary();
|
||||
writer.Write(data.Length);
|
||||
writer.Write(data);
|
||||
// other variables
|
||||
writer.Write(IsLagFrame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(Frame);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(System.IO.BinaryReader reader)
|
||||
{
|
||||
int length = reader.ReadInt32();
|
||||
byte[] data = reader.ReadBytes(length);
|
||||
LoadCoreBinary(data);
|
||||
// other variables
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
LagCount = reader.ReadInt32();
|
||||
Frame = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private byte[] SaveCoreBinary()
|
||||
{
|
||||
IntPtr ndata = IntPtr.Zero;
|
||||
uint nsize = 0;
|
||||
if (!LibMeteor.libmeteor_savestate(ref ndata, ref nsize))
|
||||
throw new Exception("libmeteor_savestate() failed!");
|
||||
if (ndata == IntPtr.Zero || nsize == 0)
|
||||
throw new Exception("libmeteor_savestate() returned bad!");
|
||||
|
||||
byte[] ret = new byte[nsize];
|
||||
Marshal.Copy(ndata, ret, 0, (int)nsize);
|
||||
LibMeteor.libmeteor_savestate_destroy(ndata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void LoadCoreBinary(byte[] data)
|
||||
{
|
||||
if (!LibMeteor.libmeteor_loadstate(data, (uint)data.Length))
|
||||
throw new Exception("libmeteor_loadstate() failed!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class GBA : IVideoProvider
|
||||
{
|
||||
public int VirtualWidth { get { return 240; } }
|
||||
public int VirtualHeight { get { return 160; } }
|
||||
public int BufferWidth { get { return 240; } }
|
||||
public int BufferHeight { get { return 160; } }
|
||||
public int BackgroundColor
|
||||
{
|
||||
get { return unchecked((int)0xff000000); }
|
||||
}
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return videobuffer;
|
||||
}
|
||||
|
||||
private int[] videobuffer;
|
||||
private GCHandle videohandle;
|
||||
}
|
||||
}
|
|
@ -1,336 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
[CoreAttributes(
|
||||
"Meteor",
|
||||
"blastrock",
|
||||
isPorted: true,
|
||||
isReleased: false,
|
||||
singleInstance: true
|
||||
)]
|
||||
[ServiceNotApplicable(typeof(IDriveLight), typeof(IRegionable))]
|
||||
public partial class GBA : IEmulator, IVideoProvider, ISoundProvider, IGBAGPUViewable, ISaveRam, IStatable, IInputPollable
|
||||
{
|
||||
[CoreConstructor("GBA")]
|
||||
public GBA(CoreComm comm, byte[] file)
|
||||
{
|
||||
ServiceProvider = new BasicServiceProvider(this);
|
||||
Tracer = new TraceBuffer
|
||||
{
|
||||
Header = " -Addr--- -Opcode- -Instruction------------------- -R0----- -R1----- -R2----- -R3----- -R4----- -R5----- -R6----- -R7----- -R8----- -R9----- -R10---- -R11---- -R12---- -R13(SP) -R14(LR) -R15(PC) -CPSR--- -SPSR---"
|
||||
};
|
||||
|
||||
(ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer);
|
||||
|
||||
CoreComm = comm;
|
||||
|
||||
comm.VsyncNum = 262144;
|
||||
comm.VsyncDen = 4389;
|
||||
comm.NominalWidth = 240;
|
||||
comm.NominalHeight = 160;
|
||||
|
||||
byte[] bios = CoreComm.CoreFileProvider.GetFirmware("GBA", "Bios", true, "GBA bios file is mandatory.");
|
||||
|
||||
if (bios.Length != 16384)
|
||||
throw new InvalidDataException("GBA bios must be exactly 16384 bytes!");
|
||||
if (file.Length > 32 * 1024 * 1024)
|
||||
throw new InvalidDataException("Rom file is too big! No GBA game is larger than 32MB");
|
||||
Init();
|
||||
LibMeteor.libmeteor_hardreset();
|
||||
LibMeteor.libmeteor_loadbios(bios, (uint)bios.Length);
|
||||
LibMeteor.libmeteor_loadrom(file, (uint)file.Length);
|
||||
|
||||
SetUpMemoryDomains();
|
||||
}
|
||||
|
||||
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
||||
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
var ret = new Dictionary<string, RegisterValue>();
|
||||
int[] data = new int[LibMeteor.regnames.Length];
|
||||
LibMeteor.libmeteor_getregs(data);
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
ret.Add(LibMeteor.regnames[i], data[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static readonly ControllerDefinition GBAController =
|
||||
new ControllerDefinition
|
||||
{
|
||||
Name = "GBA Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "L", "R", "Power"
|
||||
},
|
||||
FloatControls =
|
||||
{
|
||||
"Tilt X", "Tilt Y", "Tilt Z", "Light Sensor"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
new[] { -32767f, 0f, 32767f },
|
||||
new[] { -32767f, 0f, 32767f },
|
||||
new[] { -32767f, 0f, 32767f },
|
||||
new[] { 0f, 100f, 200f },
|
||||
}
|
||||
};
|
||||
public ControllerDefinition ControllerDefinition { get { return GBAController; } }
|
||||
public IController Controller { get; set; }
|
||||
|
||||
public void FrameAdvance(bool render, bool rendersound = true)
|
||||
{
|
||||
Frame++;
|
||||
IsLagFrame = true;
|
||||
|
||||
if (Controller.IsPressed("Power"))
|
||||
LibMeteor.libmeteor_hardreset();
|
||||
// due to the design of the tracing api, we have to poll whether it's active each frame
|
||||
LibMeteor.libmeteor_settracecallback(Tracer.Enabled ? tracecallback : null);
|
||||
if (!coredead)
|
||||
LibMeteor.libmeteor_frameadvance();
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
|
||||
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
|
||||
|
||||
// TODO: optimize managed to unmanaged using the ActiveChanged event
|
||||
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
|
||||
|
||||
private ITraceable Tracer { get; set; }
|
||||
|
||||
public string SystemId { get { return "GBA"; } }
|
||||
public bool DeterministicEmulation { get { return true; } }
|
||||
|
||||
// todo: information about the saveram type would be useful here.
|
||||
public string BoardName { get { return null; } }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
LagCount = 0;
|
||||
IsLagFrame = false;
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; private set; }
|
||||
|
||||
/// <summary>like libsnes, the library is single-instance</summary>
|
||||
static GBA attachedcore;
|
||||
/// <summary>hold pointer to message callback so it won't get GCed</summary>
|
||||
LibMeteor.MessageCallback messagecallback;
|
||||
/// <summary>hold pointer to input callback so it won't get GCed</summary>
|
||||
LibMeteor.InputCallback inputcallback;
|
||||
/// <summary>true if libmeteor aborted</summary>
|
||||
bool coredead = false;
|
||||
/// <summary>hold pointer to trace callback so it won't get GCed</summary>
|
||||
LibMeteor.TraceCallback tracecallback;
|
||||
|
||||
LibMeteor.Buttons GetInput()
|
||||
{
|
||||
InputCallbacks.Call();
|
||||
// libmeteor bitflips everything itself, so 0 == off, 1 == on
|
||||
IsLagFrame = false;
|
||||
LibMeteor.Buttons ret = 0;
|
||||
if (Controller.IsPressed("Up")) ret |= LibMeteor.Buttons.BTN_UP;
|
||||
if (Controller.IsPressed("Down")) ret |= LibMeteor.Buttons.BTN_DOWN;
|
||||
if (Controller.IsPressed("Left")) ret |= LibMeteor.Buttons.BTN_LEFT;
|
||||
if (Controller.IsPressed("Right")) ret |= LibMeteor.Buttons.BTN_RIGHT;
|
||||
if (Controller.IsPressed("Select")) ret |= LibMeteor.Buttons.BTN_SELECT;
|
||||
if (Controller.IsPressed("Start")) ret |= LibMeteor.Buttons.BTN_START;
|
||||
if (Controller.IsPressed("B")) ret |= LibMeteor.Buttons.BTN_B;
|
||||
if (Controller.IsPressed("A")) ret |= LibMeteor.Buttons.BTN_A;
|
||||
if (Controller.IsPressed("L")) ret |= LibMeteor.Buttons.BTN_L;
|
||||
if (Controller.IsPressed("R")) ret |= LibMeteor.Buttons.BTN_R;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#region messagecallbacks
|
||||
|
||||
void PrintMessage(string msg, bool abort)
|
||||
{
|
||||
Console.Write(msg.Replace("\n", "\r\n"));
|
||||
if (abort)
|
||||
StopCore(msg);
|
||||
}
|
||||
|
||||
void StopCore(string msg)
|
||||
{
|
||||
coredead = true;
|
||||
Console.WriteLine("Core stopped.");
|
||||
for (int i = 0; i < soundbuffer.Length; i++)
|
||||
soundbuffer[i] = 0;
|
||||
|
||||
var gz = new System.IO.Compression.GZipStream(
|
||||
new MemoryStream(Convert.FromBase64String(dispfont), false),
|
||||
System.IO.Compression.CompressionMode.Decompress);
|
||||
byte[] font = new byte[2048];
|
||||
gz.Read(font, 0, 2048);
|
||||
gz.Dispose();
|
||||
|
||||
// cores aren't supposed to have bad dependencies like System.Drawing, right?
|
||||
|
||||
int scx = 0;
|
||||
int scy = 0;
|
||||
|
||||
foreach (char c in msg)
|
||||
{
|
||||
if (scx == 240 || c == '\n')
|
||||
{
|
||||
scy += 8;
|
||||
scx = 0;
|
||||
}
|
||||
if (scy == 160)
|
||||
break;
|
||||
if (c == '\r' || c == '\n')
|
||||
continue;
|
||||
if (c < 256 && c != ' ')
|
||||
{
|
||||
int fpos = c * 8;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if ((font[fpos] >> i & 1) != 0)
|
||||
videobuffer[(scy + j) * 240 + scx + i] = unchecked((int)0xffff0000);
|
||||
else
|
||||
videobuffer[(scy + j) * 240 + scx + i] = unchecked((int)0xff000000);
|
||||
}
|
||||
fpos++;
|
||||
}
|
||||
}
|
||||
scx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
const string dispfont =
|
||||
"H4sICAInrFACAGZvby5yYXcARVU9q9RAFL2gjK8IT+0GDGoh1oGFGHDYQvwL2hoQroXhsdUqGGbxZ/gD" +
|
||||
"bKys7BRhIZVYLgurIghvG3ksCPKKJfGcm1nfSTJn750792smWUmIr9++/vjmdYzDZlhuh1guFotpfiRH" +
|
||||
"+dQ4n+aLxfOj/MgUR7mID8GLDMN2CftBgj54oEGG5ZuPH98sh93P3afJZHIzqGrw0e+/7LPs+OqVvuu7" +
|
||||
"7vTZJb8J223Y+MtZHvLsstwuqlAVt+E1eh+DV0JU+s3mx3q9luCChjoIsVgI7Wg2kAHBQ1mkqPu6EBhk" +
|
||||
"feYFcM5F0B0d9A74WtX2QvRtdU0SrBp6kaZpKIJ7XI341oV66sVp4TOtJS/L/IN+k8pnQkCbZb4QPEVB" +
|
||||
"nYYhKB16JHZwbsZRDuBEDWsnEnQeTzSIz60CyHWV6cg19LOXjfb1TqKb1pSrzE0VHBUOvIed8ia3dZGb" +
|
||||
"c96JM0ZhfgzPBPCbkWEPEs/4j+fO1kd2HM55Q0bf4PdmCW15E/HdFI1M7Dg/Z1xN64InguxqpGn6kkvF" +
|
||||
"GaJ0Z32/6jrRkxjntFciMB79mTwPM5NLm0ffWac3iCb7kbx0XbfqzzqhEGBPLe2i9TVKmxGtiGPFIm1N" +
|
||||
"tNj+ppMLDDl7Ywh1q62gPEUKlJX1Yw3k1uTo2P9sCseQW3Y80B4QLznrNwaOnbMGUDK9SNOvVgxt9vQH" +
|
||||
"gj51IPn7SdlRFDt4MoarIGvKwyoFd6tV34CtAWTLRySiAZF5Oq5DcHvyAvuO8/FtLgZrRNcf9tlp8l/4" +
|
||||
"sc64HPuhMnLmR/Z3jA/9cbAzexVj2CU59SPYD+rJyU6VfsiIh5NtL+j+/b7cyzmOu+op1wXrjzHXG2Ow" +
|
||||
"Qikba6pbgwL0P7J4y89XDRsY7ZxEXLcmkydP/zz9NVv74P2N4yLVVaT8wIxDNv9NaRtG1pM5kinLVqKY" +
|
||||
"ERndzXhOgOicGNe1yPLp5NUXnezAm99//3ymoX0xodQvsMKoE5GH18fr3aPx+v5ivPwFbt1KIx9VffYM" +
|
||||
"g30GyUkPbV1zJgGzJpt+sWAxGEWSHwH4izg/hwAeBjEMw0GPweTDfNLyUWzSqdroXN+L9L1z1Gy3tsKe" +
|
||||
"7Zbzpj/oOE+9P8iq5j/Nj/HUQK+S4omkuMJIaqD3g5+xQ2KwvIcEKshXE3YJNkfgjbg7/8YNLbV0Lqo6" +
|
||||
"AFEaQqJmPlM7n+l9VeDHJTm57wGJPtjRwhg53+LD1DRnMvNFO9q3q9WqFfncnq6+tm7mszbzM4QziERe" +
|
||||
"h7+LyO+zz8AYfQGerdf+P27cOBYaeUubt1RNU138q4wg74qiuFeGKjQA5BwOgxABACX8A6+GHm0ACAAA";
|
||||
|
||||
#endregion
|
||||
|
||||
// Tracer refactor TODO - rehook up meteor, if it is worth it
|
||||
//void Trace(string msg)
|
||||
//{
|
||||
// Tracer.Put(msg);
|
||||
//}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
if (attachedcore != null)
|
||||
attachedcore.Dispose();
|
||||
|
||||
messagecallback = PrintMessage;
|
||||
inputcallback = GetInput;
|
||||
|
||||
// Tracer refactor TODO - rehook up meteor, if it is worth it
|
||||
//tracecallback = Trace; // don't set this callback now, only set if enabled
|
||||
LibMeteor.libmeteor_setmessagecallback(messagecallback);
|
||||
LibMeteor.libmeteor_setkeycallback(inputcallback);
|
||||
|
||||
LibMeteor.libmeteor_init();
|
||||
videobuffer = new int[240 * 160];
|
||||
videohandle = GCHandle.Alloc(videobuffer, GCHandleType.Pinned);
|
||||
soundbuffer = new short[2048]; // nominal length of one frame is something like 1480 shorts?
|
||||
soundhandle = GCHandle.Alloc(soundbuffer, GCHandleType.Pinned);
|
||||
|
||||
if (!LibMeteor.libmeteor_setbuffers
|
||||
(videohandle.AddrOfPinnedObject(), (uint)(sizeof(int) * videobuffer.Length),
|
||||
soundhandle.AddrOfPinnedObject(), (uint)(sizeof(short) * soundbuffer.Length)))
|
||||
throw new Exception("libmeteor_setbuffers() returned false??");
|
||||
|
||||
attachedcore = this;
|
||||
}
|
||||
|
||||
private bool disposed = false;
|
||||
public void Dispose()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
disposed = true;
|
||||
videohandle.Free();
|
||||
soundhandle.Free();
|
||||
// guarantee crash if it gets accessed
|
||||
LibMeteor.libmeteor_setbuffers(IntPtr.Zero, 240 * 160 * 4, IntPtr.Zero, 4);
|
||||
messagecallback = null;
|
||||
inputcallback = null;
|
||||
tracecallback = null;
|
||||
LibMeteor.libmeteor_setmessagecallback(messagecallback);
|
||||
LibMeteor.libmeteor_setkeycallback(inputcallback);
|
||||
LibMeteor.libmeteor_settracecallback(tracecallback);
|
||||
_domainList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
short[] soundbuffer;
|
||||
GCHandle soundhandle;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
uint nbytes = LibMeteor.libmeteor_emptysound();
|
||||
samples = soundbuffer;
|
||||
if (!coredead)
|
||||
nsamp = (int)(nbytes / 4);
|
||||
else
|
||||
nsamp = 738;
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
LibMeteor.libmeteor_emptysound();
|
||||
}
|
||||
|
||||
public bool CanProvideAsync
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode == SyncSoundMode.Async)
|
||||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode
|
||||
{
|
||||
get { return SyncSoundMode.Sync; }
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,501 +0,0 @@
|
|||
namespace GarboDev
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
public class Arm7Processor
|
||||
{
|
||||
private Memory memory = null;
|
||||
private FastArmCore armCore = null;
|
||||
private ThumbCore thumbCore = null;
|
||||
private Dictionary<uint, bool> breakpoints = null;
|
||||
|
||||
private int cycles = 0;
|
||||
private int timerCycles = 0;
|
||||
private int soundCycles = 0;
|
||||
|
||||
// CPU mode definitions
|
||||
public const uint USR = 0x10;
|
||||
public const uint FIQ = 0x11;
|
||||
public const uint IRQ = 0x12;
|
||||
public const uint SVC = 0x13;
|
||||
public const uint ABT = 0x17;
|
||||
public const uint UND = 0x1B;
|
||||
public const uint SYS = 0x1F;
|
||||
|
||||
// CPSR bit definitions
|
||||
public const int N_BIT = 31;
|
||||
public const int Z_BIT = 30;
|
||||
public const int C_BIT = 29;
|
||||
public const int V_BIT = 28;
|
||||
public const int I_BIT = 7;
|
||||
public const int F_BIT = 6;
|
||||
public const int T_BIT = 5;
|
||||
|
||||
public const uint N_MASK = (uint)(1U << N_BIT);
|
||||
public const uint Z_MASK = (uint)(1U << Z_BIT);
|
||||
public const uint C_MASK = (uint)(1U << C_BIT);
|
||||
public const uint V_MASK = (uint)(1U << V_BIT);
|
||||
public const uint I_MASK = (uint)(1U << I_BIT);
|
||||
public const uint F_MASK = (uint)(1U << F_BIT);
|
||||
public const uint T_MASK = (uint)(1U << T_BIT);
|
||||
|
||||
// Standard registers
|
||||
private uint[] registers = new uint[16];
|
||||
private uint cpsr = 0;
|
||||
|
||||
// Banked registers
|
||||
private uint[] bankedFIQ = new uint[7];
|
||||
private uint[] bankedIRQ = new uint[2];
|
||||
private uint[] bankedSVC = new uint[2];
|
||||
private uint[] bankedABT = new uint[2];
|
||||
private uint[] bankedUND = new uint[2];
|
||||
|
||||
// Saved CPSR's
|
||||
private uint spsrFIQ = 0;
|
||||
private uint spsrIRQ = 0;
|
||||
private uint spsrSVC = 0;
|
||||
private uint spsrABT = 0;
|
||||
private uint spsrUND = 0;
|
||||
|
||||
private ushort keyState;
|
||||
|
||||
private bool breakpointHit = false;
|
||||
private bool cpuHalted = false;
|
||||
|
||||
public ushort KeyState
|
||||
{
|
||||
set { this.keyState = value; }
|
||||
}
|
||||
|
||||
public int Cycles
|
||||
{
|
||||
get { return this.cycles; }
|
||||
set { this.cycles = value; }
|
||||
}
|
||||
|
||||
public bool ArmState
|
||||
{
|
||||
get { return (this.cpsr & Arm7Processor.T_MASK) != Arm7Processor.T_MASK; }
|
||||
}
|
||||
|
||||
public uint[] Registers
|
||||
{
|
||||
get { return this.registers; }
|
||||
}
|
||||
|
||||
public uint CPSR
|
||||
{
|
||||
get { return this.cpsr; }
|
||||
set { this.cpsr = value; }
|
||||
}
|
||||
|
||||
public bool SPSRExists
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (this.cpsr & 0x1F)
|
||||
{
|
||||
case USR:
|
||||
case SYS:
|
||||
return false;
|
||||
case FIQ:
|
||||
case SVC:
|
||||
case ABT:
|
||||
case IRQ:
|
||||
case UND:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint SPSR
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (this.cpsr & 0x1F)
|
||||
{
|
||||
case USR:
|
||||
case SYS:
|
||||
return 0xFFFFFFFF;
|
||||
case FIQ:
|
||||
return this.spsrFIQ;
|
||||
case SVC:
|
||||
return this.spsrSVC;
|
||||
case ABT:
|
||||
return this.spsrABT;
|
||||
case IRQ:
|
||||
return this.spsrIRQ;
|
||||
case UND:
|
||||
return this.spsrUND;
|
||||
default:
|
||||
throw new Exception("Unhandled CPSR state...");
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (this.cpsr & 0x1F)
|
||||
{
|
||||
case USR:
|
||||
case SYS:
|
||||
break;
|
||||
case FIQ:
|
||||
this.spsrFIQ = value;
|
||||
break;
|
||||
case SVC:
|
||||
this.spsrSVC = value;
|
||||
break;
|
||||
case ABT:
|
||||
this.spsrABT = value;
|
||||
break;
|
||||
case IRQ:
|
||||
this.spsrIRQ = value;
|
||||
break;
|
||||
case UND:
|
||||
this.spsrUND = value;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unhandled CPSR state...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<uint, bool> Breakpoints
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.breakpoints;
|
||||
}
|
||||
}
|
||||
|
||||
public bool BreakpointHit
|
||||
{
|
||||
get { return this.breakpointHit; }
|
||||
set { this.breakpointHit = value; }
|
||||
}
|
||||
|
||||
public Arm7Processor(Memory memory)
|
||||
{
|
||||
this.memory = memory;
|
||||
this.memory.Processor = this;
|
||||
this.armCore = new FastArmCore(this, this.memory);
|
||||
this.thumbCore = new ThumbCore(this, this.memory);
|
||||
this.breakpoints = new Dictionary<uint, bool>();
|
||||
this.breakpointHit = false;
|
||||
}
|
||||
|
||||
private void SwapRegsHelper(uint[] swapRegs)
|
||||
{
|
||||
for (int i = 14; i > 14 - swapRegs.Length; i--)
|
||||
{
|
||||
uint tmp = this.registers[i];
|
||||
this.registers[i] = swapRegs[swapRegs.Length - (14 - i) - 1];
|
||||
swapRegs[swapRegs.Length - (14 - i) - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
private void SwapRegisters(uint bank)
|
||||
{
|
||||
switch (bank & 0x1F)
|
||||
{
|
||||
case FIQ:
|
||||
this.SwapRegsHelper(this.bankedFIQ);
|
||||
break;
|
||||
case SVC:
|
||||
this.SwapRegsHelper(this.bankedSVC);
|
||||
break;
|
||||
case ABT:
|
||||
this.SwapRegsHelper(this.bankedABT);
|
||||
break;
|
||||
case IRQ:
|
||||
this.SwapRegsHelper(this.bankedIRQ);
|
||||
break;
|
||||
case UND:
|
||||
this.SwapRegsHelper(this.bankedUND);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteCpsr(uint newCpsr)
|
||||
{
|
||||
if ((newCpsr & 0x1F) != (this.cpsr & 0x1F))
|
||||
{
|
||||
// Swap out the old registers
|
||||
this.SwapRegisters(this.cpsr);
|
||||
// Swap in the new registers
|
||||
this.SwapRegisters(newCpsr);
|
||||
}
|
||||
|
||||
this.cpsr = newCpsr;
|
||||
}
|
||||
|
||||
public void EnterException(uint mode, uint vector, bool interruptsDisabled, bool fiqDisabled)
|
||||
{
|
||||
uint oldCpsr = this.cpsr;
|
||||
|
||||
if ((oldCpsr & Arm7Processor.T_MASK) != 0)
|
||||
{
|
||||
registers[15] += 2U;
|
||||
}
|
||||
|
||||
// Clear T bit, and set mode
|
||||
uint newCpsr = (oldCpsr & ~0x3FU) | mode;
|
||||
if (interruptsDisabled) newCpsr |= 1 << 7;
|
||||
if (fiqDisabled) newCpsr |= 1 << 6;
|
||||
this.WriteCpsr(newCpsr);
|
||||
|
||||
this.SPSR = oldCpsr;
|
||||
registers[14] = registers[15];
|
||||
registers[15] = vector;
|
||||
|
||||
this.ReloadQueue();
|
||||
}
|
||||
|
||||
public void RequestIrq(int irq)
|
||||
{
|
||||
ushort iflag = Memory.ReadU16(this.memory.IORam, Memory.IF);
|
||||
iflag |= (ushort)(1 << irq);
|
||||
Memory.WriteU16(this.memory.IORam, Memory.IF, iflag);
|
||||
}
|
||||
|
||||
public void FireIrq()
|
||||
{
|
||||
ushort ime = Memory.ReadU16(this.memory.IORam, Memory.IME);
|
||||
ushort ie = Memory.ReadU16(this.memory.IORam, Memory.IE);
|
||||
ushort iflag = Memory.ReadU16(this.memory.IORam, Memory.IF);
|
||||
|
||||
if ((ie & (iflag)) != 0 && (ime & 1) != 0 && (this.cpsr & (1 << 7)) == 0)
|
||||
{
|
||||
// Off to the irq exception vector
|
||||
this.EnterException(Arm7Processor.IRQ, 0x18, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset(bool skipBios)
|
||||
{
|
||||
this.breakpointHit = false;
|
||||
this.cpuHalted = false;
|
||||
|
||||
// Default to ARM state
|
||||
this.cycles = 0;
|
||||
this.timerCycles = 0;
|
||||
this.soundCycles = 0;
|
||||
|
||||
this.bankedSVC[0] = 0x03007FE0;
|
||||
this.bankedIRQ[0] = 0x03007FA0;
|
||||
|
||||
this.cpsr = SYS;
|
||||
this.spsrSVC = this.cpsr;
|
||||
for (int i = 0; i < 15; i++) this.registers[i] = 0;
|
||||
|
||||
if (skipBios)
|
||||
{
|
||||
this.registers[15] = 0x8000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.registers[15] = 0;
|
||||
}
|
||||
|
||||
this.armCore.BeginExecution();
|
||||
}
|
||||
|
||||
public void Halt()
|
||||
{
|
||||
this.cpuHalted = true;
|
||||
this.cycles = 0;
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
this.breakpointHit = false;
|
||||
|
||||
if ((this.cpsr & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
|
||||
{
|
||||
this.thumbCore.Step();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.armCore.Step();
|
||||
}
|
||||
|
||||
this.UpdateTimers();
|
||||
}
|
||||
|
||||
public void ReloadQueue()
|
||||
{
|
||||
if ((this.cpsr & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
|
||||
{
|
||||
this.thumbCore.BeginExecution();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.armCore.BeginExecution();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTimer(int timer, int cycles, bool countUp)
|
||||
{
|
||||
ushort control = Memory.ReadU16(this.memory.IORam, Memory.TM0CNT + (uint)(timer * 4));
|
||||
|
||||
// Make sure timer is enabled, or count up is disabled
|
||||
if ((control & (1 << 7)) == 0) return;
|
||||
if (!countUp && (control & (1 << 2)) != 0) return;
|
||||
|
||||
if (!countUp)
|
||||
{
|
||||
switch (control & 3)
|
||||
{
|
||||
case 0: cycles *= 1 << 10; break;
|
||||
case 1: cycles *= 1 << 4; break;
|
||||
case 2: cycles *= 1 << 2; break;
|
||||
// Don't need to do anything for case 3
|
||||
}
|
||||
}
|
||||
|
||||
this.memory.TimerCnt[timer] += (uint)cycles;
|
||||
uint timerCnt = this.memory.TimerCnt[timer] >> 10;
|
||||
|
||||
if (timerCnt > 0xffff)
|
||||
{
|
||||
ushort soundCntX = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_X);
|
||||
if ((soundCntX & (1 << 7)) != 0)
|
||||
{
|
||||
ushort soundCntH = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_H);
|
||||
if (timer == ((soundCntH >> 10) & 1))
|
||||
{
|
||||
// FIFO A overflow
|
||||
this.memory.SoundManager.DequeueA();
|
||||
if (this.memory.SoundManager.QueueSizeA < 16)
|
||||
{
|
||||
this.memory.FifoDma(1);
|
||||
// TODO
|
||||
if (this.memory.SoundManager.QueueSizeA < 16)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
if (timer == ((soundCntH >> 14) & 1))
|
||||
{
|
||||
// FIFO B overflow
|
||||
this.memory.SoundManager.DequeueB();
|
||||
if (this.memory.SoundManager.QueueSizeB < 16)
|
||||
{
|
||||
this.memory.FifoDma(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overflow, attempt to fire IRQ
|
||||
if ((control & (1 << 6)) != 0)
|
||||
{
|
||||
this.RequestIrq(3 + timer);
|
||||
}
|
||||
|
||||
if (timer < 3)
|
||||
{
|
||||
ushort control2 = Memory.ReadU16(this.memory.IORam, Memory.TM0CNT + (uint)((timer + 1) * 4));
|
||||
if ((control2 & (1 << 2)) != 0)
|
||||
{
|
||||
// Count-up
|
||||
this.UpdateTimer(timer + 1, (int)((timerCnt >> 16) << 10), true);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the original value
|
||||
uint count = Memory.ReadU16(this.memory.IORam, Memory.TM0D + (uint)(timer * 4));
|
||||
this.memory.TimerCnt[timer] = count << 10;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTimers()
|
||||
{
|
||||
int cycles = this.timerCycles - this.cycles;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this.UpdateTimer(i, cycles, false);
|
||||
}
|
||||
|
||||
this.timerCycles = this.cycles;
|
||||
}
|
||||
|
||||
public void UpdateKeyState()
|
||||
{
|
||||
ushort KEYCNT = this.memory.ReadU16Debug(Memory.REG_BASE + Memory.KEYCNT);
|
||||
|
||||
if ((KEYCNT & (1 << 14)) != 0)
|
||||
{
|
||||
if ((KEYCNT & (1 << 15)) != 0)
|
||||
{
|
||||
KEYCNT &= 0x3FF;
|
||||
if (((~this.keyState) & KEYCNT) == KEYCNT)
|
||||
this.RequestIrq(12);
|
||||
}
|
||||
else
|
||||
{
|
||||
KEYCNT &= 0x3FF;
|
||||
if (((~this.keyState) & KEYCNT) != 0)
|
||||
this.RequestIrq(12);
|
||||
}
|
||||
}
|
||||
|
||||
this.memory.KeyState = this.keyState;
|
||||
}
|
||||
|
||||
public void UpdateSound()
|
||||
{
|
||||
this.memory.SoundManager.Mix(this.soundCycles);
|
||||
this.soundCycles = 0;
|
||||
}
|
||||
|
||||
public void Execute(int cycles)
|
||||
{
|
||||
this.cycles += cycles;
|
||||
this.timerCycles += cycles;
|
||||
this.soundCycles += cycles;
|
||||
this.breakpointHit = false;
|
||||
|
||||
if (this.cpuHalted)
|
||||
{
|
||||
ushort ie = Memory.ReadU16(this.memory.IORam, Memory.IE);
|
||||
ushort iflag = Memory.ReadU16(this.memory.IORam, Memory.IF);
|
||||
|
||||
if ((ie & iflag) != 0)
|
||||
{
|
||||
this.cpuHalted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.cycles = 0;
|
||||
this.UpdateTimers();
|
||||
this.UpdateSound();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (this.cycles > 0)
|
||||
{
|
||||
if ((this.cpsr & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
|
||||
{
|
||||
this.thumbCore.Execute();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.armCore.Execute();
|
||||
}
|
||||
|
||||
this.UpdateTimers();
|
||||
this.UpdateSound();
|
||||
|
||||
if (this.breakpointHit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,469 +0,0 @@
|
|||
//#define ARM_DEBUG
|
||||
|
||||
namespace GarboDev
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation;
|
||||
using BizHawk;
|
||||
|
||||
public class GbaManager : IEmulator, ISyncSoundProvider, IVideoProvider
|
||||
{
|
||||
public const int cpuFreq = 16 * 1024 * 1024;
|
||||
|
||||
private int framesRendered;
|
||||
|
||||
private Arm7Processor arm7 = null;
|
||||
private Memory memory = null;
|
||||
private VideoManager videoManager = null;
|
||||
private SoundManager soundManager = null;
|
||||
|
||||
private bool skipBios = false;
|
||||
|
||||
public delegate void CpuUpdateDelegate(Arm7Processor processor, Memory memory);
|
||||
private event CpuUpdateDelegate onCpuUpdate = null;
|
||||
|
||||
public Arm7Processor Arm7
|
||||
{
|
||||
get { return this.arm7; }
|
||||
}
|
||||
|
||||
public VideoManager VideoManager
|
||||
{
|
||||
get { return this.videoManager; }
|
||||
}
|
||||
|
||||
public SoundManager SoundManager
|
||||
{
|
||||
get { return this.soundManager; }
|
||||
}
|
||||
|
||||
public Memory Memory
|
||||
{
|
||||
get { return this.memory; }
|
||||
}
|
||||
|
||||
public Dictionary<uint, bool> Breakpoints
|
||||
{
|
||||
get { return this.arm7.Breakpoints; }
|
||||
}
|
||||
|
||||
public ushort KeyState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.memory != null)
|
||||
{
|
||||
return this.memory.KeyState;
|
||||
}
|
||||
|
||||
return 0x3FF;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this.arm7.KeyState = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int FramesRendered
|
||||
{
|
||||
get { return this.framesRendered; }
|
||||
set { this.framesRendered = value; }
|
||||
}
|
||||
|
||||
public event CpuUpdateDelegate OnCpuUpdate
|
||||
{
|
||||
add
|
||||
{
|
||||
this.onCpuUpdate += value;
|
||||
this.onCpuUpdate(this.arm7, this.memory);
|
||||
}
|
||||
remove
|
||||
{
|
||||
this.onCpuUpdate -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool SkipBios
|
||||
{
|
||||
get { return this.skipBios; }
|
||||
set { this.skipBios = value; }
|
||||
}
|
||||
|
||||
public GbaManager(CoreComm comm)
|
||||
{
|
||||
_corecomm = comm;
|
||||
|
||||
this.memory = new Memory();
|
||||
this.arm7 = new Arm7Processor(this.memory);
|
||||
this.videoManager = new VideoManager(this);
|
||||
this.videoManager.Memory = this.memory;
|
||||
this.soundManager = new SoundManager(this.memory, 44100);
|
||||
|
||||
this.framesRendered = 0;
|
||||
Renderer renderer = new Renderer();
|
||||
renderer.Initialize(null);
|
||||
VideoManager.Renderer = renderer;
|
||||
|
||||
videoManager.Presenter = delegate(uint[] data)
|
||||
{
|
||||
Buffer.BlockCopy(data, 0, this.vbuf, 0, 240 * 160 * 4);
|
||||
};
|
||||
}
|
||||
|
||||
public void Load(byte[] rom, byte[] bios)
|
||||
{
|
||||
LoadBios(bios);
|
||||
LoadRom(rom);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
//this.Halt();
|
||||
|
||||
this.arm7.Reset(this.skipBios);
|
||||
this.memory.Reset();
|
||||
this.videoManager.Reset();
|
||||
}
|
||||
|
||||
public void LoadState(BinaryReader state)
|
||||
{
|
||||
}
|
||||
|
||||
public void SaveState(BinaryWriter state)
|
||||
{
|
||||
state.Write("GARB");
|
||||
}
|
||||
|
||||
public void LoadBios(byte[] biosRom)
|
||||
{
|
||||
this.memory.LoadBios(biosRom);
|
||||
|
||||
if (this.onCpuUpdate != null)
|
||||
{
|
||||
this.onCpuUpdate(this.arm7, this.memory);
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadRom(byte[] cartRom)
|
||||
{
|
||||
//this.Halt();
|
||||
|
||||
/*
|
||||
byte[] logo = new byte[]
|
||||
{
|
||||
0x24,0xff,0xae,0x51,0x69,0x9a,0xa2,0x21,
|
||||
0x3d,0x84,0x82,0x0a,0x84,0xe4,0x09,0xad,
|
||||
0x11,0x24,0x8b,0x98,0xc0,0x81,0x7f,0x21,
|
||||
0xa3,0x52,0xbe,0x19,0x93,0x09,0xce,0x20,
|
||||
0x10,0x46,0x4a,0x4a,0xf8,0x27,0x31,0xec,
|
||||
0x58,0xc7,0xe8,0x33,0x82,0xe3,0xce,0xbf,
|
||||
0x85,0xf4,0xdf,0x94,0xce,0x4b,0x09,0xc1,
|
||||
0x94,0x56,0x8a,0xc0,0x13,0x72,0xa7,0xfc,
|
||||
0x9f,0x84,0x4d,0x73,0xa3,0xca,0x9a,0x61,
|
||||
0x58,0x97,0xa3,0x27,0xfc,0x03,0x98,0x76,
|
||||
0x23,0x1d,0xc7,0x61,0x03,0x04,0xae,0x56,
|
||||
0xbf,0x38,0x84,0x00,0x40,0xa7,0x0e,0xfd,
|
||||
0xff,0x52,0xfe,0x03,0x6f,0x95,0x30,0xf1,
|
||||
0x97,0xfb,0xc0,0x85,0x60,0xd6,0x80,0x25,
|
||||
0xa9,0x63,0xbe,0x03,0x01,0x4e,0x38,0xe2,
|
||||
0xf9,0xa2,0x34,0xff,0xbb,0x3e,0x03,0x44,
|
||||
0x78,0x00,0x90,0xcb,0x88,0x11,0x3a,0x94,
|
||||
0x65,0xc0,0x7c,0x63,0x87,0xf0,0x3c,0xaf,
|
||||
0xd6,0x25,0xe4,0x8b,0x38,0x0a,0xac,0x72,
|
||||
0x21,0xd4,0xf8,0x07
|
||||
};
|
||||
|
||||
Array.Copy(logo, 0, cartRom, 4, logo.Length);
|
||||
cartRom[0xB2] = 0x96;
|
||||
cartRom[0xBD] = 0;
|
||||
for (int i = 0xA0; i <= 0xBC; i++) cartRom[0xBD] = (byte)(cartRom[0xBD] - cartRom[i]);
|
||||
cartRom[0xBD] = (byte)((cartRom[0xBD] - 0x19) & 0xFF);
|
||||
*/
|
||||
this.memory.LoadCartridge(cartRom);
|
||||
|
||||
this.Reset();
|
||||
|
||||
if (this.onCpuUpdate != null)
|
||||
{
|
||||
this.onCpuUpdate(this.arm7, this.memory);
|
||||
}
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
//this.Halt();
|
||||
|
||||
this.arm7.Step();
|
||||
|
||||
if (this.onCpuUpdate != null)
|
||||
{
|
||||
this.onCpuUpdate(this.arm7, this.memory);
|
||||
}
|
||||
}
|
||||
|
||||
public void StepScanline()
|
||||
{
|
||||
//this.Halt();
|
||||
|
||||
this.arm7.Execute(960);
|
||||
this.videoManager.RenderLine();
|
||||
this.videoManager.EnterHBlank(this.arm7);
|
||||
this.arm7.Execute(272);
|
||||
this.videoManager.LeaveHBlank(this.arm7);
|
||||
|
||||
if (this.onCpuUpdate != null)
|
||||
{
|
||||
this.onCpuUpdate(this.arm7, this.memory);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInputState()
|
||||
{
|
||||
ushort ret = 0;
|
||||
if (_controller["Up"]) ret |= 64;
|
||||
if (_controller["Down"]) ret |= 128;
|
||||
if (_controller["Left"]) ret |= 32;
|
||||
if (_controller["Right"]) ret |= 16;
|
||||
if (_controller["Select"]) ret |= 4;
|
||||
if (_controller["Start"]) ret |= 8;
|
||||
if (_controller["B"]) ret |= 2;
|
||||
if (_controller["A"]) ret |= 1;
|
||||
if (_controller["L"]) ret |= 512;
|
||||
if (_controller["R"]) ret |= 256;
|
||||
ret ^= 0x3ff;
|
||||
KeyState = ret;
|
||||
}
|
||||
|
||||
private void StepFrame()
|
||||
{
|
||||
UpdateInputState();
|
||||
if (_controller["Power"])
|
||||
Reset();
|
||||
|
||||
int vramCycles = 0;
|
||||
bool inHblank = false;
|
||||
|
||||
//HighPerformanceTimer profileTimer = new HighPerformanceTimer();
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
||||
|
||||
const int cycleStep = 123;
|
||||
|
||||
|
||||
if (vramCycles <= 0)
|
||||
{
|
||||
if (inHblank)
|
||||
{
|
||||
vramCycles += 960;
|
||||
bool HitVBlank = this.videoManager.LeaveHBlank(this.arm7);
|
||||
inHblank = false;
|
||||
if (HitVBlank)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
vramCycles += 272;
|
||||
this.videoManager.RenderLine();
|
||||
this.videoManager.EnterHBlank(this.arm7);
|
||||
inHblank = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.arm7.Execute(cycleStep);
|
||||
#if ARM_DEBUG
|
||||
if (this.arm7.BreakpointHit)
|
||||
{
|
||||
this.waitingToHalt = true;
|
||||
Monitor.Wait(this);
|
||||
}
|
||||
#endif
|
||||
vramCycles -= cycleStep;
|
||||
this.arm7.FireIrq();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
IVideoProvider IEmulator.VideoProvider
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
ISoundProvider IEmulator.SoundProvider
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
ISyncSoundProvider IEmulator.SyncSoundProvider
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
bool IEmulator.StartAsyncSound()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void IEmulator.EndAsyncSound()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ControllerDefinition IEmulator.ControllerDefinition
|
||||
{
|
||||
get { return BizHawk.Emulation.Consoles.Nintendo.GBA.GBA.GBAController; }
|
||||
}
|
||||
|
||||
IController _controller;
|
||||
|
||||
IController IEmulator.Controller
|
||||
{
|
||||
get { return _controller; }
|
||||
set { _controller = value; }
|
||||
}
|
||||
|
||||
void IEmulator.FrameAdvance(bool render, bool rendersound)
|
||||
{
|
||||
StepFrame();
|
||||
}
|
||||
|
||||
int IEmulator.Frame
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
int IEmulator.LagCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool IEmulator.IsLagFrame
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
string IEmulator.SystemId
|
||||
{
|
||||
get { return "GBA"; }
|
||||
}
|
||||
|
||||
bool IEmulator.DeterministicEmulation
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
byte[] IEmulator.ReadSaveRam()
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
void IEmulator.StoreSaveRam(byte[] data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IEmulator.ClearSaveRam()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool IEmulator.SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void IEmulator.ResetFrameCounter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IEmulator.SaveStateText(TextWriter writer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IEmulator.LoadStateText(TextReader reader)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IEmulator.SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IEmulator.LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
byte[] IEmulator.SaveStateBinary()
|
||||
{
|
||||
return new byte[16];
|
||||
}
|
||||
|
||||
CoreComm _corecomm;
|
||||
|
||||
CoreComm IEmulator.CoreComm
|
||||
{
|
||||
get { return _corecomm; }
|
||||
}
|
||||
|
||||
IList<MemoryDomain> IEmulator.MemoryDomains
|
||||
{
|
||||
get { return new List<MemoryDomain>(); }
|
||||
}
|
||||
|
||||
MemoryDomain IEmulator.MainMemory
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int[] vbuf = new int[240 * 160];
|
||||
int[] IVideoProvider.GetVideoBuffer() { return vbuf; }
|
||||
int IVideoProvider.VirtualWidth { get { return 240; } }
|
||||
int IVideoProvider.BufferWidth { get { return 240; } }
|
||||
int IVideoProvider.BufferHeight { get { return 160; } }
|
||||
int IVideoProvider.BackgroundColor { get { return unchecked((int)0xff000000); } }
|
||||
|
||||
void ISyncSoundProvider.GetSamples(out short[] samples, out int nsamp)
|
||||
{
|
||||
nsamp = soundManager.SamplesMixed / 2;
|
||||
samples = new short[nsamp * 2];
|
||||
soundManager.GetSamples(samples, nsamp * 2);
|
||||
}
|
||||
|
||||
void ISyncSoundProvider.DiscardSamples()
|
||||
{
|
||||
// should implement
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
namespace GarboDev
|
||||
{
|
||||
using System;
|
||||
|
||||
public interface IRenderer
|
||||
{
|
||||
Memory Memory { set; }
|
||||
void Initialize(object data);
|
||||
void Reset();
|
||||
void RenderLine(int line);
|
||||
uint[] ShowFrame();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,952 +0,0 @@
|
|||
namespace GarboDev
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
public partial class Renderer : IRenderer
|
||||
{
|
||||
private Memory memory;
|
||||
private uint[] scanline = new uint[240];
|
||||
private byte[] blend = new byte[240];
|
||||
private byte[] windowCover = new byte[240];
|
||||
private uint[] back = new uint[240 * 160];
|
||||
//private uint[] front = new uint[240 * 160];
|
||||
private const uint pitch = 240;
|
||||
|
||||
// Convenience variable as I use it everywhere, set once in RenderLine
|
||||
private ushort dispCnt;
|
||||
|
||||
// Window helper variables
|
||||
private byte win0x1, win0x2, win0y1, win0y2;
|
||||
private byte win1x1, win1x2, win1y1, win1y2;
|
||||
private byte win0Enabled, win1Enabled, winObjEnabled, winOutEnabled;
|
||||
private bool winEnabled;
|
||||
|
||||
private byte blendSource, blendTarget;
|
||||
private byte blendA, blendB, blendY;
|
||||
private int blendType;
|
||||
|
||||
private int curLine = 0;
|
||||
|
||||
private static uint[] colorLUT;
|
||||
|
||||
static Renderer()
|
||||
{
|
||||
colorLUT = new uint[0x10000];
|
||||
// Pre-calculate the color LUT
|
||||
for (uint i = 0; i <= 0xFFFF; i++)
|
||||
{
|
||||
uint r = (i & 0x1FU);
|
||||
uint g = (i & 0x3E0U) >> 5;
|
||||
uint b = (i & 0x7C00U) >> 10;
|
||||
r = (r << 3) | (r >> 2);
|
||||
g = (g << 3) | (g >> 2);
|
||||
b = (b << 3) | (b >> 2);
|
||||
colorLUT[i] = (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
|
||||
public Memory Memory
|
||||
{
|
||||
set { this.memory = value; }
|
||||
}
|
||||
|
||||
public void Initialize(object data)
|
||||
{
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public uint[] ShowFrame()
|
||||
{
|
||||
//Array.Copy(this.back, this.front, this.front.Length);
|
||||
|
||||
//return this.front;
|
||||
return this.back;
|
||||
}
|
||||
|
||||
public void RenderLine(int line)
|
||||
{
|
||||
this.curLine = line;
|
||||
|
||||
// Render the line
|
||||
this.dispCnt = Memory.ReadU16(this.memory.IORam, Memory.DISPCNT);
|
||||
|
||||
if ((this.dispCnt & (1 << 7)) != 0)
|
||||
{
|
||||
uint bgColor = Renderer.GbaTo32((ushort)0x7FFF);
|
||||
for (int i = 0; i < 240; i++) this.scanline[i] = bgColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.winEnabled = false;
|
||||
|
||||
if ((this.dispCnt & (1 << 13)) != 0)
|
||||
{
|
||||
// Calculate window 0 information
|
||||
ushort winy = Memory.ReadU16(this.memory.IORam, Memory.WIN0V);
|
||||
this.win0y1 = (byte)(winy >> 8);
|
||||
this.win0y2 = (byte)(winy & 0xff);
|
||||
ushort winx = Memory.ReadU16(this.memory.IORam, Memory.WIN0H);
|
||||
this.win0x1 = (byte)(winx >> 8);
|
||||
this.win0x2 = (byte)(winx & 0xff);
|
||||
|
||||
if (this.win0x2 > 240 || this.win0x1 > this.win0x2)
|
||||
{
|
||||
this.win0x2 = 240;
|
||||
}
|
||||
|
||||
if (this.win0y2 > 160 || this.win0y1 > this.win0y2)
|
||||
{
|
||||
this.win0y2 = 160;
|
||||
}
|
||||
|
||||
this.win0Enabled = this.memory.IORam[Memory.WININ];
|
||||
this.winEnabled = true;
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 14)) != 0)
|
||||
{
|
||||
// Calculate window 1 information
|
||||
ushort winy = Memory.ReadU16(this.memory.IORam, Memory.WIN1V);
|
||||
this.win1y1 = (byte)(winy >> 8);
|
||||
this.win1y2 = (byte)(winy & 0xff);
|
||||
ushort winx = Memory.ReadU16(this.memory.IORam, Memory.WIN1H);
|
||||
this.win1x1 = (byte)(winx >> 8);
|
||||
this.win1x2 = (byte)(winx & 0xff);
|
||||
|
||||
if (this.win1x2 > 240 || this.win1x1 > this.win1x2)
|
||||
{
|
||||
this.win1x2 = 240;
|
||||
}
|
||||
|
||||
if (this.win1y2 > 160 || this.win1y1 > this.win1y2)
|
||||
{
|
||||
this.win1y2 = 160;
|
||||
}
|
||||
|
||||
this.win1Enabled = this.memory.IORam[Memory.WININ + 1];
|
||||
this.winEnabled = true;
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 15)) != 0 && (this.dispCnt & (1 << 12)) != 0)
|
||||
{
|
||||
// Object windows are enabled
|
||||
this.winObjEnabled = this.memory.IORam[Memory.WINOUT + 1];
|
||||
this.winEnabled = true;
|
||||
}
|
||||
|
||||
if (this.winEnabled)
|
||||
{
|
||||
this.winOutEnabled = this.memory.IORam[Memory.WINOUT];
|
||||
}
|
||||
|
||||
// Calculate blending information
|
||||
ushort bldcnt = Memory.ReadU16(this.memory.IORam, Memory.BLDCNT);
|
||||
this.blendType = (bldcnt >> 6) & 0x3;
|
||||
this.blendSource = (byte)(bldcnt & 0x3F);
|
||||
this.blendTarget = (byte)((bldcnt >> 8) & 0x3F);
|
||||
|
||||
ushort bldalpha = Memory.ReadU16(this.memory.IORam, Memory.BLDALPHA);
|
||||
this.blendA = (byte)(bldalpha & 0x1F);
|
||||
if (this.blendA > 0x10) this.blendA = 0x10;
|
||||
this.blendB = (byte)((bldalpha >> 8) & 0x1F);
|
||||
if (this.blendB > 0x10) this.blendB = 0x10;
|
||||
|
||||
this.blendY = (byte)(this.memory.IORam[Memory.BLDY] & 0x1F);
|
||||
if (this.blendY > 0x10) this.blendY = 0x10;
|
||||
|
||||
switch (this.dispCnt & 0x7)
|
||||
{
|
||||
case 0: this.RenderMode0Line(); break;
|
||||
case 1: this.RenderMode1Line(); break;
|
||||
case 2: this.RenderMode2Line(); break;
|
||||
case 3: this.RenderMode3Line(); break;
|
||||
case 4: this.RenderMode4Line(); break;
|
||||
case 5: this.RenderMode5Line(); break;
|
||||
}
|
||||
}
|
||||
|
||||
Array.Copy(this.scanline, 0, this.back, this.curLine * Renderer.pitch, Renderer.pitch);
|
||||
}
|
||||
|
||||
private void DrawBackdrop()
|
||||
{
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
|
||||
// Initialize window coverage buffer if neccesary
|
||||
if (this.winEnabled)
|
||||
{
|
||||
for (int i = 0; i < 240; i++)
|
||||
{
|
||||
this.windowCover[i] = this.winOutEnabled;
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 15)) != 0)
|
||||
{
|
||||
// Sprite window
|
||||
this.DrawSpriteWindows();
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 14)) != 0)
|
||||
{
|
||||
// Window 1
|
||||
if (this.curLine >= this.win1y1 && this.curLine < this.win1y2)
|
||||
{
|
||||
for (int i = this.win1x1; i < this.win1x2; i++)
|
||||
{
|
||||
this.windowCover[i] = this.win1Enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 13)) != 0)
|
||||
{
|
||||
// Window 0
|
||||
if (this.curLine >= this.win0y1 && this.curLine < this.win0y2)
|
||||
{
|
||||
for (int i = this.win0x1; i < this.win0x2; i++)
|
||||
{
|
||||
this.windowCover[i] = this.win0Enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw backdrop first
|
||||
uint bgColor = Renderer.GbaTo32((ushort)(palette[0] | (palette[1] << 8)));
|
||||
uint modColor = bgColor;
|
||||
|
||||
if (this.blendType == 2 && (this.blendSource & (1 << 5)) != 0)
|
||||
{
|
||||
// Brightness increase
|
||||
uint r = bgColor & 0xFF;
|
||||
uint g = (bgColor >> 8) & 0xFF;
|
||||
uint b = (bgColor >> 16) & 0xFF;
|
||||
r = r + (((0xFF - r) * this.blendY) >> 4);
|
||||
g = g + (((0xFF - g) * this.blendY) >> 4);
|
||||
b = b + (((0xFF - b) * this.blendY) >> 4);
|
||||
modColor = r | (g << 8) | (b << 16);
|
||||
}
|
||||
else if (this.blendType == 3 && (this.blendSource & (1 << 5)) != 0)
|
||||
{
|
||||
// Brightness decrease
|
||||
uint r = bgColor & 0xFF;
|
||||
uint g = (bgColor >> 8) & 0xFF;
|
||||
uint b = (bgColor >> 16) & 0xFF;
|
||||
r = r - ((r * this.blendY) >> 4);
|
||||
g = g - ((g * this.blendY) >> 4);
|
||||
b = b - ((b * this.blendY) >> 4);
|
||||
modColor = r | (g << 8) | (b << 16);
|
||||
}
|
||||
|
||||
if (this.winEnabled)
|
||||
{
|
||||
for (int i = 0; i < 240; i++)
|
||||
{
|
||||
if ((this.windowCover[i] & (1 << 5)) != 0)
|
||||
{
|
||||
this.scanline[i] = modColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.scanline[i] = bgColor;
|
||||
}
|
||||
this.blend[i] = 1 << 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 240; i++)
|
||||
{
|
||||
this.scanline[i] = modColor;
|
||||
this.blend[i] = 1 << 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderTextBg(int bg)
|
||||
{
|
||||
if (this.winEnabled)
|
||||
{
|
||||
switch (this.blendType)
|
||||
{
|
||||
case 0:
|
||||
this.RenderTextBgWindow(bg);
|
||||
break;
|
||||
case 1:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderTextBgWindowBlend(bg);
|
||||
else
|
||||
this.RenderTextBgWindow(bg);
|
||||
break;
|
||||
case 2:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderTextBgWindowBrightInc(bg);
|
||||
else
|
||||
this.RenderTextBgWindow(bg);
|
||||
break;
|
||||
case 3:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderTextBgWindowBrightDec(bg);
|
||||
else
|
||||
this.RenderTextBgWindow(bg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (this.blendType)
|
||||
{
|
||||
case 0:
|
||||
this.RenderTextBgNormal(bg);
|
||||
break;
|
||||
case 1:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderTextBgBlend(bg);
|
||||
else
|
||||
this.RenderTextBgNormal(bg);
|
||||
break;
|
||||
case 2:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderTextBgBrightInc(bg);
|
||||
else
|
||||
this.RenderTextBgNormal(bg);
|
||||
break;
|
||||
case 3:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderTextBgBrightDec(bg);
|
||||
else
|
||||
this.RenderTextBgNormal(bg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderRotScaleBg(int bg)
|
||||
{
|
||||
if (this.winEnabled)
|
||||
{
|
||||
switch (this.blendType)
|
||||
{
|
||||
case 0:
|
||||
this.RenderRotScaleBgWindow(bg);
|
||||
break;
|
||||
case 1:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderRotScaleBgWindowBlend(bg);
|
||||
else
|
||||
this.RenderRotScaleBgWindow(bg);
|
||||
break;
|
||||
case 2:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderRotScaleBgWindowBrightInc(bg);
|
||||
else
|
||||
this.RenderRotScaleBgWindow(bg);
|
||||
break;
|
||||
case 3:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderRotScaleBgWindowBrightDec(bg);
|
||||
else
|
||||
this.RenderRotScaleBgWindow(bg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (this.blendType)
|
||||
{
|
||||
case 0:
|
||||
this.RenderRotScaleBgNormal(bg);
|
||||
break;
|
||||
case 1:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderRotScaleBgBlend(bg);
|
||||
else
|
||||
this.RenderRotScaleBgNormal(bg);
|
||||
break;
|
||||
case 2:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderRotScaleBgBrightInc(bg);
|
||||
else
|
||||
this.RenderRotScaleBgNormal(bg);
|
||||
break;
|
||||
case 3:
|
||||
if ((this.blendSource & (1 << bg)) != 0)
|
||||
this.RenderRotScaleBgBrightDec(bg);
|
||||
else
|
||||
this.RenderRotScaleBgNormal(bg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSprites(int pri)
|
||||
{
|
||||
if (this.winEnabled)
|
||||
{
|
||||
switch (this.blendType)
|
||||
{
|
||||
case 0:
|
||||
this.DrawSpritesWindow(pri);
|
||||
break;
|
||||
case 1:
|
||||
if ((this.blendSource & (1 << 4)) != 0)
|
||||
this.DrawSpritesWindowBlend(pri);
|
||||
else
|
||||
this.DrawSpritesWindow(pri);
|
||||
break;
|
||||
case 2:
|
||||
if ((this.blendSource & (1 << 4)) != 0)
|
||||
this.DrawSpritesWindowBrightInc(pri);
|
||||
else
|
||||
this.DrawSpritesWindow(pri);
|
||||
break;
|
||||
case 3:
|
||||
if ((this.blendSource & (1 << 4)) != 0)
|
||||
this.DrawSpritesWindowBrightDec(pri);
|
||||
else
|
||||
this.DrawSpritesWindow(pri);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (this.blendType)
|
||||
{
|
||||
case 0:
|
||||
this.DrawSpritesNormal(pri);
|
||||
break;
|
||||
case 1:
|
||||
if ((this.blendSource & (1 << 4)) != 0)
|
||||
this.DrawSpritesBlend(pri);
|
||||
else
|
||||
this.DrawSpritesNormal(pri);
|
||||
break;
|
||||
case 2:
|
||||
if ((this.blendSource & (1 << 4)) != 0)
|
||||
this.DrawSpritesBrightInc(pri);
|
||||
else
|
||||
this.DrawSpritesNormal(pri);
|
||||
break;
|
||||
case 3:
|
||||
if ((this.blendSource & (1 << 4)) != 0)
|
||||
this.DrawSpritesBrightDec(pri);
|
||||
else
|
||||
this.DrawSpritesNormal(pri);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMode0Line()
|
||||
{
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
byte[] vram = this.memory.VideoRam;
|
||||
|
||||
this.DrawBackdrop();
|
||||
|
||||
for (int pri = 3; pri >= 0; pri--)
|
||||
{
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
if ((this.dispCnt & (1 << (8 + i))) != 0)
|
||||
{
|
||||
ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)i);
|
||||
|
||||
if ((bgcnt & 0x3) == pri)
|
||||
{
|
||||
this.RenderTextBg(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMode1Line()
|
||||
{
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
byte[] vram = this.memory.VideoRam;
|
||||
|
||||
this.DrawBackdrop();
|
||||
|
||||
for (int pri = 3; pri >= 0; pri--)
|
||||
{
|
||||
if ((this.dispCnt & (1 << (8 + 2))) != 0)
|
||||
{
|
||||
ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
|
||||
|
||||
if ((bgcnt & 0x3) == pri)
|
||||
{
|
||||
this.RenderRotScaleBg(2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i >= 0; i--)
|
||||
{
|
||||
if ((this.dispCnt & (1 << (8 + i))) != 0)
|
||||
{
|
||||
ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)i);
|
||||
|
||||
if ((bgcnt & 0x3) == pri)
|
||||
{
|
||||
this.RenderTextBg(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMode2Line()
|
||||
{
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
byte[] vram = this.memory.VideoRam;
|
||||
|
||||
this.DrawBackdrop();
|
||||
|
||||
for (int pri = 3; pri >= 0; pri--)
|
||||
{
|
||||
for (int i = 3; i >= 2; i--)
|
||||
{
|
||||
if ((this.dispCnt & (1 << (8 + i))) != 0)
|
||||
{
|
||||
ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)i);
|
||||
|
||||
if ((bgcnt & 0x3) == pri)
|
||||
{
|
||||
this.RenderRotScaleBg(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMode3Line()
|
||||
{
|
||||
ushort bg2Cnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
|
||||
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
byte[] vram = this.memory.VideoRam;
|
||||
|
||||
this.DrawBackdrop();
|
||||
|
||||
byte blendMaskType = (byte)(1 << 2);
|
||||
|
||||
int bgPri = bg2Cnt & 0x3;
|
||||
for (int pri = 3; pri > bgPri; pri--)
|
||||
{
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 10)) != 0)
|
||||
{
|
||||
// Background enabled, render it
|
||||
int x = this.memory.Bgx[0];
|
||||
int y = this.memory.Bgy[0];
|
||||
|
||||
short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA);
|
||||
short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC);
|
||||
|
||||
for (int i = 0; i < 240; i++)
|
||||
{
|
||||
int ax = ((int)x) >> 8;
|
||||
int ay = ((int)y) >> 8;
|
||||
|
||||
if (ax >= 0 && ax < 240 && ay >= 0 && ay < 160)
|
||||
{
|
||||
int curIdx = ((ay * 240) + ax) * 2;
|
||||
this.scanline[i] = Renderer.GbaTo32((ushort)(vram[curIdx] | (vram[curIdx + 1] << 8)));
|
||||
this.blend[i] = blendMaskType;
|
||||
}
|
||||
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
for (int pri = bgPri; pri >= 0; pri--)
|
||||
{
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMode4Line()
|
||||
{
|
||||
ushort bg2Cnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
|
||||
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
byte[] vram = this.memory.VideoRam;
|
||||
|
||||
this.DrawBackdrop();
|
||||
|
||||
byte blendMaskType = (byte)(1 << 2);
|
||||
|
||||
int bgPri = bg2Cnt & 0x3;
|
||||
for (int pri = 3; pri > bgPri; pri--)
|
||||
{
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 10)) != 0)
|
||||
{
|
||||
// Background enabled, render it
|
||||
int baseIdx = 0;
|
||||
if ((this.dispCnt & (1 << 4)) == 1 << 4) baseIdx = 0xA000;
|
||||
|
||||
int x = this.memory.Bgx[0];
|
||||
int y = this.memory.Bgy[0];
|
||||
|
||||
short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA);
|
||||
short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC);
|
||||
|
||||
for (int i = 0; i < 240; i++)
|
||||
{
|
||||
int ax = ((int)x) >> 8;
|
||||
int ay = ((int)y) >> 8;
|
||||
|
||||
if (ax >= 0 && ax < 240 && ay >= 0 && ay < 160)
|
||||
{
|
||||
int lookup = vram[baseIdx + (ay * 240) + ax];
|
||||
if (lookup != 0)
|
||||
{
|
||||
this.scanline[i] = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
|
||||
this.blend[i] = blendMaskType;
|
||||
}
|
||||
}
|
||||
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
for (int pri = bgPri; pri >= 0; pri--)
|
||||
{
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMode5Line()
|
||||
{
|
||||
ushort bg2Cnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
|
||||
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
byte[] vram = this.memory.VideoRam;
|
||||
|
||||
this.DrawBackdrop();
|
||||
|
||||
byte blendMaskType = (byte)(1 << 2);
|
||||
|
||||
int bgPri = bg2Cnt & 0x3;
|
||||
for (int pri = 3; pri > bgPri; pri--)
|
||||
{
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
|
||||
if ((this.dispCnt & (1 << 10)) != 0)
|
||||
{
|
||||
// Background enabled, render it
|
||||
int baseIdx = 0;
|
||||
if ((this.dispCnt & (1 << 4)) == 1 << 4) baseIdx += 160 * 128 * 2;
|
||||
|
||||
int x = this.memory.Bgx[0];
|
||||
int y = this.memory.Bgy[0];
|
||||
|
||||
short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA);
|
||||
short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC);
|
||||
|
||||
for (int i = 0; i < 240; i++)
|
||||
{
|
||||
int ax = ((int)x) >> 8;
|
||||
int ay = ((int)y) >> 8;
|
||||
|
||||
if (ax >= 0 && ax < 160 && ay >= 0 && ay < 128)
|
||||
{
|
||||
int curIdx = (int)(ay * 160 + ax) * 2;
|
||||
|
||||
this.scanline[i] = Renderer.GbaTo32((ushort)(vram[baseIdx + curIdx] | (vram[baseIdx + curIdx + 1] << 8)));
|
||||
this.blend[i] = blendMaskType;
|
||||
}
|
||||
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
for (int pri = bgPri; pri >= 0; pri--)
|
||||
{
|
||||
this.DrawSprites(pri);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSpriteWindows()
|
||||
{
|
||||
byte[] palette = this.memory.PaletteRam;
|
||||
byte[] vram = this.memory.VideoRam;
|
||||
|
||||
// OBJ must be enabled in this.dispCnt
|
||||
if ((this.dispCnt & (1 << 12)) == 0) return;
|
||||
|
||||
for (int oamNum = 127; oamNum >= 0; oamNum--)
|
||||
{
|
||||
ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
|
||||
|
||||
// Not an object window, so continue
|
||||
if (((attr0 >> 10) & 3) != 2) continue;
|
||||
|
||||
ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
|
||||
ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
|
||||
|
||||
int x = attr1 & 0x1FF;
|
||||
int y = attr0 & 0xFF;
|
||||
|
||||
int width = -1, height = -1;
|
||||
switch ((attr0 >> 14) & 3)
|
||||
{
|
||||
case 0:
|
||||
// Square
|
||||
switch ((attr1 >> 14) & 3)
|
||||
{
|
||||
case 0: width = 8; height = 8; break;
|
||||
case 1: width = 16; height = 16; break;
|
||||
case 2: width = 32; height = 32; break;
|
||||
case 3: width = 64; height = 64; break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// Horizontal Rectangle
|
||||
switch ((attr1 >> 14) & 3)
|
||||
{
|
||||
case 0: width = 16; height = 8; break;
|
||||
case 1: width = 32; height = 8; break;
|
||||
case 2: width = 32; height = 16; break;
|
||||
case 3: width = 64; height = 32; break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Vertical Rectangle
|
||||
switch ((attr1 >> 14) & 3)
|
||||
{
|
||||
case 0: width = 8; height = 16; break;
|
||||
case 1: width = 8; height = 32; break;
|
||||
case 2: width = 16; height = 32; break;
|
||||
case 3: width = 32; height = 64; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Check double size flag here
|
||||
|
||||
int rwidth = width, rheight = height;
|
||||
if ((attr0 & (1 << 8)) != 0)
|
||||
{
|
||||
// Rot-scale on
|
||||
if ((attr0 & (1 << 9)) != 0)
|
||||
{
|
||||
rwidth *= 2;
|
||||
rheight *= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid sprite
|
||||
if ((attr0 & (1 << 9)) != 0)
|
||||
width = -1;
|
||||
}
|
||||
|
||||
if (width == -1)
|
||||
{
|
||||
// Invalid sprite
|
||||
continue;
|
||||
}
|
||||
|
||||
// Y clipping
|
||||
if (y > ((y + rheight) & 0xff))
|
||||
{
|
||||
if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
|
||||
}
|
||||
|
||||
int scale = 1;
|
||||
if ((attr0 & (1 << 13)) != 0) scale = 2;
|
||||
|
||||
int spritey = this.curLine - y;
|
||||
if (spritey < 0) spritey += 256;
|
||||
|
||||
if ((attr0 & (1 << 8)) == 0)
|
||||
{
|
||||
if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
|
||||
|
||||
int baseSprite;
|
||||
if ((this.dispCnt & (1 << 6)) != 0)
|
||||
{
|
||||
// 1 dimensional
|
||||
baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2 dimensional
|
||||
baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
|
||||
}
|
||||
|
||||
int baseInc = scale;
|
||||
if ((attr1 & (1 << 12)) != 0)
|
||||
{
|
||||
baseSprite += ((width / 8) * scale) - scale;
|
||||
baseInc = -baseInc;
|
||||
}
|
||||
|
||||
if ((attr0 & (1 << 13)) != 0)
|
||||
{
|
||||
// 256 colors
|
||||
for (int i = x; i < x + width; i++)
|
||||
{
|
||||
if ((i & 0x1ff) < 240)
|
||||
{
|
||||
int tx = (i - x) & 7;
|
||||
if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
|
||||
int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
|
||||
int lookup = vram[0x10000 + curIdx];
|
||||
if (lookup != 0)
|
||||
{
|
||||
this.windowCover[i & 0x1ff] = this.winObjEnabled;
|
||||
}
|
||||
}
|
||||
if (((i - x) & 7) == 7) baseSprite += baseInc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 16 colors
|
||||
int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
|
||||
for (int i = x; i < x + width; i++)
|
||||
{
|
||||
if ((i & 0x1ff) < 240)
|
||||
{
|
||||
int tx = (i - x) & 7;
|
||||
if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
|
||||
int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
|
||||
int lookup = vram[0x10000 + curIdx];
|
||||
if ((tx & 1) == 0)
|
||||
{
|
||||
lookup &= 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
lookup >>= 4;
|
||||
}
|
||||
if (lookup != 0)
|
||||
{
|
||||
this.windowCover[i & 0x1ff] = this.winObjEnabled;
|
||||
}
|
||||
}
|
||||
if (((i - x) & 7) == 7) baseSprite += baseInc;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int rotScaleParam = (attr1 >> 9) & 0x1F;
|
||||
|
||||
short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
|
||||
short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
|
||||
short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
|
||||
short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
|
||||
|
||||
int cx = rwidth / 2;
|
||||
int cy = rheight / 2;
|
||||
|
||||
int baseSprite = attr2 & 0x3FF;
|
||||
int pitch;
|
||||
|
||||
if ((this.dispCnt & (1 << 6)) != 0)
|
||||
{
|
||||
// 1 dimensional
|
||||
pitch = (width / 8) * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2 dimensional
|
||||
pitch = 0x20;
|
||||
}
|
||||
|
||||
short rx = (short)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
|
||||
short ry = (short)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
|
||||
|
||||
// Draw a rot/scale sprite
|
||||
if ((attr0 & (1 << 13)) != 0)
|
||||
{
|
||||
// 256 colors
|
||||
for (int i = x; i < x + rwidth; i++)
|
||||
{
|
||||
int tx = rx >> 8;
|
||||
int ty = ry >> 8;
|
||||
|
||||
if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height)
|
||||
{
|
||||
int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
|
||||
int lookup = vram[0x10000 + curIdx];
|
||||
if (lookup != 0)
|
||||
{
|
||||
this.windowCover[i & 0x1ff] = this.winObjEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
rx += dx;
|
||||
ry += dy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 16 colors
|
||||
int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
|
||||
for (int i = x; i < x + rwidth; i++)
|
||||
{
|
||||
int tx = rx >> 8;
|
||||
int ty = ry >> 8;
|
||||
|
||||
if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height)
|
||||
{
|
||||
int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
|
||||
int lookup = vram[0x10000 + curIdx];
|
||||
if ((tx & 1) == 0)
|
||||
{
|
||||
lookup &= 0xf;
|
||||
}
|
||||
else
|
||||
{
|
||||
lookup >>= 4;
|
||||
}
|
||||
if (lookup != 0)
|
||||
{
|
||||
this.windowCover[i & 0x1ff] = this.winObjEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
rx += dx;
|
||||
ry += dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static uint GbaTo32(ushort color)
|
||||
{
|
||||
// more accurate, but slower :(
|
||||
// return colorLUT[color];
|
||||
return ((color & 0x1FU) << 19) | ((color & 0x3E0U) << 6) | ((color & 0x7C00U) >> 7);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,191 +0,0 @@
|
|||
namespace GarboDev
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
public class SoundManager
|
||||
{
|
||||
private Memory memory = null;
|
||||
private Queue<byte>[] soundQueue = new Queue<byte>[2];
|
||||
private byte latchedA, latchedB;
|
||||
private int frequency, cyclesPerSample;
|
||||
private int leftover = 0;
|
||||
|
||||
private short[] soundBuffer = new short[40000];
|
||||
private int soundBufferPos = 0;
|
||||
private int lastSoundBufferPos = 0;
|
||||
|
||||
public SoundManager(Memory memory, int frequency)
|
||||
{
|
||||
this.Frequency = frequency;
|
||||
|
||||
this.memory = memory;
|
||||
this.memory.SoundManager = this;
|
||||
|
||||
this.soundQueue[0] = new Queue<byte>(32);
|
||||
this.soundQueue[1] = new Queue<byte>(32);
|
||||
}
|
||||
|
||||
#region Public Properties
|
||||
public int Frequency
|
||||
{
|
||||
get { return this.frequency; }
|
||||
set
|
||||
{
|
||||
this.frequency = value;
|
||||
this.cyclesPerSample = (GbaManager.cpuFreq << 5) / this.frequency;
|
||||
}
|
||||
}
|
||||
|
||||
public int QueueSizeA
|
||||
{
|
||||
get { return this.soundQueue[0].Count; }
|
||||
}
|
||||
|
||||
public int QueueSizeB
|
||||
{
|
||||
get { return this.soundQueue[1].Count; }
|
||||
}
|
||||
|
||||
public int SamplesMixed
|
||||
{
|
||||
get
|
||||
{
|
||||
int value = this.soundBufferPos - this.lastSoundBufferPos;
|
||||
if (value < 0) value += this.soundBuffer.Length;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void GetSamples(short[] buffer, int length)
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (this.lastSoundBufferPos == this.soundBuffer.Length)
|
||||
{
|
||||
this.lastSoundBufferPos = 0;
|
||||
}
|
||||
buffer[i] = this.soundBuffer[this.lastSoundBufferPos++];
|
||||
}
|
||||
}
|
||||
|
||||
public void Mix(int cycles)
|
||||
{
|
||||
ushort soundCntH = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_H);
|
||||
ushort soundCntX = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_X);
|
||||
|
||||
cycles <<= 5;
|
||||
cycles += this.leftover;
|
||||
|
||||
if (cycles > 0)
|
||||
{
|
||||
// Precompute loop invariants
|
||||
short directA = (short)(sbyte)(this.latchedA);
|
||||
short directB = (short)(sbyte)(this.latchedB);
|
||||
|
||||
if ((soundCntH & (1 << 2)) == 0)
|
||||
{
|
||||
directA >>= 1;
|
||||
}
|
||||
if ((soundCntH & (1 << 3)) == 0)
|
||||
{
|
||||
directB >>= 1;
|
||||
}
|
||||
|
||||
while (cycles > 0)
|
||||
{
|
||||
short l = 0, r = 0;
|
||||
|
||||
cycles -= this.cyclesPerSample;
|
||||
|
||||
// Mixing
|
||||
if ((soundCntX & (1 << 7)) != 0)
|
||||
{
|
||||
if ((soundCntH & (1 << 8)) != 0)
|
||||
{
|
||||
r += directA;
|
||||
}
|
||||
if ((soundCntH & (1 << 9)) != 0)
|
||||
{
|
||||
l += directA;
|
||||
}
|
||||
if ((soundCntH & (1 << 12)) != 0)
|
||||
{
|
||||
r += directB;
|
||||
}
|
||||
if ((soundCntH & (1 << 13)) != 0)
|
||||
{
|
||||
l += directB;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.soundBufferPos == this.soundBuffer.Length)
|
||||
{
|
||||
this.soundBufferPos = 0;
|
||||
}
|
||||
|
||||
this.soundBuffer[this.soundBufferPos++] = (short)(l << 6);
|
||||
this.soundBuffer[this.soundBufferPos++] = (short)(r << 6);
|
||||
}
|
||||
}
|
||||
|
||||
this.leftover = cycles;
|
||||
}
|
||||
|
||||
public void ResetFifoA()
|
||||
{
|
||||
this.soundQueue[0].Clear();
|
||||
this.latchedA = 0;
|
||||
}
|
||||
|
||||
public void ResetFifoB()
|
||||
{
|
||||
this.soundQueue[1].Clear();
|
||||
this.latchedB = 0;
|
||||
}
|
||||
|
||||
public void IncrementFifoA()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this.EnqueueDSoundSample(0, this.memory.IORam[Memory.FIFO_A_L + i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void IncrementFifoB()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this.EnqueueDSoundSample(1, this.memory.IORam[Memory.FIFO_B_L + i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void DequeueA()
|
||||
{
|
||||
if (this.soundQueue[0].Count > 0)
|
||||
{
|
||||
this.latchedA = this.soundQueue[0].Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public void DequeueB()
|
||||
{
|
||||
if (this.soundQueue[1].Count > 0)
|
||||
{
|
||||
this.latchedB = this.soundQueue[1].Dequeue();
|
||||
}
|
||||
}
|
||||
#endregion Public Methods
|
||||
|
||||
private void EnqueueDSoundSample(int channel, byte sample)
|
||||
{
|
||||
if (this.soundQueue[channel].Count < 32)
|
||||
{
|
||||
this.soundQueue[channel].Enqueue(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,981 +0,0 @@
|
|||
//#define ARM_DEBUG
|
||||
|
||||
namespace GarboDev
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
public class ThumbCore
|
||||
{
|
||||
private const int COND_EQ = 0; // Z set
|
||||
private const int COND_NE = 1; // Z clear
|
||||
private const int COND_CS = 2; // C set
|
||||
private const int COND_CC = 3; // C clear
|
||||
private const int COND_MI = 4; // N set
|
||||
private const int COND_PL = 5; // N clear
|
||||
private const int COND_VS = 6; // V set
|
||||
private const int COND_VC = 7; // V clear
|
||||
private const int COND_HI = 8; // C set and Z clear
|
||||
private const int COND_LS = 9; // C clear or Z set
|
||||
private const int COND_GE = 10; // N equals V
|
||||
private const int COND_LT = 11; // N not equal to V
|
||||
private const int COND_GT = 12; // Z clear AND (N equals V)
|
||||
private const int COND_LE = 13; // Z set OR (N not equal to V)
|
||||
private const int COND_AL = 14; // Always
|
||||
private const int COND_NV = 15; // Never execute
|
||||
|
||||
private const int OP_AND = 0x0;
|
||||
private const int OP_EOR = 0x1;
|
||||
private const int OP_LSL = 0x2;
|
||||
private const int OP_LSR = 0x3;
|
||||
private const int OP_ASR = 0x4;
|
||||
private const int OP_ADC = 0x5;
|
||||
private const int OP_SBC = 0x6;
|
||||
private const int OP_ROR = 0x7;
|
||||
private const int OP_TST = 0x8;
|
||||
private const int OP_NEG = 0x9;
|
||||
private const int OP_CMP = 0xA;
|
||||
private const int OP_CMN = 0xB;
|
||||
private const int OP_ORR = 0xC;
|
||||
private const int OP_MUL = 0xD;
|
||||
private const int OP_BIC = 0xE;
|
||||
private const int OP_MVN = 0xF;
|
||||
|
||||
private Arm7Processor parent;
|
||||
private Memory memory;
|
||||
private uint[] registers;
|
||||
|
||||
// CPU flags
|
||||
private uint zero, carry, negative, overflow;
|
||||
private ushort curInstruction, instructionQueue;
|
||||
|
||||
private delegate void ExecuteInstruction();
|
||||
private ExecuteInstruction[] NormalOps = null;
|
||||
|
||||
public ThumbCore(Arm7Processor parent, Memory memory)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.memory = memory;
|
||||
this.registers = this.parent.Registers;
|
||||
|
||||
this.NormalOps = new ExecuteInstruction[256]
|
||||
{
|
||||
OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm,
|
||||
OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm,
|
||||
OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm,
|
||||
OpAddRegReg, OpAddRegReg, OpSubRegReg, OpSubRegReg, OpAddRegImm, OpAddRegImm, OpSubRegImm, OpSubRegImm,
|
||||
OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm,
|
||||
OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm,
|
||||
OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm,
|
||||
OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm,
|
||||
OpArith, OpArith, OpArith, OpArith, OpAddHi, OpCmpHi, OpMovHi, OpBx,
|
||||
OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc,
|
||||
OpStrReg, OpStrReg, OpStrhReg, OpStrhReg, OpStrbReg, OpStrbReg, OpLdrsbReg, OpLdrsbReg,
|
||||
OpLdrReg, OpLdrReg, OpLdrhReg, OpLdrhReg, OpLdrbReg, OpLdrbReg, OpLdrshReg, OpLdrshReg,
|
||||
OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm,
|
||||
OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm,
|
||||
OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm,
|
||||
OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm,
|
||||
OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm,
|
||||
OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm,
|
||||
OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp,
|
||||
OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp,
|
||||
OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc,
|
||||
OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp,
|
||||
OpSubSp, OpUnd, OpUnd, OpUnd, OpPush, OpPushLr, OpUnd, OpUnd,
|
||||
OpUnd, OpUnd, OpUnd, OpUnd, OpPop, OpPopPc, OpUnd, OpUnd,
|
||||
OpStmia, OpStmia, OpStmia, OpStmia, OpStmia, OpStmia, OpStmia, OpStmia,
|
||||
OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia,
|
||||
OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond,
|
||||
OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpUnd, OpSwi,
|
||||
OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB,
|
||||
OpUnd, OpUnd, OpUnd, OpUnd, OpUnd, OpUnd, OpUnd, OpUnd,
|
||||
OpBl1, OpBl1, OpBl1, OpBl1, OpBl1, OpBl1, OpBl1, OpBl1,
|
||||
OpBl2, OpBl2, OpBl2, OpBl2, OpBl2, OpBl2, OpBl2, OpBl2
|
||||
};
|
||||
}
|
||||
|
||||
public void BeginExecution()
|
||||
{
|
||||
this.FlushQueue();
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
this.UnpackFlags();
|
||||
|
||||
this.curInstruction = this.instructionQueue;
|
||||
this.instructionQueue = this.memory.ReadU16(registers[15]);
|
||||
registers[15] += 2;
|
||||
|
||||
// Execute the instruction
|
||||
this.NormalOps[this.curInstruction >> 8]();
|
||||
|
||||
this.parent.Cycles -= this.memory.WaitCycles;
|
||||
|
||||
if ((this.parent.CPSR & Arm7Processor.T_MASK) != Arm7Processor.T_MASK)
|
||||
{
|
||||
if ((this.curInstruction >> 8) != 0xDF) this.parent.ReloadQueue();
|
||||
}
|
||||
|
||||
this.PackFlags();
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
this.UnpackFlags();
|
||||
|
||||
while (this.parent.Cycles > 0)
|
||||
{
|
||||
this.curInstruction = this.instructionQueue;
|
||||
this.instructionQueue = this.memory.ReadU16(registers[15]);
|
||||
registers[15] += 2;
|
||||
|
||||
// Execute the instruction
|
||||
this.NormalOps[this.curInstruction >> 8]();
|
||||
|
||||
this.parent.Cycles -= this.memory.WaitCycles;
|
||||
|
||||
if ((this.parent.CPSR & Arm7Processor.T_MASK) != Arm7Processor.T_MASK)
|
||||
{
|
||||
if ((this.curInstruction >> 8) != 0xDF) this.parent.ReloadQueue();
|
||||
break;
|
||||
}
|
||||
|
||||
// Check the current PC
|
||||
#if ARM_DEBUG
|
||||
if (this.parent.Breakpoints.ContainsKey(registers[15] - 2U))
|
||||
{
|
||||
this.parent.BreakpointHit = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
this.PackFlags();
|
||||
}
|
||||
|
||||
#region Flag helpers
|
||||
public void OverflowCarryAdd(uint a, uint b, uint r)
|
||||
{
|
||||
overflow = ((a & b & ~r) | (~a & ~b & r)) >> 31;
|
||||
carry = ((a & b) | (a & ~r) | (b & ~r)) >> 31;
|
||||
}
|
||||
|
||||
public void OverflowCarrySub(uint a, uint b, uint r)
|
||||
{
|
||||
overflow = ((a & ~b & ~r) | (~a & b & r)) >> 31;
|
||||
carry = ((a & ~b) | (a & ~r) | (~b & ~r)) >> 31;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Opcodes
|
||||
private void OpLslImm()
|
||||
{
|
||||
// 0x00 - 0x07
|
||||
// lsl rd, rm, #immed
|
||||
int rd = this.curInstruction & 0x7;
|
||||
int rm = (this.curInstruction >> 3) & 0x7;
|
||||
int immed = (this.curInstruction >> 6) & 0x1F;
|
||||
|
||||
if (immed == 0)
|
||||
{
|
||||
registers[rd] = registers[rm];
|
||||
} else
|
||||
{
|
||||
carry = (registers[rm] >> (32 - immed)) & 0x1;
|
||||
registers[rd] = registers[rm] << immed;
|
||||
}
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpLsrImm()
|
||||
{
|
||||
// 0x08 - 0x0F
|
||||
// lsr rd, rm, #immed
|
||||
int rd = this.curInstruction & 0x7;
|
||||
int rm = (this.curInstruction >> 3) & 0x7;
|
||||
int immed = (this.curInstruction >> 6) & 0x1F;
|
||||
|
||||
if (immed == 0)
|
||||
{
|
||||
carry = registers[rm] >> 31;
|
||||
registers[rd] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
carry = (registers[rm] >> (immed - 1)) & 0x1;
|
||||
registers[rd] = registers[rm] >> immed;
|
||||
}
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpAsrImm()
|
||||
{
|
||||
// asr rd, rm, #immed
|
||||
int rd = this.curInstruction & 0x7;
|
||||
int rm = (this.curInstruction >> 3) & 0x7;
|
||||
int immed = (this.curInstruction >> 6) & 0x1F;
|
||||
|
||||
if (immed == 0)
|
||||
{
|
||||
carry = registers[rm] >> 31;
|
||||
if (carry == 1) registers[rd] = 0xFFFFFFFF;
|
||||
else registers[rd] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
carry = (registers[rm] >> (immed - 1)) & 0x1;
|
||||
registers[rd] = (uint)(((int)registers[rm]) >> immed);
|
||||
}
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpAddRegReg()
|
||||
{
|
||||
// add rd, rn, rm
|
||||
int rd = this.curInstruction & 0x7;
|
||||
int rn = (this.curInstruction >> 3) & 0x7;
|
||||
int rm = (this.curInstruction >> 6) & 0x7;
|
||||
|
||||
uint orn = registers[rn];
|
||||
uint orm = registers[rm];
|
||||
|
||||
registers[rd] = orn + orm;
|
||||
|
||||
this.OverflowCarryAdd(orn, orm, registers[rd]);
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpSubRegReg()
|
||||
{
|
||||
// sub rd, rn, rm
|
||||
int rd = this.curInstruction & 0x7;
|
||||
int rn = (this.curInstruction >> 3) & 0x7;
|
||||
int rm = (this.curInstruction >> 6) & 0x7;
|
||||
|
||||
uint orn = registers[rn];
|
||||
uint orm = registers[rm];
|
||||
|
||||
registers[rd] = orn - orm;
|
||||
|
||||
this.OverflowCarrySub(orn, orm, registers[rd]);
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpAddRegImm()
|
||||
{
|
||||
// add rd, rn, #immed
|
||||
int rd = this.curInstruction & 0x7;
|
||||
int rn = (this.curInstruction >> 3) & 0x7;
|
||||
uint immed = (uint)((this.curInstruction >> 6) & 0x7);
|
||||
|
||||
uint orn = registers[rn];
|
||||
|
||||
registers[rd] = orn + immed;
|
||||
|
||||
this.OverflowCarryAdd(orn, immed, registers[rd]);
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpSubRegImm()
|
||||
{
|
||||
// sub rd, rn, #immed
|
||||
int rd = this.curInstruction & 0x7;
|
||||
int rn = (this.curInstruction >> 3) & 0x7;
|
||||
uint immed = (uint)((this.curInstruction >> 6) & 0x7);
|
||||
|
||||
uint orn = registers[rn];
|
||||
|
||||
registers[rd] = orn - immed;
|
||||
|
||||
this.OverflowCarrySub(orn, immed, registers[rd]);
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpMovImm()
|
||||
{
|
||||
// mov rd, #immed
|
||||
int rd = (this.curInstruction >> 8) & 0x7;
|
||||
|
||||
registers[rd] = (uint)(this.curInstruction & 0xFF);
|
||||
|
||||
negative = 0;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpCmpImm()
|
||||
{
|
||||
// cmp rn, #immed
|
||||
int rn = (this.curInstruction >> 8) & 0x7;
|
||||
|
||||
uint alu = registers[rn] - (uint)(this.curInstruction & 0xFF);
|
||||
|
||||
this.OverflowCarrySub(registers[rn], (uint)(this.curInstruction & 0xFF), alu);
|
||||
negative = alu >> 31;
|
||||
zero = alu == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpAddImm()
|
||||
{
|
||||
// add rd, #immed
|
||||
int rd = (this.curInstruction >> 8) & 0x7;
|
||||
|
||||
uint ord = registers[rd];
|
||||
|
||||
registers[rd] += (uint)(this.curInstruction & 0xFF);
|
||||
|
||||
this.OverflowCarryAdd(ord, (uint)(this.curInstruction & 0xFF), registers[rd]);
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpSubImm()
|
||||
{
|
||||
// sub rd, #immed
|
||||
int rd = (this.curInstruction >> 8) & 0x7;
|
||||
|
||||
uint ord = registers[rd];
|
||||
|
||||
registers[rd] -= (uint)(this.curInstruction & 0xFF);
|
||||
|
||||
this.OverflowCarrySub(ord, (uint)(this.curInstruction & 0xFF), registers[rd]);
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
}
|
||||
|
||||
private void OpArith()
|
||||
{
|
||||
int rd = this.curInstruction & 0x7;
|
||||
uint rn = registers[(this.curInstruction >> 3) & 0x7];
|
||||
|
||||
uint orig, alu;
|
||||
int shiftAmt;
|
||||
|
||||
switch ((this.curInstruction >> 6) & 0xF)
|
||||
{
|
||||
case OP_ADC:
|
||||
orig = registers[rd];
|
||||
registers[rd] += rn + carry;
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
this.OverflowCarryAdd(orig, rn, registers[rd]);
|
||||
break;
|
||||
|
||||
case OP_AND:
|
||||
registers[rd] &= rn;
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_ASR:
|
||||
shiftAmt = (int)(rn & 0xFF);
|
||||
if (shiftAmt == 0)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if (shiftAmt < 32)
|
||||
{
|
||||
carry = (registers[rd] >> (shiftAmt - 1)) & 0x1;
|
||||
registers[rd] = (uint)(((int)registers[rd]) >> shiftAmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
carry = (registers[rd] >> 31) & 1;
|
||||
if (carry == 1) registers[rd] = 0xFFFFFFFF;
|
||||
else registers[rd] = 0;
|
||||
}
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_BIC:
|
||||
registers[rd] &= ~rn;
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_CMN:
|
||||
alu = registers[rd] + rn;
|
||||
|
||||
negative = alu >> 31;
|
||||
zero = alu == 0 ? 1U : 0U;
|
||||
this.OverflowCarryAdd(registers[rd], rn, alu);
|
||||
break;
|
||||
|
||||
case OP_CMP:
|
||||
alu = registers[rd] - rn;
|
||||
|
||||
negative = alu >> 31;
|
||||
zero = alu == 0 ? 1U : 0U;
|
||||
this.OverflowCarrySub(registers[rd], rn, alu);
|
||||
break;
|
||||
|
||||
case OP_EOR:
|
||||
registers[rd] ^= rn;
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_LSL:
|
||||
shiftAmt = (int)(rn & 0xFF);
|
||||
if (shiftAmt == 0)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if (shiftAmt < 32)
|
||||
{
|
||||
carry = (registers[rd] >> (32 - shiftAmt)) & 0x1;
|
||||
registers[rd] <<= shiftAmt;
|
||||
}
|
||||
else if (shiftAmt == 32)
|
||||
{
|
||||
carry = registers[rd] & 0x1;
|
||||
registers[rd] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
carry = 0;
|
||||
registers[rd] = 0;
|
||||
}
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_LSR:
|
||||
shiftAmt = (int)(rn & 0xFF);
|
||||
if (shiftAmt == 0)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if (shiftAmt < 32)
|
||||
{
|
||||
carry = (registers[rd] >> (shiftAmt - 1)) & 0x1;
|
||||
registers[rd] >>= shiftAmt;
|
||||
}
|
||||
else if (shiftAmt == 32)
|
||||
{
|
||||
carry = (registers[rd] >> 31) & 0x1;
|
||||
registers[rd] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
carry = 0;
|
||||
registers[rd] = 0;
|
||||
}
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_MUL:
|
||||
int mulCycles = 4;
|
||||
// Multiply cycle calculations
|
||||
if ((rn & 0xFFFFFF00) == 0 || (rn & 0xFFFFFF00) == 0xFFFFFF00)
|
||||
{
|
||||
mulCycles = 1;
|
||||
}
|
||||
else if ((rn & 0xFFFF0000) == 0 || (rn & 0xFFFF0000) == 0xFFFF0000)
|
||||
{
|
||||
mulCycles = 2;
|
||||
}
|
||||
else if ((rn & 0xFF000000) == 0 || (rn & 0xFF000000) == 0xFF000000)
|
||||
{
|
||||
mulCycles = 3;
|
||||
}
|
||||
|
||||
this.parent.Cycles -= mulCycles;
|
||||
|
||||
registers[rd] *= rn;
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_MVN:
|
||||
registers[rd] = ~rn;
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_NEG:
|
||||
registers[rd] = 0 - rn;
|
||||
|
||||
this.OverflowCarrySub(0, rn, registers[rd]);
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_ORR:
|
||||
registers[rd] |= rn;
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_ROR:
|
||||
shiftAmt = (int)(rn & 0xFF);
|
||||
if (shiftAmt == 0)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if ((shiftAmt & 0x1F) == 0)
|
||||
{
|
||||
carry = registers[rd] >> 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftAmt &= 0x1F;
|
||||
carry = (registers[rd] >> (shiftAmt - 1)) & 0x1;
|
||||
registers[rd] = (registers[rd] >> shiftAmt) | (registers[rd] << (32 - shiftAmt));
|
||||
}
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
case OP_SBC:
|
||||
orig = registers[rd];
|
||||
registers[rd] = (registers[rd] - rn) - (1U - carry);
|
||||
|
||||
negative = registers[rd] >> 31;
|
||||
zero = registers[rd] == 0 ? 1U : 0U;
|
||||
this.OverflowCarrySub(orig, rn, registers[rd]);
|
||||
break;
|
||||
|
||||
case OP_TST:
|
||||
alu = registers[rd] & rn;
|
||||
|
||||
negative = alu >> 31;
|
||||
zero = alu == 0 ? 1U : 0U;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("The coder screwed up on the thumb alu op...");
|
||||
}
|
||||
}
|
||||
|
||||
private void OpAddHi()
|
||||
{
|
||||
int rd = ((this.curInstruction & (1 << 7)) >> 4) | (this.curInstruction & 0x7);
|
||||
int rm = (this.curInstruction >> 3) & 0xF;
|
||||
|
||||
registers[rd] += registers[rm];
|
||||
|
||||
if (rd == 15)
|
||||
{
|
||||
registers[rd] &= ~1U;
|
||||
this.FlushQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private void OpCmpHi()
|
||||
{
|
||||
int rd = ((this.curInstruction & (1 << 7)) >> 4) | (this.curInstruction & 0x7);
|
||||
int rm = (this.curInstruction >> 3) & 0xF;
|
||||
|
||||
uint alu = registers[rd] - registers[rm];
|
||||
|
||||
negative = alu >> 31;
|
||||
zero = alu == 0 ? 1U : 0U;
|
||||
this.OverflowCarrySub(registers[rd], registers[rm], alu);
|
||||
}
|
||||
|
||||
private void OpMovHi()
|
||||
{
|
||||
int rd = ((this.curInstruction & (1 << 7)) >> 4) | (this.curInstruction & 0x7);
|
||||
int rm = (this.curInstruction >> 3) & 0xF;
|
||||
|
||||
registers[rd] = registers[rm];
|
||||
|
||||
if (rd == 15)
|
||||
{
|
||||
registers[rd] &= ~1U;
|
||||
this.FlushQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private void OpBx()
|
||||
{
|
||||
int rm = (this.curInstruction >> 3) & 0xf;
|
||||
|
||||
this.PackFlags();
|
||||
|
||||
this.parent.CPSR &= ~Arm7Processor.T_MASK;
|
||||
this.parent.CPSR |= (registers[rm] & 1) << Arm7Processor.T_BIT;
|
||||
|
||||
registers[15] = registers[rm] & (~1U);
|
||||
|
||||
this.UnpackFlags();
|
||||
|
||||
// Check for branch back to Arm Mode
|
||||
if ((this.parent.CPSR & Arm7Processor.T_MASK) != Arm7Processor.T_MASK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.FlushQueue();
|
||||
}
|
||||
|
||||
private void OpLdrPc()
|
||||
{
|
||||
int rd = (this.curInstruction >> 8) & 0x7;
|
||||
|
||||
registers[rd] = this.memory.ReadU32((registers[15] & ~2U) + (uint)((this.curInstruction & 0xFF) * 4));
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpStrReg()
|
||||
{
|
||||
this.memory.WriteU32(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7],
|
||||
registers[this.curInstruction & 0x7]);
|
||||
}
|
||||
|
||||
private void OpStrhReg()
|
||||
{
|
||||
this.memory.WriteU16(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7],
|
||||
(ushort)(registers[this.curInstruction & 0x7] & 0xFFFF));
|
||||
}
|
||||
|
||||
private void OpStrbReg()
|
||||
{
|
||||
this.memory.WriteU8(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7],
|
||||
(byte)(registers[this.curInstruction & 0x7] & 0xFF));
|
||||
}
|
||||
|
||||
private void OpLdrsbReg()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU8(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
|
||||
|
||||
if ((registers[this.curInstruction & 0x7] & (1 << 7)) != 0)
|
||||
{
|
||||
registers[this.curInstruction & 0x7] |= 0xFFFFFF00;
|
||||
}
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpLdrReg()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU32(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpLdrhReg()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU16(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpLdrbReg()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU8(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpLdrshReg()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU16(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
|
||||
|
||||
if ((registers[this.curInstruction & 0x7] & (1 << 15)) != 0)
|
||||
{
|
||||
registers[this.curInstruction & 0x7] |= 0xFFFF0000;
|
||||
}
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpStrImm()
|
||||
{
|
||||
this.memory.WriteU32(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 4),
|
||||
registers[this.curInstruction & 0x7]);
|
||||
}
|
||||
|
||||
private void OpLdrImm()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU32(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 4));
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpStrbImm()
|
||||
{
|
||||
this.memory.WriteU8(registers[(this.curInstruction >> 3) & 0x7] + (uint)((this.curInstruction >> 6) & 0x1F),
|
||||
(byte)(registers[this.curInstruction & 0x7] & 0xFF));
|
||||
}
|
||||
|
||||
private void OpLdrbImm()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU8(registers[(this.curInstruction >> 3) & 0x7] + (uint)((this.curInstruction >> 6) & 0x1F));
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpStrhImm()
|
||||
{
|
||||
this.memory.WriteU16(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 2),
|
||||
(ushort)(registers[this.curInstruction & 0x7] & 0xFFFF));
|
||||
}
|
||||
|
||||
private void OpLdrhImm()
|
||||
{
|
||||
registers[this.curInstruction & 0x7] =
|
||||
this.memory.ReadU16(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 2));
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpStrSp()
|
||||
{
|
||||
this.memory.WriteU32(registers[13] + (uint)((this.curInstruction & 0xFF) * 4),
|
||||
registers[(this.curInstruction >> 8) & 0x7]);
|
||||
}
|
||||
|
||||
private void OpLdrSp()
|
||||
{
|
||||
registers[(this.curInstruction >> 8) & 0x7] =
|
||||
this.memory.ReadU32(registers[13] + (uint)((this.curInstruction & 0xFF) * 4));
|
||||
}
|
||||
|
||||
private void OpAddPc()
|
||||
{
|
||||
registers[(this.curInstruction >> 8) & 0x7] =
|
||||
(registers[15] & ~2U) + (uint)((this.curInstruction & 0xFF) * 4);
|
||||
}
|
||||
|
||||
private void OpAddSp()
|
||||
{
|
||||
registers[(this.curInstruction >> 8) & 0x7] =
|
||||
registers[13] + (uint)((this.curInstruction & 0xFF) * 4);
|
||||
}
|
||||
|
||||
private void OpSubSp()
|
||||
{
|
||||
if ((this.curInstruction & (1 << 7)) != 0)
|
||||
registers[13] -= (uint)((this.curInstruction & 0x7F) * 4);
|
||||
else
|
||||
registers[13] += (uint)((this.curInstruction & 0x7F) * 4);
|
||||
}
|
||||
|
||||
private void OpPush()
|
||||
{
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
if (((this.curInstruction >> i) & 1) != 0)
|
||||
{
|
||||
registers[13] -= 4;
|
||||
this.memory.WriteU32(registers[13], registers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OpPushLr()
|
||||
{
|
||||
registers[13] -= 4;
|
||||
this.memory.WriteU32(registers[13], registers[14]);
|
||||
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
if (((this.curInstruction >> i) & 1) != 0)
|
||||
{
|
||||
registers[13] -= 4;
|
||||
this.memory.WriteU32(registers[13], registers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OpPop()
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (((this.curInstruction >> i) & 1) != 0)
|
||||
{
|
||||
registers[i] = this.memory.ReadU32(registers[13]);
|
||||
registers[13] += 4;
|
||||
}
|
||||
}
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpPopPc()
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (((this.curInstruction >> i) & 1) != 0)
|
||||
{
|
||||
registers[i] = this.memory.ReadU32(registers[13]);
|
||||
registers[13] += 4;
|
||||
}
|
||||
}
|
||||
|
||||
registers[15] = this.memory.ReadU32(registers[13]) & (~1U);
|
||||
registers[13] += 4;
|
||||
|
||||
// ARM9 check here
|
||||
|
||||
this.FlushQueue();
|
||||
|
||||
this.parent.Cycles--;
|
||||
}
|
||||
|
||||
private void OpStmia()
|
||||
{
|
||||
int rn = (this.curInstruction >> 8) & 0x7;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (((this.curInstruction >> i) & 1) != 0)
|
||||
{
|
||||
this.memory.WriteU32(registers[rn] & (~3U), registers[i]);
|
||||
registers[rn] += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OpLdmia()
|
||||
{
|
||||
int rn = (this.curInstruction >> 8) & 0x7;
|
||||
|
||||
uint address = registers[rn];
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (((this.curInstruction >> i) & 1) != 0)
|
||||
{
|
||||
registers[i] = this.memory.ReadU32Aligned(address & (~3U));
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (((this.curInstruction >> rn) & 1) == 0)
|
||||
{
|
||||
registers[rn] = address;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpBCond()
|
||||
{
|
||||
uint cond = 0;
|
||||
switch ((this.curInstruction >> 8) & 0xF)
|
||||
{
|
||||
case COND_AL: cond = 1; break;
|
||||
case COND_EQ: cond = zero; break;
|
||||
case COND_NE: cond = 1 - zero; break;
|
||||
case COND_CS: cond = carry; break;
|
||||
case COND_CC: cond = 1 - carry; break;
|
||||
case COND_MI: cond = negative; break;
|
||||
case COND_PL: cond = 1 - negative; break;
|
||||
case COND_VS: cond = overflow; break;
|
||||
case COND_VC: cond = 1 - overflow; break;
|
||||
case COND_HI: cond = carry & (1 - zero); break;
|
||||
case COND_LS: cond = (1 - carry) | zero; break;
|
||||
case COND_GE: cond = (1 - negative) ^ overflow; break;
|
||||
case COND_LT: cond = negative ^ overflow; break;
|
||||
case COND_GT: cond = (1 - zero) & (negative ^ (1 - overflow)); break;
|
||||
case COND_LE: cond = (negative ^ overflow) | zero; break;
|
||||
}
|
||||
|
||||
if (cond == 1)
|
||||
{
|
||||
uint offset = (uint)(this.curInstruction & 0xFF);
|
||||
if ((offset & (1 << 7)) != 0) offset |= 0xFFFFFF00;
|
||||
|
||||
registers[15] += offset << 1;
|
||||
|
||||
this.FlushQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private void OpSwi()
|
||||
{
|
||||
registers[15] -= 4U;
|
||||
this.parent.EnterException(Arm7Processor.SVC, 0x8, false, false);
|
||||
}
|
||||
|
||||
private void OpB()
|
||||
{
|
||||
uint offset = (uint)(this.curInstruction & 0x7FF);
|
||||
if ((offset & (1 << 10)) != 0) offset |= 0xFFFFF800;
|
||||
|
||||
registers[15] += offset << 1;
|
||||
|
||||
this.FlushQueue();
|
||||
}
|
||||
|
||||
private void OpBl1()
|
||||
{
|
||||
uint offset = (uint)(this.curInstruction & 0x7FF);
|
||||
if ((offset & (1 << 10)) != 0) offset |= 0xFFFFF800;
|
||||
|
||||
registers[14] = registers[15] + (offset << 12);
|
||||
}
|
||||
|
||||
private void OpBl2()
|
||||
{
|
||||
uint tmp = registers[15];
|
||||
registers[15] = registers[14] + (uint)((this.curInstruction & 0x7FF) << 1);
|
||||
registers[14] = (tmp - 2U) | 1;
|
||||
|
||||
this.FlushQueue();
|
||||
}
|
||||
|
||||
private void OpUnd()
|
||||
{
|
||||
throw new Exception("Unknown opcode");
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void PackFlags()
|
||||
{
|
||||
this.parent.CPSR &= 0x0FFFFFFF;
|
||||
this.parent.CPSR |= this.negative << Arm7Processor.N_BIT;
|
||||
this.parent.CPSR |= this.zero << Arm7Processor.Z_BIT;
|
||||
this.parent.CPSR |= this.carry << Arm7Processor.C_BIT;
|
||||
this.parent.CPSR |= this.overflow << Arm7Processor.V_BIT;
|
||||
}
|
||||
|
||||
private void UnpackFlags()
|
||||
{
|
||||
this.negative = (this.parent.CPSR >> Arm7Processor.N_BIT) & 1;
|
||||
this.zero = (this.parent.CPSR >> Arm7Processor.Z_BIT) & 1;
|
||||
this.carry = (this.parent.CPSR >> Arm7Processor.C_BIT) & 1;
|
||||
this.overflow = (this.parent.CPSR >> Arm7Processor.V_BIT) & 1;
|
||||
}
|
||||
|
||||
private void FlushQueue()
|
||||
{
|
||||
this.instructionQueue = this.memory.ReadU16(registers[15]);
|
||||
registers[15] += 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
namespace GarboDev
|
||||
{
|
||||
public class VideoManager
|
||||
{
|
||||
public delegate void OnPresent(uint[] data);
|
||||
|
||||
private Memory memory = null;
|
||||
private IRenderer renderer = null;
|
||||
private OnPresent presenter;
|
||||
private GbaManager gbaManager;
|
||||
private int curLine;
|
||||
|
||||
public Memory Memory
|
||||
{
|
||||
set{ this.memory = value; }
|
||||
}
|
||||
|
||||
public IRenderer Renderer
|
||||
{
|
||||
set
|
||||
{
|
||||
this.renderer = value;
|
||||
this.renderer.Memory = this.memory;
|
||||
}
|
||||
}
|
||||
|
||||
public OnPresent Presenter
|
||||
{
|
||||
set { this.presenter = value; }
|
||||
}
|
||||
|
||||
public VideoManager(GbaManager gbaManager)
|
||||
{
|
||||
this.gbaManager = gbaManager;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.curLine = 0;
|
||||
|
||||
this.renderer.Memory = memory;
|
||||
this.renderer.Reset();
|
||||
}
|
||||
|
||||
private void EnterVBlank(Arm7Processor processor)
|
||||
{
|
||||
ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
|
||||
dispstat |= 1;
|
||||
Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
|
||||
|
||||
// Render the frame
|
||||
this.gbaManager.FramesRendered++;
|
||||
this.presenter(this.renderer.ShowFrame());
|
||||
|
||||
if ((dispstat & (1 << 3)) != 0)
|
||||
{
|
||||
// Fire the vblank irq
|
||||
processor.RequestIrq(0);
|
||||
}
|
||||
|
||||
// Check for DMA triggers
|
||||
this.memory.VBlankDma();
|
||||
}
|
||||
|
||||
private void LeaveVBlank(Arm7Processor processor)
|
||||
{
|
||||
ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
|
||||
dispstat &= 0xFFFE;
|
||||
Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
|
||||
|
||||
processor.UpdateKeyState();
|
||||
|
||||
// Update the rot/scale values
|
||||
this.memory.Bgx[0] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG2X_L);
|
||||
this.memory.Bgx[1] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG3X_L);
|
||||
this.memory.Bgy[0] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG2Y_L);
|
||||
this.memory.Bgy[1] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG3Y_L);
|
||||
}
|
||||
|
||||
public void EnterHBlank(Arm7Processor processor)
|
||||
{
|
||||
ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
|
||||
dispstat |= 1 << 1;
|
||||
Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
|
||||
|
||||
// Advance the bgx registers
|
||||
for (int bg = 0; bg <= 1; bg++)
|
||||
{
|
||||
short dmx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PB + (uint)bg * 0x10);
|
||||
short dmy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PD + (uint)bg * 0x10);
|
||||
this.memory.Bgx[bg] += dmx;
|
||||
this.memory.Bgy[bg] += dmy;
|
||||
}
|
||||
|
||||
if (this.curLine < 160)
|
||||
{
|
||||
this.memory.HBlankDma();
|
||||
|
||||
// Trigger hblank irq
|
||||
if ((dispstat & (1 << 4)) != 0)
|
||||
{
|
||||
processor.RequestIrq(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <returns>true if end of frame</returns>
|
||||
public bool LeaveHBlank(Arm7Processor processor)
|
||||
{
|
||||
bool ret = false;
|
||||
ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
|
||||
dispstat &= 0xFFF9;
|
||||
Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
|
||||
|
||||
// Move to the next line
|
||||
this.curLine++;
|
||||
|
||||
if (this.curLine >= 228)
|
||||
{
|
||||
// Start again at the beginning
|
||||
this.curLine = 0;
|
||||
}
|
||||
|
||||
// Update registers
|
||||
Memory.WriteU16(this.memory.IORam, Memory.VCOUNT, (ushort)this.curLine);
|
||||
|
||||
// Check for vblank
|
||||
if (this.curLine == 160)
|
||||
{
|
||||
this.EnterVBlank(processor);
|
||||
ret = true;
|
||||
}
|
||||
else if (this.curLine == 0)
|
||||
{
|
||||
this.LeaveVBlank(processor);
|
||||
}
|
||||
|
||||
// Check y-line trigger
|
||||
if (((dispstat >> 8) & 0xff) == this.curLine)
|
||||
{
|
||||
dispstat = (ushort)(Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT) | (1 << 2));
|
||||
Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
|
||||
|
||||
if ((dispstat & (1 << 5)) != 0)
|
||||
{
|
||||
processor.RequestIrq(2);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void RenderLine()
|
||||
{
|
||||
if (this.curLine < 160)
|
||||
{
|
||||
this.renderer.RenderLine(this.curLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
garbodev with a quick iemulator binding. license uncertain.
|
||||
|
||||
basic functionality works (gets ingame on a number of commercial titles).
|
||||
|
||||
no GB classic sound channels.
|
||||
no savestates.
|
||||
lots of things not hooked up (saveram, etc)
|
|
@ -1,110 +0,0 @@
|
|||
# this was modified at one point so that it would compile in our bizhawk project, but isn't in
|
||||
# use at the moment. tread carefully
|
||||
|
||||
ifeq ($(platform),)
|
||||
platform = unix
|
||||
ifeq ($(shell uname -a),)
|
||||
platform = win
|
||||
else ifneq ($(findstring MINGW,$(shell uname -a)),)
|
||||
platform = win
|
||||
else ifneq ($(findstring Darwin,$(shell uname -a)),)
|
||||
platform = osx
|
||||
else ifneq ($(findstring win,$(shell uname -a)),)
|
||||
platform = win
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(platform), unix)
|
||||
TARGET := libmeteor.so
|
||||
fpic := -fPIC
|
||||
SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined
|
||||
else ifeq ($(platform), osx)
|
||||
TARGET := libmeteor.dylib
|
||||
fpic := -fPIC
|
||||
SHARED := -dynamiclib
|
||||
else
|
||||
TARGET := libmeteor.dll
|
||||
CXX = g++
|
||||
# SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined
|
||||
SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--no-undefined
|
||||
CXXFLAGS += -DNO_MEMMEM
|
||||
endif
|
||||
|
||||
#__LIBRETRO__ enables a slightly different saveram mechanism that doesn't seem to serve any useful purpose?
|
||||
#CXXFLAGS += -Wall -pedantic -I. -I../ameteor/include -pipe -D__LIBRETRO__ -Wno-parentheses -fno-exceptions -fno-rtti
|
||||
CXXFLAGS += -Wall -pedantic -I. -Iinclude -pipe -DX86_ASM -Wno-parentheses -fno-exceptions -fno-rtti
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
CXXFLAGS += -O0 -g
|
||||
else
|
||||
CFLAGS += -O3
|
||||
CXXFLAGS += -O3
|
||||
endif
|
||||
|
||||
#SRCDIR := ../ameteor/source
|
||||
SRCDIR := ./source
|
||||
|
||||
SOURCES := \
|
||||
$(SRCDIR)/audio/dsound.cpp \
|
||||
$(SRCDIR)/audio/sound1.cpp \
|
||||
$(SRCDIR)/audio/sound2.cpp \
|
||||
$(SRCDIR)/audio/sound4.cpp \
|
||||
$(SRCDIR)/audio/speaker.cpp \
|
||||
$(SRCDIR)/disassembler/argimmediate.cpp \
|
||||
$(SRCDIR)/disassembler/argmulregisters.cpp \
|
||||
$(SRCDIR)/disassembler/argpsr.cpp \
|
||||
$(SRCDIR)/disassembler/argregister.cpp \
|
||||
$(SRCDIR)/disassembler/argrelative.cpp \
|
||||
$(SRCDIR)/disassembler/argshift.cpp \
|
||||
$(SRCDIR)/disassembler/arguimmediate.cpp \
|
||||
$(SRCDIR)/disassembler/arguments.cpp \
|
||||
$(SRCDIR)/disassembler/instruction.cpp \
|
||||
$(SRCDIR)/graphics/bglayer.cpp \
|
||||
$(SRCDIR)/graphics/object.cpp \
|
||||
$(SRCDIR)/graphics/objects.cpp \
|
||||
$(SRCDIR)/graphics/renderer.cpp \
|
||||
$(SRCDIR)/graphics/screen.cpp \
|
||||
$(SRCDIR)/ameteor.cpp \
|
||||
$(SRCDIR)/bios.cpp \
|
||||
$(SRCDIR)/clock.cpp \
|
||||
$(SRCDIR)/cpu.cpp \
|
||||
$(SRCDIR)/debug.cpp \
|
||||
$(SRCDIR)/dma.cpp \
|
||||
$(SRCDIR)/eeprom.cpp \
|
||||
$(SRCDIR)/flash.cpp \
|
||||
$(SRCDIR)/cartmem.cpp \
|
||||
$(SRCDIR)/interpreter.cpp \
|
||||
$(SRCDIR)/interpreter_arm.cpp \
|
||||
$(SRCDIR)/interpreter_thumb.cpp \
|
||||
$(SRCDIR)/io.cpp \
|
||||
$(SRCDIR)/keypad.cpp \
|
||||
$(SRCDIR)/lcd.cpp \
|
||||
$(SRCDIR)/memory.cpp \
|
||||
$(SRCDIR)/sound.cpp \
|
||||
$(SRCDIR)/sram.cpp \
|
||||
$(SRCDIR)/timer.cpp \
|
||||
cinterface.cpp
|
||||
# video.cpp \
|
||||
# audio.cpp \
|
||||
# input.cpp \
|
||||
# libretro.cpp
|
||||
|
||||
OBJ := $(SOURCES:.cpp=.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
@$(CXX) -o $@ $^ $(SHARED) $(LDFLAGS) $(LIBS)
|
||||
@echo LD $(notdir $@)
|
||||
|
||||
%.o: %.cpp
|
||||
@$(CXX) -o $@ -c $< $(CXXFLAGS) $(fpic)
|
||||
@echo CXX $(notdir $<)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
rm -f $(OBJ)
|
||||
|
||||
.PHONY: clean
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
#include "ameteor.hpp"
|
||||
#include "ameteor/cartmem.hpp"
|
||||
#include "source/debug.hpp"
|
||||
#include <sstream>
|
||||
|
||||
#define EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
void (*messagecallback)(const char *msg, int abort) = NULL;
|
||||
|
||||
EXPORT void libmeteor_setmessagecallback(void (*callback)(const char *msg, int abort))
|
||||
{
|
||||
messagecallback = callback;
|
||||
print_bizhawk("libmeteor message stream operational.");
|
||||
}
|
||||
|
||||
void print_bizhawk(const char *msg)
|
||||
{
|
||||
if (messagecallback)
|
||||
messagecallback(msg, 0);
|
||||
}
|
||||
void print_bizhawk(std::string &msg)
|
||||
{
|
||||
if (messagecallback)
|
||||
messagecallback(msg.c_str(), 0);
|
||||
}
|
||||
void abort_bizhawk(const char *msg)
|
||||
{
|
||||
if (messagecallback)
|
||||
messagecallback(msg, 1);
|
||||
AMeteor::Stop(); // makes it easy to pick apart what happened
|
||||
}
|
||||
|
||||
uint16_t (*keycallback)() = NULL;
|
||||
|
||||
void keyupdate_bizhawk()
|
||||
{
|
||||
if (keycallback)
|
||||
AMeteor::_keypad.SetPadState(keycallback() ^ 0x3FF);
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_setkeycallback(uint16_t (*callback)())
|
||||
{
|
||||
keycallback = callback;
|
||||
}
|
||||
|
||||
bool traceenabled = false;
|
||||
void (*tracecallback)(const char *msg) = NULL;
|
||||
|
||||
EXPORT void libmeteor_settracecallback(void (*callback)(const char*msg))
|
||||
{
|
||||
tracecallback = callback;
|
||||
traceenabled = tracecallback != NULL;
|
||||
}
|
||||
|
||||
void trace_bizhawk(std::string msg)
|
||||
{
|
||||
if (tracecallback)
|
||||
tracecallback(msg.c_str());
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_hardreset()
|
||||
{
|
||||
AMeteor::Reset(AMeteor::UNIT_ALL ^ (AMeteor::UNIT_MEMORY_BIOS | AMeteor::UNIT_MEMORY_ROM));
|
||||
}
|
||||
|
||||
uint32_t *videobuff;
|
||||
|
||||
void videocb(const uint16_t *frame)
|
||||
{
|
||||
uint32_t *dest = videobuff;
|
||||
const uint16_t *src = frame;
|
||||
for (int i = 0; i < 240 * 160; i++, src++, dest++)
|
||||
{
|
||||
uint16_t c = *src;
|
||||
uint16_t b = c >> 10 & 31;
|
||||
uint16_t g = c >> 5 & 31;
|
||||
uint16_t r = c & 31;
|
||||
b = b << 3 | b >> 2;
|
||||
g = g << 3 | g >> 2;
|
||||
r = r << 3 | r >> 2;
|
||||
*dest = b | g << 8 | r << 16 | 0xff000000;
|
||||
}
|
||||
AMeteor::Stop(); // to the end of frame only
|
||||
}
|
||||
|
||||
int16_t *soundbuff;
|
||||
int16_t *soundbuffcur;
|
||||
int16_t *soundbuffend;
|
||||
|
||||
void soundcb(const int16_t *samples)
|
||||
{
|
||||
if (soundbuffcur < soundbuffend)
|
||||
{
|
||||
*soundbuffcur++ = *samples++;
|
||||
*soundbuffcur++ = *samples++;
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT unsigned libmeteor_emptysound()
|
||||
{
|
||||
unsigned ret = (soundbuffcur - soundbuff) * sizeof(int16_t);
|
||||
soundbuffcur = soundbuff;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT int libmeteor_setbuffers(uint32_t *vid, unsigned vidlen, int16_t *aud, unsigned audlen)
|
||||
{
|
||||
if (vidlen < 240 * 160 * sizeof(uint32_t))
|
||||
return 0;
|
||||
if (audlen < 4 || audlen % 4 != 0)
|
||||
return 0;
|
||||
videobuff = vid;
|
||||
soundbuff = aud;
|
||||
soundbuffend = soundbuff + audlen / sizeof(int16_t);
|
||||
libmeteor_emptysound();
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_init()
|
||||
{
|
||||
static bool first = true;
|
||||
if (first)
|
||||
{
|
||||
AMeteor::_lcd.GetScreen().GetRenderer().SetFrameSlot(syg::ptr_fun(videocb));
|
||||
AMeteor::_sound.GetSpeaker().SetFrameSlot(syg::ptr_fun(soundcb));
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_frameadvance()
|
||||
{
|
||||
AMeteor::Run(10000000);
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_loadrom(const void *data, unsigned size)
|
||||
{
|
||||
AMeteor::_memory.LoadRom((const uint8_t*)data, size);
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_loadbios(const void *data, unsigned size)
|
||||
{
|
||||
AMeteor::_memory.LoadBios((const uint8_t*)data, size);
|
||||
}
|
||||
|
||||
EXPORT uint8_t *libmeteor_getmemoryarea(int which)
|
||||
{
|
||||
if (which < 7)
|
||||
return AMeteor::_memory.GetMemoryArea(which);
|
||||
else if (which == 7)
|
||||
return AMeteor::_io.GetIoPointer();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT int libmeteor_loadsaveram(const void *data, unsigned size)
|
||||
{
|
||||
return AMeteor::_memory.LoadCart((const uint8_t*)data, size);
|
||||
}
|
||||
|
||||
EXPORT int libmeteor_savesaveram(void **data, unsigned *size)
|
||||
{
|
||||
return AMeteor::_memory.SaveCart((uint8_t **)data, size);
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_savesaveram_destroy(void *data)
|
||||
{
|
||||
AMeteor::_memory.SaveCartDestroy((uint8_t *)data);
|
||||
}
|
||||
|
||||
EXPORT int libmeteor_hassaveram()
|
||||
{
|
||||
return AMeteor::_memory.HasCart();
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_clearsaveram()
|
||||
{
|
||||
AMeteor::_memory.DeleteCart();
|
||||
}
|
||||
|
||||
EXPORT int libmeteor_savestate(void **data, unsigned *size)
|
||||
{
|
||||
if (!data || !size)
|
||||
return 0;
|
||||
|
||||
std::ostringstream ss = std::ostringstream(std::ios_base::binary);
|
||||
AMeteor::SaveState(ss);
|
||||
|
||||
std::string s = ss.str();
|
||||
|
||||
void *ret = std::malloc(s.size());
|
||||
if (!ret)
|
||||
return 0;
|
||||
std::memcpy(ret, s.data(), s.size());
|
||||
*data = ret;
|
||||
*size = s.size();
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_savestate_destroy(void *data)
|
||||
{
|
||||
std::free(data);
|
||||
}
|
||||
|
||||
EXPORT int libmeteor_loadstate(const void *data, unsigned size)
|
||||
{
|
||||
std::istringstream ss = std::istringstream(std::string((const char*)data, size), std::ios_base::binary);
|
||||
return AMeteor::LoadState(ss);
|
||||
}
|
||||
|
||||
// TODO: cartram memory domain, cartram in system bus memory domain
|
||||
EXPORT uint8_t libmeteor_peekbus(uint32_t addr)
|
||||
{
|
||||
return AMeteor::_memory.Peek8(addr);
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_writebus(uint32_t addr, uint8_t val)
|
||||
{
|
||||
AMeteor::_memory.Write8(addr, val);
|
||||
}
|
||||
|
||||
int slcallbackline = 400;
|
||||
void (*slcallback)() = NULL;
|
||||
|
||||
EXPORT void libmeteor_setscanlinecallback(void (*callback)(), int scanline)
|
||||
{
|
||||
if (!callback)
|
||||
slcallbackline = 400;
|
||||
else
|
||||
slcallbackline = scanline;
|
||||
slcallback = callback;
|
||||
}
|
||||
|
||||
void scanlinecallback_bizhawk()
|
||||
{
|
||||
if (slcallback)
|
||||
slcallback();
|
||||
}
|
||||
|
||||
EXPORT void libmeteor_getregs(int *dest)
|
||||
{
|
||||
AMeteor::_cpu.UpdateCpsr();
|
||||
for (int i = 0; i < 16; i++)
|
||||
dest[i] = AMeteor::_cpu.Reg(i);
|
||||
dest[16] = AMeteor::_cpu.Cpsr().dw;
|
||||
dest[17] = AMeteor::_cpu.Spsr().dw;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __AMETEOR_H__
|
||||
#define __AMETEOR_H__
|
||||
|
||||
#include "ameteor/memory.hpp"
|
||||
#include "ameteor/io.hpp"
|
||||
#include "ameteor/dma.hpp"
|
||||
#include "ameteor/interpreter.hpp"
|
||||
#include "ameteor/lcd.hpp"
|
||||
#include "ameteor/clock.hpp"
|
||||
#include "ameteor/timer.hpp"
|
||||
#include "ameteor/sound.hpp"
|
||||
#include "ameteor/keypad.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
extern Clock _clock;
|
||||
extern Io _io;
|
||||
extern Interpreter _cpu;
|
||||
extern Memory _memory;
|
||||
extern Dma _dma;
|
||||
extern Lcd _lcd;
|
||||
extern Sound _sound;
|
||||
extern Keypad _keypad;
|
||||
extern Timer _timer0;
|
||||
extern Timer _timer1;
|
||||
extern Timer _timer2;
|
||||
extern Timer _timer3;
|
||||
|
||||
const uint32_t UNIT_CLOCK = 0x0001;
|
||||
const uint32_t UNIT_IO = 0x0002;
|
||||
const uint32_t UNIT_CPU = 0x0004;
|
||||
const uint32_t UNIT_MEMORY = 0x0008;
|
||||
const uint32_t UNIT_DMA = 0x0010;
|
||||
const uint32_t UNIT_LCD = 0x0020;
|
||||
const uint32_t UNIT_SOUND = 0x0040;
|
||||
const uint32_t UNIT_KEYPAD = 0x0080;
|
||||
const uint32_t UNIT_TIMER0 = 0x0100;
|
||||
const uint32_t UNIT_TIMER1 = 0x0200;
|
||||
const uint32_t UNIT_TIMER2 = 0x0400;
|
||||
const uint32_t UNIT_TIMER3 = 0x0800;
|
||||
const uint32_t UNIT_MEMORY_ROM = 0x1000;
|
||||
const uint32_t UNIT_MEMORY_BIOS = 0x2000;
|
||||
const uint32_t UNIT_ALL = 0x3FFF;
|
||||
|
||||
void Reset (uint32_t units);
|
||||
|
||||
bool SaveState (const char* filename);
|
||||
bool LoadState (const char* filename);
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
inline void Run (unsigned int cycles)
|
||||
{
|
||||
_cpu.Run(cycles);
|
||||
}
|
||||
|
||||
inline void Stop ()
|
||||
{
|
||||
_cpu.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,78 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __AUDIO_D_SOUND_H__
|
||||
#define __AUDIO_D_SOUND_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
class DSound
|
||||
{
|
||||
public :
|
||||
static const int BUFFER_SIZE = 32;
|
||||
|
||||
DSound ();
|
||||
|
||||
void FillFifo (int8_t* buffer);
|
||||
void FillFifo (int8_t sample);
|
||||
|
||||
void NextSample ()
|
||||
{
|
||||
// if the buffer is empty, there is nothing to do
|
||||
if (m_size)
|
||||
// if this was the last sample, we reset all and send 0 to all next
|
||||
// GetSample()s until the buffer is refilled
|
||||
if (--m_size == 0)
|
||||
Reset();
|
||||
// else, we go on to next sample and we go to the first if we got
|
||||
// to the last
|
||||
else if (++m_rpos >= BUFFER_SIZE)
|
||||
m_rpos = 0;
|
||||
}
|
||||
|
||||
void Reset ()
|
||||
{
|
||||
m_buffer[0] = m_size = m_rpos = m_wpos = 0;
|
||||
}
|
||||
|
||||
int8_t GetSample()
|
||||
{
|
||||
return m_buffer[m_rpos];
|
||||
}
|
||||
|
||||
uint8_t GetSize ()
|
||||
{
|
||||
return m_size;
|
||||
};
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
int8_t m_buffer[BUFFER_SIZE];
|
||||
uint8_t m_rpos, m_wpos;
|
||||
uint8_t m_size;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __AUDIO_SOUND_1_H__
|
||||
#define __AUDIO_SOUND_1_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
class Sound1
|
||||
{
|
||||
public :
|
||||
Sound1 (uint16_t& cntl, uint16_t& cnth, uint16_t& cntx,
|
||||
uint16_t freq);
|
||||
|
||||
void Reset ();
|
||||
|
||||
// call this at the frequence given in constructor
|
||||
void SoundTick ();
|
||||
|
||||
void ResetSound ();
|
||||
void ResetEnvelope ()
|
||||
{
|
||||
m_envelope = 0;
|
||||
}
|
||||
|
||||
int8_t GetSample () const
|
||||
{
|
||||
return m_sample;
|
||||
}
|
||||
|
||||
bool IsOn () const
|
||||
{
|
||||
return m_on;
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
uint16_t &m_cntl, &m_cnth, &m_cntx;
|
||||
bool m_on;
|
||||
// positions in Period, Sweep time and Envelope step time
|
||||
uint32_t m_posP, m_posS, m_posE;
|
||||
int8_t m_sample;
|
||||
// sample period in cycles
|
||||
uint16_t m_speriod;
|
||||
// envelope level
|
||||
uint8_t m_envelope;
|
||||
// sound length in cycles
|
||||
uint32_t m_length;
|
||||
bool m_timed;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,70 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __AUDIO_SOUND_2_H__
|
||||
#define __AUDIO_SOUND_2_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
class Sound2
|
||||
{
|
||||
public :
|
||||
Sound2 (uint16_t& cntl, uint16_t& cnth, uint16_t freq);
|
||||
|
||||
void Reset ();
|
||||
|
||||
// call this at the frequence given in constructor
|
||||
void SoundTick ();
|
||||
|
||||
void ResetSound ();
|
||||
void ResetEnvelope ()
|
||||
{
|
||||
m_envelope = 0;
|
||||
}
|
||||
|
||||
int8_t GetSample () const
|
||||
{
|
||||
return m_sample;
|
||||
}
|
||||
|
||||
bool IsOn () const
|
||||
{
|
||||
return m_on;
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
uint16_t &m_cntl, &m_cnth;
|
||||
bool m_on;
|
||||
uint32_t m_posP, m_posE;
|
||||
int8_t m_sample;
|
||||
uint16_t m_speriod;
|
||||
uint8_t m_envelope;
|
||||
uint32_t m_length;
|
||||
bool m_timed;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,78 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __AUDIO_SOUND_4_H__
|
||||
#define __AUDIO_SOUND_4_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
void InitNoise ();
|
||||
|
||||
class Sound4
|
||||
{
|
||||
public :
|
||||
Sound4 (uint16_t& cntl, uint16_t& cnth, uint16_t freq);
|
||||
|
||||
void Reset ();
|
||||
|
||||
// call this at the frequence given in constructor
|
||||
void SoundTick ();
|
||||
|
||||
void ResetSound ();
|
||||
void ResetEnvelope ()
|
||||
{
|
||||
m_envelope = 0;
|
||||
}
|
||||
|
||||
int8_t GetSample () const
|
||||
{
|
||||
return m_sample;
|
||||
}
|
||||
|
||||
bool IsOn () const
|
||||
{
|
||||
return m_on;
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
uint16_t &m_cntl, &m_cnth;
|
||||
bool m_on;
|
||||
// positions in Period, position in noise and Envelope step time
|
||||
uint32_t m_posP, m_posN, m_posE;
|
||||
int8_t m_sample;
|
||||
// sample period in cycles
|
||||
uint16_t m_speriod;
|
||||
// envelope level
|
||||
uint8_t m_envelope;
|
||||
// sound length in cycles
|
||||
uint32_t m_length;
|
||||
bool m_timed;
|
||||
// clock divider
|
||||
uint8_t m_div;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,173 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __AUDIO_SPEAKER_H__
|
||||
#define __AUDIO_SPEAKER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <syg/signal.hpp>
|
||||
#include "sound1.hpp"
|
||||
#include "sound2.hpp"
|
||||
#include "sound4.hpp"
|
||||
#include "dsound.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
class Speaker
|
||||
{
|
||||
public :
|
||||
typedef syg::slot1<void, const int16_t*> FrameSlot;
|
||||
|
||||
Speaker (uint16_t& cnt1l, uint16_t& cnt1h, uint16_t& cnt1x,
|
||||
uint16_t& cnt2l, uint16_t& cnt2h,
|
||||
uint16_t& cnt4l, uint16_t& cnt4h,
|
||||
uint16_t& cntl, uint16_t& cnth, uint16_t& cntx, uint16_t& bias);
|
||||
~Speaker ();
|
||||
|
||||
inline void SetFrameSlot (const FrameSlot& slot);
|
||||
|
||||
void Reset ();
|
||||
|
||||
inline void ResetSound1 ();
|
||||
inline void ResetSound2 ();
|
||||
inline void ResetSound4 ();
|
||||
inline void ResetSound1Envelope ();
|
||||
inline void ResetSound2Envelope ();
|
||||
inline void ResetSound4Envelope ();
|
||||
|
||||
inline void FillFifoA (int8_t* buffer);
|
||||
inline void FillFifoB (int8_t* buffer);
|
||||
inline void FillFifoA (int8_t sample);
|
||||
inline void FillFifoB (int8_t sample);
|
||||
|
||||
inline void ResetFifoA ();
|
||||
inline void ResetFifoB ();
|
||||
|
||||
inline void NextSampleA ();
|
||||
inline void NextSampleB ();
|
||||
|
||||
inline uint8_t GetSizeA();
|
||||
inline uint8_t GetSizeB();
|
||||
|
||||
void SoundTick ();
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
Sound1 m_sound1;
|
||||
Sound2 m_sound2;
|
||||
Sound4 m_sound4;
|
||||
DSound m_dsa, m_dsb;
|
||||
uint16_t &m_cntl, &m_cnth, &m_cntx, &m_bias;
|
||||
|
||||
FrameSlot m_sig_frame;
|
||||
|
||||
int16_t MixSample (uint16_t cntl, uint8_t cnth);
|
||||
};
|
||||
|
||||
inline void Speaker::SetFrameSlot (const FrameSlot& slot)
|
||||
{
|
||||
m_sig_frame = slot;
|
||||
}
|
||||
|
||||
inline void Speaker::ResetSound1 ()
|
||||
{
|
||||
m_sound1.ResetSound ();
|
||||
}
|
||||
|
||||
inline void Speaker::ResetSound2 ()
|
||||
{
|
||||
m_sound2.ResetSound ();
|
||||
}
|
||||
|
||||
inline void Speaker::ResetSound4 ()
|
||||
{
|
||||
m_sound4.ResetSound ();
|
||||
}
|
||||
|
||||
inline void Speaker::ResetSound1Envelope ()
|
||||
{
|
||||
m_sound1.ResetEnvelope();
|
||||
}
|
||||
|
||||
inline void Speaker::ResetSound2Envelope ()
|
||||
{
|
||||
m_sound2.ResetEnvelope();
|
||||
}
|
||||
|
||||
inline void Speaker::ResetSound4Envelope ()
|
||||
{
|
||||
m_sound4.ResetEnvelope();
|
||||
}
|
||||
|
||||
inline void Speaker::FillFifoA (int8_t* buffer)
|
||||
{
|
||||
m_dsa.FillFifo(buffer);
|
||||
}
|
||||
|
||||
inline void Speaker::FillFifoB (int8_t* buffer)
|
||||
{
|
||||
m_dsb.FillFifo(buffer);
|
||||
}
|
||||
|
||||
inline void Speaker::FillFifoA (int8_t sample)
|
||||
{
|
||||
m_dsa.FillFifo(sample);
|
||||
}
|
||||
|
||||
inline void Speaker::FillFifoB (int8_t sample)
|
||||
{
|
||||
m_dsb.FillFifo(sample);
|
||||
}
|
||||
|
||||
inline void Speaker::ResetFifoA ()
|
||||
{
|
||||
m_dsa.Reset();
|
||||
}
|
||||
|
||||
inline void Speaker::ResetFifoB ()
|
||||
{
|
||||
m_dsb.Reset();
|
||||
}
|
||||
|
||||
inline void Speaker::NextSampleA ()
|
||||
{
|
||||
m_dsa.NextSample();
|
||||
}
|
||||
|
||||
inline void Speaker::NextSampleB ()
|
||||
{
|
||||
m_dsb.NextSample();
|
||||
}
|
||||
|
||||
inline uint8_t Speaker::GetSizeA()
|
||||
{
|
||||
return m_dsa.GetSize();
|
||||
}
|
||||
|
||||
inline uint8_t Speaker::GetSizeB()
|
||||
{
|
||||
return m_dsb.GetSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,59 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __BIOS_H__
|
||||
#define __BIOS_H__
|
||||
|
||||
#include "ameteor.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Bios
|
||||
{
|
||||
// Entry point
|
||||
void Bios000h ();
|
||||
// Software IRQ
|
||||
void Bios008h ();
|
||||
void Bios168h ();
|
||||
// Return from IntrWait (after the IRQ)
|
||||
void Bios338h ();
|
||||
// IRQ
|
||||
void Bios018h ();
|
||||
void Bios130h ();
|
||||
|
||||
void SoftReset (); // 00
|
||||
void RegisterRamReset (); // 01
|
||||
void Halt (); // 02
|
||||
void IntrWait (); // 04
|
||||
void VBlankIntrWait (); // 05
|
||||
void Div (); // 06
|
||||
void DivArm (); // 07
|
||||
void Sqrt (); // 08
|
||||
void ArcTan (); // 09
|
||||
void ArcTan2 (); // 0A
|
||||
void CpuSet (); // 0B
|
||||
void CpuFastSet (); // 0C
|
||||
void BgAffineSet (); // 0E
|
||||
void ObjAffineSet (); // 0F
|
||||
void LZ77UnCompWram (); // 11
|
||||
void LZ77UnCompVram (); // 12
|
||||
void HuffUnComp (); // 13
|
||||
void RLUnCompWram (); // 14
|
||||
void RLUnCompVram (); // 15
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,57 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __CART_MEM_H__
|
||||
#define __CART_MEM_H__
|
||||
|
||||
#include <fstream>
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class CartMem
|
||||
{
|
||||
public:
|
||||
static const unsigned int MAX_SIZE = 0x20000;
|
||||
|
||||
CartMem();
|
||||
virtual ~CartMem();
|
||||
|
||||
virtual void Reset () = 0;
|
||||
|
||||
virtual bool Load (std::istream& stream) = 0;
|
||||
virtual bool Save (std::ostream& stream) = 0;
|
||||
|
||||
virtual uint8_t Read (uint16_t add) = 0;
|
||||
// returns true if memory has been updated
|
||||
virtual bool Write (uint16_t add, uint8_t val) = 0;
|
||||
|
||||
virtual bool SaveState (std::ostream& stream);
|
||||
virtual bool LoadState (std::istream& stream);
|
||||
|
||||
protected:
|
||||
uint8_t* m_data;
|
||||
uint32_t m_size;
|
||||
};
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
extern uint8_t CartMemData[CartMem::MAX_SIZE+4];
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,111 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __CLOCK_H__
|
||||
#define __CLOCK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Clock
|
||||
{
|
||||
public :
|
||||
Clock ()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset ();
|
||||
|
||||
void ResetCounter()
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
unsigned int GetCounter() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
void TimePass (unsigned short cycles)
|
||||
{
|
||||
m_cycles += cycles;
|
||||
}
|
||||
void Commit ();
|
||||
void WaitForNext ();
|
||||
|
||||
void AddLcd (uint32_t cycles)
|
||||
{
|
||||
// The lcd clock is always enabled
|
||||
m_lcd += cycles;
|
||||
SetFirst();
|
||||
}
|
||||
|
||||
void AddTimer (uint8_t num, uint32_t cycles)
|
||||
{
|
||||
if (m_timer[num] == INT_MAX)
|
||||
m_timer[num] = cycles;
|
||||
else
|
||||
m_timer[num] += cycles;
|
||||
SetFirst();
|
||||
}
|
||||
void SetTimer (uint8_t num, uint32_t cycles)
|
||||
{
|
||||
m_timer[num] = cycles;
|
||||
SetFirst();
|
||||
}
|
||||
void DisableTimer (uint8_t num)
|
||||
{
|
||||
m_timer[num] = INT_MAX;
|
||||
SetFirst();
|
||||
}
|
||||
int GetTimer (uint8_t num)
|
||||
{
|
||||
return m_timer[num];
|
||||
}
|
||||
|
||||
//void SetBattery (uint32_t cycles)
|
||||
//{
|
||||
// m_battery = cycles;
|
||||
//}
|
||||
//void DisableBattery ()
|
||||
//{
|
||||
// m_battery = INT_MAX;
|
||||
// no need to SetFirst since battery will be disabled only in TimeEvent
|
||||
//}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
// XXX freq
|
||||
static const int SOUND_PERIOD = 380;
|
||||
|
||||
unsigned short m_cycles;
|
||||
unsigned short m_first;
|
||||
int m_lcd, m_timer[4], m_sound;//, m_battery;
|
||||
|
||||
unsigned int m_count;
|
||||
|
||||
void SetFirst ();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,148 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __CPU_H__
|
||||
#define __CPU_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Cpu
|
||||
{
|
||||
public :
|
||||
union Psr
|
||||
{
|
||||
uint32_t dw;
|
||||
struct
|
||||
{
|
||||
unsigned int mode : 5;
|
||||
unsigned int thumb : 1;
|
||||
unsigned int fiq_d : 1;
|
||||
unsigned int irq_d : 1;
|
||||
unsigned int reserved : 19;
|
||||
unsigned int s_overflow : 1;
|
||||
unsigned int f_overflow : 1;
|
||||
unsigned int f_carry : 1;
|
||||
unsigned int f_zero : 1;
|
||||
unsigned int f_sign : 1;
|
||||
} b;
|
||||
};
|
||||
struct IPsr
|
||||
{
|
||||
uint8_t mode;
|
||||
bool thumb;
|
||||
bool fiq_d;
|
||||
bool irq_d;
|
||||
bool s_overflow;
|
||||
bool f_overflow;
|
||||
bool f_carry;
|
||||
bool f_zero;
|
||||
bool f_sign;
|
||||
};
|
||||
enum Modes
|
||||
{
|
||||
M_USR = 0x10,
|
||||
M_FIQ = 0x11,
|
||||
M_IRQ = 0x12,
|
||||
M_SVC = 0x13,
|
||||
M_ABT = 0x17,
|
||||
M_UND = 0x1B,
|
||||
M_SYS = 0x1F
|
||||
};
|
||||
|
||||
Cpu ();
|
||||
virtual ~Cpu () {}
|
||||
|
||||
virtual void Reset ();
|
||||
virtual void SoftReset ();
|
||||
|
||||
void UpdateICpsr ();
|
||||
void UpdateCpsr ();
|
||||
void SwitchToMode (uint8_t newmode);
|
||||
void SwitchModeBack ();
|
||||
|
||||
virtual void SendInterrupt (uint16_t interrupt) = 0;
|
||||
virtual void CheckInterrupt () = 0;
|
||||
void Interrupt ();
|
||||
void SoftwareInterrupt (uint32_t comment);
|
||||
void SoftwareInterrupt ();
|
||||
|
||||
uint32_t& Reg(uint8_t r)
|
||||
{
|
||||
return m_st.r[r];
|
||||
}
|
||||
|
||||
Psr& Cpsr()
|
||||
{
|
||||
return m_st.cpsr;
|
||||
}
|
||||
IPsr& ICpsr()
|
||||
{
|
||||
return m_st.icpsr;
|
||||
}
|
||||
Psr& Spsr()
|
||||
{
|
||||
return m_st.spsr;
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
protected :
|
||||
struct CPUState
|
||||
{
|
||||
// Current registers
|
||||
uint32_t r[16];
|
||||
Psr cpsr, spsr;
|
||||
IPsr icpsr;
|
||||
|
||||
// System/User
|
||||
uint32_t usr_r[7]; // from 8 to 14
|
||||
|
||||
// FIQ
|
||||
uint32_t fiq_r[7]; // from 8 to 14
|
||||
Psr fiq_spsr;
|
||||
|
||||
// Supervisor
|
||||
uint32_t svc_r[2]; // 13 and 14
|
||||
Psr svc_spsr;
|
||||
|
||||
// Abort
|
||||
uint32_t abt_r[2]; // 13 and 14
|
||||
Psr abt_spsr;
|
||||
|
||||
// IRQ
|
||||
uint32_t irq_r[2]; // 13 and 14
|
||||
Psr irq_spsr;
|
||||
|
||||
// Undefined
|
||||
uint32_t und_r[2]; // 13 and 14
|
||||
Psr und_spsr;
|
||||
};
|
||||
|
||||
CPUState m_st;
|
||||
|
||||
virtual void SetInterrupt (bool interrupt) = 0;
|
||||
|
||||
private :
|
||||
void SaveMode (uint8_t mode);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,44 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARG_IMMEDIATE_H__
|
||||
#define __ARG_IMMEDIATE_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class ArgImmediate : public Argument
|
||||
{
|
||||
public :
|
||||
ArgImmediate (int32_t imm) :
|
||||
m_imm(imm)
|
||||
{ }
|
||||
|
||||
Argument* Clone () const;
|
||||
|
||||
std::string GetString () const;
|
||||
|
||||
private :
|
||||
int32_t m_imm;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,67 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARG_MUL_REGISTERS_H__
|
||||
#define __ARG_MUL_REGISTERS_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
enum SpecialRegister
|
||||
{
|
||||
SPREG_NONE = 0,
|
||||
SPREG_LR = 1,
|
||||
SPREG_PC = 2
|
||||
};
|
||||
|
||||
class ArgMulRegisters : public Argument
|
||||
{
|
||||
public :
|
||||
ArgMulRegisters (bool forceuser) :
|
||||
m_lastreg(SPREG_NONE),
|
||||
m_forceuser(forceuser)
|
||||
{ }
|
||||
|
||||
Argument* Clone () const;
|
||||
|
||||
void AddRegister(uint8_t reg)
|
||||
{
|
||||
m_regs.push_back(reg);
|
||||
}
|
||||
void AddLastRegister(SpecialRegister reg)
|
||||
{
|
||||
m_lastreg = reg;
|
||||
}
|
||||
|
||||
std::string GetString () const;
|
||||
|
||||
private :
|
||||
typedef std::vector<uint8_t> Registers;
|
||||
|
||||
Registers m_regs;
|
||||
SpecialRegister m_lastreg;
|
||||
bool m_forceuser;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,47 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARG_PSR_H__
|
||||
#define __ARG_PSR_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class ArgPsr : public Argument
|
||||
{
|
||||
public :
|
||||
ArgPsr (bool spsr, uint8_t fields = 0xFF) :
|
||||
m_spsr(spsr),
|
||||
m_fields(fields)
|
||||
{ }
|
||||
|
||||
Argument* Clone () const;
|
||||
|
||||
std::string GetString () const;
|
||||
|
||||
private :
|
||||
bool m_spsr;
|
||||
uint8_t m_fields;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,56 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARG_REGISTER_H__
|
||||
#define __ARG_REGISTER_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class ArgRegister : public Argument
|
||||
{
|
||||
public :
|
||||
ArgRegister (uint8_t reg, bool writeback = false,
|
||||
bool special = false, bool memory = false) :
|
||||
m_reg(reg),
|
||||
m_writeback(writeback),
|
||||
m_special(special),
|
||||
m_memory(memory)
|
||||
{ }
|
||||
|
||||
Argument* Clone () const;
|
||||
|
||||
std::string GetString () const;
|
||||
uint8_t GetRegister () const
|
||||
{
|
||||
return m_reg;
|
||||
}
|
||||
|
||||
private :
|
||||
uint8_t m_reg;
|
||||
bool m_writeback;
|
||||
bool m_special;
|
||||
bool m_memory;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARG_RELATIVE_H__
|
||||
#define __ARG_RELATIVE_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
#include "argregister.hpp"
|
||||
#include "argimmediate.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class ArgRelative : public Argument
|
||||
{
|
||||
public :
|
||||
ArgRelative (const ArgRegister& reg, const Argument& off,
|
||||
bool pre, bool up, bool writeback);
|
||||
ArgRelative (const ArgRelative& arg);
|
||||
~ArgRelative ();
|
||||
|
||||
Argument* Clone () const;
|
||||
|
||||
std::string GetString () const;
|
||||
|
||||
private :
|
||||
ArgRegister m_reg;
|
||||
const Argument* m_off;
|
||||
bool m_pre;
|
||||
bool m_up;
|
||||
bool m_writeback;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,56 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARG_SHIFT_H__
|
||||
#define __ARG_SHIFT_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
enum ShiftType
|
||||
{
|
||||
SHIFT_LSL = 0,
|
||||
SHIFT_LSR,
|
||||
SHIFT_ASR,
|
||||
SHIFT_ROR,
|
||||
SHIFT_RRX
|
||||
};
|
||||
|
||||
class ArgShift : public Argument
|
||||
{
|
||||
public :
|
||||
ArgShift (const Argument& arg1, const Argument& arg2,
|
||||
ShiftType type, bool memory);
|
||||
ArgShift (const ArgShift& arg);
|
||||
~ArgShift ();
|
||||
|
||||
Argument* Clone () const;
|
||||
|
||||
std::string GetString () const;
|
||||
|
||||
private :
|
||||
const Argument* m_arg1;
|
||||
const Argument* m_arg2;
|
||||
ShiftType m_type;
|
||||
bool m_memory;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARG_U_IMMEDIATE_H__
|
||||
#define __ARG_U_IMMEDIATE_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class ArgUImmediate : public Argument
|
||||
{
|
||||
public :
|
||||
ArgUImmediate (uint32_t imm) :
|
||||
m_imm(imm)
|
||||
{ }
|
||||
|
||||
Argument* Clone () const;
|
||||
|
||||
std::string GetString () const;
|
||||
|
||||
private :
|
||||
uint32_t m_imm;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,39 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARGUMENT_H__
|
||||
#define __ARGUMENT_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class Argument
|
||||
{
|
||||
public :
|
||||
virtual ~Argument ()
|
||||
{ }
|
||||
|
||||
virtual Argument* Clone () const = 0;
|
||||
|
||||
virtual std::string GetString () const = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,48 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __ARGUMENTS_H__
|
||||
#define __ARGUMENTS_H__
|
||||
|
||||
#include "argument.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class Arguments
|
||||
{
|
||||
public :
|
||||
~Arguments ();
|
||||
|
||||
void Clear ();
|
||||
|
||||
void AddArgument(const Argument& arg)
|
||||
{
|
||||
m_args.push_back(arg.Clone());
|
||||
}
|
||||
|
||||
std::string GetString () const;
|
||||
|
||||
private :
|
||||
std::vector<Argument*> m_args;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,76 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __INSTRUCTION_H__
|
||||
#define __INSTRUCTION_H__
|
||||
|
||||
#include "arguments.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
class Instruction
|
||||
{
|
||||
public :
|
||||
Instruction ()
|
||||
{
|
||||
}
|
||||
|
||||
explicit Instruction (uint32_t offset, uint32_t code)
|
||||
{
|
||||
ParseArm (offset, code);
|
||||
}
|
||||
|
||||
explicit Instruction (uint32_t offset, uint16_t code)
|
||||
{
|
||||
ParseThumb(offset, code);
|
||||
}
|
||||
|
||||
void Clear ();
|
||||
|
||||
void ParseArm (uint32_t offset, uint32_t code);
|
||||
void ParseThumb (uint32_t offset, uint16_t code);
|
||||
|
||||
const std::string& GetOperator () const
|
||||
{
|
||||
return m_operator;
|
||||
}
|
||||
|
||||
std::string GetArguments () const
|
||||
{
|
||||
return m_args.GetString();
|
||||
}
|
||||
|
||||
std::string ToString () const
|
||||
{
|
||||
return GetOperator() + ' ' + GetArguments();
|
||||
}
|
||||
|
||||
private :
|
||||
std::string m_operator;
|
||||
Arguments m_args;
|
||||
|
||||
void ParseArmDataProc (uint32_t code);
|
||||
void ParseArmCondition (uint32_t code);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,113 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __DMA_H__
|
||||
#define __DMA_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Dma
|
||||
{
|
||||
public :
|
||||
enum Reason
|
||||
{
|
||||
Immediately = 0,
|
||||
VBlank,
|
||||
HBlank,
|
||||
Special
|
||||
};
|
||||
|
||||
Dma () :
|
||||
m_graphic(false)
|
||||
{ }
|
||||
|
||||
void Reset ();
|
||||
|
||||
bool GraphicDma () const
|
||||
{
|
||||
return false;
|
||||
//return m_graphic;
|
||||
}
|
||||
|
||||
void SetReload(uint8_t channum, uint16_t reload)
|
||||
{
|
||||
m_chans[channum].reload = reload;
|
||||
}
|
||||
|
||||
void UpdateCnt (uint8_t channum);
|
||||
void Check(uint8_t channum, uint8_t reason);
|
||||
inline void CheckAll(uint8_t reason)
|
||||
{
|
||||
Check(0, reason);
|
||||
Check(1, reason);
|
||||
Check(2, reason);
|
||||
Check(3, reason);
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
struct Channel
|
||||
{
|
||||
Channel () :
|
||||
reload(0),
|
||||
src(0),
|
||||
dest(0),
|
||||
count(0),
|
||||
control(0)
|
||||
{ }
|
||||
|
||||
uint16_t reload;
|
||||
uint32_t src;
|
||||
uint32_t dest;
|
||||
uint16_t count;
|
||||
union Control
|
||||
{
|
||||
Control(uint16_t v) :
|
||||
w(v)
|
||||
{ }
|
||||
|
||||
uint16_t w;
|
||||
struct
|
||||
{
|
||||
unsigned int unused : 5;
|
||||
unsigned int dest : 2;
|
||||
unsigned int src : 2;
|
||||
unsigned int repeat : 1;
|
||||
unsigned int type : 1;
|
||||
unsigned int drq : 1;
|
||||
unsigned int start : 2;
|
||||
unsigned int irq : 1;
|
||||
unsigned int enable : 1;
|
||||
} b;
|
||||
} control;
|
||||
};
|
||||
|
||||
Channel m_chans[4];
|
||||
bool m_graphic;
|
||||
|
||||
void Process(uint8_t channel);
|
||||
void Copy (uint32_t& src, uint32_t& dest, int8_t s_inc, int8_t d_inc,
|
||||
uint32_t count, bool word);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,79 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __EEPROM_H__
|
||||
#define __EEPROM_H__
|
||||
|
||||
#include "cartmem.hpp"
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Eeprom : public CartMem
|
||||
{
|
||||
public :
|
||||
Eeprom (bool big);
|
||||
|
||||
void Reset ();
|
||||
|
||||
uint16_t GetSize () const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool Load (std::istream& f);
|
||||
bool Save (std::ostream& f);
|
||||
|
||||
uint8_t Read (uint16_t add);
|
||||
bool Write (uint16_t add, uint8_t val);
|
||||
|
||||
uint16_t Read ();
|
||||
//bool Write (uint16_t val);
|
||||
|
||||
bool Write (uint16_t* data, uint16_t size);
|
||||
//XXX
|
||||
#if 0
|
||||
void Read (uint16_t* pOut);
|
||||
#endif
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
enum State
|
||||
{
|
||||
IDLE,
|
||||
//WAITING,
|
||||
|
||||
//READ_ADD,
|
||||
//READ_END,
|
||||
READ_GARBAGE,
|
||||
READ_DATA
|
||||
|
||||
/*WRITE_ADD,
|
||||
WRITE_DATA,
|
||||
WRITE_END*/
|
||||
};
|
||||
|
||||
uint8_t m_state;
|
||||
uint16_t m_add;
|
||||
uint8_t m_pos;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __FLASH_H__
|
||||
#define __FLASH_H__
|
||||
|
||||
#include "cartmem.hpp"
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Flash : public CartMem
|
||||
{
|
||||
public :
|
||||
Flash (bool big);
|
||||
|
||||
void Reset ();
|
||||
|
||||
bool Load (std::istream& f);
|
||||
bool Save (std::ostream& f);
|
||||
|
||||
uint8_t Read (uint16_t add);
|
||||
bool Write (uint16_t add, uint8_t val);
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
uint8_t m_device_id;
|
||||
uint8_t m_manufacturer_id;
|
||||
|
||||
enum State
|
||||
{
|
||||
NORMAL,
|
||||
CMD1,
|
||||
CMD2,
|
||||
ID,
|
||||
ERASE1,
|
||||
ERASE2,
|
||||
ERASE3,
|
||||
WRITE
|
||||
};
|
||||
|
||||
State m_state;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __GRAPHICS_BG_LAYER_H__
|
||||
#define __GRAPHICS_BG_LAYER_H__
|
||||
|
||||
#include "ameteor/memory.hpp"
|
||||
#include "ameteor/io.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
class BgLayer
|
||||
{
|
||||
public :
|
||||
BgLayer (int8_t num, Memory& memory, Io& io, uint16_t* pPalette);
|
||||
~BgLayer ();
|
||||
|
||||
inline uint8_t GetNum () const;
|
||||
inline uint8_t GetPriority () const;
|
||||
|
||||
void DrawLine0 (uint8_t line, uint16_t* ptr);
|
||||
void DrawLine2 (uint16_t* ptr,
|
||||
int32_t refX, int32_t refY,
|
||||
int16_t dx, int16_t dy);
|
||||
void DrawLine3 (uint16_t* ptr,
|
||||
int32_t refX, int32_t refY,
|
||||
int16_t dx, int16_t dy);
|
||||
void DrawLine4 (uint8_t line, uint16_t* ptr,
|
||||
int32_t curX, int32_t curY,
|
||||
int16_t dx, int16_t dmx, int16_t dy, int16_t dmy, bool frame1);
|
||||
void DrawLine5 (uint16_t* ptr,
|
||||
int32_t refX, int32_t refY,
|
||||
int16_t dx, int16_t dy, bool frame1);
|
||||
void FillList ();
|
||||
|
||||
void UpdateCnt (uint16_t cnt);
|
||||
inline void UpdateXOff (uint16_t off);
|
||||
inline void UpdateYOff (uint16_t off);
|
||||
|
||||
private :
|
||||
Memory& m_memory;
|
||||
Io& m_io;
|
||||
|
||||
const uint8_t m_num;
|
||||
uint8_t m_priority;
|
||||
|
||||
uint16_t m_cnt;
|
||||
bool m_hicolor;
|
||||
uint16_t m_xoff, m_yoff;
|
||||
// in text mode
|
||||
uint8_t m_tWidth, m_tHeight;
|
||||
// in rotation/scale mode
|
||||
uint8_t m_rWidth, m_rHeight;
|
||||
|
||||
uint32_t m_mapAdd;
|
||||
uint32_t m_charAdd;
|
||||
uint16_t* m_pPalette;
|
||||
};
|
||||
|
||||
inline uint8_t BgLayer::GetNum () const
|
||||
{
|
||||
return m_num;
|
||||
}
|
||||
|
||||
inline uint8_t BgLayer::GetPriority () const
|
||||
{
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
inline void BgLayer::UpdateXOff (uint16_t off)
|
||||
{
|
||||
m_xoff = off;
|
||||
}
|
||||
|
||||
inline void BgLayer::UpdateYOff (uint16_t off)
|
||||
{
|
||||
m_yoff = off;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __GRAPHICS_OBJECT_H__
|
||||
#define __GRAPHICS_OBJECT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
class Object
|
||||
{
|
||||
public :
|
||||
static const uint8_t FLIP_HORIZONTAL = 1;
|
||||
static const uint8_t FLIP_VERTICAL = 2;
|
||||
|
||||
Object (uint16_t* pPalette, uint8_t* pChar);
|
||||
// Warning : this copy constructor must not be used on an used object
|
||||
// use it only on just created objects
|
||||
Object (const Object& obj);
|
||||
|
||||
inline uint8_t GetPriority () const;
|
||||
inline int8_t GetRotationParam () const;
|
||||
inline uint16_t GetTileNum () const;
|
||||
inline bool IsWindow () const;
|
||||
|
||||
void DrawLine (uint8_t line, uint32_t* surface, bool oneDim,
|
||||
uint8_t mosaic);
|
||||
void DrawLineRot (uint8_t line, uint32_t* surface, bool oneDim,
|
||||
int16_t a, int16_t b, int16_t c, int16_t d, uint8_t mosaic);
|
||||
void DrawWindow (uint8_t line, uint8_t* surface, bool oneDim,
|
||||
uint8_t mask);
|
||||
void DrawWindowRot (uint8_t line, uint8_t* surface,
|
||||
bool oneDim, int16_t a, int16_t b, int16_t c, int16_t d,
|
||||
uint8_t mask);
|
||||
|
||||
void UpdateAttrs (uint16_t attr0, uint16_t attr1, uint16_t attr2);
|
||||
void UpdateAttr0 (uint16_t attr);
|
||||
void UpdateAttr1 (uint16_t attr);
|
||||
void UpdateAttr2 (uint16_t attr);
|
||||
|
||||
private :
|
||||
inline void SetSize ();
|
||||
|
||||
enum Shape
|
||||
{
|
||||
SHAPE_SQUARE = 0,
|
||||
SHAPE_HORIZONTAL,
|
||||
SHAPE_VERTICAL,
|
||||
SHAPE_PROHIBITED
|
||||
};
|
||||
|
||||
uint16_t m_attr0, m_attr1, m_attr2;
|
||||
uint8_t m_width, m_height;
|
||||
uint16_t* m_pPalette;
|
||||
uint8_t* m_pChar;
|
||||
uint32_t m_charBegin;
|
||||
uint32_t m_charEnd;
|
||||
};
|
||||
|
||||
inline int8_t Object::GetRotationParam () const
|
||||
{
|
||||
return (m_attr0 & (0x1 << 8)) ? (m_attr1 >> 9) & 0x1F : -1;
|
||||
}
|
||||
|
||||
inline uint8_t Object::GetPriority () const
|
||||
{
|
||||
return (m_attr2 >> 10) & 0x3;
|
||||
}
|
||||
|
||||
inline bool Object::IsWindow () const
|
||||
{
|
||||
return (m_attr0 & (0x3 << 10)) == (0x2 << 10);
|
||||
}
|
||||
|
||||
inline uint16_t Object::GetTileNum () const
|
||||
{
|
||||
return (m_attr2 & 0x3FF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,53 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __GRAPHICS_OBJECTS_H__
|
||||
#define __GRAPHICS_OBJECTS_H__
|
||||
|
||||
#include "object.hpp"
|
||||
#include "ameteor/memory.hpp"
|
||||
#include "ameteor/io.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
class Objects
|
||||
{
|
||||
public :
|
||||
Objects (Memory& memory, Io& io, uint16_t* pPalette);
|
||||
|
||||
void DrawLine (uint8_t line, uint32_t* surface);
|
||||
void DrawLineHighOnly (uint8_t line, uint32_t* surface);
|
||||
void DrawWindow (uint8_t line, uint8_t* surface);
|
||||
|
||||
void OamWrite (uint32_t begin, uint32_t end);
|
||||
void OamWrite16 (uint32_t add);
|
||||
void OamWrite32 (uint32_t add);
|
||||
|
||||
private :
|
||||
typedef std::vector<Object> Objs;
|
||||
|
||||
Io& m_io;
|
||||
Objs m_objs;
|
||||
uint16_t* m_pOam;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __GRAPHICS_RENDERER_H__
|
||||
#define __GRAPHICS_RENDERER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <syg/signal.hpp>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
typedef syg::slot1<void, const uint16_t*> FrameSlot;
|
||||
|
||||
Renderer(const uint16_t* surface);
|
||||
|
||||
inline void SetFrameSlot(const FrameSlot& slot);
|
||||
|
||||
void VBlank();
|
||||
|
||||
private :
|
||||
const uint16_t* m_base;
|
||||
|
||||
FrameSlot m_sig_frame;
|
||||
};
|
||||
|
||||
void Renderer::SetFrameSlot(const FrameSlot& slot)
|
||||
{
|
||||
m_sig_frame = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,148 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __GRAPHICS_SCREEN_H__
|
||||
#define __GRAPHICS_SCREEN_H__
|
||||
|
||||
#include "bglayer.hpp"
|
||||
#include "objects.hpp"
|
||||
#include "renderer.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
class Screen
|
||||
{
|
||||
public :
|
||||
static const uint8_t WIDTH = 240;
|
||||
static const uint8_t HEIGHT = 160;
|
||||
|
||||
// we skip x frames every FRMSKIP_TOTAL frames
|
||||
static const uint8_t FRMSKIP_TOTAL = 10;
|
||||
|
||||
Screen (Memory& memory, Io& io);
|
||||
~Screen ();
|
||||
|
||||
Renderer& GetRenderer()
|
||||
{
|
||||
return m_renderer;
|
||||
}
|
||||
const Renderer& GetRenderer() const
|
||||
{
|
||||
return m_renderer;
|
||||
}
|
||||
|
||||
const uint16_t* GetSurface () const
|
||||
{
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
void SetFrameskip (uint8_t skip)
|
||||
{
|
||||
m_frameskip = skip;
|
||||
m_curframe = 0;
|
||||
}
|
||||
|
||||
void DrawLine (uint8_t line);
|
||||
|
||||
void UpdateDispCnt (uint16_t dispcnt)
|
||||
{
|
||||
m_dispcnt = dispcnt;
|
||||
}
|
||||
|
||||
#define UPDATE_BG_CNT(num) \
|
||||
void UpdateBg##num##Cnt (uint16_t cnt) \
|
||||
{ \
|
||||
m_bgLayer##num.UpdateCnt(cnt); \
|
||||
}
|
||||
UPDATE_BG_CNT(0)
|
||||
UPDATE_BG_CNT(1)
|
||||
UPDATE_BG_CNT(2)
|
||||
UPDATE_BG_CNT(3)
|
||||
#undef UPDATE_BG_CNT
|
||||
|
||||
#define UPDATE_BG_OFF(num, coord) \
|
||||
void UpdateBg##num##coord##Off (uint16_t off) \
|
||||
{ \
|
||||
m_bgLayer##num.Update##coord##Off(off); \
|
||||
}
|
||||
UPDATE_BG_OFF(0, X)
|
||||
UPDATE_BG_OFF(0, Y)
|
||||
UPDATE_BG_OFF(1, X)
|
||||
UPDATE_BG_OFF(1, Y)
|
||||
UPDATE_BG_OFF(2, X)
|
||||
UPDATE_BG_OFF(2, Y)
|
||||
UPDATE_BG_OFF(3, X)
|
||||
UPDATE_BG_OFF(3, Y)
|
||||
#undef UPDATE_BG_OFF
|
||||
|
||||
#define UPDATE_BG_REF(num, coord) \
|
||||
void UpdateBg##num##Ref##coord(int32_t x) \
|
||||
{ \
|
||||
m_ref##coord##num = (x & (0x1 << 27)) ? x | 0xF0000000 : x & 0x07FFFFFF; \
|
||||
}
|
||||
UPDATE_BG_REF(2, X)
|
||||
UPDATE_BG_REF(2, Y)
|
||||
UPDATE_BG_REF(3, X)
|
||||
UPDATE_BG_REF(3, Y)
|
||||
#undef UPDATE_BG_REF
|
||||
|
||||
void OamWrite (uint32_t begin, uint32_t end)
|
||||
{
|
||||
m_objs.OamWrite (begin, end);
|
||||
}
|
||||
void OamWrite16 (uint32_t add)
|
||||
{
|
||||
m_objs.OamWrite16 (add);
|
||||
}
|
||||
void OamWrite32 (uint32_t add)
|
||||
{
|
||||
m_objs.OamWrite32 (add);
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
Io& m_io;
|
||||
|
||||
uint16_t* m_surface;
|
||||
|
||||
Renderer m_renderer;
|
||||
|
||||
uint8_t m_frameskip, m_curframe;
|
||||
|
||||
uint16_t m_dispcnt;
|
||||
int32_t m_refX2, m_refY2, m_refX3, m_refY3;
|
||||
uint16_t* m_pPalette;
|
||||
|
||||
// FIXME is this REALLY useful ?
|
||||
static BgLayer Screen::* const BgLayers [4];
|
||||
BgLayer m_bgLayer0, m_bgLayer1, m_bgLayer2, m_bgLayer3;
|
||||
Objects m_objs;
|
||||
|
||||
void DrawWindow (uint8_t line, uint8_t* surface,
|
||||
uint16_t win0v, uint16_t win0h, uint8_t mask);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,133 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __INTERPRETER_H__
|
||||
#define __INTERPRETER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include "cpu.hpp"
|
||||
|
||||
#define ARM(name) \
|
||||
inline void a##name ()
|
||||
#define NIARM(name) \
|
||||
void a##name ()
|
||||
#define THUMB(name) \
|
||||
inline void t##name ()
|
||||
#define NITHUMB(name) \
|
||||
void t##name ()
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Interpreter : public Cpu
|
||||
{
|
||||
public :
|
||||
Interpreter();
|
||||
|
||||
void Reset ()
|
||||
{
|
||||
m_interrupt = m_interrupt_ = false;
|
||||
m_run = false;
|
||||
Cpu::Reset();
|
||||
}
|
||||
void SoftReset ()
|
||||
{
|
||||
m_interrupt_ = m_interrupt = false;
|
||||
Cpu::SoftReset();
|
||||
}
|
||||
|
||||
void SendInterrupt (uint16_t interrupt);
|
||||
void CheckInterrupt ();
|
||||
|
||||
void Run (unsigned int cycles);
|
||||
void Stop ()
|
||||
{
|
||||
m_run = false;
|
||||
}
|
||||
bool IsRunning ()
|
||||
{
|
||||
return m_run;
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
protected :
|
||||
void SetInterrupt (bool interrupt)
|
||||
{
|
||||
m_interrupt = interrupt;
|
||||
}
|
||||
|
||||
private :
|
||||
bool m_run;
|
||||
|
||||
bool m_interrupt;
|
||||
bool m_interrupt_;
|
||||
uint32_t code;
|
||||
uint8_t& m_haltcnt;
|
||||
// only for use in halt mode, in normal mode we use m_interrupt
|
||||
uint16_t& m_if;
|
||||
uint16_t& m_ie;
|
||||
|
||||
NIARM(_Code);
|
||||
inline bool a_CheckCondition (uint8_t cond);
|
||||
inline void a_DataProcCore(uint8_t rd, uint32_t op1, uint32_t op2,
|
||||
bool shiftcarry);
|
||||
|
||||
ARM(BXBLX);
|
||||
ARM(BBL);
|
||||
NIARM(_DataProcShiftImm);
|
||||
NIARM(_DataProcShiftReg);
|
||||
NIARM(_DataProcImm);
|
||||
ARM(PSR);
|
||||
ARM(_Multiply);
|
||||
ARM(LDRSTR);
|
||||
ARM(STRLDR_HD);
|
||||
ARM(LDMSTM);
|
||||
ARM(SWP);
|
||||
ARM(SWI);
|
||||
|
||||
NITHUMB(_Code);
|
||||
|
||||
THUMB(_Shift);
|
||||
THUMB(ADDSUB);
|
||||
THUMB(_Imm);
|
||||
THUMB(_ALU);
|
||||
THUMB(_HiRegOp);
|
||||
THUMB(LDRimm);
|
||||
THUMB(STRLDRreg);
|
||||
THUMB(STRLDRoff);
|
||||
THUMB(LDRHSTRHoff);
|
||||
THUMB(STRLDRsp);
|
||||
THUMB(ADDpcsp);
|
||||
THUMB(ADDsp);
|
||||
THUMB(PUSHPOP);
|
||||
THUMB(STMLDM);
|
||||
THUMB(_CondBranch);
|
||||
THUMB(SWI);
|
||||
THUMB(B);
|
||||
THUMB(_BL1);
|
||||
THUMB(_BL2);
|
||||
};
|
||||
}
|
||||
|
||||
#undef ARM
|
||||
#undef NIARM
|
||||
#undef THUMB
|
||||
#undef NITHUMB
|
||||
|
||||
#endif
|
|
@ -1,219 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __IO_H__
|
||||
#define __IO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Io
|
||||
{
|
||||
public :
|
||||
enum IoAddress
|
||||
{
|
||||
// LCD I/O Registers
|
||||
DISPCNT = 0x000,
|
||||
DISPSTAT = 0x004,
|
||||
VCOUNT = 0x006,
|
||||
BG0CNT = 0x008,
|
||||
BG1CNT = 0x00A,
|
||||
BG2CNT = 0x00C,
|
||||
BG3CNT = 0x00E,
|
||||
BG0HOFS = 0x010,
|
||||
BG0VOFS = 0x012,
|
||||
BG1HOFS = 0x014,
|
||||
BG1VOFS = 0x016,
|
||||
BG2HOFS = 0x018,
|
||||
BG2VOFS = 0x01A,
|
||||
BG3HOFS = 0x01C,
|
||||
BG3VOFS = 0x01E,
|
||||
BG2PA = 0x020,
|
||||
BG2PB = 0x022,
|
||||
BG2PC = 0x024,
|
||||
BG2PD = 0x026,
|
||||
BG2X_L = 0x028,
|
||||
BG2X_H = 0x02A,
|
||||
BG2Y_L = 0x02C,
|
||||
BG2Y_H = 0x02E,
|
||||
BG3PA = 0x030,
|
||||
BG3PB = 0x032,
|
||||
BG3PC = 0x034,
|
||||
BG3PD = 0x036,
|
||||
BG3X_L = 0x038,
|
||||
BG3X_H = 0x03A,
|
||||
BG3Y_L = 0x03C,
|
||||
BG3Y_H = 0x03E,
|
||||
WIN0H = 0x040,
|
||||
WIN1H = 0x042,
|
||||
WIN0V = 0x044,
|
||||
WIN1V = 0x046,
|
||||
WININ = 0x048,
|
||||
WINOUT = 0x04A,
|
||||
MOSAIC = 0x04C,
|
||||
BLDCNT = 0x050,
|
||||
BLDALPHA = 0x052,
|
||||
BLDY = 0x054,
|
||||
// Sound Registers
|
||||
SOUND1CNT_L = 0x060, NR10 = 0x060,
|
||||
SOUND1CNT_H = 0x062, NR11 = 0x062,
|
||||
NR12 = 0x063,
|
||||
SOUND1CNT_X = 0x064, NR13 = 0x064,
|
||||
NR14 = 0x065,
|
||||
SOUND2CNT_L = 0x068, NR21 = 0x068,
|
||||
NR22 = 0x069,
|
||||
SOUND2CNT_H = 0x06C, NR23 = 0x06C,
|
||||
NR24 = 0x06D,
|
||||
SOUND4CNT_L = 0x078, NR41 = 0x078,
|
||||
NR42 = 0x079,
|
||||
SOUND4CNT_H = 0x07C, NR43 = 0x07C,
|
||||
NR44 = 0x07D,
|
||||
SOUNDCNT_L = 0x080, NR50 = 0x080,
|
||||
NR51 = 0x081,
|
||||
SOUNDCNT_H = 0x082,
|
||||
SOUNDCNT_X = 0x084, NR52 = 0x084,
|
||||
SOUNDBIAS = 0x088,
|
||||
FIFO_A = 0x0A0,
|
||||
FIFO_B = 0x0A4,
|
||||
// DMA Transfer Channels
|
||||
DMA0SAD = 0x0B0,
|
||||
DMA0DAD = 0x0B4,
|
||||
DMA0CNT_L = 0x0B8,
|
||||
DMA0CNT_H = 0x0BA,
|
||||
DMA1SAD = 0x0BC,
|
||||
DMA1DAD = 0x0C0,
|
||||
DMA1CNT_L = 0x0C4,
|
||||
DMA1CNT_H = 0x0C6,
|
||||
DMA2SAD = 0x0C8,
|
||||
DMA2DAD = 0x0CC,
|
||||
DMA2CNT_L = 0x0D0,
|
||||
DMA2CNT_H = 0x0D2,
|
||||
DMA3SAD = 0x0D4,
|
||||
DMA3DAD = 0x0D8,
|
||||
DMA3CNT_L = 0x0DC,
|
||||
DMA3CNT_H = 0x0DE,
|
||||
// Timer Registers
|
||||
TM0CNT_L = 0x100,
|
||||
TM0CNT_H = 0x102,
|
||||
TM1CNT_L = 0x104,
|
||||
TM1CNT_H = 0x106,
|
||||
TM2CNT_L = 0x108,
|
||||
TM2CNT_H = 0x10A,
|
||||
TM3CNT_L = 0x10C,
|
||||
TM3CNT_H = 0x10E,
|
||||
// Keypad Input
|
||||
KEYINPUT = 0x130,
|
||||
KEYCNT = 0x132,
|
||||
// Serial Communication (2)
|
||||
RCNT = 0x134,
|
||||
// Interrupt, WaitState, and Power-Down Control
|
||||
IE = 0x200,
|
||||
IF = 0x202,
|
||||
WAITCNT = 0x204,
|
||||
IME = 0x208,
|
||||
POSTFLG = 0x300,
|
||||
HALTCNT = 0x301,
|
||||
|
||||
DMA_CHANSIZE = 0x00C,
|
||||
TIMER_SIZE = 0x004,
|
||||
// TODO make tests and everything in Write*() functions so that we can
|
||||
// make IO_SIZE 0x804 (don't forget mirrors)
|
||||
IO_SIZE = 0x1000
|
||||
};
|
||||
|
||||
Io ();
|
||||
~Io ();
|
||||
|
||||
void Reset ();
|
||||
void ClearSio ();
|
||||
void ClearSound ();
|
||||
void ClearOthers ();
|
||||
|
||||
uint8_t Read8 (uint32_t add);
|
||||
uint16_t Read16 (uint32_t add);
|
||||
uint32_t Read32 (uint32_t add);
|
||||
|
||||
void Write8 (uint32_t add, uint8_t val);
|
||||
void Write16 (uint32_t add, uint16_t val);
|
||||
void Write32 (uint32_t add, uint32_t val);
|
||||
|
||||
// Direct read and write
|
||||
// Using theses functions will write directly on IO memory without
|
||||
// doing anything else (they won't call Dma::Check for example)
|
||||
// add must be the real address & 0xFFF
|
||||
// No check is done on the memory, these functions may segfault if
|
||||
// you give them wrong values !
|
||||
|
||||
uint8_t DRead8 (uint16_t add)
|
||||
{
|
||||
return m_iomem[add];
|
||||
}
|
||||
|
||||
uint16_t DRead16 (uint16_t add)
|
||||
{
|
||||
return *(uint16_t*)(m_iomem+add);
|
||||
}
|
||||
|
||||
uint32_t DRead32 (uint16_t add)
|
||||
{
|
||||
return *(uint32_t*)(m_iomem+add);
|
||||
}
|
||||
|
||||
void DWrite8 (uint16_t add, uint8_t val)
|
||||
{
|
||||
m_iomem[add] = val;
|
||||
}
|
||||
|
||||
void DWrite16 (uint16_t add, uint16_t val)
|
||||
{
|
||||
*(uint16_t*)(m_iomem+add) = val;
|
||||
}
|
||||
|
||||
void DWrite32 (uint16_t add, uint32_t val)
|
||||
{
|
||||
*(uint32_t*)(m_iomem+add) = val;
|
||||
}
|
||||
|
||||
uint8_t& GetRef8 (uint16_t add)
|
||||
{
|
||||
return m_iomem[add];
|
||||
}
|
||||
|
||||
uint16_t& GetRef16 (uint16_t add)
|
||||
{
|
||||
return *(uint16_t*)(m_iomem+add);
|
||||
}
|
||||
|
||||
uint32_t& GetRef32 (uint16_t add)
|
||||
{
|
||||
return *(uint32_t*)(m_iomem+add);
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
// this should be considered very dangerous to use
|
||||
uint8_t* GetIoPointer() {return m_iomem;}
|
||||
|
||||
private :
|
||||
uint8_t* m_iomem;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,105 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __KEYPAD_H__
|
||||
#define __KEYPAD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Keypad
|
||||
{
|
||||
public :
|
||||
enum Button
|
||||
{
|
||||
BTN_A = 0x001,
|
||||
BTN_B = 0x002,
|
||||
BTN_SELECT = 0x004,
|
||||
BTN_START = 0x008,
|
||||
BTN_RIGHT = 0x010,
|
||||
BTN_LEFT = 0x020,
|
||||
BTN_UP = 0x040,
|
||||
BTN_DOWN = 0x080,
|
||||
BTN_R = 0x100,
|
||||
BTN_L = 0x200
|
||||
};
|
||||
|
||||
Keypad ();
|
||||
|
||||
void Reset ()
|
||||
{
|
||||
}
|
||||
|
||||
void BindKey(int code, Button btn)
|
||||
{
|
||||
m_keys[code] = (uint16_t)btn;
|
||||
}
|
||||
void UnbindKey(int code)
|
||||
{
|
||||
m_keys.erase(code);
|
||||
}
|
||||
void BindJoy(uint16_t joyid, uint16_t button, Button btn)
|
||||
{
|
||||
m_joys[((int)joyid) << 16 | button] = (uint16_t)btn;
|
||||
}
|
||||
void UnbindJoy(uint16_t joyid, uint16_t button)
|
||||
{
|
||||
m_joys.erase(((int)joyid) << 16 | button);
|
||||
}
|
||||
void BindAxis(uint16_t joyid, uint16_t axis, Button btn)
|
||||
{
|
||||
m_axis[((int)joyid) << 16 | axis] = (uint16_t)btn;
|
||||
}
|
||||
void UnbindAxis(uint16_t joyid, uint16_t axis)
|
||||
{
|
||||
m_axis.erase(((int)joyid) << 16 | axis);
|
||||
}
|
||||
|
||||
void ResetBindings()
|
||||
{
|
||||
m_keys.clear();
|
||||
m_joys.clear();
|
||||
m_axis.clear();
|
||||
}
|
||||
|
||||
inline void SetPadState(uint16_t keys);
|
||||
|
||||
void KeyPressed(int code);
|
||||
void KeyReleased(int code);
|
||||
void JoyButtonPressed (uint16_t joyid, uint16_t button);
|
||||
void JoyButtonReleased (uint16_t joyid, uint16_t button);
|
||||
void JoyMoved (uint16_t joyid, uint16_t axis, float pos);
|
||||
|
||||
void VBlank ();
|
||||
|
||||
private :
|
||||
uint16_t& m_keyinput;
|
||||
uint16_t& m_keycnt;
|
||||
|
||||
std::map<int, uint16_t> m_keys;
|
||||
std::map<int, uint16_t> m_joys;
|
||||
std::map<int, uint16_t> m_axis;
|
||||
};
|
||||
|
||||
void Keypad::SetPadState(uint16_t keys)
|
||||
{
|
||||
m_keyinput = keys;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,129 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include "clock.hpp"
|
||||
|
||||
#include "memory.hpp"
|
||||
#include "io.hpp"
|
||||
#include "graphics/screen.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
#include <syg/signal.hpp>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Lcd
|
||||
{
|
||||
public :
|
||||
Lcd ();
|
||||
|
||||
void Reset ();
|
||||
|
||||
const uint16_t* GetSurface () const
|
||||
{
|
||||
return m_screen.GetSurface();
|
||||
}
|
||||
|
||||
Graphics::Screen& GetScreen()
|
||||
{
|
||||
return m_screen;
|
||||
}
|
||||
const Graphics::Screen& GetScreen() const
|
||||
{
|
||||
return m_screen;
|
||||
}
|
||||
|
||||
void SetFrameskip (uint8_t skip)
|
||||
{
|
||||
m_screen.SetFrameskip(skip);
|
||||
}
|
||||
|
||||
void UpdateDispCnt (uint16_t dispcnt)
|
||||
{
|
||||
m_screen.UpdateDispCnt(dispcnt);
|
||||
}
|
||||
|
||||
#define UPDATE_BG_CNT(num) \
|
||||
void UpdateBg##num##Cnt (uint16_t cnt) \
|
||||
{ \
|
||||
m_screen.UpdateBg##num##Cnt(cnt); \
|
||||
}
|
||||
UPDATE_BG_CNT(0)
|
||||
UPDATE_BG_CNT(1)
|
||||
UPDATE_BG_CNT(2)
|
||||
UPDATE_BG_CNT(3)
|
||||
#undef UPDATE_BG_CNT
|
||||
|
||||
#define UPDATE_BG_OFF(num, coord) \
|
||||
void UpdateBg##num##coord##Off (uint16_t cnt) \
|
||||
{ \
|
||||
m_screen.UpdateBg##num##coord##Off(cnt); \
|
||||
}
|
||||
UPDATE_BG_OFF(0, X)
|
||||
UPDATE_BG_OFF(0, Y)
|
||||
UPDATE_BG_OFF(1, X)
|
||||
UPDATE_BG_OFF(1, Y)
|
||||
UPDATE_BG_OFF(2, X)
|
||||
UPDATE_BG_OFF(2, Y)
|
||||
UPDATE_BG_OFF(3, X)
|
||||
UPDATE_BG_OFF(3, Y)
|
||||
#undef UPDATE_BG_OFF
|
||||
|
||||
#define UPDATE_BG_REF(num, coord) \
|
||||
void UpdateBg##num##Ref##coord (int32_t cnt) \
|
||||
{ \
|
||||
m_screen.UpdateBg##num##Ref##coord (cnt); \
|
||||
}
|
||||
UPDATE_BG_REF(2, X)
|
||||
UPDATE_BG_REF(2, Y)
|
||||
UPDATE_BG_REF(3, X)
|
||||
UPDATE_BG_REF(3, Y)
|
||||
#undef UPDATE_BG_REF
|
||||
|
||||
void OamWrite (uint32_t begin, uint32_t end)
|
||||
{
|
||||
m_screen.OamWrite(begin, end);
|
||||
}
|
||||
void OamWrite16 (uint32_t add)
|
||||
{
|
||||
m_screen.OamWrite16(add);
|
||||
}
|
||||
void OamWrite32 (uint32_t add)
|
||||
{
|
||||
m_screen.OamWrite32(add);
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
//syg::signal<void> sig_vblank;
|
||||
|
||||
private :
|
||||
Graphics::Screen m_screen;
|
||||
|
||||
void TimeEvent ();
|
||||
|
||||
friend void Clock::Commit();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,162 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __MEMORY_H__
|
||||
#define __MEMORY_H__
|
||||
|
||||
#include "cartmem.hpp"
|
||||
//XXX
|
||||
#include "eeprom.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Memory
|
||||
{
|
||||
public :
|
||||
// in cycles
|
||||
static const uint32_t CART_SAVE_TIME = 16*1024*1024; // 1 second
|
||||
|
||||
enum CartType
|
||||
{
|
||||
CTYPE_UNKNOWN,
|
||||
CTYPE_EEPROM512,
|
||||
CTYPE_EEPROM8192,
|
||||
CTYPE_FLASH64,
|
||||
CTYPE_FLASH128,
|
||||
CTYPE_SRAM
|
||||
};
|
||||
enum CartError
|
||||
{
|
||||
CERR_NO_ERROR,
|
||||
CERR_NOT_FOUND,
|
||||
CERR_FAIL
|
||||
};
|
||||
|
||||
Memory ();
|
||||
~Memory ();
|
||||
|
||||
uint8_t GetCartType () const
|
||||
{
|
||||
return m_carttype;
|
||||
}
|
||||
// erases cartridge memory
|
||||
void SetCartTypeFromSize (uint32_t size);
|
||||
void SetCartType (uint8_t type);
|
||||
//void SetCartFile (const char* filename)
|
||||
//{
|
||||
// m_cartfile = filename;
|
||||
//}
|
||||
|
||||
void Reset (uint32_t params = ~0);
|
||||
void ClearWbram ();
|
||||
void ClearWcram ();
|
||||
void ClearPalette ();
|
||||
void ClearVram ();
|
||||
void ClearOam ();
|
||||
void SoftReset ();
|
||||
|
||||
bool LoadBios (const char* filename);
|
||||
void LoadBios (const uint8_t* data, uint32_t size);
|
||||
void UnloadBios ()
|
||||
{
|
||||
if (m_brom)
|
||||
{
|
||||
delete [] m_brom;
|
||||
m_brom = NULL;
|
||||
}
|
||||
}
|
||||
bool LoadRom (const char* filename);
|
||||
void LoadRom (const uint8_t* data, uint32_t size);
|
||||
//CartError LoadCart ();
|
||||
bool LoadCart (const uint8_t* data, uint32_t size);
|
||||
bool SaveCart (uint8_t** data, uint32_t* size);
|
||||
void SaveCartDestroy(uint8_t* data);
|
||||
#ifdef __LIBRETRO__
|
||||
bool LoadCartInferred ();
|
||||
#endif
|
||||
bool HasCart () const
|
||||
{
|
||||
return m_cart;
|
||||
}
|
||||
|
||||
void DeleteCart();
|
||||
|
||||
bool HasBios () const
|
||||
{
|
||||
return m_brom;
|
||||
}
|
||||
|
||||
uint8_t GetCycles16NoSeq (uint32_t add, uint32_t count);
|
||||
uint8_t GetCycles16Seq (uint32_t add, uint32_t count);
|
||||
uint8_t GetCycles32NoSeq (uint32_t add, uint32_t count);
|
||||
uint8_t GetCycles32Seq (uint32_t add, uint32_t count);
|
||||
void UpdateWaitStates (uint16_t waitcnt);
|
||||
|
||||
uint8_t* GetRealAddress(uint32_t add, uint8_t size = 0);
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
uint8_t Peek8 (uint32_t add);
|
||||
|
||||
// TODO make const members
|
||||
uint8_t Read8 (uint32_t add);
|
||||
uint16_t Read16 (uint32_t add);
|
||||
uint32_t Read32 (uint32_t add);
|
||||
|
||||
void Write8 (uint32_t add, uint8_t val);
|
||||
void Write16 (uint32_t add, uint16_t val);
|
||||
void Write32 (uint32_t add, uint32_t val);
|
||||
|
||||
void WriteEepromDma (uint32_t src, uint16_t size);
|
||||
//void ReadEepromDma (uint32_t dest, uint16_t size);
|
||||
|
||||
void TimeEvent ();
|
||||
|
||||
uint8_t* GetMemoryArea(int which);
|
||||
|
||||
private :
|
||||
// times for a 8 or 16 bits access
|
||||
uint8_t m_memtime[0xF];
|
||||
// times for a sequential 8 or 16 bits access in GamePak ROM
|
||||
uint8_t m_memtimeseq[0x3];
|
||||
|
||||
// General Internal Memory
|
||||
uint8_t* m_brom; // BIOS - System ROM
|
||||
uint8_t* m_wbram; // WRAM - On-board Work RAM
|
||||
uint8_t* m_wcram; // WRAM - In-chip Work RAM
|
||||
// Internal Display Memory
|
||||
uint8_t* m_pram; // BG/OBJ Palette RAM
|
||||
uint8_t* m_vram; // VRAM - Video RAM
|
||||
uint8_t* m_oram; // OAM - OBJ Attributes
|
||||
// External Memory (Game Pak)
|
||||
uint8_t* m_rom; // Game Pake ROM/FlashROM (max 32MB)
|
||||
|
||||
uint8_t m_carttype;
|
||||
CartMem* m_cart;
|
||||
//std::string m_cartfile;
|
||||
|
||||
uint8_t ReadCart (uint16_t add);
|
||||
void WriteCart (uint16_t add, uint8_t val);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,117 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __SOUND_H__
|
||||
#define __SOUND_H__
|
||||
|
||||
#include "audio/speaker.hpp"
|
||||
#include "clock.hpp"
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Sound
|
||||
{
|
||||
public :
|
||||
Sound ();
|
||||
|
||||
void Reset ();
|
||||
|
||||
inline Audio::Speaker& GetSpeaker();
|
||||
|
||||
void UpdateCntH1 (uint8_t val);
|
||||
|
||||
inline void ResetSound1 ();
|
||||
inline void ResetSound2 ();
|
||||
inline void ResetSound4 ();
|
||||
|
||||
inline void ResetSound1Envelope ();
|
||||
inline void ResetSound2Envelope ();
|
||||
inline void ResetSound4Envelope ();
|
||||
|
||||
void TimerOverflow (uint8_t timernum);
|
||||
|
||||
inline void SendDigitalA (uint8_t* buffer);
|
||||
inline void SendDigitalB (uint8_t* buffer);
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
Audio::Speaker m_speaker;
|
||||
|
||||
uint8_t m_fATimer, m_fBTimer;
|
||||
|
||||
inline void TimerOverflowA ();
|
||||
inline void TimerOverflowB ();
|
||||
|
||||
void TimeEvent ()
|
||||
{
|
||||
m_speaker.SoundTick();
|
||||
}
|
||||
|
||||
friend void Clock::Commit ();
|
||||
};
|
||||
|
||||
inline Audio::Speaker& Sound::GetSpeaker()
|
||||
{
|
||||
return m_speaker;
|
||||
}
|
||||
|
||||
inline void Sound::ResetSound1 ()
|
||||
{
|
||||
m_speaker.ResetSound1();
|
||||
}
|
||||
|
||||
inline void Sound::ResetSound2 ()
|
||||
{
|
||||
m_speaker.ResetSound2();
|
||||
}
|
||||
|
||||
inline void Sound::ResetSound4 ()
|
||||
{
|
||||
m_speaker.ResetSound4();
|
||||
}
|
||||
|
||||
inline void Sound::ResetSound1Envelope ()
|
||||
{
|
||||
m_speaker.ResetSound1Envelope();
|
||||
}
|
||||
|
||||
inline void Sound::ResetSound2Envelope ()
|
||||
{
|
||||
m_speaker.ResetSound2Envelope();
|
||||
}
|
||||
|
||||
inline void Sound::ResetSound4Envelope ()
|
||||
{
|
||||
m_speaker.ResetSound4Envelope();
|
||||
}
|
||||
|
||||
inline void Sound::SendDigitalA (uint8_t* buffer)
|
||||
{
|
||||
m_speaker.FillFifoA((int8_t*)buffer);
|
||||
}
|
||||
|
||||
inline void Sound::SendDigitalB (uint8_t* buffer)
|
||||
{
|
||||
m_speaker.FillFifoB((int8_t*)buffer);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,56 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __SRAM_H__
|
||||
#define __SRAM_H__
|
||||
|
||||
#include "cartmem.hpp"
|
||||
#include <stdint.h>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Sram : public CartMem
|
||||
{
|
||||
public :
|
||||
Sram ();
|
||||
|
||||
void Reset ();
|
||||
|
||||
bool Load (std::istream& f);
|
||||
bool Save (std::ostream& f);
|
||||
|
||||
uint8_t Read (uint16_t add)
|
||||
{
|
||||
return m_data[add % SIZE];
|
||||
}
|
||||
bool Write (uint16_t add, uint8_t val)
|
||||
{
|
||||
m_data[add % SIZE] = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
static const uint16_t SIZE = 0x8000;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __SWAP_H__
|
||||
#define __SWAP_H__
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
inline uint16_t Swap16(uint16_t val)
|
||||
{
|
||||
return (val << 8) | (val >> 8);
|
||||
}
|
||||
|
||||
inline uint32_t Swap32(uint32_t val)
|
||||
{
|
||||
return (val << 24) |
|
||||
((val & 0x0000FF00) << 8) |
|
||||
((val & 0x00FF0000) >> 8) |
|
||||
(val >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,86 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __TIMER_H__
|
||||
#define __TIMER_H__
|
||||
|
||||
#include "clock.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
class Timer
|
||||
{
|
||||
public :
|
||||
Timer (int8_t num, Timer* next) :
|
||||
m_num(num),
|
||||
m_reload(0),
|
||||
m_count(0),
|
||||
m_control(0),
|
||||
m_next(next)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset ();
|
||||
|
||||
void SetReload (uint16_t rel)
|
||||
{
|
||||
m_reload = rel;
|
||||
}
|
||||
void Reload ();
|
||||
|
||||
uint16_t GetCount () const;
|
||||
|
||||
bool SaveState (std::ostream& stream);
|
||||
bool LoadState (std::istream& stream);
|
||||
|
||||
private :
|
||||
union Control
|
||||
{
|
||||
Control(uint16_t v) :
|
||||
w(v)
|
||||
{ }
|
||||
|
||||
uint16_t w;
|
||||
struct
|
||||
{
|
||||
unsigned int prescaler : 2;
|
||||
unsigned int countup : 1;
|
||||
unsigned int unused1 : 3;
|
||||
unsigned int irq : 1;
|
||||
unsigned int start : 1;
|
||||
unsigned int unused2 : 8;
|
||||
} b;
|
||||
};
|
||||
|
||||
const int8_t m_num;
|
||||
uint16_t m_reload;
|
||||
uint32_t m_count;
|
||||
Control m_control;
|
||||
|
||||
Timer* m_next;
|
||||
|
||||
void TimeEvent ();
|
||||
void Countup ();
|
||||
|
||||
friend void Clock::Commit();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,389 +0,0 @@
|
|||
#ifndef SYG_connection_HPP
|
||||
#define SYG_connection_HPP
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace syg
|
||||
{
|
||||
|
||||
//------------------------------
|
||||
// connections
|
||||
//------------------------------
|
||||
|
||||
template <typename Tret>
|
||||
class connection_base
|
||||
{
|
||||
public:
|
||||
virtual Tret call() const = 0;
|
||||
virtual connection_base<Tret>* clone() const = 0;
|
||||
virtual ~connection_base() {}
|
||||
};
|
||||
|
||||
template <typename Tret, typename Targ0>
|
||||
class connection_base1
|
||||
{
|
||||
public:
|
||||
virtual Tret call(Targ0) const = 0;
|
||||
virtual connection_base1<Tret, Targ0>* clone() const = 0;
|
||||
virtual ~connection_base1() {}
|
||||
};
|
||||
|
||||
template <typename Tret>
|
||||
class connection_func : public connection_base<Tret>
|
||||
{
|
||||
public:
|
||||
typedef Tret (*FuncPtr)();
|
||||
|
||||
connection_func(FuncPtr ptr):
|
||||
_func(ptr)
|
||||
{}
|
||||
|
||||
Tret call() const
|
||||
{
|
||||
return _func();
|
||||
}
|
||||
|
||||
connection_base<Tret>* clone() const
|
||||
{
|
||||
return new connection_func<Tret>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
FuncPtr _func;
|
||||
};
|
||||
|
||||
template <typename Tret, typename Targ0>
|
||||
class connection_func1 : public connection_base1<Tret, Targ0>
|
||||
{
|
||||
public:
|
||||
typedef Tret (*FuncPtr)(Targ0);
|
||||
|
||||
connection_func1(FuncPtr ptr):
|
||||
_func(ptr)
|
||||
{}
|
||||
|
||||
Tret call(Targ0 arg0) const
|
||||
{
|
||||
return _func(arg0);
|
||||
}
|
||||
|
||||
connection_base1<Tret, Targ0>* clone() const
|
||||
{
|
||||
return new connection_func1<Tret, Targ0>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
FuncPtr _func;
|
||||
};
|
||||
|
||||
template <typename Tobj, typename Tret>
|
||||
class connection_meth : public connection_base<Tret>
|
||||
{
|
||||
public:
|
||||
typedef Tobj TypeObj;
|
||||
typedef Tret (Tobj::*FuncPtr)();
|
||||
|
||||
connection_meth(TypeObj& obj, FuncPtr ptr):
|
||||
_obj(obj),
|
||||
_meth(ptr)
|
||||
{}
|
||||
|
||||
Tret call() const
|
||||
{
|
||||
return (_obj.*_meth)();
|
||||
}
|
||||
|
||||
connection_base<Tret>* clone() const
|
||||
{
|
||||
return new connection_meth<Tobj, Tret>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
Tobj& _obj;
|
||||
FuncPtr _meth;
|
||||
};
|
||||
|
||||
template <typename Tobj, typename Tret, typename Targ0>
|
||||
class connection_meth1 : public connection_base1<Tret, Targ0>
|
||||
{
|
||||
public:
|
||||
typedef Tobj TypeObj;
|
||||
typedef Tret (Tobj::*FuncPtr)(Targ0);
|
||||
|
||||
connection_meth1(TypeObj& obj, FuncPtr ptr):
|
||||
_obj(obj),
|
||||
_meth(ptr)
|
||||
{}
|
||||
|
||||
Tret call(Targ0 arg0) const
|
||||
{
|
||||
return (_obj.*_meth)(arg0);
|
||||
}
|
||||
|
||||
connection_base1<Tret, Targ0>* clone() const
|
||||
{
|
||||
return new connection_meth1<Tobj, Tret, Targ0>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
Tobj& _obj;
|
||||
FuncPtr _meth;
|
||||
};
|
||||
|
||||
//------------------------------
|
||||
// slots
|
||||
//------------------------------
|
||||
|
||||
template <typename Tret>
|
||||
class slot;
|
||||
|
||||
template <typename Tret, typename Targ0>
|
||||
class slot1;
|
||||
|
||||
template <typename Tret>
|
||||
slot<Tret> ptr_fun(Tret (*fun)());
|
||||
|
||||
template <typename Tobj, typename Tret>
|
||||
slot<Tret> mem_fun(Tobj& obj, Tret (Tobj::*fun)());
|
||||
|
||||
template <typename Tret, typename Targ0>
|
||||
slot1<Tret, Targ0> ptr_fun(Tret (*fun)(Targ0));
|
||||
|
||||
template <typename Tobj, typename Tret, typename Targ0>
|
||||
slot1<Tret, Targ0> mem_fun(Tobj& obj, Tret (Tobj::*fun)(Targ0));
|
||||
|
||||
template <typename Tret>
|
||||
class slot
|
||||
{
|
||||
public:
|
||||
slot():
|
||||
_conn(0)
|
||||
{}
|
||||
slot(const slot<Tret>& s)
|
||||
{
|
||||
*this = s;
|
||||
}
|
||||
~slot()
|
||||
{
|
||||
delete _conn;
|
||||
}
|
||||
|
||||
slot& operator=(const slot<Tret>& s)
|
||||
{
|
||||
if (s._conn)
|
||||
_conn = s._conn->clone();
|
||||
else
|
||||
_conn = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tret call() const
|
||||
{
|
||||
return _conn->call();
|
||||
}
|
||||
|
||||
Tret operator()() const
|
||||
{
|
||||
return call();
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return _conn;
|
||||
}
|
||||
|
||||
private:
|
||||
connection_base<Tret>* _conn;
|
||||
|
||||
slot(const connection_base<Tret>& conn):
|
||||
_conn(conn.clone())
|
||||
{}
|
||||
|
||||
friend slot<Tret> ptr_fun<Tret>(Tret (*fun)());
|
||||
|
||||
template <typename Tobj2, typename Tret2>
|
||||
friend slot<Tret2> mem_fun(Tobj2& obj, Tret2 (Tobj2::*fun)());
|
||||
};
|
||||
|
||||
template <typename Tret, typename Targ0>
|
||||
class slot1
|
||||
{
|
||||
public:
|
||||
typedef slot1<Tret, Targ0> SlotType;
|
||||
|
||||
slot1():
|
||||
_conn(0)
|
||||
{}
|
||||
slot1(const SlotType& s)
|
||||
{
|
||||
*this = s;
|
||||
}
|
||||
~slot1()
|
||||
{
|
||||
delete _conn;
|
||||
}
|
||||
|
||||
slot1& operator=(const SlotType& s)
|
||||
{
|
||||
if (s._conn)
|
||||
_conn = s._conn->clone();
|
||||
else
|
||||
_conn = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tret call(Targ0 arg0) const
|
||||
{
|
||||
return _conn->call(arg0);
|
||||
}
|
||||
|
||||
Tret operator()(Targ0 arg0) const
|
||||
{
|
||||
return call(arg0);
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return _conn;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef connection_base1<Tret, Targ0> Connection;
|
||||
|
||||
Connection* _conn;
|
||||
|
||||
slot1(const Connection& conn):
|
||||
_conn(conn.clone())
|
||||
{}
|
||||
|
||||
friend SlotType ptr_fun<Tret, Targ0>(Tret (*fun)(Targ0));
|
||||
|
||||
template <typename Tobj2, typename Tret2, typename Targ02>
|
||||
friend slot1<Tret2, Targ02> mem_fun(Tobj2& obj,
|
||||
Tret2 (Tobj2::*fun)(Targ02));
|
||||
};
|
||||
|
||||
template <typename Tret>
|
||||
inline slot<Tret> ptr_fun(Tret (*fun)())
|
||||
{
|
||||
return slot<Tret>(connection_func<Tret>(fun));
|
||||
}
|
||||
|
||||
template <typename Tobj, typename Tret>
|
||||
inline slot<Tret> mem_fun(Tobj& obj, Tret (Tobj::*fun)())
|
||||
{
|
||||
return slot<Tret>(connection_meth<Tobj, Tret>(obj, fun));
|
||||
}
|
||||
|
||||
template <typename Tret, typename Targ0>
|
||||
inline slot1<Tret, Targ0> ptr_fun(Tret (*fun)(Targ0))
|
||||
{
|
||||
return slot1<Tret, Targ0>(connection_func1<Tret, Targ0>(fun));
|
||||
}
|
||||
|
||||
template <typename Tobj, typename Tret, typename Targ0>
|
||||
inline slot1<Tret, Targ0> mem_fun(Tobj& obj, Tret (Tobj::*fun)(Targ0))
|
||||
{
|
||||
return slot1<Tret, Targ0>(connection_meth1<Tobj, Tret, Targ0>(obj, fun));
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
// signals
|
||||
//------------------------------
|
||||
/*
|
||||
template <typename Tret>
|
||||
class signal;
|
||||
|
||||
template <typename Tret>
|
||||
class connection
|
||||
{
|
||||
public:
|
||||
connection():
|
||||
_list(0)
|
||||
{
|
||||
}
|
||||
|
||||
void disconnect()
|
||||
{
|
||||
_list->erase(_iter);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::list<slot<Tret> > List;
|
||||
typedef typename List::iterator Iterator;
|
||||
|
||||
List* _list;
|
||||
Iterator _iter;
|
||||
|
||||
connection(List* list, Iterator iter):
|
||||
_list(list),
|
||||
_iter(iter)
|
||||
{}
|
||||
|
||||
friend class signal<Tret>;
|
||||
};
|
||||
|
||||
template <typename Tret>
|
||||
class signal
|
||||
{
|
||||
public:
|
||||
connection<Tret> connect(const slot<Tret> s)
|
||||
{
|
||||
_slots.push_back(s);
|
||||
return connection<Tret>(&_slots, (++_slots.rbegin()).base());
|
||||
}
|
||||
|
||||
Tret emit() const
|
||||
{
|
||||
for (typename Slots::const_iterator iter = _slots.begin(),
|
||||
end = (++_slots.rbegin()).base();
|
||||
iter != end; ++iter)
|
||||
iter->call();
|
||||
|
||||
return _slots.back().call();
|
||||
}
|
||||
|
||||
Tret operator()() const
|
||||
{
|
||||
return emit();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::list<slot<Tret> > Slots;
|
||||
|
||||
Slots _slots;
|
||||
};
|
||||
|
||||
template <typename Tret, typename Targ0>
|
||||
class signal1
|
||||
{
|
||||
public:
|
||||
void connect(const slot<Tret> s)
|
||||
{
|
||||
_slots.push_back(s);
|
||||
}
|
||||
|
||||
Tret emit(Targ0 arg0) const
|
||||
{
|
||||
for (typename Slots::const_iterator iter = _slots.begin(); iter != _slots.end() - 1; ++iter)
|
||||
iter->call();
|
||||
|
||||
return _slots.back().call(arg0);
|
||||
}
|
||||
|
||||
Tret operator()(Targ0 arg0) const
|
||||
{
|
||||
return emit(arg0);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::list<slot<Tret> > Slots;
|
||||
|
||||
Slots _slots;
|
||||
};
|
||||
*/
|
||||
} // namespace syg
|
||||
|
||||
#endif
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmeteor", "libmeteor.vcxproj", "{EE01E7C1-6FC4-497F-82CC-C7C64E3BF9D1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EE01E7C1-6FC4-497F-82CC-C7C64E3BF9D1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{EE01E7C1-6FC4-497F-82CC-C7C64E3BF9D1}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{EE01E7C1-6FC4-497F-82CC-C7C64E3BF9D1}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{EE01E7C1-6FC4-497F-82CC-C7C64E3BF9D1}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,173 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{EE01E7C1-6FC4-497F-82CC-C7C64E3BF9D1}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libmeteor</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(DXSDK_DIR)Include;$(IncludePath);include;include\ameteor</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(DXSDK_DIR)Include;$(IncludePath);include;include\ameteor</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);METDEBUG;METDEBUGLOG;_ITERATOR_DEBUG_LEVEL=0;NO_MEMMEM</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4396;4800</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBMETEOR_EXPORTS;%(PreprocessorDefinitions);NO_MEMMEM</PreprocessorDefinitions>
|
||||
<DisableSpecificWarnings>4396;4800</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="cinterface.cpp" />
|
||||
<ClCompile Include="source\ameteor.cpp" />
|
||||
<ClCompile Include="source\audio\dsound.cpp" />
|
||||
<ClCompile Include="source\audio\sound1.cpp" />
|
||||
<ClCompile Include="source\audio\sound2.cpp" />
|
||||
<ClCompile Include="source\audio\sound4.cpp" />
|
||||
<ClCompile Include="source\audio\speaker.cpp" />
|
||||
<ClCompile Include="source\bios.cpp" />
|
||||
<ClCompile Include="source\cartmem.cpp" />
|
||||
<ClCompile Include="source\clock.cpp" />
|
||||
<ClCompile Include="source\cpu.cpp" />
|
||||
<ClCompile Include="source\debug.cpp" />
|
||||
<ClCompile Include="source\disassembler\argimmediate.cpp" />
|
||||
<ClCompile Include="source\disassembler\argmulregisters.cpp" />
|
||||
<ClCompile Include="source\disassembler\argpsr.cpp" />
|
||||
<ClCompile Include="source\disassembler\argregister.cpp" />
|
||||
<ClCompile Include="source\disassembler\argrelative.cpp" />
|
||||
<ClCompile Include="source\disassembler\argshift.cpp" />
|
||||
<ClCompile Include="source\disassembler\arguimmediate.cpp" />
|
||||
<ClCompile Include="source\disassembler\arguments.cpp" />
|
||||
<ClCompile Include="source\disassembler\instruction.cpp" />
|
||||
<ClCompile Include="source\dma.cpp" />
|
||||
<ClCompile Include="source\eeprom.cpp" />
|
||||
<ClCompile Include="source\flash.cpp" />
|
||||
<ClCompile Include="source\graphics\bglayer.cpp" />
|
||||
<ClCompile Include="source\graphics\object.cpp" />
|
||||
<ClCompile Include="source\graphics\objects.cpp" />
|
||||
<ClCompile Include="source\graphics\renderer.cpp" />
|
||||
<ClCompile Include="source\graphics\screen.cpp" />
|
||||
<ClCompile Include="source\interpreter.cpp" />
|
||||
<ClCompile Include="source\interpreter_arm.cpp" />
|
||||
<ClCompile Include="source\interpreter_thumb.cpp" />
|
||||
<ClCompile Include="source\io.cpp" />
|
||||
<ClCompile Include="source\keypad.cpp" />
|
||||
<ClCompile Include="source\lcd.cpp" />
|
||||
<ClCompile Include="source\memory.cpp" />
|
||||
<ClCompile Include="source\sound.cpp" />
|
||||
<ClCompile Include="source\sram.cpp" />
|
||||
<ClCompile Include="source\timer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ameteor.hpp" />
|
||||
<ClInclude Include="include\ameteor\audio\dsound.hpp" />
|
||||
<ClInclude Include="include\ameteor\audio\sound1.hpp" />
|
||||
<ClInclude Include="include\ameteor\audio\sound2.hpp" />
|
||||
<ClInclude Include="include\ameteor\audio\sound4.hpp" />
|
||||
<ClInclude Include="include\ameteor\audio\speaker.hpp" />
|
||||
<ClInclude Include="include\ameteor\bios.hpp" />
|
||||
<ClInclude Include="include\ameteor\cartmem.hpp" />
|
||||
<ClInclude Include="include\ameteor\clock.hpp" />
|
||||
<ClInclude Include="include\ameteor\cpu.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\argimmediate.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\argmulregisters.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\argpsr.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\argregister.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\argrelative.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\argshift.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\arguimmediate.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\argument.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\arguments.hpp" />
|
||||
<ClInclude Include="include\ameteor\disassembler\instruction.hpp" />
|
||||
<ClInclude Include="include\ameteor\dma.hpp" />
|
||||
<ClInclude Include="include\ameteor\eeprom.hpp" />
|
||||
<ClInclude Include="include\ameteor\flash.hpp" />
|
||||
<ClInclude Include="include\ameteor\graphics\bglayer.hpp" />
|
||||
<ClInclude Include="include\ameteor\graphics\object.hpp" />
|
||||
<ClInclude Include="include\ameteor\graphics\objects.hpp" />
|
||||
<ClInclude Include="include\ameteor\graphics\renderer.hpp" />
|
||||
<ClInclude Include="include\ameteor\graphics\screen.hpp" />
|
||||
<ClInclude Include="include\ameteor\interpreter.hpp" />
|
||||
<ClInclude Include="include\ameteor\io.hpp" />
|
||||
<ClInclude Include="include\ameteor\keypad.hpp" />
|
||||
<ClInclude Include="include\ameteor\lcd.hpp" />
|
||||
<ClInclude Include="include\ameteor\memory.hpp" />
|
||||
<ClInclude Include="include\ameteor\sound.hpp" />
|
||||
<ClInclude Include="include\ameteor\sram.hpp" />
|
||||
<ClInclude Include="include\ameteor\swap.hpp" />
|
||||
<ClInclude Include="include\ameteor\timer.hpp" />
|
||||
<ClInclude Include="include\syg\signal.hpp" />
|
||||
<ClInclude Include="source\cpu_globals.hpp" />
|
||||
<ClInclude Include="source\debug.hpp" />
|
||||
<ClInclude Include="source\globals.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,288 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\audio">
|
||||
<UniqueIdentifier>{93df073d-6997-45f7-b85f-a285bca7b310}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\graphics">
|
||||
<UniqueIdentifier>{f134ab18-d00a-4652-ad25-5179aac22dbc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\disassembler">
|
||||
<UniqueIdentifier>{b152e4ad-8658-48a8-a214-3d9d1282fc70}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\syg">
|
||||
<UniqueIdentifier>{63c54b4d-45ec-46f4-923e-38f486e19909}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\ameteor">
|
||||
<UniqueIdentifier>{e3ba08fe-cf72-4aed-857c-697b3e437472}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\ameteor\audio">
|
||||
<UniqueIdentifier>{486541a1-445b-4012-8c31-218e65ea1e0b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\ameteor\graphics">
|
||||
<UniqueIdentifier>{66d5a4ba-681b-448c-8912-ecbb110d4896}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\ameteor\disassembler">
|
||||
<UniqueIdentifier>{a989399f-ba01-4804-ae68-ba5f363a2f9f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\cinterface">
|
||||
<UniqueIdentifier>{05542396-9b85-441b-beb8-8c49f126a881}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\ameteor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\bios.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\cartmem.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\clock.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\cpu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\debug.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\dma.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\eeprom.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\flash.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\interpreter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\interpreter_arm.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\interpreter_thumb.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\io.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\keypad.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\lcd.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\memory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\sound.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\sram.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\timer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\audio\dsound.cpp">
|
||||
<Filter>Source Files\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\audio\sound1.cpp">
|
||||
<Filter>Source Files\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\audio\sound2.cpp">
|
||||
<Filter>Source Files\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\audio\sound4.cpp">
|
||||
<Filter>Source Files\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\audio\speaker.cpp">
|
||||
<Filter>Source Files\audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\graphics\bglayer.cpp">
|
||||
<Filter>Source Files\graphics</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\graphics\object.cpp">
|
||||
<Filter>Source Files\graphics</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\graphics\objects.cpp">
|
||||
<Filter>Source Files\graphics</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\graphics\renderer.cpp">
|
||||
<Filter>Source Files\graphics</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\graphics\screen.cpp">
|
||||
<Filter>Source Files\graphics</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\argimmediate.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\argmulregisters.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\argpsr.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\argregister.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\argrelative.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\argshift.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\arguimmediate.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\arguments.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\disassembler\instruction.cpp">
|
||||
<Filter>Source Files\disassembler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cinterface.cpp">
|
||||
<Filter>Source Files\cinterface</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ameteor.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\syg\signal.hpp">
|
||||
<Filter>Header Files\syg</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\bios.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\cartmem.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\clock.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\cpu.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\dma.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\eeprom.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\flash.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\interpreter.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\io.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\keypad.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\lcd.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\memory.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\sound.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\sram.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\swap.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\timer.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\audio\dsound.hpp">
|
||||
<Filter>Header Files\ameteor\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\audio\sound1.hpp">
|
||||
<Filter>Header Files\ameteor\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\audio\sound2.hpp">
|
||||
<Filter>Header Files\ameteor\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\audio\sound4.hpp">
|
||||
<Filter>Header Files\ameteor\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\audio\speaker.hpp">
|
||||
<Filter>Header Files\ameteor\audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\graphics\bglayer.hpp">
|
||||
<Filter>Header Files\ameteor\graphics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\graphics\object.hpp">
|
||||
<Filter>Header Files\ameteor\graphics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\graphics\objects.hpp">
|
||||
<Filter>Header Files\ameteor\graphics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\graphics\renderer.hpp">
|
||||
<Filter>Header Files\ameteor\graphics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\graphics\screen.hpp">
|
||||
<Filter>Header Files\ameteor\graphics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\argimmediate.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\argmulregisters.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\argpsr.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\argregister.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\argrelative.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\argshift.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\arguimmediate.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\argument.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\arguments.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ameteor\disassembler\instruction.hpp">
|
||||
<Filter>Header Files\ameteor\disassembler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\cpu_globals.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\debug.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\globals.hpp">
|
||||
<Filter>Header Files\ameteor</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,204 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "globals.hpp"
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
// TODO add version
|
||||
#define SS_MAGIC_STRING ("AMeteor SaveState")
|
||||
#define SS_MS_SIZE (sizeof(SS_MAGIC_STRING)-1)
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace
|
||||
{
|
||||
class AMeteor
|
||||
{
|
||||
public :
|
||||
AMeteor ()
|
||||
{
|
||||
Audio::InitNoise();
|
||||
}
|
||||
} __ameteor;
|
||||
}
|
||||
|
||||
// the clock must be initialized first since there are devices like
|
||||
// lcd which needs to set the timer
|
||||
Clock _clock;
|
||||
Io _io;
|
||||
// the interpreter (which is in the cpu) takes io addresses, thus the
|
||||
// cpu must be initialized after io
|
||||
Interpreter _cpu;
|
||||
Memory _memory;
|
||||
Dma _dma;
|
||||
// the lcd must be initialized after the memory since it takes
|
||||
// pointers from it
|
||||
Lcd _lcd;
|
||||
// the sound must be initialized after the io since it takes references
|
||||
// from it
|
||||
Sound _sound;
|
||||
// the keypad needs to take the vblank event from lcd, so it must be
|
||||
// initialized after lcd
|
||||
// it must also be initialized after io since it takes the keyinput
|
||||
// reference
|
||||
Keypad _keypad;
|
||||
Timer _timer3(3, NULL);
|
||||
Timer _timer2(2, &_timer3);
|
||||
Timer _timer1(1, &_timer2);
|
||||
Timer _timer0(0, &_timer1);
|
||||
|
||||
void Reset (uint32_t units)
|
||||
{
|
||||
#define RESET(u, e) \
|
||||
if (units & UNIT_##e) \
|
||||
_##u.Reset();
|
||||
RESET(clock, CLOCK);
|
||||
RESET(io, IO);
|
||||
RESET(cpu, CPU);
|
||||
RESET(dma, DMA);
|
||||
RESET(lcd, LCD);
|
||||
RESET(sound, SOUND);
|
||||
RESET(keypad, KEYPAD);
|
||||
RESET(timer0, TIMER0);
|
||||
RESET(timer1, TIMER1);
|
||||
RESET(timer2, TIMER2);
|
||||
RESET(timer3, TIMER3);
|
||||
#undef RESET
|
||||
if (units & UNIT_MEMORY)
|
||||
_memory.Reset(units);
|
||||
}
|
||||
|
||||
bool SaveState (const char* filename)
|
||||
{
|
||||
if (_cpu.IsRunning())
|
||||
return false;
|
||||
|
||||
std::ostringstream ss;
|
||||
|
||||
if (!SaveState(ss))
|
||||
return false;
|
||||
|
||||
std::ofstream file(filename);
|
||||
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
std::string buf = ss.str();
|
||||
if (!file.write(buf.c_str(), buf.length()))
|
||||
return false;
|
||||
|
||||
file.close();
|
||||
if (file.bad())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadState (const char* filename)
|
||||
{
|
||||
if (_cpu.IsRunning())
|
||||
return false;
|
||||
|
||||
std::istringstream ss;
|
||||
{
|
||||
std::ifstream file(filename);
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
// 1Mo
|
||||
std::vector<uint8_t> buf(0x100000);
|
||||
if (file.read((char*)&buf[0], 0x100000).bad())
|
||||
return false;
|
||||
int nread = file.gcount();
|
||||
|
||||
file.close();
|
||||
if (file.bad())
|
||||
return false;
|
||||
|
||||
ss.str(std::string((char*)&buf[0], nread));
|
||||
}
|
||||
|
||||
return LoadState(ss);
|
||||
}
|
||||
|
||||
bool SaveState (std::ostream& stream)
|
||||
{
|
||||
if (_cpu.IsRunning())
|
||||
return false;
|
||||
|
||||
SS_WRITE_DATA(SS_MAGIC_STRING, SS_MS_SIZE);
|
||||
|
||||
#define SAVE(dev) \
|
||||
if (!dev.SaveState(stream)) \
|
||||
return false
|
||||
SAVE(_clock);
|
||||
SAVE(_io);
|
||||
SAVE(_cpu);
|
||||
SAVE(_memory);
|
||||
SAVE(_dma);
|
||||
SAVE(_lcd);
|
||||
SAVE(_sound);
|
||||
//SAVE(_keypad);
|
||||
SAVE(_timer0);
|
||||
SAVE(_timer1);
|
||||
SAVE(_timer2);
|
||||
SAVE(_timer3);
|
||||
#undef SAVE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadState (std::istream& stream)
|
||||
{
|
||||
if (_cpu.IsRunning())
|
||||
return false;
|
||||
|
||||
{
|
||||
char buf[SS_MS_SIZE];
|
||||
SS_READ_DATA(buf, SS_MS_SIZE);
|
||||
if (std::memcmp(buf, SS_MAGIC_STRING, SS_MS_SIZE))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#define LOAD(dev) \
|
||||
if (!dev.LoadState(stream)) \
|
||||
return false
|
||||
LOAD(_clock);
|
||||
LOAD(_io);
|
||||
LOAD(_cpu);
|
||||
LOAD(_memory);
|
||||
LOAD(_dma);
|
||||
LOAD(_lcd);
|
||||
LOAD(_sound);
|
||||
//LOAD(_keypad);
|
||||
LOAD(_timer0);
|
||||
LOAD(_timer1);
|
||||
LOAD(_timer2);
|
||||
LOAD(_timer3);
|
||||
#undef LOAD
|
||||
|
||||
uint8_t xxx;
|
||||
// if there is garbage at end of file
|
||||
if (stream.read((char*)&xxx, 1))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/audio/dsound.hpp"
|
||||
#include "../globals.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
DSound::DSound () :
|
||||
m_rpos(0),
|
||||
m_wpos(0),
|
||||
m_size(0)
|
||||
{
|
||||
std::memset(m_buffer, 0, sizeof(m_buffer));
|
||||
}
|
||||
|
||||
void DSound::FillFifo (int8_t* buffer)
|
||||
{
|
||||
int8_t* pmbuf = m_buffer + m_wpos;
|
||||
// we copy 16 bytes of data
|
||||
for (int8_t* pbuf = buffer;
|
||||
pbuf < buffer + BUFFER_SIZE/2 && m_size < 32; ++pbuf, ++pmbuf)
|
||||
{
|
||||
if (pmbuf >= m_buffer + BUFFER_SIZE)
|
||||
pmbuf = m_buffer;
|
||||
|
||||
*pmbuf = *pbuf;
|
||||
++m_size;
|
||||
}
|
||||
|
||||
m_wpos = pmbuf - m_buffer;
|
||||
}
|
||||
|
||||
void DSound::FillFifo (int8_t sample)
|
||||
{
|
||||
if (m_size == 32)
|
||||
return;
|
||||
if (m_wpos == BUFFER_SIZE)
|
||||
m_wpos = 0;
|
||||
m_buffer[m_wpos++] = sample;
|
||||
++m_size;
|
||||
}
|
||||
|
||||
bool DSound::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_rpos);
|
||||
SS_WRITE_VAR(m_wpos);
|
||||
SS_WRITE_VAR(m_size);
|
||||
|
||||
SS_WRITE_ARRAY(m_buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSound::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_rpos);
|
||||
SS_READ_VAR(m_wpos);
|
||||
SS_READ_VAR(m_size);
|
||||
|
||||
SS_READ_ARRAY(m_buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/audio/sound1.hpp"
|
||||
#include "../globals.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
Sound1::Sound1 (uint16_t& cntl, uint16_t& cnth, uint16_t& cntx,
|
||||
uint16_t freq) :
|
||||
m_cntl(cntl),
|
||||
m_cnth(cnth),
|
||||
m_cntx(cntx),
|
||||
m_on(false),
|
||||
m_posP(0),
|
||||
m_posS(0),
|
||||
m_posE(0),
|
||||
m_sample(0),
|
||||
m_speriod(16*1024*1024/freq),
|
||||
m_envelope(0),
|
||||
m_length(0),
|
||||
m_timed(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Sound1::Reset ()
|
||||
{
|
||||
m_on = false;
|
||||
m_timed = false;
|
||||
m_length = 0;
|
||||
m_envelope = 0;
|
||||
m_posP = m_posE = m_posS = 0;
|
||||
m_sample = 0;
|
||||
}
|
||||
|
||||
void Sound1::ResetSound ()
|
||||
{
|
||||
m_on = true;
|
||||
m_timed = (m_cntx & (0x1 << 14));
|
||||
m_length = (64 - (m_cnth & 0x3F)) * ((16*1024*1024)/256);
|
||||
m_envelope = m_cnth >> 12;
|
||||
m_posE = m_posS = 0;
|
||||
}
|
||||
|
||||
void Sound1::SoundTick ()
|
||||
{
|
||||
// remember here that the processors runs at 16MHz = 16,777,216 cycles/s
|
||||
// and this function is called normally at 44,100 Hz
|
||||
|
||||
m_posP += m_speriod;
|
||||
m_posS += m_speriod;
|
||||
m_posE += m_speriod;
|
||||
if (m_length > m_speriod)
|
||||
m_length -= m_speriod;
|
||||
else
|
||||
{
|
||||
if (m_timed)
|
||||
m_on = false;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
// sweep time in cycles
|
||||
// maximum is 917,504, so we need a 32 bits int
|
||||
uint32_t sweeptime = ((m_cntl >> 4) & 0x7) * ((16*1024*1024)/128);
|
||||
// period in cycles
|
||||
// period = 16M/freq
|
||||
// freq = 128K/(2048 - (SOUND1CNT_X & 0x7FF))
|
||||
// maximum is 262,144, so we need a 32 bits int
|
||||
uint32_t period =
|
||||
((16*1024*1024) / (128*1024)) * (2048 - (m_cntx & 0x7FF));
|
||||
// frequency as contained in SOUND1CNT_X
|
||||
uint16_t freq = m_cntx & 0x7FF;
|
||||
|
||||
// we rewind posP
|
||||
m_posP %= period;
|
||||
|
||||
// the envelope now
|
||||
// envelope step time in cycles
|
||||
uint32_t steptime = ((m_cnth >> 8) & 0x7) * ((16*1024*1024)/64);
|
||||
// the envelope can't do two steps between to calls of SoundTick
|
||||
if (steptime && m_posE > steptime)
|
||||
{
|
||||
if (m_cnth & (0x1 << 11))
|
||||
{
|
||||
if (m_envelope < 15)
|
||||
++m_envelope;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_envelope > 0)
|
||||
--m_envelope;
|
||||
}
|
||||
|
||||
m_posE -= steptime;
|
||||
}
|
||||
|
||||
// if the envelope is null or the sound is finished, no need to calculate
|
||||
// anything
|
||||
if (m_on && m_envelope)
|
||||
{
|
||||
// we set the sample according to the position in the current period
|
||||
// and the wave duty cycle
|
||||
switch ((m_cnth >> 6) & 0x3)
|
||||
{
|
||||
case 0: // 12.5%
|
||||
m_sample = m_posP < period/8 ? 112 : -16;
|
||||
break;
|
||||
case 1: // 25%
|
||||
m_sample = m_posP < period/4 ? 96 : -32;
|
||||
break;
|
||||
case 2: // 50%
|
||||
m_sample = m_posP < period/2 ? 64 : -64;
|
||||
break;
|
||||
case 3: // 75%
|
||||
m_sample = m_posP < (3*period)/4 ? 32 : -96;
|
||||
break;
|
||||
}
|
||||
|
||||
m_sample = (((int16_t)m_sample) * m_envelope)/15;
|
||||
}
|
||||
else
|
||||
m_sample = 0;
|
||||
|
||||
// there can't have been more than one sweep between two call of
|
||||
// SoundTick since SoundTick is called at least at a frequency of 4,000Hz
|
||||
// (alsa can't output at a lower samplerate on my sound card) and sweeps
|
||||
// happen at maximum at a frequency of 128Hz
|
||||
|
||||
// if the channel is on and sweep is enabled and it's time to sweep
|
||||
if (m_on && sweeptime && m_posS > sweeptime)
|
||||
{
|
||||
// n = sweep shifts (in SOUND1CNT_L)
|
||||
if (m_cntl & (0x1 << 3))
|
||||
// F(t+1) = F(t) - F(t) / 2^n
|
||||
freq = freq - freq / (1 << (m_cntl & 0x7));
|
||||
// freq won't go under 1 since when freq = 2, freq - freq / 2 (the
|
||||
// minimum sweep shift) = 1 and then freq - freq / 2 = 1
|
||||
// because 1/2 = 0
|
||||
else
|
||||
{
|
||||
// F(t+1) = F(t) + F(t) / 2^n
|
||||
freq = freq + freq / (1 << (m_cntl & 0x7));
|
||||
if (freq > 2047)
|
||||
{
|
||||
m_on = false;
|
||||
freq = 2047;
|
||||
}
|
||||
}
|
||||
|
||||
// we update the frequency in the cntx register
|
||||
m_cntx = (m_cntx & 0xF800) | freq;
|
||||
|
||||
// now we rewind posS
|
||||
m_posS -= sweeptime;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sound1::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_on);
|
||||
SS_WRITE_VAR(m_posP);
|
||||
SS_WRITE_VAR(m_posS);
|
||||
SS_WRITE_VAR(m_posE);
|
||||
SS_WRITE_VAR(m_sample);
|
||||
SS_WRITE_VAR(m_envelope);
|
||||
SS_WRITE_VAR(m_length);
|
||||
SS_WRITE_VAR(m_timed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sound1::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_on);
|
||||
SS_READ_VAR(m_posP);
|
||||
SS_READ_VAR(m_posS);
|
||||
SS_READ_VAR(m_posE);
|
||||
SS_READ_VAR(m_sample);
|
||||
SS_READ_VAR(m_envelope);
|
||||
SS_READ_VAR(m_length);
|
||||
SS_READ_VAR(m_timed);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/audio/sound2.hpp"
|
||||
#include "../globals.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
Sound2::Sound2 (uint16_t& cntl, uint16_t& cnth, uint16_t freq) :
|
||||
m_cntl(cntl),
|
||||
m_cnth(cnth),
|
||||
m_on(false),
|
||||
m_posP(0),
|
||||
m_posE(0),
|
||||
m_sample(0),
|
||||
m_speriod(16*1024*1024/freq),
|
||||
m_envelope(0),
|
||||
m_length(0),
|
||||
m_timed(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Sound2::Reset ()
|
||||
{
|
||||
m_on = false;
|
||||
m_timed = false;
|
||||
m_length = 0;
|
||||
m_envelope = 0;
|
||||
m_posP = m_posE = 0;
|
||||
m_sample = 0;
|
||||
}
|
||||
|
||||
void Sound2::ResetSound ()
|
||||
{
|
||||
m_on = true;
|
||||
m_timed = (m_cnth & (0x1 << 14));
|
||||
m_length = (64 - (m_cntl & 0x3F)) * ((16*1024*1024)/256);
|
||||
m_envelope = m_cntl >> 12;
|
||||
m_posE = 0;
|
||||
}
|
||||
|
||||
void Sound2::SoundTick ()
|
||||
{
|
||||
// refer at sound1 to know how sound2 works
|
||||
|
||||
m_posP += m_speriod;
|
||||
m_posE += m_speriod;
|
||||
if (m_length > m_speriod)
|
||||
m_length -= m_speriod;
|
||||
else
|
||||
{
|
||||
if (m_timed)
|
||||
m_on = false;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
uint32_t period =
|
||||
((16*1024*1024) / (128*1024)) * (2048 - (m_cnth & 0x7FF));
|
||||
|
||||
m_posP %= period;
|
||||
|
||||
uint32_t steptime = ((m_cntl >> 8) & 0x7) * ((16*1024*1024)/64);
|
||||
if (steptime && m_posE > steptime)
|
||||
{
|
||||
if (m_cntl & (0x1 << 11))
|
||||
{
|
||||
if (m_envelope < 15)
|
||||
++m_envelope;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_envelope > 0)
|
||||
--m_envelope;
|
||||
}
|
||||
|
||||
m_posE -= steptime;
|
||||
}
|
||||
|
||||
if (m_on && m_envelope)
|
||||
{
|
||||
switch ((m_cntl >> 6) & 0x3)
|
||||
{
|
||||
case 0: // 12.5%
|
||||
m_sample = m_posP < period/8 ? 112 : -16;
|
||||
break;
|
||||
case 1: // 25%
|
||||
m_sample = m_posP < period/4 ? 96 : -32;
|
||||
break;
|
||||
case 2: // 50%
|
||||
m_sample = m_posP < period/2 ? 64 : -64;
|
||||
break;
|
||||
case 3: // 75%
|
||||
m_sample = m_posP < (3*period)/4 ? 32 : -96;
|
||||
break;
|
||||
}
|
||||
|
||||
m_sample = (((int16_t)m_sample) * m_envelope)/15;
|
||||
}
|
||||
else
|
||||
m_sample = 0;
|
||||
}
|
||||
|
||||
bool Sound2::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_on);
|
||||
SS_WRITE_VAR(m_posP);
|
||||
SS_WRITE_VAR(m_posE);
|
||||
SS_WRITE_VAR(m_sample);
|
||||
SS_WRITE_VAR(m_envelope);
|
||||
SS_WRITE_VAR(m_length);
|
||||
SS_WRITE_VAR(m_timed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sound2::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_on);
|
||||
SS_READ_VAR(m_posP);
|
||||
SS_READ_VAR(m_posE);
|
||||
SS_READ_VAR(m_sample);
|
||||
SS_READ_VAR(m_envelope);
|
||||
SS_READ_VAR(m_length);
|
||||
SS_READ_VAR(m_timed);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/audio/sound4.hpp"
|
||||
#include "../globals.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
static bool Noise7Stages[127];
|
||||
static bool Noise15Stages[32767];
|
||||
|
||||
void InitNoise ()
|
||||
{
|
||||
unsigned short i = 0x7f;
|
||||
bool* pNoise = Noise7Stages;
|
||||
do
|
||||
{
|
||||
*pNoise++ = i & 1;
|
||||
i = (i >> 1) | (((i & 1) << 6) ^ ((i & 2) << 5));
|
||||
} while (i != 0x7f);
|
||||
|
||||
i = 0x7fff;
|
||||
pNoise = Noise15Stages;
|
||||
do
|
||||
{
|
||||
*pNoise++ = i & 1;
|
||||
i = (i >> 1) | (((i & 1) << 14) ^ ((i & 2) << 13));
|
||||
} while (i != 0x7fff);
|
||||
}
|
||||
|
||||
Sound4::Sound4 (uint16_t& cntl, uint16_t& cnth, uint16_t freq) :
|
||||
m_cntl(cntl),
|
||||
m_cnth(cnth),
|
||||
m_on(false),
|
||||
m_posP(0),
|
||||
m_posN(0),
|
||||
m_posE(0),
|
||||
m_sample(0),
|
||||
m_speriod(16*1024*1024/freq),
|
||||
m_envelope(0),
|
||||
m_length(0),
|
||||
m_timed(false),
|
||||
m_div(4*8/2)
|
||||
{
|
||||
}
|
||||
|
||||
void Sound4::Reset ()
|
||||
{
|
||||
m_on = false;
|
||||
m_timed = false;
|
||||
m_length = 0;
|
||||
m_envelope = 0;
|
||||
m_posP = m_posE = m_posN = 0;
|
||||
m_sample = 0;
|
||||
m_div = 4*8/2;
|
||||
}
|
||||
|
||||
void Sound4::ResetSound ()
|
||||
{
|
||||
m_on = true;
|
||||
m_timed = (m_cnth & (0x1 << 14));
|
||||
m_length = (64 - (m_cntl & 0x3F)) * ((16*1024*1024)/256);
|
||||
m_envelope = m_cntl >> 12;
|
||||
m_div = ((m_cnth & 0x7) ? 4*8*(m_cnth & 0x7) : 4*8/2);
|
||||
m_posE = m_posP = 0;
|
||||
}
|
||||
|
||||
void Sound4::SoundTick ()
|
||||
{
|
||||
// rest is the number of processor clock ticks that were not yet taken by
|
||||
// the noise clock divider (if the total divider is 8 and we have 10
|
||||
// ticks of the processor clock, only 8 were taken by the noise clock),
|
||||
// the rest will be taken by the next call of SoundTick()
|
||||
uint16_t rest = m_posP + m_speriod;
|
||||
// advance is the number of noise ticks that have passed
|
||||
uint16_t advance = m_posP + m_speriod;
|
||||
|
||||
// time of one sound tick in cycles
|
||||
uint32_t tick = m_div;
|
||||
// if shift is 111X in binary
|
||||
if (((m_cnth >> 5) & 0x7) == 0x7)
|
||||
// not used
|
||||
// assume 13
|
||||
tick *= 1 << 14;
|
||||
else
|
||||
tick *= (2 << ((m_cnth >> 4) & 0xF));
|
||||
|
||||
rest %= tick;
|
||||
advance /= tick;
|
||||
|
||||
m_posP = rest;
|
||||
m_posN += advance;
|
||||
// we have this modulo on posN so that when you switch from 15 stages to
|
||||
// 7 stages and then you switch back, you won't restart the 15 stages
|
||||
// pattern from the beginning
|
||||
// don't know if GBA handle this like that
|
||||
m_posN %= 32768;
|
||||
|
||||
m_posE += m_speriod;
|
||||
if (m_length > m_speriod)
|
||||
m_length -= m_speriod;
|
||||
else
|
||||
{
|
||||
if (m_timed)
|
||||
m_on = false;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
uint32_t steptime = ((m_cntl >> 8) & 0x7) * ((16*1024*1024)/64);
|
||||
if (steptime && m_posE > steptime)
|
||||
{
|
||||
if (m_cnth & (0x1 << 11))
|
||||
{
|
||||
if (m_envelope < 15)
|
||||
++m_envelope;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_envelope > 0)
|
||||
--m_envelope;
|
||||
}
|
||||
|
||||
m_posE -= steptime;
|
||||
}
|
||||
|
||||
if (m_on && m_envelope)
|
||||
{
|
||||
if (m_cnth & (0x1 << 3))
|
||||
m_sample = Noise7Stages[m_posN % 128];
|
||||
else
|
||||
m_sample = Noise15Stages[m_posN];
|
||||
|
||||
m_sample = m_sample ? 127 : -127;
|
||||
m_sample = (((int16_t)m_sample) * m_envelope)/15;
|
||||
}
|
||||
else
|
||||
m_sample = 0;
|
||||
}
|
||||
|
||||
bool Sound4::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_on);
|
||||
SS_WRITE_VAR(m_posP);
|
||||
SS_WRITE_VAR(m_posE);
|
||||
SS_WRITE_VAR(m_posN);
|
||||
SS_WRITE_VAR(m_sample);
|
||||
SS_WRITE_VAR(m_envelope);
|
||||
SS_WRITE_VAR(m_length);
|
||||
SS_WRITE_VAR(m_timed);
|
||||
SS_WRITE_VAR(m_div);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sound4::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_on);
|
||||
SS_READ_VAR(m_posP);
|
||||
SS_READ_VAR(m_posE);
|
||||
SS_READ_VAR(m_posN);
|
||||
SS_READ_VAR(m_sample);
|
||||
SS_READ_VAR(m_envelope);
|
||||
SS_READ_VAR(m_length);
|
||||
SS_READ_VAR(m_timed);
|
||||
SS_READ_VAR(m_div);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/audio/speaker.hpp"
|
||||
#include "../debug.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Audio
|
||||
{
|
||||
Speaker::Speaker (uint16_t& cnt1l, uint16_t& cnt1h, uint16_t& cnt1x,
|
||||
uint16_t& cnt2l, uint16_t& cnt2h,
|
||||
uint16_t& cnt4l, uint16_t& cnt4h,
|
||||
uint16_t& cntl, uint16_t& cnth, uint16_t& cntx, uint16_t& bias) :
|
||||
// XXX freq
|
||||
m_sound1(cnt1l, cnt1h, cnt1x, 44100),
|
||||
m_sound2(cnt2l, cnt2h, 44100),
|
||||
m_sound4(cnt4l, cnt4h, 44100),
|
||||
m_cntl(cntl),
|
||||
m_cnth(cnth),
|
||||
m_cntx(cntx),
|
||||
m_bias(bias)
|
||||
{
|
||||
}
|
||||
|
||||
Speaker::~Speaker ()
|
||||
{
|
||||
}
|
||||
|
||||
void Speaker::Reset ()
|
||||
{
|
||||
m_sound1.Reset();
|
||||
m_sound2.Reset();
|
||||
m_sound4.Reset();
|
||||
m_dsa.Reset();
|
||||
m_dsb.Reset();
|
||||
}
|
||||
|
||||
void Speaker::SoundTick ()
|
||||
{
|
||||
int16_t f[2];
|
||||
|
||||
// if master is enabled
|
||||
if (m_cntx & (0x1 << 7))
|
||||
{
|
||||
m_sound1.SoundTick();
|
||||
if (m_sound1.IsOn())
|
||||
m_cntx |= 0x0001;
|
||||
else
|
||||
m_cntx &= 0xFFFE;
|
||||
m_sound2.SoundTick();
|
||||
if (m_sound2.IsOn())
|
||||
m_cntx |= 0x0002;
|
||||
else
|
||||
m_cntx &= 0xFFFD;
|
||||
m_sound4.SoundTick();
|
||||
if (m_sound4.IsOn())
|
||||
m_cntx |= 0x0008;
|
||||
else
|
||||
m_cntx &= 0xFFF7;
|
||||
}
|
||||
|
||||
// left
|
||||
f[0] = MixSample (m_cntl >> 4, m_cnth >> 9);
|
||||
// right
|
||||
f[1] = MixSample (m_cntl, m_cnth >> 8);
|
||||
|
||||
m_sig_frame(f);
|
||||
}
|
||||
|
||||
int16_t Speaker::MixSample (uint16_t cntl, uint8_t cnth)
|
||||
{
|
||||
int16_t sample;
|
||||
|
||||
// if master is enabled
|
||||
if (m_cntx & (0x1 << 7))
|
||||
{
|
||||
int8_t s1, s2, s4;
|
||||
s1 = (cntl & (0x1 << 8)) ? m_sound1.GetSample() : 0;
|
||||
s2 = (cntl & (0x1 << 9)) ? m_sound2.GetSample() : 0;
|
||||
s4 = (cntl & (0x1 << 11)) ? m_sound4.GetSample() : 0;
|
||||
|
||||
int16_t dmg = s1 + s2 + s4;
|
||||
dmg = (dmg * (cntl & 0x7)) / 7;
|
||||
switch (m_cnth & 0x3)
|
||||
{
|
||||
case 0: // 25%
|
||||
dmg /= 4;
|
||||
break;
|
||||
case 1: // 50%
|
||||
dmg /= 2;
|
||||
break;
|
||||
case 2: // 100%
|
||||
break;
|
||||
case 3: // Prohibited
|
||||
met_abort("Invalid SOUNDCNT_H sound # 1-4 volume");
|
||||
break;
|
||||
}
|
||||
|
||||
int16_t sA, sB;
|
||||
sA = (cnth & (0x1 )) ? m_dsa.GetSample() : 0;
|
||||
sB = (cnth & (0x1 << 4)) ? m_dsb.GetSample() : 0;
|
||||
|
||||
if (!(m_cnth & (0x1 << 2)))
|
||||
sA /= 2;
|
||||
if (!(m_cnth & (0x1 << 3)))
|
||||
sB /= 2;
|
||||
|
||||
// TODO when finished put this all together on one line
|
||||
sample = (sA + sB) * 4 + dmg;
|
||||
}
|
||||
else
|
||||
sample = 0;
|
||||
|
||||
sample += m_bias & 0x3FF;
|
||||
if (sample < 0)
|
||||
sample = 0;
|
||||
else if (sample >= 0x400)
|
||||
sample = 0x3FF;
|
||||
sample -= 0x200;
|
||||
sample <<= 6;
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
bool Speaker::SaveState (std::ostream& stream)
|
||||
{
|
||||
#define WRITE(var) \
|
||||
if (!var.SaveState(stream)) \
|
||||
return false
|
||||
WRITE(m_sound1);
|
||||
WRITE(m_sound2);
|
||||
WRITE(m_sound4);
|
||||
WRITE(m_dsa);
|
||||
WRITE(m_dsb);
|
||||
#undef WRITE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Speaker::LoadState (std::istream& stream)
|
||||
{
|
||||
#define READ(var) \
|
||||
if (!var.LoadState(stream)) \
|
||||
return false
|
||||
READ(m_sound1);
|
||||
READ(m_sound2);
|
||||
READ(m_sound4);
|
||||
READ(m_dsa);
|
||||
READ(m_dsb);
|
||||
#undef READ
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,919 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/bios.hpp"
|
||||
#include "ameteor/cpu.hpp"
|
||||
#include "ameteor/memory.hpp"
|
||||
|
||||
#include "globals.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Bios
|
||||
{
|
||||
static const int16_t sineTable[256] = {
|
||||
(int16_t)0x0000, (int16_t)0x0192, (int16_t)0x0323, (int16_t)0x04B5,
|
||||
(int16_t)0x0645, (int16_t)0x07D5, (int16_t)0x0964, (int16_t)0x0AF1,
|
||||
(int16_t)0x0C7C, (int16_t)0x0E05, (int16_t)0x0F8C, (int16_t)0x1111,
|
||||
(int16_t)0x1294, (int16_t)0x1413, (int16_t)0x158F, (int16_t)0x1708,
|
||||
(int16_t)0x187D, (int16_t)0x19EF, (int16_t)0x1B5D, (int16_t)0x1CC6,
|
||||
(int16_t)0x1E2B, (int16_t)0x1F8B, (int16_t)0x20E7, (int16_t)0x223D,
|
||||
(int16_t)0x238E, (int16_t)0x24DA, (int16_t)0x261F, (int16_t)0x275F,
|
||||
(int16_t)0x2899, (int16_t)0x29CD, (int16_t)0x2AFA, (int16_t)0x2C21,
|
||||
(int16_t)0x2D41, (int16_t)0x2E5A, (int16_t)0x2F6B, (int16_t)0x3076,
|
||||
(int16_t)0x3179, (int16_t)0x3274, (int16_t)0x3367, (int16_t)0x3453,
|
||||
(int16_t)0x3536, (int16_t)0x3612, (int16_t)0x36E5, (int16_t)0x37AF,
|
||||
(int16_t)0x3871, (int16_t)0x392A, (int16_t)0x39DA, (int16_t)0x3A82,
|
||||
(int16_t)0x3B20, (int16_t)0x3BB6, (int16_t)0x3C42, (int16_t)0x3CC5,
|
||||
(int16_t)0x3D3E, (int16_t)0x3DAE, (int16_t)0x3E14, (int16_t)0x3E71,
|
||||
(int16_t)0x3EC5, (int16_t)0x3F0E, (int16_t)0x3F4E, (int16_t)0x3F84,
|
||||
(int16_t)0x3FB1, (int16_t)0x3FD3, (int16_t)0x3FEC, (int16_t)0x3FFB,
|
||||
(int16_t)0x4000, (int16_t)0x3FFB, (int16_t)0x3FEC, (int16_t)0x3FD3,
|
||||
(int16_t)0x3FB1, (int16_t)0x3F84, (int16_t)0x3F4E, (int16_t)0x3F0E,
|
||||
(int16_t)0x3EC5, (int16_t)0x3E71, (int16_t)0x3E14, (int16_t)0x3DAE,
|
||||
(int16_t)0x3D3E, (int16_t)0x3CC5, (int16_t)0x3C42, (int16_t)0x3BB6,
|
||||
(int16_t)0x3B20, (int16_t)0x3A82, (int16_t)0x39DA, (int16_t)0x392A,
|
||||
(int16_t)0x3871, (int16_t)0x37AF, (int16_t)0x36E5, (int16_t)0x3612,
|
||||
(int16_t)0x3536, (int16_t)0x3453, (int16_t)0x3367, (int16_t)0x3274,
|
||||
(int16_t)0x3179, (int16_t)0x3076, (int16_t)0x2F6B, (int16_t)0x2E5A,
|
||||
(int16_t)0x2D41, (int16_t)0x2C21, (int16_t)0x2AFA, (int16_t)0x29CD,
|
||||
(int16_t)0x2899, (int16_t)0x275F, (int16_t)0x261F, (int16_t)0x24DA,
|
||||
(int16_t)0x238E, (int16_t)0x223D, (int16_t)0x20E7, (int16_t)0x1F8B,
|
||||
(int16_t)0x1E2B, (int16_t)0x1CC6, (int16_t)0x1B5D, (int16_t)0x19EF,
|
||||
(int16_t)0x187D, (int16_t)0x1708, (int16_t)0x158F, (int16_t)0x1413,
|
||||
(int16_t)0x1294, (int16_t)0x1111, (int16_t)0x0F8C, (int16_t)0x0E05,
|
||||
(int16_t)0x0C7C, (int16_t)0x0AF1, (int16_t)0x0964, (int16_t)0x07D5,
|
||||
(int16_t)0x0645, (int16_t)0x04B5, (int16_t)0x0323, (int16_t)0x0192,
|
||||
(int16_t)0x0000, (int16_t)0xFE6E, (int16_t)0xFCDD, (int16_t)0xFB4B,
|
||||
(int16_t)0xF9BB, (int16_t)0xF82B, (int16_t)0xF69C, (int16_t)0xF50F,
|
||||
(int16_t)0xF384, (int16_t)0xF1FB, (int16_t)0xF074, (int16_t)0xEEEF,
|
||||
(int16_t)0xED6C, (int16_t)0xEBED, (int16_t)0xEA71, (int16_t)0xE8F8,
|
||||
(int16_t)0xE783, (int16_t)0xE611, (int16_t)0xE4A3, (int16_t)0xE33A,
|
||||
(int16_t)0xE1D5, (int16_t)0xE075, (int16_t)0xDF19, (int16_t)0xDDC3,
|
||||
(int16_t)0xDC72, (int16_t)0xDB26, (int16_t)0xD9E1, (int16_t)0xD8A1,
|
||||
(int16_t)0xD767, (int16_t)0xD633, (int16_t)0xD506, (int16_t)0xD3DF,
|
||||
(int16_t)0xD2BF, (int16_t)0xD1A6, (int16_t)0xD095, (int16_t)0xCF8A,
|
||||
(int16_t)0xCE87, (int16_t)0xCD8C, (int16_t)0xCC99, (int16_t)0xCBAD,
|
||||
(int16_t)0xCACA, (int16_t)0xC9EE, (int16_t)0xC91B, (int16_t)0xC851,
|
||||
(int16_t)0xC78F, (int16_t)0xC6D6, (int16_t)0xC626, (int16_t)0xC57E,
|
||||
(int16_t)0xC4E0, (int16_t)0xC44A, (int16_t)0xC3BE, (int16_t)0xC33B,
|
||||
(int16_t)0xC2C2, (int16_t)0xC252, (int16_t)0xC1EC, (int16_t)0xC18F,
|
||||
(int16_t)0xC13B, (int16_t)0xC0F2, (int16_t)0xC0B2, (int16_t)0xC07C,
|
||||
(int16_t)0xC04F, (int16_t)0xC02D, (int16_t)0xC014, (int16_t)0xC005,
|
||||
(int16_t)0xC000, (int16_t)0xC005, (int16_t)0xC014, (int16_t)0xC02D,
|
||||
(int16_t)0xC04F, (int16_t)0xC07C, (int16_t)0xC0B2, (int16_t)0xC0F2,
|
||||
(int16_t)0xC13B, (int16_t)0xC18F, (int16_t)0xC1EC, (int16_t)0xC252,
|
||||
(int16_t)0xC2C2, (int16_t)0xC33B, (int16_t)0xC3BE, (int16_t)0xC44A,
|
||||
(int16_t)0xC4E0, (int16_t)0xC57E, (int16_t)0xC626, (int16_t)0xC6D6,
|
||||
(int16_t)0xC78F, (int16_t)0xC851, (int16_t)0xC91B, (int16_t)0xC9EE,
|
||||
(int16_t)0xCACA, (int16_t)0xCBAD, (int16_t)0xCC99, (int16_t)0xCD8C,
|
||||
(int16_t)0xCE87, (int16_t)0xCF8A, (int16_t)0xD095, (int16_t)0xD1A6,
|
||||
(int16_t)0xD2BF, (int16_t)0xD3DF, (int16_t)0xD506, (int16_t)0xD633,
|
||||
(int16_t)0xD767, (int16_t)0xD8A1, (int16_t)0xD9E1, (int16_t)0xDB26,
|
||||
(int16_t)0xDC72, (int16_t)0xDDC3, (int16_t)0xDF19, (int16_t)0xE075,
|
||||
(int16_t)0xE1D5, (int16_t)0xE33A, (int16_t)0xE4A3, (int16_t)0xE611,
|
||||
(int16_t)0xE783, (int16_t)0xE8F8, (int16_t)0xEA71, (int16_t)0xEBED,
|
||||
(int16_t)0xED6C, (int16_t)0xEEEF, (int16_t)0xF074, (int16_t)0xF1FB,
|
||||
(int16_t)0xF384, (int16_t)0xF50F, (int16_t)0xF69C, (int16_t)0xF82B,
|
||||
(int16_t)0xF9BB, (int16_t)0xFB4B, (int16_t)0xFCDD, (int16_t)0xFE6E
|
||||
};
|
||||
|
||||
void Bios000h ()
|
||||
{
|
||||
debug("Bios entry point");
|
||||
R(13) = 0x03007FE0;
|
||||
R(15) = 0x08000004;
|
||||
CPU.SwitchToMode(Cpu::M_IRQ);
|
||||
R(13) = 0x03007FA0;
|
||||
CPU.SwitchToMode(Cpu::M_SYS);
|
||||
R(13) = 0x03007F00;
|
||||
ICPSR.irq_d = false;
|
||||
IO.Write8(Io::POSTFLG, 0x01);
|
||||
}
|
||||
|
||||
void Bios008h ()
|
||||
{
|
||||
// if we are here, we should be in SVC mode (0x13)
|
||||
// store the spsr, r11, r12 and r14 on the stack
|
||||
uint32_t baseadd = R(13) - (4*4), add = (baseadd & 0xFFFFFFFC);
|
||||
MEM.Write32(add , SPSR);
|
||||
MEM.Write32(add += 4, R(11));
|
||||
MEM.Write32(add += 4, R(12));
|
||||
MEM.Write32(add + 4, R(14));
|
||||
R(13) = baseadd;
|
||||
|
||||
uint8_t swiComment = MEM.Read8(R(14) - 2);
|
||||
|
||||
// put 0x1F in cpsr but don't touch to the irq disable bit
|
||||
CPU.SwitchToMode(0x1F);
|
||||
CPSR = 0x0000001F | (CPSR & (0x1 << 7));
|
||||
CPU.UpdateICpsr();
|
||||
|
||||
// store r11 and r14 (of the user mode) on the stack
|
||||
baseadd = R(13) - (2*4); add = (baseadd & 0xFFFFFFFC);
|
||||
MEM.Write32(add , R(11));
|
||||
MEM.Write32(add + 4, R(14));
|
||||
R(13) = baseadd;
|
||||
|
||||
R(14) = 0x168;
|
||||
|
||||
debug("Software IRQ start");
|
||||
switch (swiComment)
|
||||
{
|
||||
case 0x04:
|
||||
IntrWait();
|
||||
break;
|
||||
case 0x05:
|
||||
VBlankIntrWait();
|
||||
break;
|
||||
default:
|
||||
met_abort("not implemented : " << (int)swiComment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Bios168h ()
|
||||
{
|
||||
uint32_t add = R(13) & 0xFFFFFFFC;
|
||||
R( 2) = MEM.Read32(add );
|
||||
R(14) = MEM.Read32(add += 4);
|
||||
R(13) += 2*4;
|
||||
|
||||
// SVC with fiq and irq disabled
|
||||
CPU.SwitchToMode(0x13); // SVC
|
||||
CPSR = 0x000000D3;
|
||||
CPU.UpdateICpsr();
|
||||
add = R(13) & 0xFFFFFFFC;
|
||||
|
||||
SPSR = MEM.Read32(add);
|
||||
|
||||
R(11) = MEM.Read32(add += 4);
|
||||
R(12) = MEM.Read32(add += 4);
|
||||
R(14) = MEM.Read32(add + 4);
|
||||
R(13) += 4*4;
|
||||
|
||||
// FIXME this works (for thumb) ?
|
||||
if (CPU.Spsr().b.thumb)
|
||||
R(15) = R(14) + 2;
|
||||
else
|
||||
R(15) = R(14) + 4;
|
||||
|
||||
debug("Software IRQ end");
|
||||
CPU.SwitchModeBack();
|
||||
}
|
||||
|
||||
void Bios018h ()
|
||||
{
|
||||
debug("IRQ start");
|
||||
// stmfd r13!,r0-r3,r12,r14
|
||||
uint32_t baseadd = R(13) - (6*4), add = (baseadd & 0xFFFFFFFC);
|
||||
MEM.Write32(add , R( 0));
|
||||
MEM.Write32(add += 4, R( 1));
|
||||
MEM.Write32(add += 4, R( 2));
|
||||
MEM.Write32(add += 4, R( 3));
|
||||
MEM.Write32(add += 4, R(12));
|
||||
MEM.Write32(add + 4, R(14));
|
||||
|
||||
R(13) = baseadd;
|
||||
|
||||
// add r14,r15,0h
|
||||
R(14) = 0x00000130;
|
||||
|
||||
R(15) = MEM.Read32(0x03007FFC) + 4;
|
||||
}
|
||||
|
||||
void Bios130h ()
|
||||
{
|
||||
debug("IRQ end");
|
||||
// ldmfd r13!,r0-r3,r12,r14
|
||||
uint32_t add = R(13) & 0xFFFFFFFC;
|
||||
R( 0) = MEM.Read32(add );
|
||||
R( 1) = MEM.Read32(add += 4);
|
||||
R( 2) = MEM.Read32(add += 4);
|
||||
R( 3) = MEM.Read32(add += 4);
|
||||
R(12) = MEM.Read32(add += 4);
|
||||
R(14) = MEM.Read32(add + 4);
|
||||
|
||||
R(13) += 6*4;
|
||||
|
||||
// subs r15,r14,4h
|
||||
R(15) = R(14);
|
||||
if (CPU.Spsr().b.thumb)
|
||||
R(15) -= 2;
|
||||
|
||||
CPU.SwitchModeBack();
|
||||
|
||||
// XXX FIXME, usefull ? test on breath of fire !
|
||||
/*if (FLAG_T)
|
||||
R(15) &= 0xFFFFFFFE;
|
||||
else
|
||||
R(15) &= 0xFFFFFFFC;*/
|
||||
}
|
||||
|
||||
void SoftReset ()
|
||||
{
|
||||
CPU.SoftReset ();
|
||||
if (MEM.Read8(0x03007FFA))
|
||||
R(15) = 0x02000004;
|
||||
else
|
||||
R(15) = 0x08000004;
|
||||
|
||||
MEM.SoftReset ();
|
||||
}
|
||||
|
||||
void RegisterRamReset ()
|
||||
{
|
||||
IO.Write16(Io::DISPCNT, 0x0080);
|
||||
uint8_t flagRes = R(0);
|
||||
if (flagRes & (0x1 ))
|
||||
MEM.ClearWbram();
|
||||
if (flagRes & (0x1 << 1))
|
||||
MEM.ClearWcram();
|
||||
if (flagRes & (0x1 << 2))
|
||||
MEM.ClearPalette();
|
||||
if (flagRes & (0x1 << 3))
|
||||
MEM.ClearVram();
|
||||
if (flagRes & (0x1 << 4))
|
||||
MEM.ClearOam();
|
||||
if (flagRes & (0x1 << 5))
|
||||
IO.ClearSio ();
|
||||
if (flagRes & (0x1 << 6))
|
||||
IO.ClearSound ();
|
||||
if (flagRes & (0x1 << 7))
|
||||
IO.ClearOthers ();
|
||||
}
|
||||
|
||||
void Halt ()
|
||||
{
|
||||
IO.Write8(Io::HALTCNT, 0);
|
||||
}
|
||||
|
||||
void IntrWait ()
|
||||
{
|
||||
// FIXME ugly
|
||||
R(13) -= 8;
|
||||
MEM.Write32(R(13) & 0xFFFFFFFC, R(4));
|
||||
MEM.Write32((R(13)+4) & 0xFFFFFFFC, R(14));
|
||||
|
||||
uint16_t& intFlags = *(uint16_t*)MEM.GetRealAddress(0x03007FF8);
|
||||
|
||||
if (R(0))
|
||||
{
|
||||
if (intFlags & R(1))
|
||||
intFlags = (intFlags & R(1)) ^ intFlags;
|
||||
else
|
||||
FLAG_Z = 1;
|
||||
IO.Write16(Io::IME, 1);
|
||||
}
|
||||
|
||||
IO.Write8(Io::HALTCNT, 0);
|
||||
|
||||
// return address (after IRQ)
|
||||
R(15) = 0x33C;
|
||||
|
||||
debug("IntrWait start");
|
||||
}
|
||||
|
||||
void Bios338h ()
|
||||
{
|
||||
uint16_t& intFlags = *(uint16_t*)MEM.GetRealAddress(0x03007FF8);
|
||||
|
||||
if (!(intFlags & R(1)))
|
||||
{
|
||||
IO.Write16(Io::IME, 1);
|
||||
IO.Write8(Io::HALTCNT, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
intFlags = (intFlags & R(1)) ^ intFlags;
|
||||
IO.Write16(Io::IME, 1);
|
||||
|
||||
// FIXME ugly
|
||||
R(4) = MEM.Read32(R(13) & 0xFFFFFFFC);
|
||||
R(14) = MEM.Read32((R(13)+4) & 0xFFFFFFFC);
|
||||
R(13) += 8;
|
||||
|
||||
// should lead to 0x168
|
||||
R(15) = R(14)+4;
|
||||
}
|
||||
|
||||
debug("IntWait end");
|
||||
}
|
||||
|
||||
void VBlankIntrWait ()
|
||||
{
|
||||
R(0) = 1;
|
||||
R(1) = 1;
|
||||
IntrWait();
|
||||
}
|
||||
|
||||
void Div ()
|
||||
{
|
||||
if (!R(1))
|
||||
met_abort("Div by 0");
|
||||
|
||||
int32_t number = R(0), denom = R(1);
|
||||
|
||||
int32_t div = number / denom;
|
||||
R(0) = div;
|
||||
R(1) = number % denom;
|
||||
R(3) = div < 0 ? -div : div;
|
||||
}
|
||||
|
||||
void DivArm ()
|
||||
{
|
||||
uint32_t tmp = R(0);
|
||||
R(0) = R(1);
|
||||
R(1) = tmp;
|
||||
Div();
|
||||
}
|
||||
|
||||
void Sqrt ()
|
||||
{
|
||||
R(0) = (uint16_t)sqrt((float)R(0));
|
||||
}
|
||||
|
||||
void ArcTan ()
|
||||
{
|
||||
int32_t a = -(((int32_t)R(0) * R(0)) >> 14);
|
||||
int32_t b = 0xA9;
|
||||
b = ((a * b) >> 14) + 0x0390;
|
||||
b = ((a * b) >> 14) + 0x091C;
|
||||
b = ((a * b) >> 14) + 0x0FB6;
|
||||
b = ((a * b) >> 14) + 0X16AA;
|
||||
b = ((a * b) >> 14) + 0X2081;
|
||||
b = ((a * b) >> 14) + 0X3651;
|
||||
b = ((a * b) >> 14) + 0XA2F9;
|
||||
|
||||
R(0) = (R(0) * b) >> 16;
|
||||
}
|
||||
|
||||
void ArcTan2 ()
|
||||
{
|
||||
int16_t x = R(0), y = R(1);
|
||||
if (y)
|
||||
if (x)
|
||||
if (abs(x) < abs(y))
|
||||
{
|
||||
R(0) <<= 14;
|
||||
Div();
|
||||
ArcTan();
|
||||
R(0) = 0x4000 - R(0);
|
||||
if (y < 0)
|
||||
R(0) += 0x8000;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t r1 = R(1);
|
||||
R(1) = R(0);
|
||||
R(0) = r1 << 14;
|
||||
Div();
|
||||
ArcTan();
|
||||
if (x < 0)
|
||||
R(0) += 0x8000;
|
||||
else if (y < 0)
|
||||
R(0) += 0x10000;
|
||||
}
|
||||
else
|
||||
if (y < 0)
|
||||
R(0) = 0xc000;
|
||||
else
|
||||
R(0) = 0x4000;
|
||||
else
|
||||
if (x < 0)
|
||||
R(0) = 0x8000;
|
||||
else
|
||||
R(0) = 0x0000;
|
||||
}
|
||||
|
||||
void CpuSet ()
|
||||
{
|
||||
if (R(2) & (0x1 << 26)) // 32 bits
|
||||
{
|
||||
if (R(2) & (0x1 << 24)) // fixed source address
|
||||
{
|
||||
uint32_t source = MEM.Read32(R(0) & 0xFFFFFFFC);
|
||||
uint32_t address = R(1) & 0xFFFFFFFC;
|
||||
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
|
||||
{
|
||||
MEM.Write32(address, source);
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
else // copy
|
||||
{
|
||||
uint32_t src = R(0) & 0xFFFFFFFC;
|
||||
uint32_t dest = R(1) & 0xFFFFFFFC;
|
||||
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
|
||||
{
|
||||
MEM.Write32(dest, MEM.Read32(src));
|
||||
src += 4;
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // 16 bits
|
||||
{
|
||||
if (R(2) & (0x1 << 24)) // fixed source address
|
||||
{
|
||||
uint16_t source = MEM.Read16(R(0));
|
||||
uint32_t address = R(1);
|
||||
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
|
||||
{
|
||||
MEM.Write16(address, source);
|
||||
address += 2;
|
||||
}
|
||||
}
|
||||
else // copy
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t dest = R(1);
|
||||
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
|
||||
{
|
||||
MEM.Write16(dest, MEM.Read16(src));
|
||||
src += 2;
|
||||
dest += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpuFastSet ()
|
||||
{
|
||||
if (R(2) & (0x1 << 24)) // fixed source address
|
||||
{
|
||||
uint32_t source = MEM.Read32(R(0));
|
||||
uint32_t address = R(1);
|
||||
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
|
||||
{
|
||||
MEM.Write32(address, source);
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
else // copy
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t dest = R(1);
|
||||
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
|
||||
{
|
||||
MEM.Write32(dest, MEM.Read32(src));
|
||||
src += 4;
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BgAffineSet ()
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t dest = R(1);
|
||||
uint32_t num = R(2);
|
||||
|
||||
int32_t cx, cy;
|
||||
int16_t dix, diy, rx, ry;
|
||||
uint16_t alpha;
|
||||
|
||||
int32_t cos, sin;
|
||||
int16_t dx, dmx, dy, dmy;
|
||||
|
||||
while (num--)
|
||||
{
|
||||
cx = MEM.Read32(src);
|
||||
src += 4;
|
||||
cy = MEM.Read32(src);
|
||||
src += 4;
|
||||
dix = MEM.Read16(src);
|
||||
src += 2;
|
||||
diy = MEM.Read16(src);
|
||||
src += 2;
|
||||
rx = MEM.Read16(src);
|
||||
src += 2;
|
||||
ry = MEM.Read16(src);
|
||||
src += 2;
|
||||
alpha = MEM.Read16(src) >> 8;
|
||||
src += 2;
|
||||
|
||||
sin = sineTable[alpha];
|
||||
cos = sineTable[(alpha + 0x40) & 0xFF];
|
||||
|
||||
dx = (rx * cos) >> 14;
|
||||
dmx = -((rx * sin) >> 14);
|
||||
dy = (ry * sin) >> 14;
|
||||
dmy = (ry * cos) >> 14;
|
||||
|
||||
MEM.Write16(dest, dx);
|
||||
dest += 2;
|
||||
MEM.Write16(dest, dmx);
|
||||
dest += 2;
|
||||
MEM.Write16(dest, dy);
|
||||
dest += 2;
|
||||
MEM.Write16(dest, dmy);
|
||||
dest += 2;
|
||||
|
||||
MEM.Write32(dest, cx - dx * dix - dmx * diy);
|
||||
dest += 4;
|
||||
MEM.Write32(dest, cy - dy * dix - dmy * diy);
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjAffineSet ()
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t dest = R(1);
|
||||
uint32_t num = R(2);
|
||||
uint32_t off = R(3);
|
||||
|
||||
int16_t rx, ry;
|
||||
uint16_t alpha;
|
||||
|
||||
int32_t cos, sin;
|
||||
int16_t dx, dmx, dy, dmy;
|
||||
|
||||
while (num--)
|
||||
{
|
||||
rx = MEM.Read16(src);
|
||||
src += 2;
|
||||
ry = MEM.Read16(src);
|
||||
src += 2;
|
||||
alpha = MEM.Read16(src) >> 8;
|
||||
src += 4;
|
||||
|
||||
sin = sineTable[alpha];
|
||||
cos = sineTable[(alpha + 0x40) & 0xFF];
|
||||
|
||||
dx = (rx * cos) >> 14;
|
||||
dmx = -((rx * sin) >> 14);
|
||||
dy = (ry * sin) >> 14;
|
||||
dmy = (ry * cos) >> 14;
|
||||
|
||||
MEM.Write16(dest, dx);
|
||||
dest += off;
|
||||
MEM.Write16(dest, dmx);
|
||||
dest += off;
|
||||
MEM.Write16(dest, dy);
|
||||
dest += off;
|
||||
MEM.Write16(dest, dmy);
|
||||
dest += off;
|
||||
}
|
||||
}
|
||||
|
||||
void LZ77UnCompWram ()
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t header = MEM.Read32(src);
|
||||
src += 4;
|
||||
if (((header >> 4) & 0xF) != 1)
|
||||
met_abort("This is not LZ77 data");
|
||||
uint32_t size = header >> 8;
|
||||
debug("LZ77UnCompWram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
|
||||
uint32_t dest = R(1);
|
||||
uint8_t flags;
|
||||
uint16_t block;
|
||||
uint8_t blocklen;
|
||||
uint32_t realaddr;
|
||||
|
||||
// for each block of a flags byte + 8 blocks
|
||||
while (true)
|
||||
{
|
||||
flags = MEM.Read8(src++);
|
||||
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
{
|
||||
// compressed block of 2 bytes
|
||||
if (flags & 0x80)
|
||||
{
|
||||
block = MEM.Read8(src) << 8 | MEM.Read8(src+1);
|
||||
src += 2;
|
||||
blocklen = (block >> 12) + 3;
|
||||
realaddr = dest - (block & 0x0FFF) - 1;
|
||||
for(uint16_t j = 0; j < blocklen; ++j)
|
||||
{
|
||||
MEM.Write8(dest++, MEM.Read8(realaddr++));
|
||||
|
||||
--size;
|
||||
if(size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// uncompressed block of 1 byte
|
||||
else
|
||||
{
|
||||
MEM.Write8(dest++, MEM.Read8(src++));
|
||||
|
||||
--size;
|
||||
if (size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LZ77UnCompVram ()
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t header = MEM.Read32(src);
|
||||
src += 4;
|
||||
if (((header >> 4) & 0xF) != 1)
|
||||
met_abort("This is not LZ77 data");
|
||||
uint32_t size = header >> 8;
|
||||
debug("LZ77UnCompVram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
|
||||
uint32_t dest = R(1);
|
||||
uint8_t flags;
|
||||
uint16_t out = 0;
|
||||
uint8_t shift = 0;
|
||||
uint16_t block;
|
||||
uint8_t blocklen;
|
||||
uint32_t realaddr;
|
||||
|
||||
// for each block of a flags byte + 8 blocks
|
||||
while (true)
|
||||
{
|
||||
flags = MEM.Read8(src++);
|
||||
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
{
|
||||
// compressed block of 2 bytes
|
||||
if (flags & 0x80)
|
||||
{
|
||||
block = MEM.Read8(src) << 8 | MEM.Read8(src+1);
|
||||
src += 2;
|
||||
blocklen = (block >> 12) + 3;
|
||||
realaddr = dest + (shift/8) - (block & 0x0FFF) - 1;
|
||||
for(uint16_t j = 0; j < blocklen; ++j) {
|
||||
out |= MEM.Read8(realaddr++) << shift;
|
||||
shift += 8;
|
||||
|
||||
if(shift == 16) {
|
||||
MEM.Write16(dest, out);
|
||||
dest += 2;
|
||||
out = 0;
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
--size;
|
||||
if(size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// uncompressed block of 1 byte
|
||||
else
|
||||
{
|
||||
out |= MEM.Read8(src++) << shift;
|
||||
shift += 8;
|
||||
|
||||
if (shift == 16)
|
||||
{
|
||||
MEM.Write16(dest, out);
|
||||
dest += 2;
|
||||
shift = 0;
|
||||
out = 0;
|
||||
}
|
||||
|
||||
--size;
|
||||
if (size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HuffUnComp ()
|
||||
{
|
||||
uint32_t src = R(0) & 0xFFFFFFFC;
|
||||
uint32_t dest = R(1);
|
||||
uint32_t header = MEM.Read32(src);
|
||||
src += 4;
|
||||
if (((header >> 4) & 0xF) != 2)
|
||||
met_abort("This is not Huffman data");
|
||||
uint8_t blockLen = header & 0xF;
|
||||
uint32_t size = header >> 8;
|
||||
if (size % 4)
|
||||
met_abort("Size not multiple of 4 in HuffUnComp");
|
||||
uint32_t treeStart = src + 1;
|
||||
src += 2 + MEM.Read8(src) * 2;
|
||||
|
||||
uint32_t cData = MEM.Read32(src);
|
||||
src += 4;
|
||||
uint32_t mask = 0x80000000;
|
||||
uint32_t treePos = treeStart;
|
||||
uint8_t node = MEM.Read8(treePos);
|
||||
bool endNode = false;
|
||||
uint32_t oData = 0;
|
||||
uint8_t oShift = 0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
treePos = (treePos & 0xFFFFFFFE) + (node & 0x3F) * 2 + 2;
|
||||
if (cData & mask)
|
||||
{
|
||||
++treePos;
|
||||
if (node & (0x1 << 6))
|
||||
endNode = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node & (0x1 << 7))
|
||||
endNode = true;
|
||||
}
|
||||
node = MEM.Read8(treePos);
|
||||
|
||||
if (endNode)
|
||||
{
|
||||
oData |= ((uint32_t)node) << oShift;
|
||||
oShift += blockLen;
|
||||
|
||||
if (oShift >= 32)
|
||||
{
|
||||
MEM.Write32(dest, oData);
|
||||
dest += 4;
|
||||
size -= 4;
|
||||
|
||||
oShift -= 32;
|
||||
if (oShift)
|
||||
oData = node >> (8 - oShift);
|
||||
else
|
||||
oData = 0;
|
||||
}
|
||||
endNode = false;
|
||||
treePos = treeStart;
|
||||
node = MEM.Read8(treePos);
|
||||
}
|
||||
|
||||
mask >>= 1;
|
||||
if (!mask)
|
||||
{
|
||||
cData = MEM.Read32(src);
|
||||
src += 4;
|
||||
mask = 0x80000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RLUnCompWram ()
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t header = MEM.Read32(src);
|
||||
src += 4;
|
||||
if (((header >> 4) & 0xF) != 3)
|
||||
met_abort("This is not RL data");
|
||||
uint32_t size = header >> 8;
|
||||
debug("RLUnCompWram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
|
||||
uint32_t dest = R(1);
|
||||
uint8_t flags;
|
||||
uint8_t block;
|
||||
uint8_t blocklen;
|
||||
|
||||
// for each block
|
||||
while (true)
|
||||
{
|
||||
flags = MEM.Read8(src++);
|
||||
blocklen = flags & 0x7F;
|
||||
|
||||
// compressed block
|
||||
if (flags & 0x80)
|
||||
{
|
||||
blocklen += 3;
|
||||
block = MEM.Read8(src++);
|
||||
|
||||
for(uint8_t i = 0; i < blocklen; ++i) {
|
||||
MEM.Write8(dest++, block);
|
||||
|
||||
--size;
|
||||
if(size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// uncompressed block
|
||||
else
|
||||
{
|
||||
blocklen += 1;
|
||||
|
||||
for (uint8_t i = 0; i < blocklen; ++i)
|
||||
{
|
||||
MEM.Write8(dest++, MEM.Read8(src++));
|
||||
|
||||
--size;
|
||||
if (size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RLUnCompVram ()
|
||||
{
|
||||
uint32_t src = R(0);
|
||||
uint32_t header = MEM.Read32(src);
|
||||
src += 4;
|
||||
if (((header >> 4) & 0xF) != 3)
|
||||
met_abort("This is not RL data");
|
||||
uint32_t size = header >> 8;
|
||||
debug("RLUnCompVram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
|
||||
uint32_t dest = R(1);
|
||||
uint8_t flags;
|
||||
uint16_t out = 0;
|
||||
uint8_t shift = 0;
|
||||
uint8_t block;
|
||||
uint8_t blocklen;
|
||||
|
||||
// for each block
|
||||
while (true)
|
||||
{
|
||||
flags = MEM.Read8(src++);
|
||||
blocklen = flags & 0x7F;
|
||||
|
||||
// compressed block
|
||||
if (flags & 0x80)
|
||||
{
|
||||
blocklen += 3;
|
||||
block = MEM.Read8(src++);
|
||||
|
||||
for(uint8_t i = 0; i < blocklen; ++i) {
|
||||
out |= block << shift;
|
||||
shift += 8;
|
||||
|
||||
if(shift == 16) {
|
||||
MEM.Write16(dest, out);
|
||||
dest += 2;
|
||||
out = 0;
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
--size;
|
||||
if(size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// uncompressed block
|
||||
else
|
||||
{
|
||||
blocklen += 1;
|
||||
|
||||
for (uint8_t i = 0; i < blocklen; ++i)
|
||||
{
|
||||
out |= MEM.Read8(src++) << shift;
|
||||
shift += 8;
|
||||
|
||||
if (shift == 16)
|
||||
{
|
||||
MEM.Write16(dest, out);
|
||||
dest += 2;
|
||||
shift = 0;
|
||||
out = 0;
|
||||
}
|
||||
|
||||
--size;
|
||||
if (size == 0)
|
||||
{
|
||||
size = header >> 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/cartmem.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
#ifdef __LIBRETRO__
|
||||
uint8_t CartMemData[CartMem::MAX_SIZE+4];
|
||||
#endif
|
||||
|
||||
CartMem::CartMem() :
|
||||
#ifdef __LIBRETRO__
|
||||
m_data(CartMemData)
|
||||
#else
|
||||
m_data(new uint8_t[MAX_SIZE+4])
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
CartMem::~CartMem()
|
||||
{
|
||||
#ifndef __LIBRETRO__
|
||||
delete [] m_data;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CartMem::SaveState (std::ostream& stream)
|
||||
{
|
||||
stream.write((char*)m_data, MAX_SIZE);
|
||||
SS_WRITE_VAR(m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CartMem::LoadState (std::istream& stream)
|
||||
{
|
||||
stream.read((char*)m_data, MAX_SIZE);
|
||||
SS_READ_VAR(m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/clock.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
void Clock::Reset ()
|
||||
{
|
||||
// lcd is enabled by default
|
||||
m_first = m_count = m_cycles = m_lcd = m_sound = 0;
|
||||
// timers and battery are disabled by default
|
||||
/*m_battery =*/ m_timer[0] = m_timer[1] = m_timer[2] = m_timer[3] =
|
||||
INT_MAX;
|
||||
}
|
||||
|
||||
void Clock::Commit ()
|
||||
{
|
||||
unsigned short tocommit;
|
||||
|
||||
//m_count += m_cycles;
|
||||
|
||||
// this loop is here because a timer can trigger a dma which will take a
|
||||
// long time, during this time the lcd must draw and the timers continue
|
||||
while (m_cycles >= m_first)
|
||||
{
|
||||
m_count += m_cycles;
|
||||
|
||||
tocommit = m_cycles;
|
||||
m_cycles = 0;
|
||||
|
||||
m_lcd -= tocommit;
|
||||
while (m_lcd <= 0)
|
||||
LCD.TimeEvent();
|
||||
|
||||
m_sound -= tocommit;
|
||||
while (m_sound <= 0)
|
||||
{
|
||||
SOUND.TimeEvent();
|
||||
// XXX freq
|
||||
m_sound += SOUND_PERIOD;
|
||||
}
|
||||
|
||||
#define COMMIT(dev, obj) \
|
||||
if (m_##dev != INT_MAX) \
|
||||
{ \
|
||||
m_##dev -= tocommit; \
|
||||
while (m_##dev <= 0) \
|
||||
obj.TimeEvent(); \
|
||||
}
|
||||
COMMIT(timer[0], TIMER0)
|
||||
COMMIT(timer[1], TIMER1)
|
||||
COMMIT(timer[2], TIMER2)
|
||||
COMMIT(timer[3], TIMER3)
|
||||
//COMMIT(battery, MEM)
|
||||
#undef COMMIT
|
||||
|
||||
SetFirst();
|
||||
}
|
||||
}
|
||||
|
||||
void Clock::WaitForNext ()
|
||||
{
|
||||
m_cycles = m_first;
|
||||
Commit();
|
||||
}
|
||||
|
||||
#define SETFIRST(dev) \
|
||||
if (m_##dev < m_first) \
|
||||
m_first = m_##dev
|
||||
void Clock::SetFirst ()
|
||||
{
|
||||
m_first = m_lcd;
|
||||
SETFIRST(timer[0]);
|
||||
SETFIRST(timer[1]);
|
||||
SETFIRST(timer[2]);
|
||||
SETFIRST(timer[3]);
|
||||
SETFIRST(sound);
|
||||
//SETFIRST(battery);
|
||||
}
|
||||
#undef SETFIRST
|
||||
|
||||
bool Clock::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_cycles);
|
||||
SS_WRITE_VAR(m_first);
|
||||
SS_WRITE_VAR(m_lcd);
|
||||
SS_WRITE_VAR(m_sound);
|
||||
//SS_WRITE_VAR(m_battery);
|
||||
|
||||
SS_WRITE_ARRAY(m_timer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Clock::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_cycles);
|
||||
SS_READ_VAR(m_first);
|
||||
SS_READ_VAR(m_lcd);
|
||||
SS_READ_VAR(m_sound);
|
||||
//SS_READ_VAR(m_battery);
|
||||
|
||||
SS_READ_ARRAY(m_timer);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,447 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/cpu.hpp"
|
||||
#include "ameteor/bios.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "cpu_globals.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
Cpu::Cpu ()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Cpu::Reset ()
|
||||
{
|
||||
std::memset(&m_st, 0, sizeof(m_st));
|
||||
R(15) = 0x00000004;
|
||||
m_st.icpsr.mode = M_SVC;
|
||||
m_st.icpsr.fiq_d = true;
|
||||
m_st.icpsr.irq_d = true;
|
||||
}
|
||||
|
||||
void Cpu::SoftReset ()
|
||||
{
|
||||
std::memset(&m_st, 0, sizeof(m_st));
|
||||
R(13) = 0x03007F00;
|
||||
R(15) = 0x08000004;
|
||||
m_st.irq_r[0] = 0x03007FA0; // R13
|
||||
m_st.svc_r[0] = 0x03007FE0; // R13
|
||||
m_st.icpsr.mode = 0x1F;
|
||||
m_st.icpsr.fiq_d = true;
|
||||
}
|
||||
|
||||
void Cpu::UpdateICpsr ()
|
||||
{
|
||||
m_st.icpsr.mode = m_st.cpsr.b.mode;
|
||||
m_st.icpsr.irq_d = m_st.cpsr.b.irq_d;
|
||||
m_st.icpsr.fiq_d = m_st.cpsr.b.fiq_d;
|
||||
m_st.icpsr.thumb = m_st.cpsr.b.thumb;
|
||||
m_st.icpsr.s_overflow = m_st.cpsr.b.s_overflow;
|
||||
m_st.icpsr.f_overflow = m_st.cpsr.b.f_overflow;
|
||||
m_st.icpsr.f_carry = m_st.cpsr.b.f_carry;
|
||||
m_st.icpsr.f_zero = m_st.cpsr.b.f_zero;
|
||||
m_st.icpsr.f_sign = m_st.cpsr.b.f_sign;
|
||||
}
|
||||
|
||||
void Cpu::UpdateCpsr ()
|
||||
{
|
||||
m_st.cpsr.b.mode = m_st.icpsr.mode;
|
||||
m_st.cpsr.b.irq_d = m_st.icpsr.irq_d;
|
||||
m_st.cpsr.b.fiq_d = m_st.icpsr.fiq_d;
|
||||
m_st.cpsr.b.thumb = m_st.icpsr.thumb;
|
||||
m_st.cpsr.b.s_overflow = m_st.icpsr.s_overflow;
|
||||
m_st.cpsr.b.f_overflow = m_st.icpsr.f_overflow;
|
||||
m_st.cpsr.b.f_carry = m_st.icpsr.f_carry;
|
||||
m_st.cpsr.b.f_zero = m_st.icpsr.f_zero;
|
||||
m_st.cpsr.b.f_sign = m_st.icpsr.f_sign;
|
||||
}
|
||||
|
||||
void Cpu::SwitchToMode (uint8_t newmode)
|
||||
{
|
||||
SaveMode(m_st.icpsr.mode);
|
||||
|
||||
switch (newmode)
|
||||
{
|
||||
case 0x10: // User (non-privileged)
|
||||
case 0x1F: // System (privileged 'User' mode)
|
||||
switch (m_st.icpsr.mode)
|
||||
{
|
||||
case 0x10:
|
||||
case 0x1F:
|
||||
case 0x11:
|
||||
std::memcpy(m_st.r + 8, m_st.usr_r, sizeof(m_st.usr_r));
|
||||
break;
|
||||
default:
|
||||
std::memcpy(m_st.r + 13, m_st.usr_r + 5, 2*4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x11: // FIQ
|
||||
std::memcpy(m_st.r + 8, m_st.fiq_r, sizeof(m_st.fiq_r));
|
||||
break;
|
||||
case 0x12: // IRQ
|
||||
std::memcpy(m_st.r + 13, m_st.irq_r, sizeof(m_st.irq_r));
|
||||
break;
|
||||
case 0x13: // Supervisor (SWI)
|
||||
std::memcpy(m_st.r + 13, m_st.svc_r, sizeof(m_st.svc_r));
|
||||
break;
|
||||
case 0x17: // Abort
|
||||
std::memcpy(m_st.r + 13, m_st.abt_r, sizeof(m_st.abt_r));
|
||||
break;
|
||||
case 0x1B: // Undefined
|
||||
std::memcpy(m_st.r + 13, m_st.und_r, sizeof(m_st.und_r));
|
||||
break;
|
||||
default:
|
||||
met_abort("Unknown CPU mode : " << IOS_ADD << (int)newmode);
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateCpsr();
|
||||
m_st.spsr.dw = m_st.cpsr.dw;
|
||||
m_st.icpsr.mode = newmode;
|
||||
}
|
||||
|
||||
void Cpu::SwitchModeBack ()
|
||||
{
|
||||
// oldmode is the mode on which we want to switch back
|
||||
uint8_t oldmode = m_st.spsr.b.mode, curmode = m_st.icpsr.mode;
|
||||
// we don't care if the spsr of the mode we are using is modified
|
||||
SaveMode(curmode);
|
||||
|
||||
m_st.cpsr.dw = m_st.spsr.dw;
|
||||
UpdateICpsr();
|
||||
CheckInterrupt();
|
||||
switch (oldmode)
|
||||
{
|
||||
case 0x10: // User (non-privileged)
|
||||
case 0x1F: // System (privileged 'User' mode)
|
||||
switch (curmode)
|
||||
{
|
||||
case 0x10:
|
||||
case 0x1F:
|
||||
case 0x11:
|
||||
std::memcpy(m_st.r + 8, m_st.usr_r, sizeof(m_st.usr_r));
|
||||
break;
|
||||
default:
|
||||
std::memcpy(m_st.r + 13, m_st.usr_r + 5, 2*4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x11: // FIQ
|
||||
std::memcpy(m_st.r + 8, m_st.fiq_r, sizeof(m_st.fiq_r));
|
||||
m_st.spsr.dw = m_st.fiq_spsr.dw;
|
||||
break;
|
||||
case 0x12: // IRQ
|
||||
std::memcpy(m_st.r + 13, m_st.irq_r, sizeof(m_st.irq_r));
|
||||
m_st.spsr.dw = m_st.irq_spsr.dw;
|
||||
break;
|
||||
case 0x13: // Supervisor (SWI)
|
||||
std::memcpy(m_st.r + 13, m_st.svc_r, sizeof(m_st.svc_r));
|
||||
m_st.spsr.dw = m_st.svc_spsr.dw;
|
||||
break;
|
||||
case 0x17: // Abort
|
||||
std::memcpy(m_st.r + 13, m_st.abt_r, sizeof(m_st.abt_r));
|
||||
m_st.spsr.dw = m_st.abt_spsr.dw;
|
||||
break;
|
||||
case 0x1B: // Undefined
|
||||
std::memcpy(m_st.r + 13, m_st.und_r, sizeof(m_st.und_r));
|
||||
m_st.spsr.dw = m_st.und_spsr.dw;
|
||||
break;
|
||||
default:
|
||||
met_abort("Unknown CPU mode : " << IOS_ADD << (int)oldmode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Cpu::SaveMode (uint8_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 0x10: // User (non-privileged)
|
||||
case 0x1F: // System (privileged 'User' mode)
|
||||
std::memcpy(m_st.usr_r, m_st.r + 8, sizeof(m_st.usr_r));
|
||||
break;
|
||||
case 0x11: // FIQ
|
||||
std::memcpy(m_st.fiq_r, m_st.r + 8, sizeof(m_st.fiq_r));
|
||||
m_st.fiq_spsr.dw = m_st.spsr.dw;
|
||||
break;
|
||||
case 0x12: // IRQ
|
||||
std::memcpy(m_st.irq_r, m_st.r + 13, sizeof(m_st.irq_r));
|
||||
m_st.irq_spsr.dw = m_st.spsr.dw;
|
||||
break;
|
||||
case 0x13: // Supervisor (SWI)
|
||||
std::memcpy(m_st.svc_r, m_st.r + 13, sizeof(m_st.svc_r));
|
||||
m_st.svc_spsr.dw = m_st.spsr.dw;
|
||||
break;
|
||||
case 0x17: // Abort
|
||||
std::memcpy(m_st.abt_r, m_st.r + 13, sizeof(m_st.abt_r));
|
||||
m_st.abt_spsr.dw = m_st.spsr.dw;
|
||||
break;
|
||||
case 0x1B: // Undefined
|
||||
std::memcpy(m_st.und_r, m_st.r + 13, sizeof(m_st.und_r));
|
||||
m_st.und_spsr.dw = m_st.spsr.dw;
|
||||
break;
|
||||
default:
|
||||
met_abort("Unknown CPU mode : " << IOS_ADD << (int)mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Cpu::Interrupt ()
|
||||
{
|
||||
// Switch mode
|
||||
SwitchToMode(0x12); // IRQ
|
||||
// Save PC
|
||||
R(14) = R(15);
|
||||
// FIXME : why ? this seems to be USELESS ! (look at bios irq end)
|
||||
if (m_st.icpsr.thumb)
|
||||
R(14) += 2;
|
||||
// Switch to ARM
|
||||
m_st.icpsr.thumb = false;
|
||||
// Disable IRQ
|
||||
m_st.icpsr.irq_d = true;
|
||||
SetInterrupt(false);
|
||||
// Branch on 0x18
|
||||
R(15) = 0x1C;
|
||||
}
|
||||
|
||||
void Cpu::SoftwareInterrupt ()
|
||||
{
|
||||
// Switch mode
|
||||
SwitchToMode(0x13); // Supervisor
|
||||
// Save PC
|
||||
R(14) = R(15) - (m_st.icpsr.thumb ? 2 : 4);
|
||||
// Switch to ARM
|
||||
m_st.icpsr.thumb = false;
|
||||
// Disable IRQ
|
||||
m_st.icpsr.irq_d = true;
|
||||
SetInterrupt(false);
|
||||
// Branch on 0x8
|
||||
R(15) = 0xC;
|
||||
}
|
||||
|
||||
// TODO put this in Bios, no ?
|
||||
void Cpu::SoftwareInterrupt (uint32_t comment)
|
||||
{
|
||||
if (true)
|
||||
{
|
||||
char buff[256];
|
||||
int pos = 0;
|
||||
pos += sprintf (buff + pos, "SWI %02xh : ", comment);
|
||||
switch (comment) // no one cares about the sound driver
|
||||
{
|
||||
case 0x00: pos += sprintf (buff + pos, "SoftReset");
|
||||
break;
|
||||
case 0x01: pos += sprintf (buff + pos, "RegisterRamReset"); // todo: display flags
|
||||
break;
|
||||
case 0x02: pos += sprintf (buff + pos, "Halt");
|
||||
break;
|
||||
case 0x03: pos += sprintf (buff + pos, "Stop");
|
||||
break;
|
||||
case 0x04: pos += sprintf (buff + pos, "IntrWait"); // todo: display flags
|
||||
break;
|
||||
case 0x05: pos += sprintf (buff + pos, "VBlankIntrWait");
|
||||
break;
|
||||
case 0x06: pos += sprintf (buff + pos, "Div: ");
|
||||
pos += sprintf (buff + pos, "%08xh/%08xh", R(0), R(1));
|
||||
break;
|
||||
case 0x07: pos += sprintf (buff + pos, "DivArm: ");
|
||||
pos += sprintf (buff + pos, "%08xh/%08xh", R(1), R(0));
|
||||
break;
|
||||
case 0x08: pos += sprintf (buff + pos, "Sqrt: ");
|
||||
pos += sprintf (buff + pos, "sqrt(%08xh)", R(0));
|
||||
break;
|
||||
case 0x09: pos += sprintf (buff + pos, "ArcTan: ");
|
||||
pos += sprintf (buff + pos, "atan(%04xh)", R(0) & 0xffff);
|
||||
break;
|
||||
case 0x0a: pos += sprintf (buff + pos, "ArcTan2: ");
|
||||
pos += sprintf (buff + pos, "atan2(%04xh,%04xh)", R(1) & 0xffff, R(0) & 0xffff);
|
||||
break;
|
||||
case 0x0b: pos += sprintf (buff + pos, "CpuSet: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], wcnt=%xh, fixed=%c, size=%d", R(0), R(1), R(2) & 0x1fffff, R(2) & 0x1000000 ? 'Y' : 'N', R(2) & 0x4000000 ? 32 : 16);
|
||||
break;
|
||||
case 0x0c: pos += sprintf (buff + pos, "CpuFastSet: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], wcnt=%xh, fixed=%c", R(0), R(1), R(2) & 0x1fffff, R(2) & 0x1000000 ? 'Y' : 'N');
|
||||
break;
|
||||
case 0x0d: pos += sprintf (buff + pos, "GetBiosChecksum");
|
||||
break;
|
||||
case 0x0e: pos += sprintf (buff + pos, "BgAffineSet: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], cnt=%d", R(0), R(1), R(2));
|
||||
break;
|
||||
case 0x0f: pos += sprintf (buff + pos, "ObjAffineSet: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], cnt=%d, offs=%d", R(0), R(1), R(2), R(3));
|
||||
break;
|
||||
case 0x10: pos += sprintf (buff + pos, "BitUnPack: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], info=[%08xh]", R(0), R(1), R(2));
|
||||
break;
|
||||
case 0x11: pos += sprintf (buff + pos, "LZ77UnCompWram: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x12: pos += sprintf (buff + pos, "LZ77UnCompVram: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x13: pos += sprintf (buff + pos, "HuffUnComp: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x14: pos += sprintf (buff + pos, "RLUnCompWram: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x15: pos += sprintf (buff + pos, "RLUnCompVram: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x16: pos += sprintf (buff + pos, "Diff8bitUnFilterWram: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x17: pos += sprintf (buff + pos, "Diff8bitUnFilterVram: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x18: pos += sprintf (buff + pos, "Diff16bitUnFilter: ");
|
||||
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
|
||||
break;
|
||||
case 0x19: pos += sprintf (buff + pos, "SoundBias");
|
||||
break;
|
||||
case 0x1a: pos += sprintf (buff + pos, "SoundDriverInit");
|
||||
break;
|
||||
case 0x1b: pos += sprintf (buff + pos, "SoundDriverMode");
|
||||
break;
|
||||
case 0x1c: pos += sprintf (buff + pos, "SoundDriverMain");
|
||||
break;
|
||||
case 0x1d: pos += sprintf (buff + pos, "SoundDriverVSync");
|
||||
break;
|
||||
case 0x1e: pos += sprintf (buff + pos, "SoundChannelClear");
|
||||
break;
|
||||
case 0x1f: pos += sprintf (buff + pos, "MidiKey2Freq");
|
||||
break;
|
||||
case 0x20: pos += sprintf (buff + pos, "SoundWhatever0");
|
||||
break;
|
||||
case 0x21: pos += sprintf (buff + pos, "SoundWhatever1");
|
||||
break;
|
||||
case 0x22: pos += sprintf (buff + pos, "SoundWhatever2");
|
||||
break;
|
||||
case 0x23: pos += sprintf (buff + pos, "SoundWhatever3");
|
||||
break;
|
||||
case 0x24: pos += sprintf (buff + pos, "SoundWhatever4");
|
||||
break;
|
||||
case 0x25: pos += sprintf (buff + pos, "MultiBoot: ");
|
||||
pos += sprintf (buff + pos, "mbp=[%08xh], mode=%d", R(0), R(1));
|
||||
break;
|
||||
case 0x26: pos += sprintf (buff + pos, "HardReset");
|
||||
break;
|
||||
case 0x27: pos += sprintf (buff + pos, "CustomHalt: ");
|
||||
pos += sprintf (buff + pos, "val=%02xh", R(2) & 0xff);
|
||||
break;
|
||||
case 0x28: pos += sprintf (buff + pos, "SoundDriverVSyncOff");
|
||||
break;
|
||||
case 0x29: pos += sprintf (buff + pos, "SoundDriverVSyncOnn");
|
||||
break;
|
||||
case 0x2a: pos += sprintf (buff + pos, "SoundGetJumpList");
|
||||
break;
|
||||
default: pos += sprintf (buff + pos, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
pos += sprintf (buff + pos, "\n");
|
||||
print_bizhawk(buff);
|
||||
}
|
||||
if (MEM.HasBios())
|
||||
SoftwareInterrupt();
|
||||
else
|
||||
switch (comment)
|
||||
{
|
||||
case 0x00:
|
||||
Bios::SoftReset();
|
||||
break;
|
||||
case 0x01:
|
||||
Bios::RegisterRamReset();
|
||||
break;
|
||||
case 0x02:
|
||||
Bios::Halt();
|
||||
break;
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
SoftwareInterrupt();
|
||||
break;
|
||||
case 0x06:
|
||||
Bios::Div();
|
||||
break;
|
||||
case 0x07:
|
||||
Bios::DivArm();
|
||||
break;
|
||||
case 0x08:
|
||||
Bios::Sqrt();
|
||||
break;
|
||||
case 0x09:
|
||||
Bios::ArcTan();
|
||||
break;
|
||||
case 0x0A:
|
||||
Bios::ArcTan2();
|
||||
break;
|
||||
case 0x0B:
|
||||
Bios::CpuSet();
|
||||
break;
|
||||
case 0x0C:
|
||||
Bios::CpuFastSet();
|
||||
break;
|
||||
case 0x0E:
|
||||
Bios::BgAffineSet();
|
||||
break;
|
||||
case 0x0F:
|
||||
Bios::ObjAffineSet();
|
||||
break;
|
||||
case 0x11:
|
||||
Bios::LZ77UnCompWram();
|
||||
break;
|
||||
case 0x12:
|
||||
Bios::LZ77UnCompVram();
|
||||
break;
|
||||
case 0x13:
|
||||
Bios::HuffUnComp();
|
||||
break;
|
||||
case 0x14:
|
||||
Bios::RLUnCompWram();
|
||||
break;
|
||||
case 0x15:
|
||||
Bios::RLUnCompVram();
|
||||
break;
|
||||
default:
|
||||
met_abort("Unknown software interrupt : " << IOS_ADD << comment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Cpu::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_st);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cpu::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_st);
|
||||
|
||||
CheckInterrupt();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __CPU_GLOBALS_H__
|
||||
#define __CPU_GLOBALS_H__
|
||||
|
||||
#undef R
|
||||
#define R(reg) m_st.r[reg]
|
||||
|
||||
#undef CPU
|
||||
#define CPU (*this)
|
||||
|
||||
#undef CPSR
|
||||
#undef SPSR
|
||||
#undef FLAG_Z
|
||||
#undef FLAG_N
|
||||
#undef FLAG_C
|
||||
#undef FLAG_V
|
||||
#undef FLAG_T
|
||||
#define CPSR (m_st.cpsr.dw)
|
||||
#define SPSR (m_st.spsr.dw)
|
||||
#define FLAG_Z (m_st.icpsr.f_zero)
|
||||
#define FLAG_N (m_st.icpsr.f_sign)
|
||||
#define FLAG_C (m_st.icpsr.f_carry)
|
||||
#define FLAG_V (m_st.icpsr.f_overflow)
|
||||
#define FLAG_T (m_st.icpsr.thumb)
|
||||
|
||||
#endif
|
|
@ -1,85 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "debug.hpp"
|
||||
#include "ameteor/cpu.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
// TODO make this more guidelined (like the above assert)
|
||||
void debug_bits(uint32_t u)
|
||||
{
|
||||
#if defined METDEBUG && defined METDEBUGLOG
|
||||
for (register int8_t c = 31; c >= 0; --c)
|
||||
{
|
||||
STDBG << !!(u & (((uint32_t)0x1) << c));
|
||||
if (!(c % 8))
|
||||
STDBG << ' ';
|
||||
}
|
||||
STDBG << std::endl;
|
||||
#else
|
||||
(void)u;
|
||||
#endif
|
||||
}
|
||||
|
||||
void debug_bits_16(uint16_t u)
|
||||
{
|
||||
#if defined METDEBUG && defined METDEBUGLOG
|
||||
for (register int8_t c = 15; c >= 0; --c)
|
||||
{
|
||||
STDBG << !!(u & (((uint32_t)0x1) << c));
|
||||
if (!(c % 8))
|
||||
STDBG << ' ';
|
||||
}
|
||||
STDBG << std::endl;
|
||||
#else
|
||||
(void)u;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MET_REGS_DEBUG
|
||||
void PrintRegs ()
|
||||
{
|
||||
static uint32_t regs[17] = {0};
|
||||
|
||||
for (uint8_t c = 0; c <= 15; ++c)
|
||||
if (R(c) != regs[c])
|
||||
{
|
||||
STDBG << "R" << std::setbase(10) << (int)c << " = " << IOS_ADD << R(c) << '\n';
|
||||
regs[c] = R(c);
|
||||
}
|
||||
CPU.UpdateCpsr();
|
||||
if (CPSR != regs[16])
|
||||
{
|
||||
STDBG << "R16 = " << IOS_ADD << CPSR << '\n';
|
||||
regs[16] = CPSR;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintStack (uint32_t stackadd)
|
||||
{
|
||||
uint32_t add = stackadd;
|
||||
debug("Stack : " << IOS_ADD << add);
|
||||
for (; add < 0x03008000; add += 4)
|
||||
debug(IOS_ADD << MEM.Read32(add));
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
|
||||
// for abort macro
|
||||
#include "ameteor.hpp"
|
||||
|
||||
// from cinterface.cpp
|
||||
void print_bizhawk(const char *msg);
|
||||
void print_bizhawk(std::string &msg);
|
||||
void abort_bizhawk(const char *msg);
|
||||
void keyupdate_bizhawk();
|
||||
extern bool traceenabled;
|
||||
void trace_bizhawk(std::string msg);
|
||||
extern int slcallbackline;
|
||||
void scanlinecallback_bizhawk();
|
||||
|
||||
#if 0
|
||||
#define met_abort(str) \
|
||||
{ \
|
||||
std::cerr << IOS_NOR << "Fatal error :\n" << str << "\nFile : " \
|
||||
<< __FILE__ << "\nLine : " << __LINE__ << "\nr15 = " \
|
||||
<< IOS_ADD << ::AMeteor::_cpu.Reg(15) << "\n[r15] = " << IOS_ADD \
|
||||
<< ::AMeteor::_memory.Read32(::AMeteor::_cpu.Reg(15)) \
|
||||
<< "\nFlag T : " << ::AMeteor::_cpu.ICpsr().thumb << std::endl; \
|
||||
abort(); \
|
||||
}
|
||||
#endif
|
||||
#ifdef METDEBUG
|
||||
#include <sstream>
|
||||
//extern "C" int __stdcall MessageBoxA(int, const char *, const char *, int);
|
||||
#define met_abort(_str) if(true)\
|
||||
{ \
|
||||
std::stringstream _zisrny; \
|
||||
_zisrny << IOS_NOR << "Fatal error :\n" << _str << "\nFile : " \
|
||||
<< __FILE__ << "\nLine : " << __LINE__ << "\nr15 = " \
|
||||
<< IOS_ADD << ::AMeteor::_cpu.Reg(15) << "\n[r15] = " << IOS_ADD \
|
||||
<< ::AMeteor::_memory.Read32(::AMeteor::_cpu.Reg(15)) \
|
||||
<< "\nFlag T : " << ::AMeteor::_cpu.ICpsr().thumb << std::endl; \
|
||||
abort_bizhawk(_zisrny.str().c_str()); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define met_abort(str) {}
|
||||
#endif
|
||||
|
||||
#define STDBG std::cout
|
||||
//#define STDBG debug_stream
|
||||
|
||||
#if defined METDEBUG && defined METDEBUGLOG
|
||||
//XXX
|
||||
# define MYDEBUG
|
||||
# define debug(_str) \
|
||||
{ \
|
||||
std::stringstream _zisrny; \
|
||||
_zisrny << _str << std::endl; \
|
||||
print_bizhawk(_zisrny.str()); \
|
||||
}
|
||||
//STDBG << str << std::endl
|
||||
//# define debug_(str) \
|
||||
// STDBG << str
|
||||
#else
|
||||
# define debug(s) {}
|
||||
//# define debug_(s) {}
|
||||
#endif
|
||||
|
||||
#define IOS_ADD \
|
||||
"0x" << std::setbase(16) << std::setw(8) << std::setfill('0') \
|
||||
<< std::uppercase
|
||||
#define IOS_TRACE \
|
||||
std::setbase(16) << std::setw(8) << std::setfill('0') << std::uppercase
|
||||
#define IOS_NOR \
|
||||
std::setbase(10) << std::setw(0) << std::setfill(' ')
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
void debug_bits(uint32_t u);
|
||||
void debug_bits_16(uint16_t u);
|
||||
|
||||
#if defined MET_REGS_DEBUG
|
||||
void PrintRegs ();
|
||||
void PrintStack (uint32_t stackadd);
|
||||
#else
|
||||
#define PrintRegs()
|
||||
#define PrintStack(b)
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,39 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/argimmediate.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
std::string ArgImmediate::GetString () const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << '#';
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << m_imm << 'h';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Argument* ArgImmediate::Clone () const
|
||||
{
|
||||
return new ArgImmediate(*this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/argmulregisters.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
std::string ArgMulRegisters::GetString () const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << '{';
|
||||
|
||||
bool open = false;
|
||||
|
||||
for (Registers::const_iterator iter = m_regs.begin();
|
||||
iter != m_regs.end(); ++iter)
|
||||
{
|
||||
if (open &&
|
||||
iter + 1 < m_regs.end() &&
|
||||
*(iter + 1) == (*iter) + 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (iter + 2 < m_regs.end() &&
|
||||
*(iter + 1) == (*iter) + 1 &&
|
||||
*(iter + 2) == (*iter) + 2)
|
||||
{
|
||||
ss << 'r' << (int)*iter << '-';
|
||||
open = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << 'r' << (int)*iter;
|
||||
open = false;
|
||||
if (iter + 1 != m_regs.end())
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_lastreg == SPREG_LR)
|
||||
{
|
||||
if (ss.width() != 1)
|
||||
ss << ", ";
|
||||
ss << "lr";
|
||||
}
|
||||
else if (m_lastreg == SPREG_PC)
|
||||
{
|
||||
if (ss.width() != 1)
|
||||
ss << ", ";
|
||||
ss << "pc";
|
||||
}
|
||||
|
||||
ss << '}';
|
||||
|
||||
if (m_forceuser)
|
||||
ss << '^';
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Argument* ArgMulRegisters::Clone () const
|
||||
{
|
||||
return new ArgMulRegisters(*this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/argpsr.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
std::string ArgPsr::GetString () const
|
||||
{
|
||||
std::string out;
|
||||
|
||||
if (m_spsr)
|
||||
out = "SPSR";
|
||||
else
|
||||
out = "CPSR";
|
||||
|
||||
if (m_fields <= 0xF)
|
||||
{
|
||||
out += '_';
|
||||
if (m_fields & 0x1)
|
||||
out += 'c';
|
||||
if (m_fields & 0x2)
|
||||
out += 'x';
|
||||
if (m_fields & 0x4)
|
||||
out += 's';
|
||||
if (m_fields & 0x8)
|
||||
out += 'f';
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Argument* ArgPsr::Clone () const
|
||||
{
|
||||
return new ArgPsr(*this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/argregister.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
std::string ArgRegister::GetString () const
|
||||
{
|
||||
static const char* SpeRegisters[] = {"SP", "LR", "PC"};
|
||||
|
||||
std::ostringstream ss;
|
||||
|
||||
if (m_memory)
|
||||
ss << '[';
|
||||
|
||||
if (m_special)
|
||||
ss << SpeRegisters[m_reg-13];
|
||||
else
|
||||
ss << 'r' << (int)m_reg;
|
||||
|
||||
if (m_memory)
|
||||
ss << ']';
|
||||
|
||||
if (m_writeback)
|
||||
ss << '!';
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Argument* ArgRegister::Clone () const
|
||||
{
|
||||
return new ArgRegister(*this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/argrelative.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
ArgRelative::ArgRelative (const ArgRegister& reg, const Argument& off,
|
||||
bool pre, bool up, bool writeback) :
|
||||
Argument(),
|
||||
m_reg(reg),
|
||||
m_off(off.Clone()),
|
||||
m_pre(pre),
|
||||
m_up(up),
|
||||
m_writeback(writeback)
|
||||
{ }
|
||||
|
||||
ArgRelative::ArgRelative (const ArgRelative& arg) :
|
||||
Argument(),
|
||||
m_reg(arg.m_reg),
|
||||
m_off(arg.m_off->Clone()),
|
||||
m_pre(arg.m_pre),
|
||||
m_up(arg.m_up),
|
||||
m_writeback(arg.m_writeback)
|
||||
{ }
|
||||
|
||||
ArgRelative::~ArgRelative ()
|
||||
{
|
||||
delete m_off;
|
||||
}
|
||||
|
||||
Argument* ArgRelative::Clone () const
|
||||
{
|
||||
return new ArgRelative(*this);
|
||||
}
|
||||
|
||||
std::string ArgRelative::GetString () const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "[r" << (int)m_reg.GetRegister();
|
||||
|
||||
if (m_pre)
|
||||
{
|
||||
ss << (m_up ? ", +" : ", -") << m_off->GetString() << ']';
|
||||
if (m_writeback)
|
||||
ss << '!';
|
||||
}
|
||||
else
|
||||
ss << (m_up ? "], +" : "], -") << m_off->GetString();
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/argshift.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
ArgShift::ArgShift (const Argument& arg1, const Argument& arg2,
|
||||
ShiftType type, bool memory) :
|
||||
Argument(),
|
||||
m_arg1(arg1.Clone()),
|
||||
m_arg2(arg2.Clone()),
|
||||
m_type(type),
|
||||
m_memory(memory)
|
||||
{ }
|
||||
|
||||
ArgShift::ArgShift (const ArgShift& arg) :
|
||||
Argument(),
|
||||
m_arg1(arg.m_arg1->Clone()),
|
||||
m_arg2(arg.m_arg2->Clone()),
|
||||
m_type(arg.m_type),
|
||||
m_memory(arg.m_memory)
|
||||
{ }
|
||||
|
||||
ArgShift::~ArgShift ()
|
||||
{
|
||||
delete m_arg1;
|
||||
delete m_arg2;
|
||||
}
|
||||
|
||||
Argument* ArgShift::Clone () const
|
||||
{
|
||||
return new ArgShift(*this);
|
||||
}
|
||||
|
||||
std::string ArgShift::GetString () const
|
||||
{
|
||||
static const char* Shifts[] = {", LSL ", ", LSR ", ", ASR ", ", ROR ",
|
||||
", RRX "};
|
||||
|
||||
std::ostringstream ss;
|
||||
|
||||
if (m_memory)
|
||||
ss << '[';
|
||||
|
||||
ss << m_arg1->GetString() << Shifts[m_type] << m_arg2->GetString();
|
||||
|
||||
if (m_memory)
|
||||
ss << ']';
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/arguimmediate.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
std::string ArgUImmediate::GetString () const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << '#';
|
||||
ss << std::hex << std::setw(8) << std::setfill('0') << m_imm << 'h';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
Argument* ArgUImmediate::Clone () const
|
||||
{
|
||||
return new ArgUImmediate(*this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/arguments.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
Arguments::~Arguments ()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Arguments::Clear ()
|
||||
{
|
||||
for (std::vector<Argument*>::iterator iter = m_args.begin();
|
||||
iter != m_args.end(); ++iter)
|
||||
{
|
||||
delete *iter;
|
||||
}
|
||||
m_args.clear();
|
||||
}
|
||||
|
||||
std::string Arguments::GetString () const
|
||||
{
|
||||
std::string out;
|
||||
for (std::vector<Argument*>::const_iterator iter = m_args.begin();
|
||||
iter != m_args.end(); ++iter)
|
||||
{
|
||||
if (!out.empty())
|
||||
out += ", ";
|
||||
out += (*iter)->GetString();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,691 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/disassembler/instruction.hpp"
|
||||
|
||||
#include "ameteor/disassembler/argregister.hpp"
|
||||
#include "ameteor/disassembler/argrelative.hpp"
|
||||
#include "ameteor/disassembler/argimmediate.hpp"
|
||||
#include "ameteor/disassembler/arguimmediate.hpp"
|
||||
#include "ameteor/disassembler/argshift.hpp"
|
||||
#include "ameteor/disassembler/argpsr.hpp"
|
||||
#include "ameteor/disassembler/argmulregisters.hpp"
|
||||
|
||||
#include "../globals.hpp" // for ROR
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Disassembler
|
||||
{
|
||||
void Instruction::Clear ()
|
||||
{
|
||||
m_operator.clear();
|
||||
m_args.Clear();
|
||||
}
|
||||
|
||||
#define Rn ((code >> 16) & 0xF)
|
||||
#define Rd ((code >> 12) & 0xF)
|
||||
#define Rs ((code >> 8) & 0xF)
|
||||
#define Rm (code & 0xF)
|
||||
|
||||
void Instruction::ParseArm (uint32_t offset, uint32_t code)
|
||||
{
|
||||
Clear();
|
||||
|
||||
if ((code & 0x0FFFFFD0) == 0x12FFF10)
|
||||
{
|
||||
if (code & (0x1 << 5))
|
||||
m_operator = "BLX";
|
||||
else
|
||||
m_operator = "BX";
|
||||
m_args.AddArgument(ArgRegister(Rm));
|
||||
ParseArmCondition(code);
|
||||
}
|
||||
else if (((code >> 25) & 0x7) == 0x5)
|
||||
{
|
||||
if (((code >> 28) & 0xF) == 0xF)
|
||||
{
|
||||
m_operator = "BLX";
|
||||
m_args.AddArgument(ArgImmediate(offset + 8 +
|
||||
(((code & (0x1 << 23)) ? 0xFF000000 | (code & 0x00FFFFFF)
|
||||
: (code & 0x00FFFFFF)) << 2)
|
||||
+ ((code & (0x1 << 24)) ? 2 : 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (code & (0x1 << 24))
|
||||
m_operator = "BL";
|
||||
else
|
||||
m_operator = "B";
|
||||
m_args.AddArgument(ArgImmediate(offset + 8 +
|
||||
(((code & (0x1 << 23)) ? 0xFF000000 | (code & 0x00FFFFFF)
|
||||
: (code & 0x00FFFFFF)) << 2)));
|
||||
ParseArmCondition(code);
|
||||
}
|
||||
}
|
||||
else if (((code >> 25) & 0x7) == 0x1)
|
||||
{
|
||||
ParseArmDataProc(code);
|
||||
}
|
||||
else if (((code >> 26) & 0x3) == 0x1)
|
||||
{
|
||||
if ((code & 0xF0100000) != 0xF0100000) // not PLD
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
if (code & (0x1 << 25)) // register offset
|
||||
{
|
||||
switch ((code >> 5) & 0x3)
|
||||
{
|
||||
case 0: // Logical Shift Left
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_LSL, false),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
break;
|
||||
case 1: // Logical Shift Right
|
||||
if (code & (0x1F << 7))
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_LSR, false),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
else
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate(32), SHIFT_LSR, false),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
break;
|
||||
case 2: // Arithmetic Shift Right
|
||||
if (code & (0x1F << 7))
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_ASR, false),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
else
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate(32), SHIFT_ASR, false),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
break;
|
||||
case 3: // ROtate Right
|
||||
if (code & (0x1F << 7))
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_ROR, false),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
else
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate(1), SHIFT_RRX, false),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // immediate offset
|
||||
{
|
||||
m_args.AddArgument(ArgRelative(Rn, ArgImmediate(code & 0xFFF),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
}
|
||||
|
||||
if ((code & 0xF0100000) == 0xF0100000)
|
||||
m_operator = "PLD";
|
||||
else
|
||||
{
|
||||
if (code & (0x1 << 20))
|
||||
m_operator = "LDR";
|
||||
else
|
||||
m_operator = "STR";
|
||||
if (code & (0x1 << 22))
|
||||
m_operator += "B";
|
||||
|
||||
ParseArmCondition(code);
|
||||
}
|
||||
}
|
||||
else if (((code >> 25) & 0x7) == 0x4)
|
||||
{
|
||||
if (code & (0x1 << 20))
|
||||
m_operator = "LDM";
|
||||
else
|
||||
m_operator = "STM";
|
||||
|
||||
if (code & (0x1 << 23))
|
||||
m_operator += 'I';
|
||||
else
|
||||
m_operator += 'D';
|
||||
|
||||
if (code & (0x1 << 24))
|
||||
m_operator += 'B';
|
||||
else
|
||||
m_operator += 'A';
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rn, code & (0x1 << 21)));
|
||||
|
||||
ArgMulRegisters argRegs(code & (0x1 << 22));
|
||||
for (register uint8_t n = 0; n < 16; ++n)
|
||||
if (code & (0x1 << n))
|
||||
argRegs.AddRegister(n);
|
||||
m_args.AddArgument(argRegs);
|
||||
|
||||
ParseArmCondition(code);
|
||||
}
|
||||
else if (((code >> 25) & 0x7) == 0x0)
|
||||
{
|
||||
if ((code & 0x0FC000F0) == 0x00000090 ||
|
||||
(code & 0x0F8000F0) == 0x00800090 ||
|
||||
(code & 0x0F900090) == 0x01000080)
|
||||
{
|
||||
// NOTE : In this instruction Rn and Rd are inverted
|
||||
static const char* Instructions[] = {"MUL", "MLA", "Reserved",
|
||||
"Reserved", "UMULL", "UMLAL", "SMULL", "SMLAL", "SMLAxy",
|
||||
"", // This is for SMLAWy and SMULWy
|
||||
"SMLALxy", "SMULxy", "Reserved", "Reserved", "Reserved",
|
||||
"Reserved"};
|
||||
|
||||
uint8_t opcode = (code >> 21) & 0xF;
|
||||
if (opcode == 0x9)
|
||||
m_operator = (code & (0x1 << 5)) ? "SMULWy" : "SMLAWy";
|
||||
else
|
||||
m_operator = Instructions[opcode];
|
||||
if (!(opcode & (0x1 << 4)) && (code & (0x1 << 20)))
|
||||
m_operator += 'S';
|
||||
|
||||
ParseArmCondition(code);
|
||||
|
||||
if ((opcode & 0xC) == 0x4 || opcode == 0xA)
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgRegister(Rn));
|
||||
m_args.AddArgument(ArgRegister(Rm));
|
||||
m_args.AddArgument(ArgRegister(Rs));
|
||||
if ((opcode & 0xE) == 0x8 || opcode == 0x1)
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
}
|
||||
else if ((code & (0x1 << 7)) && (code & (0x1 << 4)))
|
||||
{
|
||||
if (((code >> 23) & 0x3) == 0x2 && ((code >> 20) & 0x3) == 0x0
|
||||
&& ((code >> 4) & 0xFF) == 0x09)
|
||||
{
|
||||
if (code & (0x1 << 22)) // SWPB
|
||||
m_operator = "SWPB";
|
||||
else // SWP
|
||||
m_operator = "SWP";
|
||||
|
||||
ParseArmCondition(code);
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgRegister(Rm));
|
||||
m_args.AddArgument(ArgRegister(Rn, false, false, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char* Instructions[] = {"Reserved", "STRH", "LDRD",
|
||||
"STRD", "Reserved", "LDRH", "LDRSB", "LDRSH"};
|
||||
|
||||
m_operator = Instructions[((code >> 18) & 0x4)
|
||||
| ((code >> 5) & 0x3)];
|
||||
|
||||
ParseArmCondition(code);
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
|
||||
if (code & (0x1 << 22)) // immediate
|
||||
{
|
||||
m_args.AddArgument(ArgRelative(ArgRegister(Rn),
|
||||
ArgImmediate(((code >> 4) & 0xF0) | (code & 0xF)),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_args.AddArgument(ArgRelative(ArgRegister(Rn),
|
||||
ArgRegister(code & 0xF),
|
||||
code & (0x1 << 24), code & (0x1 << 23),
|
||||
code & (0x1 << 21)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (((code >> 23) & 0x3) == 0x2)
|
||||
{
|
||||
if (!((code >> 20) & 0x1))
|
||||
{
|
||||
if (code & (0x1 << 21))
|
||||
{
|
||||
m_operator = "MSR";
|
||||
|
||||
m_args.AddArgument(ArgPsr(code & (0x1 << 22),
|
||||
(code >> 16) & 0xF));
|
||||
|
||||
if (code & (0x1 << 25)) // immediate
|
||||
{
|
||||
m_args.AddArgument(ArgUImmediate(
|
||||
ROR(code & 0xFF, (code >> 8) & 0xF)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_args.AddArgument(ArgRegister(Rm));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_operator = "MRS";
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgPsr(code & (0x1 << 22)));
|
||||
}
|
||||
|
||||
ParseArmCondition(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseArmDataProc(code);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseArmDataProc(code);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_operator = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void Instruction::ParseArmDataProc (uint32_t code)
|
||||
{
|
||||
static const char* ops[] = {"AND", "EOR", "SUB", "RSB", "ADD", "ADC",
|
||||
"SBC", "RSC", "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN"};
|
||||
|
||||
uint8_t opcode = (code >> 21) & 0xF;
|
||||
|
||||
if (opcode < 0x8 || opcode > 0xB)
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
if (opcode != 0xD && opcode != 0xF)
|
||||
m_args.AddArgument(ArgRegister(Rn));
|
||||
|
||||
if (code & (0x1 << 25)) // Immediate operand 2
|
||||
{
|
||||
/*if (code & (0xF << 8))
|
||||
m_args.AddArgument(ArgShift(ArgImmediate(code & 0xFF),
|
||||
ArgImmediate(((code >> 8) & 0xF) << 1), SHIFT_ROR, false));
|
||||
else
|
||||
m_args.AddArgument(ArgImmediate(code & 0xFF));*/
|
||||
m_args.AddArgument(ArgUImmediate(
|
||||
ROR(code & 0xFF, (code >> 7) & 0x1E)));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((code >> 5) & 0x3)
|
||||
{
|
||||
case 0: // Logical Shift Left
|
||||
if (code & (0x1 << 4)) // Shift by register
|
||||
{
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgRegister(Rs), SHIFT_LSL, false));
|
||||
}
|
||||
else // Shift by immediate
|
||||
{
|
||||
if (code & (0x1F << 7))
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_LSL, false));
|
||||
else
|
||||
m_args.AddArgument(ArgRegister(Rm));
|
||||
}
|
||||
break;
|
||||
case 1: // Logical Shift Right
|
||||
if (code & (0x1 << 4)) // Shift by register
|
||||
{
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgRegister(Rs), SHIFT_LSR, false));
|
||||
}
|
||||
else // Shift by immediate
|
||||
{
|
||||
if (code & (0x1F << 7))
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_LSR, false));
|
||||
else
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate(32), SHIFT_LSR, false));
|
||||
}
|
||||
break;
|
||||
case 2: // Arithmetic Shift Right
|
||||
if (code & (0x1 << 4)) // Shift by register
|
||||
{
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgRegister(Rs), SHIFT_ASR, false));
|
||||
}
|
||||
else // Shift by immediate
|
||||
{
|
||||
if (code & (0x1F << 7))
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_ASR, false));
|
||||
else
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate(32), SHIFT_ASR, false));
|
||||
}
|
||||
break;
|
||||
case 3: // ROtate Right
|
||||
if (code & (0x1 << 4)) // Shift by register
|
||||
{
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgRegister(Rs), SHIFT_ROR, false));
|
||||
}
|
||||
else // Shift by immediate
|
||||
{
|
||||
if (code & (0x1F << 7))
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate((code >> 7) & 0x1F), SHIFT_ROR, false));
|
||||
else
|
||||
m_args.AddArgument(ArgShift(ArgRegister(Rm),
|
||||
ArgImmediate(1), SHIFT_RRX, false));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_operator = ops[opcode];
|
||||
|
||||
if (code & (0x1 << 20) && (opcode < 0x8 || opcode > 0xB))
|
||||
{
|
||||
m_operator += "S";
|
||||
}
|
||||
ParseArmCondition(code);
|
||||
}
|
||||
|
||||
void Instruction::ParseArmCondition (uint32_t code)
|
||||
{
|
||||
static const char* Conditions[] = {"EQ", "NE", "CS", "CC", "MI", "PL",
|
||||
"VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"};
|
||||
|
||||
m_operator += Conditions[code >> 28];
|
||||
}
|
||||
|
||||
#undef Rn
|
||||
#undef Rd
|
||||
#undef Rs
|
||||
#undef Rm
|
||||
|
||||
#define Rb ((code >> 8) & 0x7)
|
||||
#define Ro ((code >> 6) & 0x7)
|
||||
#define Rs ((code >> 3) & 0x7)
|
||||
#define Rd ((code ) & 0x7)
|
||||
#define Imm (code & 0xFF)
|
||||
#define Off ((code >> 6) & 0x1F)
|
||||
|
||||
#define HiRs ((code >> 3) & 0xF)
|
||||
#define HiRd (((code & (0x1 << 7)) >> 4) | Rd)
|
||||
|
||||
void Instruction::ParseThumb (uint32_t offset, uint16_t code)
|
||||
{
|
||||
Clear ();
|
||||
|
||||
if ((code >> 12) == 0xB && ((code >> 9) & 0x3) == 0x2) // 1011x10
|
||||
{
|
||||
if (code & (0x1 << 11))
|
||||
m_operator = "POP";
|
||||
else
|
||||
m_operator = "PUSH";
|
||||
|
||||
ArgMulRegisters argRegs(false);
|
||||
for (register uint8_t n = 0; n < 8; ++n)
|
||||
if (Imm & (0x1 << n))
|
||||
argRegs.AddRegister(n);
|
||||
|
||||
if (code & (0x1 << 8))
|
||||
{
|
||||
if (code & (0x1 << 11))
|
||||
argRegs.AddLastRegister(SPREG_PC);
|
||||
else
|
||||
argRegs.AddLastRegister(SPREG_LR);
|
||||
}
|
||||
m_args.AddArgument(argRegs);
|
||||
}
|
||||
else if ((code >> 11) == 0x9) // 01001
|
||||
{
|
||||
m_operator = "LDR";
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rb));
|
||||
m_args.AddArgument(ArgRelative(15, ArgImmediate(Imm << 2),
|
||||
true, true, false));
|
||||
}
|
||||
else if ((code >> 12) == 0x8) // 1000
|
||||
{
|
||||
if (code & (0x1 << 11))
|
||||
m_operator = "LDRH";
|
||||
else
|
||||
m_operator = "STRH";
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgRelative(Rs, ArgImmediate(Off << 1),
|
||||
true, true, false));
|
||||
}
|
||||
else if ((code >> 10) == 0x10) // 010000
|
||||
{
|
||||
static const char* Instructions[] = {"AND", "EOR", "LSL", "LSR", "ASR",
|
||||
"ADC", "SBC", "ROR", "TST", "NEG", "CMP", "CMN", "ORR", "MUL", "BIC",
|
||||
"MVN"};
|
||||
|
||||
m_operator = Instructions[(code >> 6) & 0xF];
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgRegister(Rs));
|
||||
}
|
||||
else if ((code >> 10) == 0x11) // 010001
|
||||
{
|
||||
switch ((code >> 8) & 0x3)
|
||||
{
|
||||
case 0x0: // ADD
|
||||
m_operator = "ADD";
|
||||
m_args.AddArgument(ArgRegister(HiRd));
|
||||
m_args.AddArgument(ArgRegister(HiRs));
|
||||
break;
|
||||
case 0x1: // CMP
|
||||
m_operator = "CMP";
|
||||
m_args.AddArgument(ArgRegister(HiRd));
|
||||
m_args.AddArgument(ArgRegister(HiRs));
|
||||
break;
|
||||
case 0x2:
|
||||
if (HiRd != 8 || HiRs != 8) // MOV
|
||||
{
|
||||
m_operator = "MOV";
|
||||
m_args.AddArgument(ArgRegister(HiRd));
|
||||
m_args.AddArgument(ArgRegister(HiRs));
|
||||
}
|
||||
else
|
||||
m_operator = "NOP";
|
||||
break;
|
||||
case 0x3:
|
||||
if (code & (0x1 << 7)) // BLX
|
||||
{
|
||||
m_operator = "BLX";
|
||||
m_args.AddArgument(ArgRegister(HiRs));
|
||||
}
|
||||
else // BX
|
||||
{
|
||||
m_operator = "BX";
|
||||
m_args.AddArgument(ArgRegister(HiRs));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((code >> 13) == 0x1) // 001
|
||||
{
|
||||
static const char* Instructions[] = {"MOV", "CMP", "ADD", "SUB"};
|
||||
|
||||
m_operator = Instructions[(code >> 11) & 0x3];
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rb));
|
||||
m_args.AddArgument(ArgImmediate(Imm));
|
||||
}
|
||||
else if ((code >> 13) == 0x3) // 011
|
||||
{
|
||||
static const char* Instructions[] = {"STR", "LDR", "STRB", "LDRB"};
|
||||
|
||||
m_operator = Instructions[(code >> 11) & 0x3];
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
if (code & (0x1 << 12))
|
||||
m_args.AddArgument(ArgRelative(Rs, ArgImmediate(Off), true,
|
||||
true, false));
|
||||
else
|
||||
m_args.AddArgument(ArgRelative(Rs, ArgImmediate(Off << 2), true,
|
||||
true, false));
|
||||
}
|
||||
else if ((code >> 12) == 0xC) // 1100
|
||||
{
|
||||
if (code & (0x1 << 11))
|
||||
m_operator = "LDMIA";
|
||||
else
|
||||
m_operator = "STMIA";
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rb, true));
|
||||
|
||||
ArgMulRegisters argRegs(false);
|
||||
for (register uint8_t n = 0; n < 8; ++n)
|
||||
if (Imm & (0x1 << n))
|
||||
argRegs.AddRegister(n);
|
||||
m_args.AddArgument(argRegs);
|
||||
}
|
||||
else if ((code >> 13) == 0x0) // 000
|
||||
{
|
||||
if ((code >> 11) == 0x3) // 00011
|
||||
{
|
||||
if ((code >> 9) & 0x1)
|
||||
m_operator = "SUB";
|
||||
else
|
||||
m_operator = "ADD";
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgRegister(Rs));
|
||||
|
||||
if ((code >> 10) & 0x1) // imm
|
||||
m_args.AddArgument(ArgImmediate(Ro));
|
||||
else // reg
|
||||
m_args.AddArgument(ArgRegister(Ro));
|
||||
}
|
||||
else // 000
|
||||
{
|
||||
static const char* Instructions[] = {"LSL", "LSR", "ASR", "Reserved"};
|
||||
|
||||
m_operator = Instructions[(code >> 11) & 0x3];
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgRegister(Rs));
|
||||
m_args.AddArgument(ArgImmediate(Off));
|
||||
}
|
||||
}
|
||||
else if ((code >> 11) == 0x1E) // 11110
|
||||
{
|
||||
m_operator = "BL.W1";
|
||||
|
||||
m_args.AddArgument(ArgImmediate(offset + 4 + ((code & 0x7FF) << 12)));
|
||||
}
|
||||
else if ((code >> 13) == 0x7 && (code & (0x1 << 11))) // 111x1
|
||||
{
|
||||
m_operator = "BL.W2";
|
||||
|
||||
m_args.AddArgument(ArgImmediate((code & 0x7FF) << 1));
|
||||
}
|
||||
else if ((code >> 11) == 0x1C) // 11100
|
||||
{
|
||||
m_operator = "B";
|
||||
|
||||
if (code & (0x1 << 10))
|
||||
m_args.AddArgument(ArgUImmediate(offset + 4 +
|
||||
((int32_t)(((code & 0x3FF) << 1) | 0xFFFFF800))));
|
||||
else
|
||||
m_args.AddArgument(ArgUImmediate(offset + 4 + ((code & 0x3FF) << 1)));
|
||||
}
|
||||
else if ((code >> 12) == 0xD) // 1101
|
||||
{
|
||||
if (((code >> 8) & 0xF) == 0xF) // 11011111
|
||||
{
|
||||
m_operator = "SWI";
|
||||
|
||||
m_args.AddArgument(ArgImmediate(code & 0xFF));
|
||||
}
|
||||
else // 1101
|
||||
{
|
||||
static const char* Conditions[] = {"EQ", "NE", "CS", "CC", "MI", "PL",
|
||||
"VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "__", "**"};
|
||||
|
||||
m_operator = "B";
|
||||
m_operator += Conditions[(code >> 8) & 0xF];
|
||||
|
||||
m_args.AddArgument(ArgUImmediate(offset + 4 +
|
||||
(((int32_t)(int8_t)Imm) << 1)));
|
||||
}
|
||||
}
|
||||
else if ((code >> 8) == 0xB0) // 10110000
|
||||
{
|
||||
m_operator = "ADD";
|
||||
|
||||
m_args.AddArgument(ArgRegister(13, false, true));
|
||||
if (code & (0x1 << 7)) // substract
|
||||
m_args.AddArgument(ArgImmediate(-((code & 0x7F) << 2)));
|
||||
else // add
|
||||
m_args.AddArgument(ArgImmediate((code & 0x7F) << 2));
|
||||
}
|
||||
else if ((code >> 12) == 0x5) // 0101
|
||||
{
|
||||
if (code & (0x1 << 11))
|
||||
m_operator = "LDR";
|
||||
else
|
||||
m_operator = "STR";
|
||||
|
||||
if (code & (0x1 << 10))
|
||||
m_operator += 'B';
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rd));
|
||||
m_args.AddArgument(ArgRelative(Rs, ArgRegister(Ro), true, true, false));
|
||||
}
|
||||
else if ((code >> 12) == 0x9) // 1001
|
||||
{
|
||||
if (code & (0x1 << 11))
|
||||
m_operator = "LDR";
|
||||
else
|
||||
m_operator = "STR";
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rb));
|
||||
m_args.AddArgument(ArgRelative(ArgRegister(13, false, true),
|
||||
ArgImmediate(Imm << 2), true, true, false));
|
||||
}
|
||||
else if ((code >> 12) == 0xA) // 1010
|
||||
{
|
||||
m_operator = "ADD";
|
||||
|
||||
m_args.AddArgument(ArgRegister(Rb));
|
||||
if (code & (0x1 << 11)) // with SP
|
||||
m_args.AddArgument(ArgRegister(13, false, true));
|
||||
else // with PC
|
||||
m_args.AddArgument(ArgRegister(15, false, true));
|
||||
m_args.AddArgument(ArgImmediate(Imm << 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_operator = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#undef Rb
|
||||
#undef Ro
|
||||
#undef Rs
|
||||
#undef Rd
|
||||
#undef Imm
|
||||
#undef Off
|
||||
|
||||
#undef HiRs
|
||||
#undef HiRd
|
||||
}
|
||||
}
|
|
@ -1,317 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/dma.hpp"
|
||||
#include "ameteor/io.hpp"
|
||||
#include "ameteor/memory.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
void Dma::Reset ()
|
||||
{
|
||||
for (Channel* chan = m_chans; chan < m_chans+4; ++chan)
|
||||
{
|
||||
chan->src = 0;
|
||||
chan->dest = 0;
|
||||
chan->count = 0;
|
||||
chan->control.w = 0;
|
||||
}
|
||||
m_graphic = 0;
|
||||
}
|
||||
|
||||
void Dma::UpdateCnt (uint8_t channum)
|
||||
{
|
||||
Channel& chan = m_chans[channum];
|
||||
|
||||
if (chan.control.w !=
|
||||
IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE))
|
||||
{
|
||||
if (!chan.control.b.enable &&
|
||||
(IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE)
|
||||
& (0x1 << 15)))
|
||||
// if we changed enable from 0 to 1
|
||||
{
|
||||
chan.dest = IO.DRead32(Io::DMA0DAD + channum * Io::DMA_CHANSIZE);
|
||||
if (channum == 3)
|
||||
chan.dest &= 0x0FFFFFFF;
|
||||
else
|
||||
chan.dest &= 0x07FFFFFF;
|
||||
|
||||
chan.src = IO.DRead32(Io::DMA0SAD + channum * Io::DMA_CHANSIZE);
|
||||
if (channum == 0)
|
||||
chan.src &= 0x07FFFFFF;
|
||||
else
|
||||
chan.src &= 0x0FFFFFFF;
|
||||
|
||||
chan.count = chan.reload;
|
||||
if (channum != 3)
|
||||
chan.count &= 0x3FFF;
|
||||
|
||||
chan.control.w =
|
||||
IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE);
|
||||
|
||||
Check(channum, Immediately);
|
||||
}
|
||||
else
|
||||
chan.control.w =
|
||||
IO.DRead16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE);
|
||||
|
||||
if (chan.control.b.start == Special)
|
||||
{
|
||||
switch (channum)
|
||||
{
|
||||
case 0:
|
||||
met_abort("prohibited !");
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
// sound dma
|
||||
if (chan.dest != 0x040000A0 && chan.dest != 0x040000A4)
|
||||
met_abort("Special DMA 1 or 2 with unauthorized address : "
|
||||
<< IOS_ADD << chan.dest);
|
||||
if (!chan.control.b.repeat)
|
||||
met_abort("Special DMA 1 or 2 without repeat");
|
||||
|
||||
// 4 words of 32 bits
|
||||
chan.count = 4;
|
||||
chan.control.b.type = 1;
|
||||
// no increment
|
||||
chan.control.b.dest = 2;
|
||||
break;
|
||||
case 3:
|
||||
met_abort("not implemented");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dma::Check (uint8_t channum, uint8_t reason)
|
||||
{
|
||||
register Channel::Control cnt = m_chans[channum].control;
|
||||
|
||||
if (cnt.b.enable &&
|
||||
cnt.b.start == reason)
|
||||
Process(channum);
|
||||
}
|
||||
|
||||
void Dma::Process (uint8_t channum)
|
||||
{
|
||||
Channel& chan = m_chans[channum];
|
||||
|
||||
int8_t s_inc, d_inc;
|
||||
s_inc = d_inc = 2; // increment or increment reload
|
||||
|
||||
if (chan.control.b.src == 1) // decrement
|
||||
s_inc = -2;
|
||||
else if (chan.control.b.src == 2) // fixed
|
||||
s_inc = 0;
|
||||
else if (chan.control.b.src == 3)
|
||||
met_abort("prohibited");
|
||||
|
||||
if (chan.control.b.dest == 1)
|
||||
d_inc = -2;
|
||||
else if (chan.control.b.dest == 2)
|
||||
d_inc = 0;
|
||||
//else if (chan.control.b.dest == 3)
|
||||
// same as 0, but we do something at the end
|
||||
|
||||
if (chan.control.b.type) // 32 bits transfer
|
||||
{
|
||||
s_inc <<= 1;
|
||||
d_inc <<= 1;
|
||||
}
|
||||
|
||||
if (chan.count == 0)
|
||||
{
|
||||
if (channum != 3)
|
||||
chan.count = 0x4000;
|
||||
// 0x10000 doesn't fill in 16 bits, we treat this case in the Copy() call
|
||||
}
|
||||
|
||||
//printf("DMA%hhu from %08X to %08X of %hu %s\n", channum, chan.src, chan.dest, chan.count, chan.control.b.type ? "words":"halfwords");
|
||||
//if (i > debut)
|
||||
debug ("DMA" << IOS_NOR << (int)channum << ", from " << IOS_ADD << chan.src
|
||||
<< " to " << IOS_ADD << chan.dest
|
||||
<< " of " << IOS_NOR << (chan.count ? chan.count : 0x10000)
|
||||
<< (chan.control.b.type ? " words" : " halfwords"));
|
||||
if (traceenabled)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "DMA" << IOS_NOR << (int)channum << ", from " << IOS_ADD << chan.src
|
||||
<< " to " << IOS_ADD << chan.dest
|
||||
<< " of " << IOS_NOR << (chan.count ? chan.count : 0x10000)
|
||||
<< (chan.control.b.type ? " words" : " halfwords");
|
||||
trace_bizhawk(ss.str());
|
||||
}
|
||||
#if 0
|
||||
if (channum == 3 && (chan.dest >> 24) == 0x0D || (chan.src >> 24) == 0x0D)
|
||||
{
|
||||
if (chan.control.b.type)
|
||||
met_abort("Word copy for EEPROM DMA3");
|
||||
if (d_inc != 2 || s_inc != 2)
|
||||
met_abort("Source or destination not incremeting in EEPROM DMA3");
|
||||
if ((chan.dest >> 24) == 0x0D)
|
||||
MEM.WriteEepromDma(chan.src, chan.count ? chan.count : 0x10000);
|
||||
else if ((chan.src >> 24) == 0x0D)
|
||||
MEM.ReadEepromDma(chan.dest, chan.count ? chan.count : 0x10000);
|
||||
chan.src += chan.count * 2;
|
||||
chan.dest += chan.count * 2;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (channum == 3 && (chan.dest >> 24) == 0x0D)
|
||||
{
|
||||
if (chan.control.b.type)
|
||||
met_abort("Word copy for EEPROM DMA3");
|
||||
if (d_inc != 2 || s_inc != 2)
|
||||
met_abort("Source or destination not incremeting in EEPROM DMA3");
|
||||
MEM.WriteEepromDma(chan.src, chan.count);
|
||||
chan.src += chan.count * 2;
|
||||
chan.dest += chan.count * 2;
|
||||
}
|
||||
else
|
||||
Copy(chan.src, chan.dest, s_inc, d_inc,
|
||||
chan.count ? chan.count : 0x10000, chan.control.b.type);
|
||||
|
||||
if (chan.control.b.type)
|
||||
{
|
||||
CYCLES32NSeq(chan.src, chan.count);
|
||||
CYCLES32NSeq(chan.dest, chan.count);
|
||||
ICYCLES(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
CYCLES16NSeq(chan.src, chan.count);
|
||||
CYCLES16NSeq(chan.dest, chan.count);
|
||||
ICYCLES(2);
|
||||
}
|
||||
uint32_t d = chan.dest >> 24;
|
||||
uint32_t s = chan.src >> 24;
|
||||
if (d >= 0x08 && d <= 0x0D && s >= 0x08 && s <= 0x0D)
|
||||
// if both source and destination are in GamePak
|
||||
ICYCLES(2);
|
||||
|
||||
if (chan.control.b.irq)
|
||||
CPU.SendInterrupt(0x1 << (8 + channum));
|
||||
|
||||
if (chan.control.b.dest == 3)
|
||||
{
|
||||
chan.dest = IO.DRead32(Io::DMA0DAD + channum * Io::DMA_CHANSIZE);
|
||||
if (channum == 3)
|
||||
chan.dest &= 0x0FFFFFFF;
|
||||
else
|
||||
chan.dest &= 0x07FFFFFF;
|
||||
}
|
||||
|
||||
// if repeat but not sound dma
|
||||
//if (!((channum == 1 || channum == 2) && chan.control.b.start == Special) && chan.control.b.repeat)
|
||||
if (((channum != 1 && channum != 2) || chan.control.b.start != Special)
|
||||
&& chan.control.b.repeat)
|
||||
{
|
||||
chan.count = chan.reload;
|
||||
}
|
||||
|
||||
if (!chan.control.b.repeat || chan.control.b.start == Immediately)
|
||||
{
|
||||
chan.control.b.enable = 0;
|
||||
IO.GetRef16(Io::DMA0CNT_H + channum * Io::DMA_CHANSIZE) &= 0x7FFF;
|
||||
}
|
||||
}
|
||||
|
||||
void Dma::Copy (uint32_t& src, uint32_t& dest, int8_t s_inc, int8_t d_inc,
|
||||
uint32_t count, bool word)
|
||||
{
|
||||
uint32_t basedest = dest;
|
||||
|
||||
if (word)
|
||||
{
|
||||
src &= 0xFFFFFFFC;
|
||||
dest &= 0xFFFFFFFC;
|
||||
}
|
||||
else
|
||||
{
|
||||
src &= 0xFFFFFFFE;
|
||||
dest &= 0xFFFFFFFE;
|
||||
}
|
||||
|
||||
// sound
|
||||
if (dest == 0x040000A0)
|
||||
{
|
||||
SOUND.SendDigitalA((uint8_t*)MEM.GetRealAddress(src));
|
||||
src += 4*4;
|
||||
if (d_inc != 0)
|
||||
met_abort("dinc != 0 on dma sound, should not happen");
|
||||
return;
|
||||
}
|
||||
if (dest == 0x040000A4)
|
||||
{
|
||||
SOUND.SendDigitalB((uint8_t*)MEM.GetRealAddress(src));
|
||||
src += 4*4;
|
||||
if (d_inc != 0)
|
||||
met_abort("dinc != 0 on dma sound, should not happen");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dest >> 24) >= 0x05 &&
|
||||
(dest >> 24) <= 0x07)
|
||||
m_graphic = true;
|
||||
|
||||
if (word)
|
||||
{
|
||||
for (uint32_t cur = 0; cur < count; ++cur)
|
||||
{
|
||||
MEM.Write32(dest, MEM.Read32(src));
|
||||
src += s_inc;
|
||||
dest += d_inc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t cur = 0; cur < count; ++cur)
|
||||
{
|
||||
MEM.Write16(dest, MEM.Read16(src));
|
||||
src += s_inc;
|
||||
dest += d_inc;
|
||||
}
|
||||
}
|
||||
|
||||
m_graphic = false;
|
||||
//if ((basedest >> 24) == 0x07)
|
||||
// LCD.OamWrite(basedest, dest);
|
||||
}
|
||||
|
||||
bool Dma::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_ARRAY(m_chans);
|
||||
// no need to save or load m_graphic since we shouldn't save or load during
|
||||
// a dma
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dma::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_ARRAY(m_chans);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,272 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/eeprom.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "debug.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
Eeprom::Eeprom (bool big) :
|
||||
CartMem(),
|
||||
m_state(IDLE),
|
||||
m_add(0),
|
||||
m_pos(0)
|
||||
{
|
||||
if (big)
|
||||
m_size = 0x2000;
|
||||
else
|
||||
m_size = 0x0200;
|
||||
|
||||
*(uint32_t*)(m_data+MAX_SIZE) = m_size;
|
||||
}
|
||||
|
||||
void Eeprom::Reset ()
|
||||
{
|
||||
std::memset(m_data, 0, m_size);
|
||||
}
|
||||
|
||||
bool Eeprom::Load (std::istream& f)
|
||||
{
|
||||
f.read((char*)m_data, m_size);
|
||||
return f.good();
|
||||
}
|
||||
|
||||
bool Eeprom::Save (std::ostream& f)
|
||||
{
|
||||
f.write((char*)m_data, m_size);
|
||||
return f.good();
|
||||
}
|
||||
|
||||
uint8_t Eeprom::Read (uint16_t MET_UNUSED(add))
|
||||
{
|
||||
met_abort("8 bits write to EEPROM");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t Eeprom::Read ()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case READ_GARBAGE:
|
||||
++m_pos;
|
||||
if (m_pos == 4)
|
||||
{
|
||||
m_pos = 0;
|
||||
m_state = READ_DATA;
|
||||
}
|
||||
return 0;
|
||||
case READ_DATA:
|
||||
{
|
||||
uint16_t ret =
|
||||
(m_data[m_add + m_pos / 8] & (0x1 << (7 - (m_pos % 8)))) ? 1 : 0;
|
||||
++m_pos;
|
||||
if (m_pos == 64)
|
||||
m_state = IDLE;
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Eeprom::Write (uint16_t MET_UNUSED(add), uint8_t MET_UNUSED(val))
|
||||
{
|
||||
met_abort("8 bits write to EEPROM");
|
||||
return false;
|
||||
}
|
||||
//XXX
|
||||
#if 0
|
||||
bool Eeprom::Write (uint16_t val)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case IDLE:
|
||||
if (val & 0x1)
|
||||
m_state = WAITING;
|
||||
else
|
||||
met_abort("First bit is not 1");
|
||||
return false;
|
||||
case WAITING:
|
||||
m_add = 0;
|
||||
m_pos = 0;
|
||||
if (val & 0x1)
|
||||
m_state = READ_ADD;
|
||||
else
|
||||
m_state = WRITE_ADD;
|
||||
return false;
|
||||
|
||||
case READ_ADD:
|
||||
m_add <<= 1;
|
||||
m_add |= val & 0x1;
|
||||
++m_pos;
|
||||
if (m_size == 0x0200 && m_pos == 6 ||
|
||||
m_size == 0x2000 && m_pos == 14)
|
||||
{
|
||||
m_state = READ_END;
|
||||
if (m_size == 0x2000 && (m_add & 0x3C000))
|
||||
met_abort("In large EEPROM, 4 upper address bits are not 0");
|
||||
}
|
||||
return false;
|
||||
case READ_END:
|
||||
if (val & 0x1)
|
||||
met_abort("Last bit of EEPROM read request is not 0");
|
||||
m_pos = 0;
|
||||
m_state = READ_GARBAGE;
|
||||
return false;
|
||||
|
||||
case WRITE_ADD:
|
||||
m_add <<= 1;
|
||||
m_add |= val & 0x1;
|
||||
++m_pos;
|
||||
if (m_size == 0x0200 && m_pos == 6 ||
|
||||
m_size == 0x2000 && m_pos == 14)
|
||||
{
|
||||
m_state = WRITE_DATA;
|
||||
m_pos = 0;
|
||||
if (m_size == 0x2000 && (m_add & 0x3C000))
|
||||
met_abort("In large EEPROM, 4 upper address bits are not 0");
|
||||
}
|
||||
return false;
|
||||
case WRITE_DATA:
|
||||
{
|
||||
uint8_t& d = m_data[m_add + m_pos / 8];
|
||||
d <<= 1;
|
||||
d |= val & 0x1;
|
||||
}
|
||||
++m_pos;
|
||||
if (m_pos == 64)
|
||||
m_state = WRITE_END;
|
||||
return true;
|
||||
case WRITE_END:
|
||||
if (val & 0x1)
|
||||
met_abort("Last bit of EEPROM write request is not 0");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Eeprom::Write (uint16_t* pData, uint16_t size)
|
||||
{
|
||||
if (!(*pData & 0x1))
|
||||
met_abort("Bit 1 is not 1 in EEPROM DMA");
|
||||
++pData;
|
||||
|
||||
uint16_t add = 0;
|
||||
if (*pData & 0x1) // read
|
||||
{
|
||||
if (size != 9 && size != 17)
|
||||
met_abort("Invalid size for read");
|
||||
++pData;
|
||||
|
||||
// read address
|
||||
for (uint8_t i = 0, end = (m_size == 0x0200) ? 6 : 14; i < end;
|
||||
++i, ++pData)
|
||||
add = (add << 1) | (*pData & 0x1);
|
||||
if (m_size == 0x2000 && (add & 0x3C00))
|
||||
met_abort("In large EEPROM, 4 upper address bits are not 0");
|
||||
|
||||
//XXX
|
||||
/*if (*pData & 0x1)
|
||||
met_abort("Last bit of EEPROM read request is not 0");*/
|
||||
|
||||
m_add = add*8;
|
||||
m_state = READ_GARBAGE;
|
||||
m_pos = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
else // write
|
||||
{
|
||||
if (size != 73 && size != 81)
|
||||
met_abort("Invalid size for write");
|
||||
++pData;
|
||||
|
||||
// read address
|
||||
for (uint8_t i = 0, end = (m_size == 0x0200) ? 6 : 14; i < end;
|
||||
++i, ++pData)
|
||||
add = (add << 1) | (*pData & 0x1);
|
||||
if (m_size == 0x2000 && (add & 0x3C00))
|
||||
met_abort("In large EEPROM, 4 upper address bits are not 0");
|
||||
|
||||
// read data
|
||||
uint8_t* pMem = m_data + add*8;
|
||||
for (uint8_t i = 0; i < 8; ++i, ++pMem)
|
||||
{
|
||||
for (uint8_t j = 0; j < 8; ++j, ++pData)
|
||||
{
|
||||
*pMem <<= 1;
|
||||
*pMem |= (*pData & 0x1);
|
||||
}
|
||||
}
|
||||
|
||||
if (*pData & 0x1)
|
||||
met_abort("Last bit of EEPROM write request is not 0");
|
||||
|
||||
m_state = IDLE;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX
|
||||
#if 0
|
||||
void Eeprom::Read (uint16_t* pOut)
|
||||
{
|
||||
if (m_state != READ)
|
||||
met_abort("Read in invalid EEPROM state");
|
||||
|
||||
pOut += 4; // ignore these
|
||||
uint8_t* pData = m_data + m_add;
|
||||
uint8_t cur;
|
||||
for (uint8_t i = 0; i < 8; ++i, ++pData)
|
||||
{
|
||||
cur = *pData;
|
||||
pOut += 7;
|
||||
for (uint8_t j = 0; j < 8; ++j, --pOut, cur >>= 1)
|
||||
*pOut = cur & 0x1;
|
||||
pOut += 9;
|
||||
}
|
||||
|
||||
m_state = NORMAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Eeprom::SaveState (std::ostream& stream)
|
||||
{
|
||||
//XXX TODO
|
||||
SS_WRITE_VAR(m_size);
|
||||
SS_WRITE_VAR(m_state);
|
||||
SS_WRITE_VAR(m_add);
|
||||
|
||||
SS_WRITE_DATA(m_data, m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Eeprom::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_size);
|
||||
SS_READ_VAR(m_state);
|
||||
SS_READ_VAR(m_add);
|
||||
|
||||
SS_READ_DATA(m_data, m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/flash.hpp"
|
||||
#include "globals.hpp"
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
Flash::Flash (bool big) :
|
||||
CartMem(),
|
||||
m_state(NORMAL)
|
||||
{
|
||||
if (big)
|
||||
{
|
||||
m_device_id = 0x13;
|
||||
m_manufacturer_id = 0x62;
|
||||
m_size = 128*1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_device_id = 0x1B;
|
||||
m_manufacturer_id = 0x32;
|
||||
m_size = 64*1024;
|
||||
}
|
||||
|
||||
*(uint32_t*)(m_data+MAX_SIZE) = m_size;
|
||||
}
|
||||
|
||||
void Flash::Reset ()
|
||||
{
|
||||
std::memset(m_data, 0, m_size);
|
||||
}
|
||||
|
||||
bool Flash::Load (std::istream& f)
|
||||
{
|
||||
f.read((char*)m_data, m_size);
|
||||
return f.good();
|
||||
}
|
||||
|
||||
bool Flash::Save (std::ostream& f)
|
||||
{
|
||||
f.write((char*)m_data, m_size);
|
||||
return f.good();
|
||||
}
|
||||
|
||||
uint8_t Flash::Read (uint16_t add)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case NORMAL:
|
||||
return m_data[add];
|
||||
case ID:
|
||||
switch (add)
|
||||
{
|
||||
case 0: return m_manufacturer_id;
|
||||
case 1: return m_device_id;
|
||||
default: return 0;
|
||||
}
|
||||
// FIXME vba returns 0xff after an erase regardless of the read address
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Flash::Write (uint16_t add, uint8_t val)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case ID:
|
||||
case NORMAL:
|
||||
if (add == 0x5555 && val == 0xAA)
|
||||
m_state = CMD1;
|
||||
else
|
||||
m_state = NORMAL; // for case ID
|
||||
break;
|
||||
case CMD1:
|
||||
if (add == 0x2AAA && val == 0x55)
|
||||
m_state = CMD2;
|
||||
else
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
case CMD2:
|
||||
if (add == 0x5555)
|
||||
switch (val)
|
||||
{
|
||||
case 0x80: // erase mode
|
||||
m_state = ERASE1;
|
||||
break;
|
||||
case 0x90: // id mode
|
||||
m_state = ID;
|
||||
break;
|
||||
case 0xA0: // write byte
|
||||
m_state = WRITE;
|
||||
break;
|
||||
case 0xF0:
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
default:
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
case ERASE1:
|
||||
if (add == 0x5555 && val == 0xAA)
|
||||
m_state = ERASE2;
|
||||
else
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
case ERASE2:
|
||||
if (add == 0x2AAA && val == 0x55)
|
||||
m_state = ERASE3;
|
||||
else
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
case ERASE3:
|
||||
// according to vba, after a whole erase command we can juste repeat the
|
||||
// last byte of the command to execute another erase command
|
||||
switch (val)
|
||||
{
|
||||
case 0x10: // erase entire chip
|
||||
if (add == 0x5555)
|
||||
memset(m_data, 0xFF, m_size);
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
case 0x30: // erase sector
|
||||
if (!(add & 0x0FFF))
|
||||
memset(m_data+add, 0xFF, 0x1000);
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
default:
|
||||
m_state = NORMAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WRITE:
|
||||
// I think this is how it works
|
||||
m_data[add] &= val;
|
||||
m_state = NORMAL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Flash::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_state);
|
||||
|
||||
SS_WRITE_DATA(m_data, m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Flash::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_state);
|
||||
|
||||
SS_READ_DATA(m_data, m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef __GLOBALS_H__
|
||||
#define __GLOBALS_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SPDUP_FRMSKIP 9
|
||||
#define SPDUP_SNDSKIP 3969
|
||||
|
||||
#define R(reg) CPU.Reg(reg)
|
||||
|
||||
#define CPU _cpu
|
||||
#define MEM _memory
|
||||
#define IO _io
|
||||
#define DMA _dma
|
||||
#define LCD _lcd
|
||||
#define SOUND _sound
|
||||
#define KEYPAD _keypad
|
||||
#define CLOCK _clock
|
||||
#define TIMER0 _timer0
|
||||
#define TIMER1 _timer1
|
||||
#define TIMER2 _timer2
|
||||
#define TIMER3 _timer3
|
||||
|
||||
#define CYCLES16NSeq(add, count) \
|
||||
CLOCK.TimePass(MEM.GetCycles16NoSeq(add, count))
|
||||
#define CYCLES16Seq(add, count) \
|
||||
CLOCK.TimePass(MEM.GetCycles16Seq(add, count))
|
||||
#define CYCLES32NSeq(add, count) \
|
||||
CLOCK.TimePass(MEM.GetCycles32NoSeq(add, count))
|
||||
#define CYCLES32Seq(add, count) \
|
||||
CLOCK.TimePass(MEM.GetCycles32Seq(add, count))
|
||||
#define ICYCLES(i) \
|
||||
CLOCK.TimePass(i)
|
||||
// we don't mind if the following code is slow since a MUL
|
||||
// instruction is slow on a GBA too
|
||||
#define MULICYCLES(reg) \
|
||||
{ \
|
||||
uint32_t rs = R(reg) >> 8; \
|
||||
for (uint8_t i = 1; i <= 4; ++i, rs >>= 8) \
|
||||
{ \
|
||||
if (!rs || rs == (0xFFFFFFFF >> (i*8))) \
|
||||
{ \
|
||||
ICYCLES(i); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CPSR (CPU.Cpsr().dw)
|
||||
#define ICPSR (CPU.ICpsr())
|
||||
#define SPSR (CPU.Spsr().dw)
|
||||
#define FLAG_Z (CPU.ICpsr().f_zero)
|
||||
#define FLAG_N (CPU.ICpsr().f_sign)
|
||||
#define FLAG_C (CPU.ICpsr().f_carry)
|
||||
#define FLAG_V (CPU.ICpsr().f_overflow)
|
||||
#define FLAG_T (CPU.ICpsr().thumb)
|
||||
#define SETF(flag, val) \
|
||||
FLAG_##flag = (val) ? 1 : 0
|
||||
#define SETFB(flag, val) \
|
||||
FLAG_##flag = (val)
|
||||
|
||||
#define FZ(val) \
|
||||
SETF(Z, !(val))
|
||||
#define FN(val) \
|
||||
SETF(N, NEG(val))
|
||||
|
||||
#define POS(a) ((~a) >> 31)
|
||||
#define NEG(a) ((a) >> 31)
|
||||
|
||||
// inspired by VisualBoyAdvance
|
||||
#define ADDCARRY(a, b, c) \
|
||||
((NEG(a) & NEG(b)) | \
|
||||
(NEG(a) & POS(c)) | \
|
||||
(NEG(b) & POS(c)))
|
||||
#define ADDOVERFLOW(a, b, c) \
|
||||
((NEG(a) & NEG(b) & POS(c)) | \
|
||||
(POS(a) & POS(b) & NEG(c)))
|
||||
#define SUBCARRY(a, b, c) \
|
||||
((NEG(a) & POS(b)) | \
|
||||
(NEG(a) & POS(c)) | \
|
||||
(POS(b) & POS(c)))
|
||||
#define SUBOVERFLOW(a, b, c) \
|
||||
((NEG(a) & POS(b) & POS(c)) | \
|
||||
(POS(a) & NEG(b) & NEG(c)))
|
||||
|
||||
// Save states macros
|
||||
#define SS_WRITE_VAR(var) \
|
||||
if (!stream.write((char*)&var, sizeof(var))) \
|
||||
return false
|
||||
#define SS_WRITE_ARRAY(var) \
|
||||
if (!stream.write((char*)var, sizeof(var))) \
|
||||
return false
|
||||
#define SS_WRITE_DATA(var, size) \
|
||||
if (!stream.write((char*)var, size)) \
|
||||
return false
|
||||
#define SS_READ_VAR(var) \
|
||||
if (!stream.read((char*)&var, sizeof(var))) \
|
||||
return false
|
||||
#define SS_READ_ARRAY(var) \
|
||||
if (!stream.read((char*)var, sizeof(var))) \
|
||||
return false
|
||||
#define SS_READ_DATA(var, size) \
|
||||
if (!stream.read((char*)var, size)) \
|
||||
return false
|
||||
|
||||
// macro to avoid getting warnings about and unused parameter on GCC
|
||||
#ifdef _MSC_VER
|
||||
#define MET_UNUSED(v)
|
||||
#else
|
||||
#define MET_UNUSED(v) \
|
||||
__attribute__((unused)) MET_UNUSED_##v
|
||||
#endif
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
// ROtate Right
|
||||
inline uint32_t ROR(uint32_t val, uint8_t shift)
|
||||
{
|
||||
return (val >> shift) | (val << (32 - shift));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,475 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/graphics/bglayer.hpp"
|
||||
#include "ameteor/graphics/screen.hpp"
|
||||
#include "../debug.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
BgLayer::BgLayer (int8_t num, Memory& memory, Io& io, uint16_t* pPalette) :
|
||||
m_memory(memory),
|
||||
m_io(io),
|
||||
m_num(num),
|
||||
m_priority(0),
|
||||
m_cnt(0),
|
||||
m_xoff(0),
|
||||
m_yoff(0),
|
||||
m_tWidth(32),
|
||||
m_tHeight(32),
|
||||
m_rWidth(16),
|
||||
m_rHeight(16),
|
||||
m_mapAdd(0x06000000),
|
||||
m_charAdd(0x06000000),
|
||||
m_pPalette(pPalette)
|
||||
{
|
||||
}
|
||||
|
||||
BgLayer::~BgLayer ()
|
||||
{
|
||||
}
|
||||
|
||||
void BgLayer::DrawLine0 (uint8_t line, uint16_t* ptr)
|
||||
{
|
||||
uint8_t mosH;
|
||||
if (m_cnt & (0x1 << 6))
|
||||
{
|
||||
mosH = m_io.DRead8(Io::MOSAIC);
|
||||
uint8_t mosV = mosH >> 4;
|
||||
mosH &= 0x0F;
|
||||
|
||||
++mosV;
|
||||
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
|
||||
++mosH;
|
||||
|
||||
line /= mosV;
|
||||
line *= mosV;
|
||||
}
|
||||
else
|
||||
mosH = 0;
|
||||
|
||||
uint16_t* pMap = (uint16_t*)m_memory.GetRealAddress(m_mapAdd), *pTile;
|
||||
uint8_t* pChar = m_memory.GetRealAddress(m_charAdd), *tpChar;
|
||||
uint8_t i = 0;
|
||||
|
||||
// theses are the coordinates on the layer from which we will draw a line
|
||||
uint16_t xoff = m_xoff % (m_tWidth * 8);
|
||||
uint16_t yoff = (m_yoff + line) % (m_tHeight * 8);
|
||||
|
||||
// theses are the coordinates on the tile of the pixels we are drawing
|
||||
// NOTE : if the tile is horizontally flipped tileX = 8 - tileX, thus
|
||||
// when we draw it is ALWAYS incremented no matter how the tile is
|
||||
// flipped
|
||||
// NOTE : tileY is NOT redefined if the tile is flipped vertically
|
||||
int8_t tileX = xoff % 8, tileY;
|
||||
bool flipH;
|
||||
|
||||
// sets pTile to the tile we must draw first
|
||||
// +---+---+
|
||||
// | 1 | 2 |
|
||||
// +---+---+
|
||||
// | 3 | 4 |
|
||||
// +---+---+
|
||||
if (yoff >= 256)
|
||||
if (m_tWidth == 64)
|
||||
if (xoff >= 256)
|
||||
// zone 4
|
||||
pTile = pMap + 32*32 + 32*32 + 32*32
|
||||
+ 32 * ((yoff-256)/8) + (xoff-256)/8;
|
||||
else
|
||||
// zone 3 (large map)
|
||||
pTile = pMap + 32*32 + 32*32 + 32 * ((yoff-256)/8) + xoff/8;
|
||||
else
|
||||
// zone 3 (no large map)
|
||||
pTile = pMap + 32*32 + 32 * ((yoff-256)/8) + xoff/8;
|
||||
else
|
||||
if (xoff >= 256)
|
||||
// zone 2
|
||||
pTile = pMap + 32*32 + 32 * (yoff/8) + (xoff-256)/8;
|
||||
else
|
||||
// zone 1
|
||||
pTile = pMap + 32 * (yoff/8) + xoff/8;
|
||||
|
||||
if (m_hicolor)
|
||||
{
|
||||
while (i < 240)
|
||||
{
|
||||
flipH = (bool)(*pTile & (0x1 << 10));
|
||||
|
||||
// if the tile is vertically fliped
|
||||
if (*pTile & (0x1 << 11))
|
||||
tileY = 7 - (yoff % 8);
|
||||
else
|
||||
tileY = yoff % 8;
|
||||
|
||||
if (flipH)
|
||||
tpChar = pChar + (*pTile & 0x3FF)*8*8 + tileY*8 + 7 - tileX;
|
||||
else
|
||||
tpChar = pChar + (*pTile & 0x3FF)*8*8 + tileY*8 + tileX;
|
||||
|
||||
while (tileX < 8)
|
||||
{
|
||||
if (mosH && i % mosH)
|
||||
*ptr = ptr[-1];
|
||||
else
|
||||
{
|
||||
if (*tpChar)
|
||||
*ptr = m_pPalette[*tpChar] | 0x8000;
|
||||
else
|
||||
*ptr = 0x0;
|
||||
}
|
||||
if (flipH)
|
||||
--tpChar;
|
||||
else
|
||||
++tpChar;
|
||||
|
||||
++ptr;
|
||||
++tileX;
|
||||
++i;
|
||||
|
||||
if (i == 240)
|
||||
return;
|
||||
}
|
||||
tileX = 0;
|
||||
++pTile;
|
||||
|
||||
// support for big maps and wrap around
|
||||
if (!((pTile - pMap) % 32))
|
||||
if (m_tWidth == 32)
|
||||
pTile -= 32;
|
||||
else
|
||||
if (yoff >= 256 && pTile - pMap > 32*32 * 3
|
||||
|| yoff < 256 && pTile - pMap > 32*32)
|
||||
pTile -= 32*33;
|
||||
else
|
||||
pTile += 32*31;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t* pPalette;
|
||||
uint8_t colorInd;
|
||||
|
||||
// for each pixel of the line we are drawing
|
||||
while (i < 240)
|
||||
{
|
||||
pPalette = m_pPalette + ((*pTile >> 12) & 0xF) * 16;
|
||||
flipH = (bool)(*pTile & (0x1 << 10));
|
||||
|
||||
// if the tile is vertically fliped
|
||||
if (*pTile & (0x1 << 11))
|
||||
tileY = 7 - (yoff % 8);
|
||||
else
|
||||
tileY = yoff % 8;
|
||||
|
||||
if (flipH)
|
||||
tpChar = pChar + ((*pTile & 0x3FF)*8*8 + tileY*8 + 7 - tileX)/2;
|
||||
else
|
||||
tpChar = pChar + ((*pTile & 0x3FF)*8*8 + tileY*8 + tileX)/2;
|
||||
|
||||
// we draw until the end of the tile or the line
|
||||
while (tileX < 8)
|
||||
{
|
||||
if (flipH)
|
||||
if (tileX % 2)
|
||||
{
|
||||
colorInd = *tpChar & 0xF;
|
||||
--tpChar;
|
||||
}
|
||||
else
|
||||
colorInd = *tpChar >> 4;
|
||||
else
|
||||
if (tileX % 2)
|
||||
{
|
||||
colorInd = *tpChar >> 4;
|
||||
++tpChar;
|
||||
}
|
||||
else
|
||||
colorInd = *tpChar & 0xF;
|
||||
|
||||
if (mosH && i % mosH)
|
||||
*ptr = ptr[-1];
|
||||
else
|
||||
{
|
||||
if (colorInd)
|
||||
*ptr = pPalette[colorInd] | 0x8000;
|
||||
else
|
||||
*ptr = 0x0;
|
||||
}
|
||||
|
||||
++ptr;
|
||||
++tileX;
|
||||
++i;
|
||||
|
||||
// if this was the last pixel of the line
|
||||
if (i == 240)
|
||||
return;
|
||||
}
|
||||
|
||||
// we have finished drawing a tile, so we go to the next tile
|
||||
tileX = 0;
|
||||
++pTile;
|
||||
|
||||
// support for big maps and wrap around
|
||||
if (!((pTile - pMap) % 32))
|
||||
if (m_tWidth == 32)
|
||||
pTile -= 32;
|
||||
else
|
||||
if (yoff >= 256 && pTile - pMap > 32*32 * 3
|
||||
|| yoff < 256 && pTile - pMap > 32*32)
|
||||
pTile -= 32*33;
|
||||
else
|
||||
pTile += 32*31;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BgLayer::DrawLine2 (uint16_t* ptr,
|
||||
int32_t curX, int32_t curY,
|
||||
int16_t dx, int16_t dy)
|
||||
{
|
||||
if (!m_hicolor)
|
||||
{
|
||||
//FIXME is this possible ??
|
||||
//this seems to be impossible, but we should not crash since some games
|
||||
//do it
|
||||
//puts("rotated layer with 16 colors");
|
||||
//abort();
|
||||
// XXX
|
||||
//it seems now that we should not care about this flag, we draw in 256
|
||||
//colors, that's all
|
||||
//return;
|
||||
}
|
||||
int32_t intX, intY;
|
||||
|
||||
uint16_t colorInd;
|
||||
|
||||
uint8_t* pMap = (uint8_t*)m_memory.GetRealAddress(m_mapAdd);
|
||||
uint8_t* pChar = m_memory.GetRealAddress(m_charAdd);
|
||||
|
||||
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
|
||||
{
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
// if we are off layer
|
||||
if (intX < 0 || intX >= m_rWidth*8)
|
||||
if (m_cnt & (0x1 << 13))
|
||||
{
|
||||
// NOTE : in C++, the modulus can be negative, this is because in
|
||||
// x86, the IDIV instruction gives a remainder of the same sign of
|
||||
// the dividend
|
||||
curX %= m_rWidth*8 << 8;
|
||||
if (curX < 0)
|
||||
curX += m_rWidth*8 << 8;
|
||||
intX = curX >> 8;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
if (intY < 0 || intY >= m_rHeight*8)
|
||||
if (m_cnt & (0x1 << 13))
|
||||
{
|
||||
curY %= m_rHeight*8 << 8;
|
||||
if (curY < 0)
|
||||
curY += m_rHeight*8 << 8;
|
||||
intY = curY >> 8;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
colorInd = pChar[pMap[intY / 8 * m_rWidth + intX / 8] * 8 * 8
|
||||
+ (intY % 8) * 8 + intX % 8];
|
||||
|
||||
if (colorInd)
|
||||
*ptr = m_pPalette[colorInd] | 0x8000;
|
||||
else
|
||||
*ptr = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
void BgLayer::DrawLine3 (uint16_t* ptr,
|
||||
int32_t curX, int32_t curY,
|
||||
int16_t dx, int16_t dy)
|
||||
{
|
||||
int32_t intX, intY;
|
||||
|
||||
uint16_t* pChar = (uint16_t*) m_memory.GetRealAddress(0x06000000);
|
||||
|
||||
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
|
||||
{
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
// if we are off layer
|
||||
if (intX < 0 || intX >= 240)
|
||||
/*
|
||||
if (m_cnt & (0x1 << 13))
|
||||
{
|
||||
// NOTE : in C++, the modulus can be negative
|
||||
intX %= 240;
|
||||
if (intX < 0)
|
||||
intX += 240;
|
||||
}
|
||||
else*/
|
||||
continue;
|
||||
if (intY < 0 || intY >= 160)
|
||||
/*
|
||||
if (m_cnt & (0x1 << 13))
|
||||
{
|
||||
intY %= 160;
|
||||
if (intY < 0)
|
||||
intY += 160;
|
||||
}
|
||||
else*/
|
||||
continue;
|
||||
|
||||
*ptr = pChar[intY * 240 + intX] | 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
void BgLayer::DrawLine4 (uint8_t line, uint16_t* ptr,
|
||||
int32_t curX, int32_t curY,
|
||||
int16_t dx, int16_t dmx, int16_t dy, int16_t dmy, bool frame1)
|
||||
{
|
||||
uint8_t mosH;
|
||||
if (m_cnt & (0x1 << 6))
|
||||
{
|
||||
// TODO horizontal mosaic not implemented
|
||||
mosH = m_io.DRead8(Io::MOSAIC);
|
||||
uint8_t mosV = mosH >> 4;
|
||||
mosH &= 0x0F;
|
||||
|
||||
++mosV;
|
||||
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
|
||||
++mosH;
|
||||
|
||||
uint8_t back = line % mosV;
|
||||
|
||||
curX -= back*dmx;
|
||||
curY -= back*dmy;
|
||||
}
|
||||
else
|
||||
mosH = 0;
|
||||
|
||||
int32_t intX, intY;
|
||||
|
||||
uint16_t colorInd;
|
||||
|
||||
uint8_t* pChar =
|
||||
m_memory.GetRealAddress(frame1 ? 0x0600A000 : 0x06000000);
|
||||
|
||||
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
|
||||
{
|
||||
if (mosH && x % mosH)
|
||||
{
|
||||
*ptr = ptr[-1];
|
||||
continue;
|
||||
}
|
||||
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
// if we are off layer
|
||||
if (intX < 0 || intX >= 240)
|
||||
if (m_cnt & (0x1 << 13))
|
||||
{
|
||||
// NOTE : in C++, the modulus can be negative
|
||||
intX %= 240;
|
||||
if (intX < 0)
|
||||
intX += 240;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
if (intY < 0 || intY >= 160)
|
||||
if (m_cnt & (0x1 << 13))
|
||||
{
|
||||
intY %= 160;
|
||||
if (intY < 0)
|
||||
intY += 160;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
colorInd = pChar[intY * 240 + intX];
|
||||
|
||||
if (colorInd)
|
||||
*ptr = m_pPalette[colorInd] | 0x8000;
|
||||
else
|
||||
*ptr = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
void BgLayer::DrawLine5 (uint16_t* ptr,
|
||||
int32_t curX, int32_t curY,
|
||||
int16_t dx, int16_t dy, bool frame1)
|
||||
{
|
||||
int32_t intX, intY;
|
||||
|
||||
uint16_t* pChar = (uint16_t*) m_memory.GetRealAddress(frame1 ? 0x0600A000 : 0x06000000);
|
||||
|
||||
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
|
||||
{
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
// if we are off layer
|
||||
if (intX < 0 || intX >= 160)
|
||||
continue;
|
||||
if (intY < 0 || intY >= 128)
|
||||
continue;
|
||||
|
||||
*ptr = pChar[intY * 160 + intX] | 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
void BgLayer::UpdateCnt (uint16_t cnt)
|
||||
{
|
||||
if (m_cnt == cnt)
|
||||
return;
|
||||
|
||||
switch (cnt >> 14)
|
||||
{
|
||||
case 0:
|
||||
m_tWidth = m_tHeight = 32;
|
||||
m_rWidth = m_rHeight = 16;
|
||||
break;
|
||||
case 1:
|
||||
m_tWidth = 64;
|
||||
m_tHeight = 32;
|
||||
m_rWidth = m_rHeight = 32;
|
||||
break;
|
||||
case 2:
|
||||
m_tWidth = 32;
|
||||
m_tHeight = 64;
|
||||
m_rWidth = m_rHeight = 64;
|
||||
break;
|
||||
case 3:
|
||||
m_tWidth = m_tHeight = 64;
|
||||
m_rWidth = m_rHeight = 128;
|
||||
break;
|
||||
}
|
||||
|
||||
m_priority = (cnt & 0x3);
|
||||
m_charAdd = 0x06000000 + ((cnt >> 2) & 0x3) * 0x4000;
|
||||
m_hicolor = cnt & (0x1 << 7);
|
||||
m_mapAdd = 0x06000000 + ((cnt >> 8) & 0x1F) * 0x0800;
|
||||
|
||||
m_cnt = cnt;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,698 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/graphics/object.hpp"
|
||||
#include "ameteor/graphics/screen.hpp"
|
||||
#include "../debug.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
Object::Object (uint16_t* pPalette, uint8_t* pChar) :
|
||||
m_attr0(0),
|
||||
m_attr1(0),
|
||||
m_attr2(0),
|
||||
m_width(1),
|
||||
m_height(1),
|
||||
m_pPalette(pPalette),
|
||||
m_pChar(pChar),
|
||||
m_charBegin(0x06010000),
|
||||
m_charEnd(0x06010020)
|
||||
{
|
||||
}
|
||||
|
||||
Object::Object (const Object& obj) :
|
||||
m_attr0(obj.m_attr0),
|
||||
m_attr1(obj.m_attr1),
|
||||
m_attr2(obj.m_attr2),
|
||||
m_width(obj.m_width),
|
||||
m_height(obj.m_height),
|
||||
m_pPalette(obj.m_pPalette),
|
||||
m_pChar(obj.m_pChar),
|
||||
m_charBegin(obj.m_charBegin),
|
||||
m_charEnd(obj.m_charEnd)
|
||||
{
|
||||
}
|
||||
|
||||
void Object::DrawLine (uint8_t line, uint32_t* surface, bool oneDim,
|
||||
uint8_t mosaic)
|
||||
{
|
||||
// if the object is disabled or it's an obj window
|
||||
if (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) == 2)
|
||||
return;
|
||||
|
||||
// don't draw sprites with "prohibited" size
|
||||
if (m_width == 0)
|
||||
return;
|
||||
|
||||
int16_t yoff = (m_attr0 & 0xFF);
|
||||
if (yoff > Screen::HEIGHT)
|
||||
yoff -= 256;
|
||||
|
||||
// if the object does not appear on the line
|
||||
if (yoff > line || yoff + m_height*8 <= line)
|
||||
return;
|
||||
|
||||
uint8_t mosH;
|
||||
if (m_attr0 & (0x1 << 12))
|
||||
{
|
||||
uint8_t mosV = mosaic >> 4;
|
||||
mosH = mosaic & 0xF;
|
||||
|
||||
++mosV;
|
||||
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
|
||||
++mosH;
|
||||
|
||||
line /= mosV;
|
||||
line *= mosV;
|
||||
}
|
||||
else
|
||||
mosH = 0;
|
||||
|
||||
int16_t xoff = (m_attr1 & 0x1FF);
|
||||
if (xoff & (0x1 << 8))
|
||||
xoff |= 0xFE00; // extend sign bit
|
||||
|
||||
uint32_t* ptr = surface + xoff;
|
||||
|
||||
uint32_t prio = (((uint32_t)m_attr2) << 6) & (0x3 << 16);
|
||||
uint32_t mask = prio;
|
||||
// if semi transparent
|
||||
if (((m_attr0 >> 10) & 0x3) == 0x1)
|
||||
mask |= (0x1 << 18);
|
||||
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
||||
bool flipH = m_attr1 & (0x1 << 12);
|
||||
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
||||
{
|
||||
// if the tile is vertically flipped
|
||||
if (m_attr1 & (0x1 << 13))
|
||||
{
|
||||
// go to the tile
|
||||
if (oneDim)
|
||||
pChar += m_width * (8 * 8) * (m_height -1 -((line-yoff) / 8));
|
||||
else
|
||||
pChar += (16 * 8 * 8) * (m_height -1 -((line-yoff) / 8));
|
||||
// advance to the right line
|
||||
pChar += 8 * (7 - ((line-yoff) % 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
// go to the tile
|
||||
if (oneDim)
|
||||
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
|
||||
else
|
||||
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
|
||||
// advance to the right line
|
||||
pChar += 8 * ((line-yoff) % 8);
|
||||
}
|
||||
// go to the end of the line if the object is flipped
|
||||
if (flipH)
|
||||
pChar += (m_width-1) * (8*8) + 8 - 1;
|
||||
|
||||
for (uint8_t j = 0; j < m_width*8; ++j, ++ptr)
|
||||
{
|
||||
// if we are on screen
|
||||
if (ptr - surface < Screen::WIDTH && ptr >= surface)
|
||||
{
|
||||
if (mosH && (ptr - surface) % mosH)
|
||||
*ptr = ptr[-1];
|
||||
else
|
||||
{
|
||||
// if there is something to draw
|
||||
if (*pChar)
|
||||
{
|
||||
// if we have priority or there is nothing behind
|
||||
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
||||
*ptr = m_pPalette[*pChar] | 0x8000 | mask;
|
||||
}
|
||||
// if we have nothing to draw
|
||||
else
|
||||
// if we have better priority
|
||||
if (prio < (*ptr & (0x3 << 16)))
|
||||
// we just modify priority and keep what was behind
|
||||
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
||||
}
|
||||
}
|
||||
|
||||
if (flipH)
|
||||
if ((j % 8) == 7)
|
||||
// go to previous tile
|
||||
pChar -= ((8*8) - (8) + 1);
|
||||
else
|
||||
--pChar;
|
||||
else
|
||||
if ((j % 8) == 7)
|
||||
// go to next tile
|
||||
pChar += ((8*8) - (8) + 1);
|
||||
else
|
||||
++pChar;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the tile is vertically flipped
|
||||
if (m_attr1 & (0x1 << 13))
|
||||
{
|
||||
// go to the tile
|
||||
if (oneDim)
|
||||
pChar += m_width * (8 * 8 / 2) * (m_height -1 -((line-yoff) / 8));
|
||||
else
|
||||
pChar += (32 * 8 * 8 / 2) * (m_height -1 -((line-yoff) / 8));
|
||||
// advance to the right line
|
||||
pChar += (8/2) * (7 - ((line-yoff) % 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
// go to the tile
|
||||
if (oneDim)
|
||||
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
|
||||
else
|
||||
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
|
||||
// advance to the right line
|
||||
pChar += (8/2) * ((line-yoff) % 8);
|
||||
}
|
||||
// go to the end of the line if the object is flipped
|
||||
if (flipH)
|
||||
pChar += (m_width-1) * (8*8/2) + 8/2 - 1;
|
||||
|
||||
uint16_t* pPalette = m_pPalette + 16 * (m_attr2 >> 12);
|
||||
uint8_t colorInd;
|
||||
for (uint8_t j = 0; j < m_width*8; ++j, ++ptr)
|
||||
{
|
||||
if (flipH)
|
||||
if (j % 2)
|
||||
{
|
||||
colorInd = *pChar & 0xF;
|
||||
|
||||
if ((j % 8) == 7)
|
||||
// go to next tile
|
||||
// it doesn't matter if we are in one or two dimensions mapping
|
||||
// since we never go on the next line
|
||||
pChar -= ((8*8/2) - (8/2) + 1);
|
||||
else
|
||||
--pChar;
|
||||
}
|
||||
else
|
||||
colorInd = *pChar >> 4;
|
||||
else
|
||||
if (j % 2)
|
||||
{
|
||||
colorInd = *pChar >> 4;
|
||||
|
||||
if ((j % 8) == 7)
|
||||
// go to next tile
|
||||
// it doesn't matter if we are in one or two dimensions mapping
|
||||
// since we never go on the next line
|
||||
pChar += ((8*8/2) - (8/2) + 1);
|
||||
else
|
||||
++pChar;
|
||||
}
|
||||
else
|
||||
colorInd = *pChar & 0xF;
|
||||
|
||||
// if we are on screen
|
||||
if (ptr - surface < Screen::WIDTH && ptr >= surface)
|
||||
{
|
||||
if (mosH && (ptr - surface) % mosH)
|
||||
*ptr = ptr[-1];
|
||||
else
|
||||
{
|
||||
// if there is something to draw
|
||||
if (colorInd)
|
||||
{
|
||||
// if we have priority or there is nothing behind
|
||||
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
||||
*ptr = pPalette[colorInd] | 0x8000 | mask;
|
||||
}
|
||||
// if we have nothing to draw
|
||||
else
|
||||
// if we have better priority
|
||||
if (prio < (*ptr & (0x3 << 16)))
|
||||
// we just modify priority and keep what was behind
|
||||
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Object::DrawLineRot (uint8_t line, uint32_t* surface, bool oneDim,
|
||||
int16_t a, int16_t b, int16_t c, int16_t d, uint8_t mosaic)
|
||||
{
|
||||
// if it's an obj window
|
||||
if (((m_attr0 >> 10) & 0x3) == 2)
|
||||
return;
|
||||
|
||||
// don't draw sprites with "prohibited" size
|
||||
if (m_width == 0)
|
||||
return;
|
||||
|
||||
int16_t yoff = (m_attr0 & 0xFF);
|
||||
if (yoff > Screen::HEIGHT)
|
||||
yoff -= 256;
|
||||
|
||||
int16_t xoff = (m_attr1 & 0x1FF);
|
||||
if (xoff & (0x1 << 8))
|
||||
xoff |= 0xFE00; // extend sign bit
|
||||
|
||||
uint8_t fwidth = m_width*8, fheight = m_height*8;
|
||||
if (m_attr0 & (0x1 << 9))
|
||||
{
|
||||
fwidth *= 2;
|
||||
fheight *= 2;
|
||||
}
|
||||
|
||||
// if the object does not appear on the line
|
||||
if (yoff > line || yoff + fheight <= line)
|
||||
return;
|
||||
|
||||
uint8_t mosH;
|
||||
if (m_attr0 & (0x1 << 12))
|
||||
{
|
||||
uint8_t mosV = mosaic >> 4;
|
||||
mosH = mosaic & 0xF;
|
||||
|
||||
++mosV;
|
||||
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
|
||||
++mosH;
|
||||
|
||||
line /= mosV;
|
||||
line *= mosV;
|
||||
}
|
||||
else
|
||||
mosH = 0;
|
||||
|
||||
int32_t curX = ((m_width*8) << 8)/2
|
||||
+ (-fwidth/2) * a + (line-yoff-fheight/2) * b;
|
||||
int32_t curY = ((m_height*8) << 8)/2
|
||||
+ (-fwidth/2) * c + (line-yoff-fheight/2) * d;
|
||||
int32_t intX, intY;
|
||||
|
||||
uint32_t* ptr = surface + xoff;
|
||||
|
||||
uint32_t prio = (((uint32_t)m_attr2) << 6) & (0x3 << 16);
|
||||
uint32_t mask = prio;
|
||||
// if semi transparent
|
||||
if (((m_attr0 >> 10) & 0x3) == 0x1)
|
||||
mask |= (0x1 << 18);
|
||||
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
||||
uint8_t colorInd;
|
||||
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
||||
{
|
||||
for (uint8_t i = 0; i < fwidth; ++i)
|
||||
{
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
// if we are on the object
|
||||
if (intX >= 0 && intX < m_width*8 &&
|
||||
intY >= 0 && intY < m_height*8 &&
|
||||
// and we are on screen
|
||||
ptr - surface < Screen::WIDTH && ptr >= surface)
|
||||
{
|
||||
if (mosH && (ptr - surface) % mosH)
|
||||
*ptr = ptr[-1];
|
||||
else
|
||||
{
|
||||
colorInd = pChar[
|
||||
(intY/8) * (oneDim ? m_width : 16) * 8*8
|
||||
+ (intX/8) * 8*8
|
||||
+ (intY%8) * 8
|
||||
+ (intX%8)];
|
||||
|
||||
// if there is something to draw
|
||||
if (colorInd)
|
||||
{
|
||||
// if we have priority or there is nothing behind
|
||||
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
||||
*ptr = m_pPalette[colorInd] | 0x8000 | mask;
|
||||
}
|
||||
// if we have nothing to draw
|
||||
else
|
||||
// if we have better priority
|
||||
if (prio < (*ptr & (0x3 << 16)))
|
||||
// we just modify priority and keep what was behind
|
||||
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
||||
}
|
||||
}
|
||||
|
||||
++ptr;
|
||||
curX += a;
|
||||
curY += c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t* pPalette = m_pPalette + 16 * (m_attr2 >> 12);
|
||||
for (uint8_t i = 0; i < fwidth; ++i)
|
||||
{
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
// if we are on the object
|
||||
if (intX >= 0 && intX < m_width*8 &&
|
||||
intY >= 0 && intY < m_height*8 &&
|
||||
// and we are on screen
|
||||
ptr - surface < Screen::WIDTH && ptr >= surface)
|
||||
{
|
||||
if (mosH && (ptr - surface) % mosH)
|
||||
*ptr = ptr[-1];
|
||||
else
|
||||
{
|
||||
colorInd = pChar[(
|
||||
(intY/8) * (oneDim ? m_width : 32) * 8*8
|
||||
+ (intX/8) * 8*8
|
||||
+ (intY%8) * 8
|
||||
+ (intX%8)
|
||||
) / 2];
|
||||
|
||||
if (intX % 2)
|
||||
colorInd >>= 4;
|
||||
else
|
||||
colorInd &= 0xF;
|
||||
|
||||
// if there is something to draw
|
||||
if (colorInd)
|
||||
{
|
||||
// if we have priority or there is nothing behind
|
||||
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
||||
*ptr = pPalette[colorInd] | 0x8000 | mask;
|
||||
}
|
||||
// if we have nothing to draw
|
||||
else
|
||||
// if we have better priority
|
||||
if (prio < (*ptr & (0x3 << 16)))
|
||||
// we just modify priority and keep what was behind
|
||||
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
||||
}
|
||||
}
|
||||
|
||||
++ptr;
|
||||
curX += a;
|
||||
curY += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Object::DrawWindow (uint8_t line, uint8_t* surface, bool oneDim,
|
||||
uint8_t mask)
|
||||
{
|
||||
// if the object is disabled or it's not an obj window
|
||||
if (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) != 2)
|
||||
return;
|
||||
|
||||
// don't draw sprites with "prohibited" size
|
||||
if (m_width == 0)
|
||||
return;
|
||||
|
||||
int16_t yoff = (m_attr0 & 0xFF);
|
||||
if (yoff > Screen::HEIGHT)
|
||||
yoff -= 256;
|
||||
|
||||
// if the object does not appear on the line
|
||||
if (yoff > line || yoff + m_height*8 <= line)
|
||||
return;
|
||||
|
||||
int16_t xoff = (m_attr1 & 0x1FF);
|
||||
if (xoff & (0x1 << 8))
|
||||
xoff |= 0xFE00; // extend sign bit
|
||||
|
||||
bool flipH = m_attr1 & (0x1 << 12);
|
||||
uint8_t* ptr = surface + xoff;
|
||||
if (flipH)
|
||||
ptr += m_width * 8 - 1;
|
||||
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
||||
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
||||
{
|
||||
// TODO 2d map, vert flips
|
||||
// we set pChar on the tile
|
||||
if (oneDim)
|
||||
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
|
||||
else
|
||||
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
|
||||
// and we go to the first pixel we need to draw
|
||||
pChar += 8 * ((line-yoff) % 8);
|
||||
for (uint8_t j = 0; j < m_width*8; ++j)
|
||||
{
|
||||
if (ptr - surface < Screen::WIDTH && ptr >= surface && *pChar)
|
||||
*ptr = mask;
|
||||
|
||||
if (flipH)
|
||||
--ptr;
|
||||
else
|
||||
++ptr;
|
||||
|
||||
if ((j % 8) == 7)
|
||||
// go to next tile
|
||||
pChar += ((8*8) - (8) + 1);
|
||||
else
|
||||
++pChar;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO verts flips
|
||||
// we set pChar on the tile
|
||||
if (oneDim)
|
||||
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
|
||||
else
|
||||
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
|
||||
// and we go to the first pixel we need to draw
|
||||
pChar += (8/2) * ((line-yoff) % 8);
|
||||
uint8_t colorInd;
|
||||
for (uint8_t j = 0; j < m_width*8; ++j)
|
||||
{
|
||||
if (j % 2)
|
||||
{
|
||||
colorInd = *pChar >> 4;
|
||||
|
||||
if ((j % 8) == 7)
|
||||
// go to next tile
|
||||
// it doesn't matter if we are in one or two dimensions mapping
|
||||
// since we never go on the next line
|
||||
pChar += ((8*8/2) - (8/2) + 1);
|
||||
else
|
||||
++pChar;
|
||||
}
|
||||
else
|
||||
colorInd = *pChar & 0xF;
|
||||
|
||||
// if we are not offscreen and there is a color
|
||||
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
|
||||
*ptr = mask;
|
||||
|
||||
if (flipH)
|
||||
--ptr;
|
||||
else
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Object::DrawWindowRot (uint8_t line, uint8_t* surface,
|
||||
bool oneDim, int16_t a, int16_t b, int16_t c, int16_t d, uint8_t mask)
|
||||
{
|
||||
// if it's not an obj window
|
||||
if (((m_attr0 >> 10) & 0x3) != 2)
|
||||
return;
|
||||
|
||||
// don't draw sprites with "prohibited" size
|
||||
if (m_width == 0)
|
||||
return;
|
||||
|
||||
int16_t yoff = (m_attr0 & 0xFF);
|
||||
if (yoff > Screen::HEIGHT)
|
||||
yoff -= 256;
|
||||
|
||||
int16_t xoff = (m_attr1 & 0x1FF);
|
||||
if (xoff & (0x1 << 8))
|
||||
xoff |= 0xFE00; // extend sign bit
|
||||
|
||||
uint8_t fwidth = m_width*8, fheight = m_height*8;
|
||||
if (m_attr0 & (0x1 << 9))
|
||||
{
|
||||
fwidth *= 2;
|
||||
fheight *= 2;
|
||||
}
|
||||
|
||||
// if the object does not appear on the line
|
||||
if (yoff > line || yoff + fheight <= line)
|
||||
return;
|
||||
|
||||
int32_t curX = ((m_width*8) << 8)/2
|
||||
+ (-fwidth/2) * a + (line-yoff-fheight/2) * b;
|
||||
int32_t curY = ((m_height*8) << 8)/2
|
||||
+ (-fwidth/2) * c + (line-yoff-fheight/2) * d;
|
||||
int32_t intX, intY;
|
||||
|
||||
uint8_t* ptr = surface + xoff;
|
||||
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
||||
uint8_t colorInd;
|
||||
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
||||
{
|
||||
for (uint8_t i = 0; i < fwidth; ++i)
|
||||
{
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
if (intX >= 0 && intX < m_width*8 &&
|
||||
intY >= 0 && intY < m_height*8)
|
||||
{
|
||||
colorInd = pChar[
|
||||
(intY/8) * (oneDim ? m_width : 32) * 8*8
|
||||
+ (intX/8) * 8*8
|
||||
+ (intY%8) * 8
|
||||
+ (intX%8)];
|
||||
|
||||
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
|
||||
*ptr = mask;
|
||||
}
|
||||
|
||||
++ptr;
|
||||
curX += a;
|
||||
curY += c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8_t i = 0; i < fwidth; ++i)
|
||||
{
|
||||
intX = curX >> 8;
|
||||
intY = curY >> 8;
|
||||
|
||||
if (intX >= 0 && intX < m_width*8 &&
|
||||
intY >= 0 && intY < m_height*8)
|
||||
{
|
||||
colorInd = pChar[(
|
||||
(intY/8) * (oneDim ? m_width : 32) * 8*8
|
||||
+ (intX/8) * 8*8
|
||||
+ (intY%8) * 8
|
||||
+ (intX%8)
|
||||
) / 2];
|
||||
|
||||
if (intX % 2)
|
||||
colorInd >>= 4;
|
||||
else
|
||||
colorInd &= 0xF;
|
||||
|
||||
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
|
||||
*ptr = mask;
|
||||
}
|
||||
|
||||
++ptr;
|
||||
curX += a;
|
||||
curY += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Object::UpdateAttrs (uint16_t attr0, uint16_t attr1, uint16_t attr2)
|
||||
{
|
||||
bool setsize = false, reload = false;
|
||||
if ((m_attr0 & 0xFF00) != (attr0 & 0xFF00))
|
||||
{
|
||||
reload = true;
|
||||
setsize = true;
|
||||
}
|
||||
m_attr0 = attr0;
|
||||
|
||||
if ((m_attr1 & 0xF000) != (attr1 & 0xF000))
|
||||
{
|
||||
reload = true;
|
||||
setsize = true;
|
||||
}
|
||||
m_attr1 = attr1;
|
||||
|
||||
if ((m_attr2 & 0xF1FF) != (attr2 & 0xF1FF))
|
||||
reload = true;
|
||||
m_attr2 = attr2;
|
||||
|
||||
if (setsize)
|
||||
{
|
||||
SetSize();
|
||||
|
||||
if (reload)
|
||||
{
|
||||
m_charBegin = 0x06010000 + (m_attr2 & 0x3FF)*32;
|
||||
m_charEnd = m_charBegin + m_width*m_height*8*
|
||||
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Object::UpdateAttr0 (uint16_t attr0)
|
||||
{
|
||||
// FIXME : we can do a more restrictive condition
|
||||
if ((m_attr0 & 0xFF00) != (attr0 & 0xFF00))
|
||||
{
|
||||
m_attr0 = attr0;
|
||||
SetSize();
|
||||
m_charEnd = m_charBegin + m_width*m_height*8*
|
||||
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
||||
}
|
||||
else
|
||||
m_attr0 = attr0;
|
||||
}
|
||||
|
||||
void Object::UpdateAttr1 (uint16_t attr1)
|
||||
{
|
||||
// if the size has changed
|
||||
if ((m_attr1 & 0xC000) != (attr1 & 0xC000))
|
||||
{
|
||||
m_attr1 = attr1;
|
||||
SetSize();
|
||||
m_charEnd = m_charBegin + m_width*m_height*8*
|
||||
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
||||
}
|
||||
else
|
||||
m_attr1 = attr1;
|
||||
}
|
||||
|
||||
void Object::UpdateAttr2 (uint16_t attr2)
|
||||
{
|
||||
if ((m_attr2 & 0xF1FF) != (attr2 & 0xF1FF))
|
||||
{
|
||||
m_attr2 = attr2;
|
||||
m_charBegin = 0x06010000 + (m_attr2 & 0x3FF)*32;
|
||||
m_charEnd = m_charBegin + m_width*m_height*8*
|
||||
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
||||
}
|
||||
else
|
||||
m_attr2 = attr2;
|
||||
}
|
||||
|
||||
inline void Object::SetSize ()
|
||||
{
|
||||
static const uint8_t Width[4][4] = {
|
||||
{1, 2, 4, 8}, // Square
|
||||
{2, 4, 4, 8}, // Horizontal
|
||||
{1, 1, 2, 4}, // Vertical
|
||||
{0, 0, 0, 0} // Prohibited
|
||||
};
|
||||
static const uint8_t Height[4][4] = {
|
||||
{1, 2, 4, 8}, // Square
|
||||
{1, 1, 2, 4}, // Horizontal
|
||||
{2, 4, 4, 8}, // Vertical
|
||||
{0, 0, 0, 0} // Prohibited
|
||||
};
|
||||
|
||||
m_width = Width[m_attr0 >> 14][m_attr1 >> 14];
|
||||
m_height = Height[m_attr0 >> 14][m_attr1 >> 14];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/graphics/objects.hpp"
|
||||
#include "../debug.hpp"
|
||||
#include <string.h>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
Objects::Objects (Memory& memory, Io& io, uint16_t* pPalette) :
|
||||
m_io(io),
|
||||
m_objs(128, Object(pPalette,
|
||||
memory.GetRealAddress(0x06010000))),
|
||||
m_pOam((uint16_t*)memory.GetRealAddress(0x07000000))
|
||||
{
|
||||
}
|
||||
|
||||
void Objects::DrawLine (uint8_t line, uint32_t* surface)
|
||||
{
|
||||
bool oneDim = m_io.DRead16(Io::DISPCNT) & (0x1 << 6);
|
||||
uint8_t mosaic = m_io.DRead8(Io::MOSAIC+1);
|
||||
int16_t rotSel;
|
||||
for (Objs::iterator iter = m_objs.begin();
|
||||
iter != m_objs.end(); ++iter)
|
||||
{
|
||||
rotSel = iter->GetRotationParam();
|
||||
if (rotSel == -1)
|
||||
iter->DrawLine (line, surface, oneDim, mosaic);
|
||||
else
|
||||
{
|
||||
rotSel *= 16;
|
||||
iter->DrawLineRot (line, surface, oneDim, m_pOam[rotSel + 3],
|
||||
m_pOam[rotSel + 7], m_pOam[rotSel + 11], m_pOam[rotSel + 15],
|
||||
mosaic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::DrawLineHighOnly (uint8_t line, uint32_t* surface)
|
||||
{
|
||||
bool oneDim = m_io.DRead16(Io::DISPCNT) & (0x1 << 6);
|
||||
uint8_t mosaic = m_io.DRead8(Io::MOSAIC+1);
|
||||
int16_t rotSel;
|
||||
for (Objs::iterator iter = m_objs.begin();
|
||||
iter != m_objs.end(); ++iter)
|
||||
if (iter->GetTileNum() >= 512)
|
||||
{
|
||||
rotSel = iter->GetRotationParam();
|
||||
if (rotSel == -1)
|
||||
iter->DrawLine (line, surface, oneDim, mosaic);
|
||||
else
|
||||
{
|
||||
rotSel *= 16;
|
||||
iter->DrawLineRot (line, surface, oneDim, m_pOam[rotSel + 3],
|
||||
m_pOam[rotSel + 7], m_pOam[rotSel + 11], m_pOam[rotSel + 15],
|
||||
mosaic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::DrawWindow (uint8_t line, uint8_t* surface)
|
||||
{
|
||||
bool oneDim = m_io.DRead16(Io::DISPCNT) & (0x1 << 6);
|
||||
int16_t rotSel;
|
||||
uint8_t mask = (m_io.DRead16(Io::WINOUT) >> 8) & 0x3F;
|
||||
for (Objs::iterator iter = m_objs.begin(); iter != m_objs.end(); ++iter)
|
||||
if (iter->IsWindow())
|
||||
{
|
||||
rotSel = iter->GetRotationParam();
|
||||
if (rotSel == -1)
|
||||
iter->DrawWindow (line, surface, oneDim, mask);
|
||||
else
|
||||
{
|
||||
rotSel *= 16;
|
||||
iter->DrawWindowRot (line, surface, oneDim, m_pOam[rotSel + 3],
|
||||
m_pOam[rotSel + 7], m_pOam[rotSel + 11], m_pOam[rotSel + 15],
|
||||
mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::OamWrite (uint32_t begin, uint32_t end)
|
||||
{
|
||||
uint32_t objnum;
|
||||
// FIXME is this possible ?
|
||||
if (begin & 0x3)
|
||||
met_abort("OamWrite not 4 byte aligned");
|
||||
if (begin <= 0x07000000)
|
||||
objnum = 0;
|
||||
else
|
||||
objnum = (begin - 0x07000000);
|
||||
uint16_t* pOam = m_pOam + objnum/2;
|
||||
objnum /= 8;
|
||||
|
||||
Objs::iterator iterStart;
|
||||
iterStart = m_objs.begin() + objnum;
|
||||
Objs::iterator iterEnd = m_objs.begin() + (end - 0x07000000 + 7)/8;
|
||||
if (iterEnd > m_objs.end())
|
||||
iterEnd = m_objs.end();
|
||||
|
||||
for (Objs::iterator iter = iterStart; iter != iterEnd; ++iter, ++objnum)
|
||||
{
|
||||
iter->UpdateAttrs(pOam[0], pOam[1], pOam[2]);
|
||||
pOam += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::OamWrite16 (uint32_t add)
|
||||
{
|
||||
uint16_t objnum = (add - 0x07000000) / 8;
|
||||
uint16_t* pOam = m_pOam + objnum*4;
|
||||
Objs::iterator iter = m_objs.begin() + objnum;
|
||||
switch ((add - 0x07000000) % 8)
|
||||
{
|
||||
case 0:
|
||||
iter->UpdateAttr0(pOam[0]);
|
||||
break;
|
||||
case 2:
|
||||
iter->UpdateAttr1(pOam[1]);
|
||||
break;
|
||||
case 4:
|
||||
iter->UpdateAttr2(pOam[2]);
|
||||
break;
|
||||
case 6:
|
||||
break;
|
||||
default :
|
||||
met_abort("Oam access not 16 bits aligned");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::OamWrite32 (uint32_t add)
|
||||
{
|
||||
add -= 0x07000000;
|
||||
uint16_t objnum = add / 8;
|
||||
uint16_t* pOam = m_pOam + objnum * 4;
|
||||
Objs::iterator iter = m_objs.begin() + objnum;
|
||||
switch (add % 8)
|
||||
{
|
||||
case 0:
|
||||
iter->UpdateAttr0(pOam[0]);
|
||||
iter->UpdateAttr1(pOam[1]);
|
||||
break;
|
||||
case 4:
|
||||
iter->UpdateAttr2(pOam[2]);
|
||||
break;
|
||||
default :
|
||||
met_abort("Oam access not 32 bits aligned");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/graphics/renderer.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
Renderer::Renderer (const uint16_t* surface) :
|
||||
m_base(surface)
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::VBlank ()
|
||||
{
|
||||
if (m_sig_frame)
|
||||
m_sig_frame(m_base);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,423 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/graphics/screen.hpp"
|
||||
#include "../globals.hpp"
|
||||
#include "../debug.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
BgLayer Screen::* const Screen::BgLayers [4] =
|
||||
{ &Screen::m_bgLayer0, &Screen::m_bgLayer1,
|
||||
&Screen::m_bgLayer2, &Screen::m_bgLayer3 };
|
||||
|
||||
// TODO there is no more need to pass theses references
|
||||
Screen::Screen (Memory& memory, Io& io) :
|
||||
m_io(io),
|
||||
m_surface(new uint16_t[WIDTH*HEIGHT]),
|
||||
m_renderer(m_surface),
|
||||
m_frameskip(0),
|
||||
m_curframe(0),
|
||||
m_dispcnt(0),
|
||||
m_refX2(0), m_refY2(0), m_refX3(0), m_refY3(0),
|
||||
m_pPalette((uint16_t*)memory.GetRealAddress(0x05000000)),
|
||||
m_bgLayer0(0, memory, io, m_pPalette),
|
||||
m_bgLayer1(1, memory, io, m_pPalette),
|
||||
m_bgLayer2(2, memory, io, m_pPalette),
|
||||
m_bgLayer3(3, memory, io, m_pPalette),
|
||||
m_objs(memory, io, m_pPalette + 256)
|
||||
{
|
||||
}
|
||||
|
||||
Screen::~Screen ()
|
||||
{
|
||||
delete [] m_surface;
|
||||
}
|
||||
|
||||
void Screen::DrawLine (uint8_t line)
|
||||
{
|
||||
if (m_curframe < m_frameskip)
|
||||
{
|
||||
// we skip this frame
|
||||
// VBlank
|
||||
if (line == 159)
|
||||
// we don't update screen since we haven't drawn anything on it, it
|
||||
// would show up a buffer with the previous image or maybe only
|
||||
// garbage (we use double buffering)
|
||||
m_curframe = (m_curframe + 1) % FRMSKIP_TOTAL;
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t* lineBg = new uint16_t[4*WIDTH];
|
||||
// layers may draw transparent pixels, so we need to clear them
|
||||
memset(lineBg, 0, 4*WIDTH*sizeof(uint16_t));
|
||||
uint32_t* lineObj = new uint32_t[WIDTH];
|
||||
for (uint32_t* p = lineObj + WIDTH - 1; p >= lineObj; --p)
|
||||
*p = 0x00030000;
|
||||
uint8_t prio[4];
|
||||
prio[0] = m_bgLayer0.GetPriority();
|
||||
prio[1] = m_bgLayer1.GetPriority();
|
||||
prio[2] = m_bgLayer2.GetPriority();
|
||||
prio[3] = m_bgLayer3.GetPriority();
|
||||
uint8_t layersOn = (m_dispcnt >> 8) & 0x1F;
|
||||
|
||||
switch (m_dispcnt & 0x7)
|
||||
{
|
||||
case 0: // all in mode 0
|
||||
// if the bg is enabled draw it
|
||||
if (layersOn & (0x1 )) m_bgLayer0.DrawLine0(line, lineBg);
|
||||
if (layersOn & (0x1 << 1)) m_bgLayer1.DrawLine0(line, lineBg+WIDTH);
|
||||
if (layersOn & (0x1 << 2)) m_bgLayer2.DrawLine0(line, lineBg+2*WIDTH);
|
||||
if (layersOn & (0x1 << 3)) m_bgLayer3.DrawLine0(line, lineBg+3*WIDTH);
|
||||
// if objects are enabled draw them
|
||||
if (layersOn & (0x1 << 4)) m_objs.DrawLine(line, lineObj);
|
||||
break;
|
||||
case 1: // bg0 and bg1 in mode 0 and bg2 in mode 2, no bg3
|
||||
// disable layer 3
|
||||
layersOn &= 0xF7;
|
||||
// if the bg is enabled draw it
|
||||
if (layersOn & (0x1 )) m_bgLayer0.DrawLine0(line, lineBg);
|
||||
if (layersOn & (0x1 << 1)) m_bgLayer1.DrawLine0(line, lineBg+WIDTH);
|
||||
if (layersOn & (0x1 << 2))
|
||||
m_bgLayer2.DrawLine2(lineBg+2*WIDTH,
|
||||
m_refX2, m_refY2,
|
||||
m_io.DRead16(Io::BG2PA),
|
||||
m_io.DRead16(Io::BG2PC));
|
||||
// if objects are enabled draw them
|
||||
if (layersOn & (0x1 << 4)) m_objs.DrawLine(line, lineObj);
|
||||
break;
|
||||
case 2: // bg2 and bg3 in mode 2, no bg0 and bg1
|
||||
// disable layers 0 and 1
|
||||
layersOn &= 0xFC;
|
||||
// if the bg is enabled draw it
|
||||
if (layersOn & (0x1 << 2))
|
||||
m_bgLayer2.DrawLine2(lineBg+2*WIDTH,
|
||||
m_refX2, m_refY2,
|
||||
m_io.DRead16(Io::BG2PA),
|
||||
m_io.DRead16(Io::BG2PC));
|
||||
if (layersOn & (0x1 << 3))
|
||||
m_bgLayer3.DrawLine2(lineBg+3*WIDTH,
|
||||
m_refX3, m_refY3,
|
||||
m_io.DRead16(Io::BG3PA),
|
||||
m_io.DRead16(Io::BG3PC));
|
||||
// if objects are enabled draw them
|
||||
if (layersOn & (0x1 << 4)) m_objs.DrawLine(line, lineObj);
|
||||
break;
|
||||
case 3: // bg2 only 15 bit direct color 240x160
|
||||
layersOn &= 0xF4;
|
||||
if (layersOn & (0x1 << 2))
|
||||
m_bgLayer2.DrawLine3(lineBg+2*WIDTH,
|
||||
m_refX2, m_refY2,
|
||||
m_io.DRead16(Io::BG2PA),
|
||||
m_io.DRead16(Io::BG2PC));
|
||||
if (layersOn & (0x1 << 4))
|
||||
m_objs.DrawLineHighOnly(line, lineObj);
|
||||
break;
|
||||
// TODO (remember, HIGH ONLY for objs, don't make shitty copy paste)
|
||||
case 4: // bg2 only in mode 4 (bitmap 256)
|
||||
layersOn &= 0xF4;
|
||||
// if bg2 is enabled
|
||||
if (layersOn & (0x1 << 2))
|
||||
// draw it
|
||||
m_bgLayer2.DrawLine4(
|
||||
line,
|
||||
lineBg+2*WIDTH,
|
||||
m_refX2, m_refY2,
|
||||
m_io.DRead16(Io::BG2PA),
|
||||
m_io.DRead16(Io::BG2PB),
|
||||
m_io.DRead16(Io::BG2PC),
|
||||
m_io.DRead16(Io::BG2PD),
|
||||
m_dispcnt & (0x1 << 4));
|
||||
// if objs are enabled
|
||||
if (layersOn & (0x1 << 4))
|
||||
// all objs with the current priority
|
||||
m_objs.DrawLineHighOnly(line, lineObj);
|
||||
break;
|
||||
case 5: // bg2 only 15 bit direct color 160x128 2 frames
|
||||
layersOn &= 0xF4;
|
||||
if (layersOn & (0x1 << 2))
|
||||
m_bgLayer2.DrawLine5(lineBg+2*WIDTH,
|
||||
m_refX2, m_refY2,
|
||||
m_io.DRead16(Io::BG2PA),
|
||||
m_io.DRead16(Io::BG2PC),
|
||||
m_dispcnt & (0x1 << 4));
|
||||
if (layersOn & (0x1 << 4))
|
||||
m_objs.DrawLineHighOnly(line, lineObj);
|
||||
break;
|
||||
default :
|
||||
met_abort("not supported : " << (m_dispcnt & 0x7));
|
||||
break;
|
||||
}
|
||||
|
||||
// windows
|
||||
/* I got very little information for this, it may not be accurate. All
|
||||
* the sources don't say the same thing */
|
||||
uint8_t* window = NULL;
|
||||
if (m_dispcnt >> 13)
|
||||
{
|
||||
window = new uint8_t[WIDTH];
|
||||
// Outside window
|
||||
memset(window, m_io.DRead16(Io::WINOUT) & 0x3F, WIDTH*sizeof(uint8_t));
|
||||
// OBJ window
|
||||
if (m_dispcnt & (0x1 << 15))
|
||||
m_objs.DrawWindow(line, window);
|
||||
// Window 1
|
||||
if (m_dispcnt & (0x1 << 14))
|
||||
DrawWindow(line, window,
|
||||
m_io.DRead16(Io::WIN1V), m_io.DRead16(Io::WIN1H),
|
||||
(m_io.DRead16(Io::WININ) >> 8) & 0x3F);
|
||||
// Window 0
|
||||
if (m_dispcnt & (0x1 << 13))
|
||||
DrawWindow(line, window,
|
||||
m_io.DRead16(Io::WIN0V), m_io.DRead16(Io::WIN0H),
|
||||
m_io.DRead16(Io::WININ) & 0x3F);
|
||||
}
|
||||
|
||||
// color effects
|
||||
uint16_t bldcnt = m_io.DRead16(Io::BLDCNT);
|
||||
uint8_t colorEffect = (bldcnt >> 6) & 0x3;
|
||||
uint8_t eva = std::min(m_io.DRead8(Io::BLDALPHA) & 0x1F, 16);
|
||||
uint8_t evb = std::min(m_io.DRead8(Io::BLDALPHA+1) & 0x1F, 16);
|
||||
uint8_t evy = std::min(m_io.DRead8(Io::BLDY) & 0x1F, 16);
|
||||
|
||||
// blending
|
||||
uint16_t* surface = m_surface + line*WIDTH;
|
||||
uint16_t out, bout;
|
||||
// top and back are formated as follow :
|
||||
// 4 bits | 4 bits
|
||||
// priority | layer
|
||||
uint8_t top, back;
|
||||
uint8_t curprio;
|
||||
uint32_t* pObj = lineObj;
|
||||
uint16_t* pBg = lineBg;
|
||||
uint8_t* pWin = window;
|
||||
uint8_t winmask;
|
||||
// if window are disabled, we draw everything which is enabled by
|
||||
// layersOn
|
||||
if (!window)
|
||||
winmask = 0xFF;
|
||||
for (uint8_t x = 0; x < WIDTH; ++x, ++pBg, ++pObj, ++pWin)
|
||||
{
|
||||
if (window)
|
||||
winmask = *pWin;
|
||||
|
||||
// backdrop
|
||||
bout = out = m_pPalette[0];
|
||||
back = top = 0xF5;
|
||||
|
||||
// for each layer
|
||||
for (uint8_t l = 0; l < 4; ++l)
|
||||
// if layer is enabled and
|
||||
if ((layersOn & (0x1 << l)) &&
|
||||
// pixel to draw is not transparent
|
||||
(pBg[l*WIDTH] & 0x8000))
|
||||
{
|
||||
curprio = ((prio[l] << 4) | l);
|
||||
|
||||
if (curprio < back && curprio > top)
|
||||
{
|
||||
bout = pBg[l*WIDTH];
|
||||
back = curprio;
|
||||
}
|
||||
else if (
|
||||
// priority is lower than current top pixel and
|
||||
curprio < top &&
|
||||
// this layer should be drawn in current window
|
||||
(winmask & (0x1 << l)))
|
||||
{
|
||||
bout = out;
|
||||
out = pBg[l*WIDTH];
|
||||
back = top;
|
||||
top = curprio;
|
||||
}
|
||||
}
|
||||
|
||||
// now objects
|
||||
// if objects are enabled
|
||||
if ((layersOn & (0x1 << 4)) &&
|
||||
// pixel to draw is not transparent
|
||||
(*pObj & 0x8000))
|
||||
{
|
||||
curprio = ((*pObj >> (16 - 4)) & (0x3 << 4));
|
||||
|
||||
if (curprio <= (back & 0xF0) && curprio > (top & 0xF0))
|
||||
{
|
||||
bout = *pObj;
|
||||
back = curprio | 4;
|
||||
}
|
||||
else if (// priority is lower than current top pixel and
|
||||
// NOTE : objects are OVER bg with same priority
|
||||
curprio <= (top & 0xF0) &&
|
||||
// objects should be drawn in current window
|
||||
(winmask & (0x1 << 4)))
|
||||
{
|
||||
bout = out;
|
||||
out = *pObj;
|
||||
back = top;
|
||||
top = curprio | 4;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have an object on top and it has semi transparency
|
||||
if ((top & 0xF) == 4 && (*pObj & (0x1 << 18)))
|
||||
{
|
||||
// if second target is just behind
|
||||
if (bldcnt & ((0x1 << 8) << (back & 0xF)))
|
||||
// apply alpha blend
|
||||
out =
|
||||
std::min(((bout & 0x001F) * evb +
|
||||
(out & 0x001F) * eva) / 16, 0x001F) |
|
||||
std::min((((bout & 0x03E0) * evb +
|
||||
(out & 0x03E0) * eva) / 16) & 0xFFE0, 0x03E0) |
|
||||
// no need to take care of over flow since u16 & s32 = s32
|
||||
std::min((((bout & 0x7C00) * evb +
|
||||
(out & 0x7C00) * eva) / 16) & 0xFC00, 0x7C00);
|
||||
}
|
||||
// else if no window or window and effects are enabled in window
|
||||
// and we have a first target on top
|
||||
else if ((!window || (*pWin & (0x1 << 5)))
|
||||
&& (bldcnt & (0x1 << (top & 0xF))))
|
||||
switch (colorEffect)
|
||||
{
|
||||
case 1: // alpha blend
|
||||
// if second target is just behind
|
||||
// TODO optimization : special cases for eva = 0 or evb = 0
|
||||
if (bldcnt & ((0x1 << 8) << (back & 0xF)))
|
||||
// apply alpha blend
|
||||
out =
|
||||
std::min(((bout & 0x001F) * evb +
|
||||
(out & 0x001F) * eva) / 16, 0x001F) |
|
||||
std::min((((bout & 0x03E0) * evb +
|
||||
(out & 0x03E0) * eva) / 16) & 0xFFE0, 0x03E0) |
|
||||
// no need to take care of over flow since u16 & s32 = s32
|
||||
std::min((((bout & 0x7C00) * evb +
|
||||
(out & 0x7C00) * eva) / 16) & 0xFC00, 0x7C00);
|
||||
break;
|
||||
case 2: // brightness increase
|
||||
// we don't need saturation since the formula makes it so it never
|
||||
// goes above 0x1F
|
||||
out =
|
||||
(((out & 0x001F) +
|
||||
((0x001F - (out & 0x001F)) * evy) / 16) & 0x001F) |
|
||||
(((out & 0x03E0) +
|
||||
((0x03E0 - (out & 0x03E0)) * evy) / 16) & 0x03E0) |
|
||||
(((out & 0x7C00) +
|
||||
((0x7C00 - (out & 0x7C00)) * evy) / 16) & 0x7C00);
|
||||
break;
|
||||
case 3: // brightness decrease
|
||||
// we don't need saturation since the formula makes it so it never
|
||||
// goes below 0
|
||||
out =
|
||||
((((out & 0x001F) * (16-evy)) / 16) & 0x001F) |
|
||||
((((out & 0x03E0) * (16-evy)) / 16) & 0x03E0) |
|
||||
((((out & 0x7C00) * (16-evy)) / 16) & 0x7C00);
|
||||
break;
|
||||
}
|
||||
|
||||
*surface = out;
|
||||
++surface;
|
||||
}
|
||||
|
||||
m_refX2 += (int16_t)m_io.DRead16(Io::BG2PB);
|
||||
m_refY2 += (int16_t)m_io.DRead16(Io::BG2PD);
|
||||
m_refX3 += (int16_t)m_io.DRead16(Io::BG3PB);
|
||||
m_refY3 += (int16_t)m_io.DRead16(Io::BG3PD);
|
||||
|
||||
if (window)
|
||||
delete [] window;
|
||||
delete [] lineBg;
|
||||
delete [] lineObj;
|
||||
|
||||
// VBlank
|
||||
if (line == 159)
|
||||
{
|
||||
m_curframe = (m_curframe + 1) % FRMSKIP_TOTAL;
|
||||
m_renderer.VBlank();
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::DrawWindow (uint8_t line, uint8_t* surface,
|
||||
uint16_t win0v, uint16_t win0h, uint8_t mask)
|
||||
{
|
||||
// the variables are called win0, but this function works also for win1
|
||||
uint8_t win0t = win0v >> 8, win0b = win0v & 0xFF;
|
||||
// VBA says that if t == b and they are greater than 228, we are in the
|
||||
// window
|
||||
// This is from Tonc documentation
|
||||
if (win0t >= 227)
|
||||
return;
|
||||
else if (win0b > win0t && line >= win0t && line < win0b
|
||||
// the above is the normal behaviour
|
||||
|| win0b < win0t && (line >= win0t || line < win0b)
|
||||
// the above is the "inverted" behaviour
|
||||
)
|
||||
{
|
||||
uint8_t win0l, win0r;
|
||||
uint8_t* ptr;
|
||||
win0l = win0h >> 8;
|
||||
win0r = win0h & 0xFF;
|
||||
// this seems wrong
|
||||
//if (win0l > 240)
|
||||
// win0l = 240;
|
||||
//if (win0r > 240)
|
||||
// win0r = 240;
|
||||
|
||||
// if this is the normal behaviour
|
||||
if (win0l <= win0r)
|
||||
{
|
||||
ptr = surface + win0l;
|
||||
for (uint8_t i = win0l; i < win0r && i < 240; ++i, ++ptr)
|
||||
*ptr = mask;
|
||||
}
|
||||
// else, this is the inverted behaviour
|
||||
else
|
||||
{
|
||||
ptr = surface;
|
||||
for (uint8_t i = 0; i < win0r && i < 240; ++i, ++ptr)
|
||||
*ptr = mask;
|
||||
ptr = surface + win0l;
|
||||
for (uint8_t i = win0l; i < 240; ++i, ++ptr)
|
||||
*ptr = mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Screen::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_refX2);
|
||||
SS_WRITE_VAR(m_refY2);
|
||||
SS_WRITE_VAR(m_refX3);
|
||||
SS_WRITE_VAR(m_refY3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Screen::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_refX2);
|
||||
SS_READ_VAR(m_refY2);
|
||||
SS_READ_VAR(m_refX3);
|
||||
SS_READ_VAR(m_refY3);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/interpreter.hpp"
|
||||
#include "ameteor/cpu.hpp"
|
||||
#include "ameteor/memory.hpp"
|
||||
#include "ameteor/bios.hpp"
|
||||
#include "ameteor/disassembler/instruction.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "cpu_globals.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
Interpreter::Interpreter() :
|
||||
m_run(false),
|
||||
m_interrupt_(false),
|
||||
m_haltcnt(IO.GetRef8(Io::HALTCNT)),
|
||||
m_if(IO.GetRef16(Io::IF)),
|
||||
m_ie(IO.GetRef16(Io::IE))
|
||||
{
|
||||
}
|
||||
|
||||
void Interpreter::SendInterrupt (uint16_t interrupt)
|
||||
{
|
||||
IO.GetRef16(Io::IF) |= interrupt;
|
||||
if ((interrupt & IO.DRead16(Io::IE)) &&
|
||||
(IO.DRead16(Io::IME) & 0x1) &&
|
||||
!m_st.icpsr.irq_d)
|
||||
// irq are enabled and theses irq are enabled...
|
||||
m_interrupt = true;
|
||||
}
|
||||
|
||||
void Interpreter::CheckInterrupt ()
|
||||
{
|
||||
m_interrupt =
|
||||
(IO.DRead16(Io::IF) & IO.DRead16(Io::IE)) &&
|
||||
(IO.DRead16(Io::IME) & 0x1) &&
|
||||
!m_st.icpsr.irq_d;
|
||||
}
|
||||
|
||||
void Interpreter::Run (unsigned int cycles)
|
||||
{
|
||||
m_run = true;
|
||||
CLOCK.ResetCounter();
|
||||
while(m_run && CLOCK.GetCounter() < cycles)
|
||||
{
|
||||
switch (m_haltcnt)
|
||||
{
|
||||
case 255: // normal mode
|
||||
PrintRegs();
|
||||
if (FLAG_T)
|
||||
{
|
||||
if (R(15) & 0x1)
|
||||
met_abort("PC not 16 bit aligned : " << IOS_ADD << R(15));
|
||||
|
||||
code = MEM.Read16(R(15)-2);
|
||||
if (traceenabled)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << IOS_TRACE << R(15) - 2 << ':' << std::setw(4) << code << " ";
|
||||
ss.setf(std::ios::left, std::ios::adjustfield);
|
||||
ss << std::setw(32) << std::setfill(' ') << Disassembler::Instruction(R(15), (uint16_t)code).ToString();
|
||||
ss.setf(std::ios::right, std::ios::adjustfield);
|
||||
ss << IOS_TRACE;
|
||||
for (int i = 0; i < 16; i++)
|
||||
ss << std::setw(8) << R(i) << ' ';
|
||||
UpdateCpsr();
|
||||
ss << std::setw(8) << m_st.cpsr.dw << ' ';
|
||||
ss << std::setw(8) << m_st.spsr.dw << ' ';
|
||||
trace_bizhawk(ss.str());
|
||||
}
|
||||
R(15) += 2;
|
||||
t_Code();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (R(15) & 0x3)
|
||||
met_abort("PC not 32 bit aligned : " << IOS_ADD << R(15));
|
||||
|
||||
if (R(15) < 0x01000000 && !MEM.HasBios())
|
||||
{
|
||||
switch (R(15))
|
||||
{
|
||||
case 0x004:
|
||||
Bios::Bios000h();
|
||||
break;
|
||||
case 0x00C:
|
||||
Bios::Bios008h();
|
||||
break;
|
||||
case 0x01C:
|
||||
Bios::Bios018h();
|
||||
break;
|
||||
case 0x134:
|
||||
Bios::Bios130h();
|
||||
break;
|
||||
case 0x33C:
|
||||
Bios::Bios338h();
|
||||
break;
|
||||
case 0x16C:
|
||||
Bios::Bios168h();
|
||||
break;
|
||||
default:
|
||||
met_abort("Jump to " << IOS_ADD << R(15));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
code = MEM.Read32(R(15)-4);
|
||||
if (traceenabled)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << IOS_TRACE << R(15) - 4 << ':' << std::setw(8) << code << ' ';
|
||||
ss.setf(std::ios::left, std::ios::adjustfield);
|
||||
ss << std::setw(32) << std::setfill(' ') << Disassembler::Instruction(R(15), (uint32_t)code).ToString();
|
||||
ss.setf(std::ios::right, std::ios::adjustfield);
|
||||
ss << IOS_TRACE;
|
||||
for (int i = 0; i < 16; i++)
|
||||
ss << std::setw(8) << R(i) << ' ';
|
||||
UpdateCpsr();
|
||||
ss << std::setw(8) << m_st.cpsr.dw << ' ';
|
||||
ss << std::setw(8) << m_st.spsr.dw << ' ';
|
||||
trace_bizhawk(ss.str());
|
||||
}
|
||||
R(15) += 4;
|
||||
a_Code();
|
||||
}
|
||||
}
|
||||
if (R(15) < 0x01000000 && FLAG_T && !MEM.HasBios())
|
||||
met_abort("Jump to " << IOS_ADD << R(15));
|
||||
|
||||
CLOCK.Commit();
|
||||
|
||||
if (m_interrupt)
|
||||
// irq are enabled and there are irq waiting...
|
||||
{
|
||||
// FIXME : do we really need this ??
|
||||
// if not, we can get rid of save and load state and reset
|
||||
if (m_interrupt_)
|
||||
{
|
||||
m_interrupt_ = false;
|
||||
// XXX we must be sure the cpu isn't halted when an interrupt
|
||||
// occurs
|
||||
// should be removed after since it takes no time to make a new
|
||||
// iteration of the loop
|
||||
m_haltcnt = 255;
|
||||
CPU.Interrupt();
|
||||
}
|
||||
else
|
||||
{
|
||||
// XXX
|
||||
if (m_haltcnt != 255)
|
||||
{
|
||||
m_haltcnt = 255;
|
||||
CPU.Interrupt();
|
||||
}
|
||||
else
|
||||
m_interrupt_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 0: // halt mode
|
||||
if (m_if & m_ie) // interrupt occured
|
||||
{
|
||||
m_haltcnt = 255; // return to normal mode
|
||||
CPU.Interrupt();
|
||||
// XXX use an else
|
||||
break;
|
||||
}
|
||||
|
||||
CLOCK.WaitForNext();
|
||||
|
||||
// XXX remove this block
|
||||
if (m_if & m_ie) // interrupt occured
|
||||
{
|
||||
m_haltcnt = 255; // return to normal mode
|
||||
CPU.Interrupt();
|
||||
}
|
||||
|
||||
break;
|
||||
case 1: // stop mode
|
||||
met_abort("Stop mode not implemented");
|
||||
break;
|
||||
default:
|
||||
met_abort("Unknown HALTCNT value : " << (int)m_haltcnt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_run = false;
|
||||
}
|
||||
|
||||
bool Interpreter::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_VAR(m_interrupt_);
|
||||
|
||||
return Cpu::SaveState(stream);
|
||||
}
|
||||
|
||||
bool Interpreter::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_VAR(m_interrupt_);
|
||||
|
||||
return Cpu::LoadState(stream);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,508 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/io.hpp"
|
||||
#include "ameteor/dma.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "ameteor.hpp"
|
||||
#include <cstring>
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
#define W8(add, val) \
|
||||
m_iomem[(add) & 0xFFF] = (val)
|
||||
#define W16(add, val) \
|
||||
*(uint16_t*)(m_iomem + ((add) & 0xFFF)) = (val)
|
||||
#define W32(add, val) \
|
||||
*(uint32_t*)(m_iomem + ((add) & 0xFFF)) = (val)
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
Io::Io ()
|
||||
{
|
||||
m_iomem = new uint8_t[IO_SIZE];
|
||||
Reset ();
|
||||
}
|
||||
|
||||
Io::~Io ()
|
||||
{
|
||||
delete [] m_iomem;
|
||||
}
|
||||
|
||||
void Io::Reset ()
|
||||
{
|
||||
std::memset(m_iomem, 0, IO_SIZE);
|
||||
|
||||
// TODO use clears intead
|
||||
|
||||
// TODO DISPCNT should be 0x80 by default
|
||||
// TODO do it also for clears
|
||||
// TODO lcd should draw white lines when hblank forced
|
||||
// TODO when passing disabling hblank forced, lcd should start drawing from
|
||||
// first line
|
||||
W16(SOUNDBIAS, 0x0200); // default value
|
||||
W16(KEYINPUT, 0x03FF); // all keys released
|
||||
W8(HALTCNT, 0xFF); // normal mode (internal)
|
||||
W16(DISPSTAT, 0x0004); // vcount match (since default vcount is 0)
|
||||
W16(BG2PA, 0x0100);
|
||||
W16(BG2PD, 0x0100);
|
||||
W16(BG3PA, 0x0100);
|
||||
W16(BG3PD, 0x0100);
|
||||
W16(RCNT, 0x8000); // we start in general purpose mode
|
||||
}
|
||||
|
||||
void Io::ClearSio ()
|
||||
{
|
||||
// TODO
|
||||
W16(RCNT, 0x8000);
|
||||
}
|
||||
|
||||
void Io::ClearSound ()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Io::ClearOthers ()
|
||||
{
|
||||
// FIXME !! shouldn't we call Write*() ?
|
||||
// lcd
|
||||
for (uint8_t i = 0x0; i < 0x56; i += 2)
|
||||
Write16(i, 0x0000);
|
||||
// dma
|
||||
for (uint8_t i = 0xB0; i < 0xE0; i += 4)
|
||||
Write32(i, 0x0000);
|
||||
// FIXME : should timers be set to 0 too ? (vba does not)
|
||||
W8(HALTCNT, 0xFF); // normal mode (internal)
|
||||
W16(IE, 0x0000);
|
||||
W16(IF, 0x0000);
|
||||
W16(IME, 0x0000);
|
||||
Write16(WAITCNT, 0x0000);
|
||||
W16(BG2PA, 0x0100);
|
||||
W16(BG2PD, 0x0100);
|
||||
W16(BG3PA, 0x0100);
|
||||
W16(BG3PD, 0x0100);
|
||||
}
|
||||
|
||||
// TODO implement unreadable or write-only io
|
||||
uint8_t Io::Read8 (uint32_t add)
|
||||
{
|
||||
if ((add & 0xFFE) == KEYINPUT)
|
||||
keyupdate_bizhawk();
|
||||
//debug ("IO Read8 at " << IOS_ADD << add << " of " << IOS_ADD << (int)*(uint8_t*)(m_iomem + (add & 0xFFF)));
|
||||
if ((add & 0xFF0) == 0x100)
|
||||
switch (add & 0xF)
|
||||
{
|
||||
case 0x0:
|
||||
case 0x4:
|
||||
case 0x8:
|
||||
case 0xC:
|
||||
met_abort("Misaligned reading of timers");
|
||||
}
|
||||
return m_iomem[add & 0xFFF];
|
||||
}
|
||||
|
||||
uint16_t Io::Read16 (uint32_t add)
|
||||
{
|
||||
if ((add & 0xFFE) == KEYINPUT)
|
||||
keyupdate_bizhawk();
|
||||
//debug ("IO Read16 at " << IOS_ADD << add << " of " << IOS_ADD << *(uint16_t*)(m_iomem + (add & 0xFFF)));
|
||||
// special case, reading timers
|
||||
if ((add & 0xFF0) == 0x100)
|
||||
switch (add & 0xF)
|
||||
{
|
||||
case 0x0: return TIMER0.GetCount();
|
||||
case 0x4: return TIMER1.GetCount();
|
||||
case 0x8: return TIMER2.GetCount();
|
||||
case 0xC: return TIMER3.GetCount();
|
||||
}
|
||||
return *(uint16_t*)(m_iomem + (add & 0xFFF));
|
||||
}
|
||||
|
||||
uint32_t Io::Read32 (uint32_t add)
|
||||
{
|
||||
if ((add & 0xFFC) == KEYINPUT)
|
||||
keyupdate_bizhawk();
|
||||
//debug ("IO Read32 at " << IOS_ADD << add << " of " << IOS_ADD << *(uint32_t*)(m_iomem + (add & 0xFFF)));
|
||||
// special case, reading timers
|
||||
if ((add & 0xFF0) == 0x100)
|
||||
switch (add & 0xF)
|
||||
{
|
||||
case 0x0: return TIMER0.GetCount();
|
||||
case 0x4: return TIMER1.GetCount();
|
||||
case 0x8: return TIMER2.GetCount();
|
||||
case 0xC: return TIMER3.GetCount();
|
||||
}
|
||||
return *(uint32_t*)(m_iomem + (add & 0xFFF));
|
||||
}
|
||||
|
||||
void Io::Write8 (uint32_t add, uint8_t val)
|
||||
{
|
||||
//debug ("IO Write8 at " << IOS_ADD << add << " of " << IOS_ADD << (int)val);
|
||||
switch (add & 0xFFF)
|
||||
{
|
||||
case NR10+1:
|
||||
case NR52+1:
|
||||
case NR52+2:
|
||||
case NR52+3:
|
||||
break;
|
||||
case NR10:
|
||||
case NR11:
|
||||
case NR13:
|
||||
case NR21:
|
||||
case NR23:
|
||||
case NR41:
|
||||
case NR43:
|
||||
case NR50:
|
||||
case NR51:
|
||||
case SOUNDCNT_H:
|
||||
W8(add, val);
|
||||
break;
|
||||
case NR12:
|
||||
W8(add, val);
|
||||
if (!(val & (0xF << 4)))
|
||||
SOUND.ResetSound1Envelope();
|
||||
break;
|
||||
case NR14:
|
||||
W8(add, val & 0xC7);
|
||||
if (val & (0x1 << 7))
|
||||
SOUND.ResetSound1();
|
||||
break;
|
||||
case NR22:
|
||||
W8(add, val);
|
||||
if (!(val & (0xF << 4)))
|
||||
SOUND.ResetSound2Envelope();
|
||||
break;
|
||||
case NR24:
|
||||
W8(add, val & 0xC7);
|
||||
if (val & (0x1 << 7))
|
||||
SOUND.ResetSound2();
|
||||
break;
|
||||
case NR42:
|
||||
W8(add, val);
|
||||
if (!(val & (0xF << 4)))
|
||||
SOUND.ResetSound4Envelope();
|
||||
break;
|
||||
case NR44:
|
||||
W8(add, val & 0xC7);
|
||||
if (val & (0x1 << 7))
|
||||
SOUND.ResetSound4();
|
||||
break;
|
||||
case SOUNDCNT_H+1:
|
||||
W8(add, val);
|
||||
SOUND.UpdateCntH1(val);
|
||||
break;
|
||||
case NR52:
|
||||
// this will also reset the sound on flags
|
||||
W8(add, val & 0x80);
|
||||
break;
|
||||
case POSTFLG:
|
||||
// FIXME is this right, i have no idea about why i should do that
|
||||
if (val)
|
||||
val &= 0xFE;
|
||||
W8(add, val);
|
||||
break;
|
||||
case HALTCNT:
|
||||
W8(add, val);
|
||||
break;
|
||||
default:
|
||||
//W8(add, val);
|
||||
// TODO make a function which will apply masks to IO memory and trigger
|
||||
// the update functions, this function will be called by write8 and
|
||||
// write16
|
||||
#if 1
|
||||
add &= 0xFFF;
|
||||
if (add % 2)
|
||||
Write16(add & ~0x1, (val << 8) | m_iomem[add & ~0x1]);
|
||||
else
|
||||
Write16(add, (m_iomem[add | 0x1] << 8) | val);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Io::Write16 (uint32_t add, uint16_t val)
|
||||
{
|
||||
//debug ("IO Write16 at " << IOS_ADD << add << " of " << IOS_ADD << val);
|
||||
//*(uint16_t*)(m_iomem + (add & 0xFFF)) = val;
|
||||
|
||||
switch (add & 0xFFF)
|
||||
{
|
||||
case KEYINPUT:
|
||||
case VCOUNT:
|
||||
break;
|
||||
case DMA0CNT_L:
|
||||
case DMA1CNT_L:
|
||||
case DMA2CNT_L:
|
||||
case DMA3CNT_L:
|
||||
//W16(add, val);
|
||||
DMA.SetReload(((add & 0xFFF) - DMA0CNT_L) / DMA_CHANSIZE, val);
|
||||
break;
|
||||
case KEYCNT:
|
||||
W16(add, val & 0xC3FF);
|
||||
break;
|
||||
case IME:
|
||||
W16(add, val & 0x0001);
|
||||
CPU.CheckInterrupt();
|
||||
break;
|
||||
case IE:
|
||||
W16(add, val & 0x3FFF);
|
||||
CPU.CheckInterrupt();
|
||||
break;
|
||||
case IF:
|
||||
*((uint16_t*)(m_iomem+IF)) ^= (val & (*((uint16_t*)(m_iomem+IF))));
|
||||
CPU.CheckInterrupt();
|
||||
break;
|
||||
case BG0CNT:
|
||||
W16(add, val & 0xFFCF);
|
||||
LCD.UpdateBg0Cnt(val & 0xFFCF);
|
||||
break;
|
||||
case BG1CNT:
|
||||
W16(add, val & 0xFFCF);
|
||||
LCD.UpdateBg1Cnt(val & 0xFFCF);
|
||||
break;
|
||||
case BG2CNT:
|
||||
W16(add, val & 0xFFCF);
|
||||
LCD.UpdateBg2Cnt(val & 0xFFCF);
|
||||
break;
|
||||
case BG3CNT:
|
||||
W16(add, val & 0xFFCF);
|
||||
LCD.UpdateBg3Cnt(val & 0xFFCF);
|
||||
break;
|
||||
case DISPSTAT:
|
||||
// the first 3 bits are read only and they are used by the lcd
|
||||
// NOTE : we are in LITTLE ENDIAN
|
||||
// FIXME : if vcount setting has changed to current vcount, we should
|
||||
// update the vcounter flag and eventually trigger an interrupt
|
||||
W16(add, (val & 0xFFF8) | (m_iomem[add & 0xFFF] & 0x07));
|
||||
break;
|
||||
// The BG*OFS are write-only, we don't need to W16()
|
||||
// You do if you're ever going to load them from a savestate...
|
||||
case BG0HOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg0XOff(val & 0x1FF);
|
||||
break;
|
||||
case BG0VOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg0YOff(val & 0x1FF);
|
||||
break;
|
||||
case BG1HOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg1XOff(val & 0x1FF);
|
||||
break;
|
||||
case BG1VOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg1YOff(val & 0x1FF);
|
||||
break;
|
||||
case BG2HOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg2XOff(val & 0x1FF);
|
||||
break;
|
||||
case BG2VOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg2YOff(val & 0x1FF);
|
||||
break;
|
||||
case BG3HOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg3XOff(val & 0x1FF);
|
||||
break;
|
||||
case BG3VOFS:
|
||||
W16(add, val & 0x1FF);
|
||||
LCD.UpdateBg3YOff(val & 0x1FF);
|
||||
break;
|
||||
case BG2X_H:
|
||||
val &= 0x0FFF;
|
||||
case BG2X_L:
|
||||
W16(add, val);
|
||||
LCD.UpdateBg2RefX(IO.DRead32(Io::BG2X_L));
|
||||
break;
|
||||
case BG2Y_H:
|
||||
val &= 0x0FFF;
|
||||
case BG2Y_L:
|
||||
W16(add, val);
|
||||
LCD.UpdateBg2RefY(IO.DRead32(Io::BG2Y_L));
|
||||
break;
|
||||
case BG3X_H:
|
||||
val &= 0x0FFF;
|
||||
case BG3X_L:
|
||||
W16(add, val);
|
||||
LCD.UpdateBg3RefX(IO.DRead32(Io::BG3X_L));
|
||||
break;
|
||||
case BG3Y_H:
|
||||
val &= 0x0FFF;
|
||||
case BG3Y_L:
|
||||
W16(add, val);
|
||||
LCD.UpdateBg3RefY(IO.DRead32(Io::BG3Y_L));
|
||||
break;
|
||||
case WIN0H:
|
||||
case WIN1H:
|
||||
case WIN0V:
|
||||
case WIN1V:
|
||||
case WININ:
|
||||
case WINOUT:
|
||||
W16(add, val);
|
||||
break;
|
||||
case BLDCNT:
|
||||
W16(add, val);
|
||||
break;
|
||||
case MOSAIC:
|
||||
W16(add, val);
|
||||
break;
|
||||
case DISPCNT:
|
||||
W16(add, val);
|
||||
LCD.UpdateDispCnt(val);
|
||||
break;
|
||||
case DMA0CNT_H:
|
||||
case DMA1CNT_H:
|
||||
case DMA2CNT_H:
|
||||
case DMA3CNT_H:
|
||||
W16(add, val & 0xFFE0);
|
||||
DMA.UpdateCnt(((add & 0xFFF) - DMA0CNT_H) / DMA_CHANSIZE);
|
||||
break;
|
||||
case WAITCNT:
|
||||
W16(add, val & 0xDFFF);
|
||||
MEM.UpdateWaitStates (val & 0xDFFF);
|
||||
break;
|
||||
case SOUND1CNT_L:
|
||||
case SOUND1CNT_H:
|
||||
case SOUND1CNT_X:
|
||||
case SOUND2CNT_L:
|
||||
case SOUND2CNT_H:
|
||||
case SOUND4CNT_L:
|
||||
case SOUND4CNT_H:
|
||||
case SOUNDCNT_L:
|
||||
case SOUNDCNT_H:
|
||||
case SOUNDCNT_X:
|
||||
case POSTFLG:
|
||||
Write8(add, val & 0xFF);
|
||||
Write8(add + 1, val >> 8);
|
||||
break;
|
||||
case TM0CNT_L:
|
||||
TIMER0.SetReload(val);
|
||||
break;
|
||||
case TM1CNT_L:
|
||||
TIMER1.SetReload(val);
|
||||
break;
|
||||
case TM2CNT_L:
|
||||
TIMER2.SetReload(val);
|
||||
break;
|
||||
case TM3CNT_L:
|
||||
TIMER3.SetReload(val);
|
||||
break;
|
||||
case TM0CNT_H:
|
||||
W16(add, val & 0x00C7);
|
||||
TIMER0.Reload();
|
||||
break;
|
||||
case TM1CNT_H:
|
||||
W16(add, val & 0x00C7);
|
||||
TIMER1.Reload();
|
||||
break;
|
||||
case TM2CNT_H:
|
||||
W16(add, val & 0x00C7);
|
||||
TIMER2.Reload();
|
||||
break;
|
||||
case TM3CNT_H:
|
||||
W16(add, val & 0x00C7);
|
||||
TIMER3.Reload();
|
||||
break;
|
||||
default:
|
||||
//met_abort("Unknown IO at " << IOS_ADD << add);
|
||||
W16(add, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Io::Write32 (uint32_t add, uint32_t val)
|
||||
{
|
||||
//debug ("IO Write32 at " << IOS_ADD << add << " of " << IOS_ADD << val);
|
||||
switch (add & 0xFF)
|
||||
{
|
||||
case DMA1DAD:
|
||||
case DMA0SAD:
|
||||
case DMA1SAD:
|
||||
case DMA2SAD:
|
||||
case DMA3SAD:
|
||||
case DMA0DAD:
|
||||
case DMA2DAD:
|
||||
case DMA3DAD:
|
||||
W32(add, val);
|
||||
break;
|
||||
case BG0HOFS:
|
||||
case BG1HOFS:
|
||||
case BG2HOFS:
|
||||
case BG3HOFS:
|
||||
Write16(add, val & 0xFFFF);
|
||||
Write16(add+2, val >> 16);
|
||||
break;
|
||||
case BG2X_L:
|
||||
W32(add, val & 0x0FFFFFFF);
|
||||
LCD.UpdateBg2RefX(IO.DRead32(Io::BG2X_L));
|
||||
break;
|
||||
case BG2Y_L:
|
||||
W32(add, val & 0x0FFFFFFF);
|
||||
LCD.UpdateBg2RefY(IO.DRead32(Io::BG2Y_L));
|
||||
break;
|
||||
case BG3X_L:
|
||||
W32(add, val & 0x0FFFFFFF);
|
||||
LCD.UpdateBg3RefX(IO.DRead32(Io::BG3X_L));
|
||||
break;
|
||||
case BG3Y_L:
|
||||
W32(add, val & 0x0FFFFFFF);
|
||||
LCD.UpdateBg3RefY(IO.DRead32(Io::BG3Y_L));
|
||||
break;
|
||||
case BG2PA:
|
||||
case BG2PC:
|
||||
case BG3PA:
|
||||
case BG3PC:
|
||||
case WIN0H:
|
||||
case WIN0V:
|
||||
case WININ:
|
||||
Write16(add, val & 0xFFFF);
|
||||
Write16(add+2, val >> 16);
|
||||
break;
|
||||
case DMA0CNT_L:
|
||||
case DMA1CNT_L:
|
||||
case DMA2CNT_L:
|
||||
case DMA3CNT_L:
|
||||
Write16(add, val & 0xFFFF);
|
||||
Write16(add+2, val >> 16);
|
||||
break;
|
||||
case FIFO_A:
|
||||
case FIFO_B:
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
//met_abort("Unknown IO at " << IOS_ADD << add);
|
||||
//*(uint32_t*)(m_iomem + (add & 0xFFF)) = val;
|
||||
Write16(add, val & 0xFFFF);
|
||||
Write16(add+2, val >> 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Io::SaveState (std::ostream& stream)
|
||||
{
|
||||
SS_WRITE_DATA(m_iomem, IO_SIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Io::LoadState (std::istream& stream)
|
||||
{
|
||||
SS_READ_DATA(m_iomem, IO_SIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
// Meteor - A Nintendo Gameboy Advance emulator
|
||||
// Copyright (C) 2009-2011 Philippe Daouadi
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ameteor/keypad.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "ameteor.hpp"
|
||||
|
||||
namespace AMeteor
|
||||
{
|
||||
Keypad::Keypad () :
|
||||
m_keyinput(IO.GetRef16(Io::KEYINPUT)),
|
||||
m_keycnt(IO.GetRef16(Io::KEYCNT))
|
||||
{
|
||||
}
|
||||
|
||||
void Keypad::KeyPressed(int code)
|
||||
{
|
||||
if (m_keys.count(code))
|
||||
m_keyinput &= ~m_keys[code];
|
||||
}
|
||||
|
||||
void Keypad::KeyReleased(int code)
|
||||
{
|
||||
if (m_keys.count(code))
|
||||
m_keyinput |= m_keys[code];
|
||||
}
|
||||
|
||||
void Keypad::JoyButtonPressed (uint16_t joyid, uint16_t button)
|
||||
{
|
||||
uint32_t id = ((int)joyid) << 16 | button;
|
||||
if (m_joys.count(id))
|
||||
m_keyinput &= ~m_joys[id];
|
||||
}
|
||||
|
||||
void Keypad::JoyButtonReleased (uint16_t joyid, uint16_t button)
|
||||
{
|
||||
uint32_t id = ((int)joyid) << 16 | button;
|
||||
if (m_joys.count(id))
|
||||
m_keyinput |= m_joys[id];
|
||||
}
|
||||
|
||||
void Keypad::JoyMoved (uint16_t joyid, uint16_t axis, float pos)
|
||||
{
|
||||
uint32_t id = (((int)joyid) << 16) | ((pos < 0) << 15) | (axis & 0x7FFF);
|
||||
// if pos is 0, we disable the positive and negative targets
|
||||
if (pos == 0)
|
||||
{
|
||||
if (m_axis.count(id))
|
||||
m_keyinput |= m_axis[id];
|
||||
if (m_axis.count(id | (1 << 15)))
|
||||
m_keyinput |= m_axis[id | (1 << 15)];
|
||||
}
|
||||
else
|
||||
{
|
||||
// we enable the corresponding button
|
||||
if (m_axis.count(id))
|
||||
m_keyinput &= ~((uint16_t)m_axis[id]);
|
||||
// we disable the opposite button (we may have skipped 0)
|
||||
if (m_axis.count(id ^ 0x8000))
|
||||
m_keyinput |= m_axis[id ^ 0x8000];
|
||||
}
|
||||
}
|
||||
|
||||
void Keypad::VBlank ()
|
||||
{
|
||||
// if keypad IRQ are enabled
|
||||
if (m_keycnt & (0x1 << 14))
|
||||
// if irq condition is and
|
||||
if (m_keycnt & (0x1 << 15))
|
||||
{
|
||||
// if condition is satisfied
|
||||
if ((~m_keyinput & m_keycnt & 0x3FF) == (m_keycnt & 0x3FF))
|
||||
CPU.SendInterrupt(0x1000);
|
||||
}
|
||||
// if irq condition is or
|
||||
else
|
||||
{
|
||||
// if condition is satisfied
|
||||
if (~m_keyinput & m_keycnt & 0x3FF)
|
||||
CPU.SendInterrupt(0x1000);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue