mednafen 0.9.34.1 "cygne" (wonderswan)
This commit is contained in:
parent
2053349e31
commit
c306e61d5b
|
@ -23,6 +23,7 @@ using BizHawk.Emulation.Cores.Sega.Saturn;
|
|||
using BizHawk.Emulation.Cores.Sony.PSP;
|
||||
using BizHawk.Emulation.Cores.Sony.PSX;
|
||||
using BizHawk.Emulation.DiscSystem;
|
||||
using BizHawk.Emulation.Cores.WonderSwan;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
|
@ -413,6 +414,9 @@ namespace BizHawk.Client.Common
|
|||
case "N64":
|
||||
nextEmulator = new N64(nextComm, game, rom.RomData, GetCoreSyncSettings<N64>());
|
||||
break;
|
||||
case "WSWAN":
|
||||
nextEmulator = new WonderSwan(nextComm, rom.RomData);
|
||||
break;
|
||||
case "DEBUG":
|
||||
if (VersionInfo.INTERIM)
|
||||
{
|
||||
|
|
|
@ -324,6 +324,11 @@ namespace BizHawk.Emulation.Common
|
|||
case ".DEBUG":
|
||||
game.System = "DEBUG";
|
||||
break;
|
||||
|
||||
case ".WS":
|
||||
case ".WSC":
|
||||
game.System = "WSWAN";
|
||||
break;
|
||||
}
|
||||
|
||||
game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' ');
|
||||
|
|
|
@ -470,6 +470,8 @@
|
|||
<Compile Include="Consoles\Sony\PSP\PSP.cs" />
|
||||
<Compile Include="Consoles\Sony\PSX\LibMednahawkDll.cs" />
|
||||
<Compile Include="Consoles\Sony\PSX\Octoshock.cs" />
|
||||
<Compile Include="Consoles\WonderSwan\BizSwan.cs" />
|
||||
<Compile Include="Consoles\WonderSwan\WonderSwan.cs" />
|
||||
<Compile Include="CPUs\68000\Diassembler.cs" />
|
||||
<Compile Include="CPUs\68000\Instructions\BitArithemetic.cs" />
|
||||
<Compile Include="CPUs\68000\Instructions\DataMovement.cs" />
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.WonderSwan
|
||||
{
|
||||
public static class BizSwan
|
||||
{
|
||||
const CallingConvention cc = CallingConvention.Cdecl;
|
||||
const string dd = "bizswan.dll";
|
||||
|
||||
[DllImport(dd, CallingConvention = cc)]
|
||||
public static extern IntPtr bizswan_new();
|
||||
|
||||
[DllImport(dd, CallingConvention = cc)]
|
||||
public static extern void bizswan_delete(IntPtr core);
|
||||
|
||||
[DllImport(dd, CallingConvention = cc)]
|
||||
public static extern void bizswan_reset(IntPtr core);
|
||||
|
||||
[DllImport(dd, CallingConvention = cc)]
|
||||
public static extern void bizswan_advance(IntPtr core, Buttons buttons, bool novideo, int[] surface, short[] soundbuff, ref int soundbuffsize);
|
||||
|
||||
[DllImport(dd, CallingConvention = cc)]
|
||||
public static extern bool bizswan_load(IntPtr core, byte[] data, int length, [In] ref Settings settings);
|
||||
|
||||
[Flags]
|
||||
public enum Buttons : ushort
|
||||
{
|
||||
UpX = 0x0001,
|
||||
DownX = 0x0002,
|
||||
LeftX = 0x0004,
|
||||
RightX = 0x0008,
|
||||
UpY = 0x0010,
|
||||
DownY = 0x0020,
|
||||
LeftY = 0x0040,
|
||||
RightY = 0x0080,
|
||||
Start = 0x0100,
|
||||
B = 0x0200,
|
||||
A = 0x0400,
|
||||
}
|
||||
|
||||
public enum Language : byte
|
||||
{
|
||||
Japanese = 0,
|
||||
English = 1
|
||||
}
|
||||
|
||||
public enum Bloodtype : byte
|
||||
{
|
||||
A = 1,
|
||||
B = 2,
|
||||
O = 3,
|
||||
AB = 4
|
||||
}
|
||||
|
||||
public enum Gender : byte
|
||||
{
|
||||
Male = 1,
|
||||
Female = 2
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct Settings
|
||||
{
|
||||
public ushort byear;
|
||||
public byte bmonth;
|
||||
public byte bday;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
|
||||
public byte[] name;
|
||||
public Language language;
|
||||
public Gender sex;
|
||||
public Bloodtype blood;
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public bool rotateinput;
|
||||
|
||||
public void SetName(string newname)
|
||||
{
|
||||
byte[] data = Encoding.ASCII.GetBytes(newname);
|
||||
name = new byte[17];
|
||||
Buffer.BlockCopy(data, 0, name, 0, Math.Min(data.Length, name.Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.WonderSwan
|
||||
{
|
||||
[CoreAttributes("Mednafen/Cygne", "Dox", true, false)]
|
||||
public class WonderSwan : IEmulator, IVideoProvider, ISyncSoundProvider
|
||||
{
|
||||
#region Controller
|
||||
|
||||
public static readonly ControllerDefinition WonderSwanController = new ControllerDefinition
|
||||
{
|
||||
Name = "WonderSwan Controller",
|
||||
BoolButtons = { "Up X, Down X, Left X, Right X, Up Y, Down Y, Left Y, Right Y, Start, B, A, Power" }
|
||||
};
|
||||
public ControllerDefinition ControllerDefinition { get { return WonderSwanController; } }
|
||||
public IController Controller { get; set; }
|
||||
|
||||
BizSwan.Buttons GetButtons()
|
||||
{
|
||||
BizSwan.Buttons ret = 0;
|
||||
if (Controller["Up X"]) ret |= BizSwan.Buttons.UpX;
|
||||
if (Controller["Down X"]) ret |= BizSwan.Buttons.DownX;
|
||||
if (Controller["Left X"]) ret |= BizSwan.Buttons.LeftX;
|
||||
if (Controller["Right X"]) ret |= BizSwan.Buttons.RightX;
|
||||
if (Controller["Up Y"]) ret |= BizSwan.Buttons.UpY;
|
||||
if (Controller["Down Y"]) ret |= BizSwan.Buttons.DownY;
|
||||
if (Controller["Left Y"]) ret |= BizSwan.Buttons.LeftY;
|
||||
if (Controller["Right Y"]) ret |= BizSwan.Buttons.RightY;
|
||||
if (Controller["Start"]) ret |= BizSwan.Buttons.Start;
|
||||
if (Controller["B"]) ret |= BizSwan.Buttons.B;
|
||||
if (Controller["A"]) ret |= BizSwan.Buttons.A;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public WonderSwan(CoreComm comm, byte[] rom)
|
||||
{
|
||||
this.CoreComm = comm;
|
||||
Core = BizSwan.bizswan_new();
|
||||
if (Core == IntPtr.Zero)
|
||||
throw new InvalidOperationException("bizswan_new() returned NULL!");
|
||||
try
|
||||
{
|
||||
var ss = new BizSwan.Settings
|
||||
{
|
||||
sex = BizSwan.Gender.Male,
|
||||
blood = BizSwan.Bloodtype.A,
|
||||
language = BizSwan.Language.Japanese,
|
||||
rotateinput = false, // TODO
|
||||
bday = 5,
|
||||
bmonth = 12,
|
||||
byear = 1968
|
||||
};
|
||||
ss.SetName("LaForge");
|
||||
|
||||
if (!BizSwan.bizswan_load(Core, rom, rom.Length, ref ss))
|
||||
throw new InvalidOperationException("bizswan_load() returned FALSE!");
|
||||
|
||||
CoreComm.VsyncNum = 3072000; // master CPU clock, also pixel clock
|
||||
CoreComm.VsyncDen = (144 + 15) * (224 + 32); // 144 vislines, 15 vblank lines; 224 vispixels, 32 hblank pixels
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Core != IntPtr.Zero)
|
||||
{
|
||||
BizSwan.bizswan_delete(Core);
|
||||
Core = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void FrameAdvance(bool render, bool rendersound = true)
|
||||
{
|
||||
Frame++;
|
||||
IsLagFrame = true;
|
||||
|
||||
if (Controller["Power"])
|
||||
BizSwan.bizswan_reset(Core);
|
||||
|
||||
int soundbuffsize = sbuff.Length;
|
||||
BizSwan.bizswan_advance(Core, GetButtons(), !render, vbuff, sbuff, ref soundbuffsize);
|
||||
if (soundbuffsize == sbuff.Length)
|
||||
throw new Exception();
|
||||
sbuffcontains = soundbuffsize;
|
||||
|
||||
IsLagFrame = false; // TODO
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
IntPtr Core;
|
||||
|
||||
public int Frame { get; private set; }
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; private set; }
|
||||
|
||||
|
||||
public string SystemId { get { return "WSWAN"; } }
|
||||
public bool DeterministicEmulation { get { return true; } }
|
||||
public string BoardName { get { return null; } }
|
||||
|
||||
#region SaveRam
|
||||
|
||||
public byte[] ReadSaveRam()
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ClearSaveRam()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#region Savestates
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public bool BinarySaveStatesPreferred
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public CoreComm CoreComm { get; private set; }
|
||||
|
||||
#region Debugging
|
||||
|
||||
public MemoryDomainList MemoryDomains
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public Dictionary<string, int> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Settings
|
||||
|
||||
public object GetSettings()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public object GetSyncSettings()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool PutSettings(object o)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool PutSyncSettings(object o)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IVideoProvider
|
||||
|
||||
public IVideoProvider VideoProvider { get { return this; } }
|
||||
|
||||
private int[] vbuff = new int[224 * 144];
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return vbuff;
|
||||
}
|
||||
|
||||
public int VirtualWidth { get { return 224; } }
|
||||
public int VirtualHeight { get { return 144; } }
|
||||
public int BufferWidth { get { return 224; } }
|
||||
public int BufferHeight { get { return 144; } }
|
||||
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
private short[] sbuff = new short[1536];
|
||||
private int sbuffcontains = 0;
|
||||
|
||||
public ISoundProvider SoundProvider { get { throw new InvalidOperationException(); } }
|
||||
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
|
||||
public bool StartAsyncSound() { return false; }
|
||||
public void EndAsyncSound() { }
|
||||
|
||||
public void GetSamples(out short[] samples, out int nsamp)
|
||||
{
|
||||
samples = sbuff;
|
||||
nsamp = sbuffcontains;
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
sbuffcontains = 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bizswan", "bizswan.vcxproj", "{F92A3734-EAE1-44D9-B474-FF80AE039790}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F92A3734-EAE1-44D9-B474-FF80AE039790}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F92A3734-EAE1-44D9-B474-FF80AE039790}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F92A3734-EAE1-44D9-B474-FF80AE039790}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F92A3734-EAE1-44D9-B474-FF80AE039790}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,110 @@
|
|||
<?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>{F92A3734-EAE1-44D9-B474-FF80AE039790}</ProjectGuid>
|
||||
<RootNamespace>bizswan</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</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 />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..;$(ProjectDir)\..\msvc</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);LSB_FIRST</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<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>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..;$(ProjectDir)\..\msvc</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);LSB_FIRST</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<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="..\blip\Blip_Buffer.cpp" />
|
||||
<ClCompile Include="..\eeprom.cpp" />
|
||||
<ClCompile Include="..\gfx.cpp" />
|
||||
<ClCompile Include="..\interrupt.cpp" />
|
||||
<ClCompile Include="..\main.cpp" />
|
||||
<ClCompile Include="..\memory.cpp" />
|
||||
<ClCompile Include="..\rtc.cpp" />
|
||||
<ClCompile Include="..\sound.cpp" />
|
||||
<ClCompile Include="..\system.cpp" />
|
||||
<ClCompile Include="..\tcache.cpp" />
|
||||
<ClCompile Include="..\v30mz.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\blip\Blip_Buffer.h" />
|
||||
<ClInclude Include="..\eeprom.h" />
|
||||
<ClInclude Include="..\gfx.h" />
|
||||
<ClInclude Include="..\interrupt.h" />
|
||||
<ClInclude Include="..\mednafen\state.h" />
|
||||
<ClInclude Include="..\mednafen\types.h" />
|
||||
<ClInclude Include="..\memory.h" />
|
||||
<ClInclude Include="..\msvc\inttypes.h" />
|
||||
<ClInclude Include="..\msvc\stdint.h" />
|
||||
<ClInclude Include="..\rtc.h" />
|
||||
<ClInclude Include="..\sound.h" />
|
||||
<ClInclude Include="..\system.h" />
|
||||
<ClInclude Include="..\v30mz-private.h" />
|
||||
<ClInclude Include="..\v30mz.h" />
|
||||
<ClInclude Include="..\wswan.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\start.inc" />
|
||||
<None Include="..\v30mz-ea.inc" />
|
||||
<None Include="..\v30mz-modrm.inc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,122 @@
|
|||
<?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="Header Files\msvc">
|
||||
<UniqueIdentifier>{d0b85f88-6eca-4fa8-bf29-4d75ff7471fe}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\mednafen">
|
||||
<UniqueIdentifier>{fc621339-f39c-496f-8085-9f3bf7e64a80}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\blip">
|
||||
<UniqueIdentifier>{f7aba5a2-698c-4085-a191-b0ffd3522298}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\blip">
|
||||
<UniqueIdentifier>{4fb57465-2aae-4d75-87de-a2669a0570b4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\eeprom.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\gfx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\interrupt.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\memory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\rtc.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\sound.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\tcache.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\v30mz.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\blip\Blip_Buffer.cpp">
|
||||
<Filter>Source Files\blip</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\system.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\eeprom.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\gfx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\interrupt.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\memory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\rtc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\sound.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\v30mz.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\v30mz-private.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\wswan.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\msvc\inttypes.h">
|
||||
<Filter>Header Files\msvc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\msvc\stdint.h">
|
||||
<Filter>Header Files\msvc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\mednafen\types.h">
|
||||
<Filter>Header Files\mednafen</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\mednafen\state.h">
|
||||
<Filter>Header Files\mednafen</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\blip\Blip_Buffer.h">
|
||||
<Filter>Header Files\blip</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\system.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\start.inc">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="..\v30mz-ea.inc">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="..\v30mz-modrm.inc">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,457 @@
|
|||
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
|
||||
|
||||
#include "Blip_Buffer.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#ifdef BLARGG_ENABLE_OPTIMIZER
|
||||
#include BLARGG_ENABLE_OPTIMIZER
|
||||
#endif
|
||||
|
||||
int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
|
||||
|
||||
Blip_Buffer::Blip_Buffer()
|
||||
{
|
||||
factor_ = (blip_u64)ULLONG_MAX;
|
||||
offset_ = 0;
|
||||
buffer_ = 0;
|
||||
buffer_size_ = 0;
|
||||
sample_rate_ = 0;
|
||||
reader_accum_ = 0;
|
||||
bass_shift_ = 0;
|
||||
clock_rate_ = 0;
|
||||
bass_freq_ = 16;
|
||||
length_ = 0;
|
||||
|
||||
// assumptions code makes about implementation-defined features
|
||||
#ifndef NDEBUG
|
||||
// right shift of negative value preserves sign
|
||||
buf_t_ i = -0x7FFFFFFE;
|
||||
assert( (i >> 1) == -0x3FFFFFFF );
|
||||
|
||||
// casting to short truncates to 16 bits and sign-extends
|
||||
i = 0x18000;
|
||||
assert( (short) i == -0x8000 );
|
||||
#endif
|
||||
}
|
||||
|
||||
Blip_Buffer::~Blip_Buffer()
|
||||
{
|
||||
if ( buffer_size_ != silent_buf_size )
|
||||
free( buffer_ );
|
||||
}
|
||||
|
||||
Silent_Blip_Buffer::Silent_Blip_Buffer()
|
||||
{
|
||||
factor_ = 0;
|
||||
buffer_ = buf;
|
||||
buffer_size_ = silent_buf_size;
|
||||
memset( buf, 0, sizeof buf ); // in case machine takes exception for signed overflow
|
||||
}
|
||||
|
||||
void Blip_Buffer::clear( int entire_buffer )
|
||||
{
|
||||
offset_ = 0;
|
||||
reader_accum_ = 0;
|
||||
modified_ = 0;
|
||||
if ( buffer_ )
|
||||
{
|
||||
long count = (entire_buffer ? buffer_size_ : samples_avail());
|
||||
memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) );
|
||||
}
|
||||
}
|
||||
|
||||
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
|
||||
{
|
||||
if ( buffer_size_ == silent_buf_size )
|
||||
{
|
||||
assert( 0 );
|
||||
return "Internal (tried to resize Silent_Blip_Buffer)";
|
||||
}
|
||||
|
||||
// start with maximum length that resampled time can represent
|
||||
blip_s64 new_size = (ULLONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64;
|
||||
|
||||
// simple safety check, since code elsewhere may not be safe for sizes approaching (2 ^ 31).
|
||||
if(new_size > ((1LL << 30) - 1))
|
||||
new_size = (1LL << 30) - 1;
|
||||
|
||||
if ( msec != blip_max_length )
|
||||
{
|
||||
blip_s64 s = ((blip_s64)new_rate * (msec + 1) + 999) / 1000;
|
||||
if ( s < new_size )
|
||||
new_size = s;
|
||||
else
|
||||
assert( 0 ); // fails if requested buffer length exceeds limit
|
||||
}
|
||||
|
||||
if ( buffer_size_ != new_size )
|
||||
{
|
||||
void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ );
|
||||
if ( !p )
|
||||
return "Out of memory";
|
||||
|
||||
//if(new_size > buffer_size_)
|
||||
// memset(buffer_ + buffer_size_, 0, (new_size + blip_buffer_extra_) * sizeof *buffer_
|
||||
|
||||
buffer_ = (buf_t_*) p;
|
||||
}
|
||||
|
||||
buffer_size_ = new_size;
|
||||
assert( buffer_size_ != silent_buf_size );
|
||||
|
||||
// update things based on the sample rate
|
||||
sample_rate_ = new_rate;
|
||||
length_ = new_size * 1000 / new_rate - 1;
|
||||
if ( msec )
|
||||
assert( length_ == msec ); // ensure length is same as that passed in
|
||||
if ( clock_rate_ )
|
||||
clock_rate( clock_rate_ );
|
||||
bass_freq( bass_freq_ );
|
||||
|
||||
clear();
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
|
||||
{
|
||||
double ratio = (double) sample_rate_ / rate;
|
||||
blip_s64 factor = (blip_s64) floor( ratio * (1LL << BLIP_BUFFER_ACCURACY) + 0.5 );
|
||||
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
|
||||
return (blip_resampled_time_t) factor;
|
||||
}
|
||||
|
||||
void Blip_Buffer::bass_freq( int freq )
|
||||
{
|
||||
bass_freq_ = freq;
|
||||
int shift = 31;
|
||||
if ( freq > 0 )
|
||||
{
|
||||
shift = 13;
|
||||
long f = (freq << 16) / sample_rate_;
|
||||
while ( (f >>= 1) && --shift ) { }
|
||||
}
|
||||
bass_shift_ = shift;
|
||||
//printf("%d\n", bass_shift_);
|
||||
}
|
||||
|
||||
void Blip_Buffer::end_frame( blip_time_t t )
|
||||
{
|
||||
offset_ += t * factor_;
|
||||
assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
|
||||
}
|
||||
|
||||
void Blip_Buffer::remove_silence( long count )
|
||||
{
|
||||
assert( count <= samples_avail() ); // tried to remove more samples than available
|
||||
offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
|
||||
}
|
||||
|
||||
long Blip_Buffer::count_samples( blip_time_t t ) const
|
||||
{
|
||||
unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
|
||||
unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
|
||||
return (long) (last_sample - first_sample);
|
||||
}
|
||||
|
||||
blip_time_t Blip_Buffer::count_clocks( long count ) const
|
||||
{
|
||||
if ( !factor_ )
|
||||
{
|
||||
assert( 0 ); // sample rate and clock rates must be set first
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( count > buffer_size_ )
|
||||
count = buffer_size_;
|
||||
blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
|
||||
return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
|
||||
}
|
||||
|
||||
void Blip_Buffer::remove_samples( long count )
|
||||
{
|
||||
if ( count )
|
||||
{
|
||||
remove_silence( count );
|
||||
|
||||
// copy remaining samples to beginning and clear old samples
|
||||
long remain = samples_avail() + blip_buffer_extra_;
|
||||
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
|
||||
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
|
||||
}
|
||||
}
|
||||
|
||||
// Blip_Synth_
|
||||
|
||||
Blip_Synth_Fast_::Blip_Synth_Fast_()
|
||||
{
|
||||
buf = 0;
|
||||
last_amp = 0;
|
||||
delta_factor = 0;
|
||||
}
|
||||
|
||||
void Blip_Synth_Fast_::volume_unit( double new_unit )
|
||||
{
|
||||
delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5);
|
||||
}
|
||||
|
||||
#if !BLIP_BUFFER_FAST
|
||||
|
||||
Blip_Synth_::Blip_Synth_( short* p, int w ) :
|
||||
impulses( p ),
|
||||
width( w )
|
||||
{
|
||||
volume_unit_ = 0.0;
|
||||
kernel_unit = 0;
|
||||
buf = 0;
|
||||
last_amp = 0;
|
||||
delta_factor = 0;
|
||||
}
|
||||
|
||||
#undef PI
|
||||
#define PI 3.1415926535897932384626433832795029
|
||||
|
||||
static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
|
||||
{
|
||||
if ( cutoff >= 0.999 )
|
||||
cutoff = 0.999;
|
||||
|
||||
if ( treble < -300.0 )
|
||||
treble = -300.0;
|
||||
if ( treble > 5.0 )
|
||||
treble = 5.0;
|
||||
|
||||
double const maxh = 4096.0;
|
||||
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
|
||||
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
|
||||
double const to_angle = PI / 2 / maxh / oversample;
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
double angle = ((i - count) * 2 + 1) * to_angle;
|
||||
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
|
||||
double cos_nc_angle = cos( maxh * cutoff * angle );
|
||||
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
|
||||
double cos_angle = cos( angle );
|
||||
|
||||
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
|
||||
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
|
||||
double b = 2.0 - cos_angle - cos_angle;
|
||||
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
|
||||
|
||||
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
|
||||
}
|
||||
}
|
||||
|
||||
void blip_eq_t::generate( float* out, int count ) const
|
||||
{
|
||||
// lower cutoff freq for narrow kernels with their wider transition band
|
||||
// (8 points->1.49, 16 points->1.15)
|
||||
double oversample = blip_res * 2.25 / count + 0.85;
|
||||
double half_rate = sample_rate * 0.5;
|
||||
if ( cutoff_freq )
|
||||
oversample = half_rate / cutoff_freq;
|
||||
double cutoff = rolloff_freq * oversample / half_rate;
|
||||
|
||||
gen_sinc( out, count, blip_res * oversample, treble, cutoff );
|
||||
|
||||
// apply (half of) hamming window
|
||||
double to_fraction = PI / (count - 1);
|
||||
for ( int i = count; i--; )
|
||||
out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction );
|
||||
}
|
||||
|
||||
void Blip_Synth_::adjust_impulse()
|
||||
{
|
||||
// sum pairs for each phase and add error correction to end of first half
|
||||
int const size = impulses_size();
|
||||
for ( int p = blip_res; p-- >= blip_res / 2; )
|
||||
{
|
||||
int p2 = blip_res - 2 - p;
|
||||
long error = kernel_unit;
|
||||
for ( int i = 1; i < size; i += blip_res )
|
||||
{
|
||||
error -= impulses [i + p ];
|
||||
error -= impulses [i + p2];
|
||||
}
|
||||
if ( p == p2 )
|
||||
error /= 2; // phase = 0.5 impulse uses same half for both sides
|
||||
impulses [size - blip_res + p] += (short) error;
|
||||
//printf( "error: %ld\n", error );
|
||||
}
|
||||
|
||||
//for ( int i = blip_res; i--; printf( "\n" ) )
|
||||
// for ( int j = 0; j < width / 2; j++ )
|
||||
// printf( "%5ld,", impulses [j * blip_res + i + 1] );
|
||||
}
|
||||
|
||||
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
|
||||
{
|
||||
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
|
||||
|
||||
int const half_size = blip_res / 2 * (width - 1);
|
||||
eq.generate( &fimpulse [blip_res], half_size );
|
||||
|
||||
int i;
|
||||
|
||||
// need mirror slightly past center for calculation
|
||||
for ( i = blip_res; i--; )
|
||||
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
|
||||
|
||||
// starts at 0
|
||||
for ( i = 0; i < blip_res; i++ )
|
||||
fimpulse [i] = 0.0f;
|
||||
|
||||
// find rescale factor
|
||||
double total = 0.0;
|
||||
for ( i = 0; i < half_size; i++ )
|
||||
total += fimpulse [blip_res + i];
|
||||
|
||||
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
|
||||
//double const base_unit = 37888.0; // allows treble to +5 dB
|
||||
double const base_unit = 32768.0; // necessary for blip_unscaled to work
|
||||
double rescale = base_unit / 2 / total;
|
||||
kernel_unit = (long) base_unit;
|
||||
|
||||
// integrate, first difference, rescale, convert to int
|
||||
double sum = 0.0;
|
||||
double next = 0.0;
|
||||
int const impulses_size_local = this->impulses_size();
|
||||
for ( i = 0; i < impulses_size_local; i++ )
|
||||
{
|
||||
impulses [i] = (short) floor( (next - sum) * rescale + 0.5 );
|
||||
sum += fimpulse [i];
|
||||
next += fimpulse [i + blip_res];
|
||||
}
|
||||
adjust_impulse();
|
||||
|
||||
// volume might require rescaling
|
||||
double vol = volume_unit_;
|
||||
if ( vol )
|
||||
{
|
||||
volume_unit_ = 0.0;
|
||||
volume_unit( vol );
|
||||
}
|
||||
}
|
||||
|
||||
void Blip_Synth_::volume_unit( double new_unit )
|
||||
{
|
||||
if ( new_unit != volume_unit_ )
|
||||
{
|
||||
// use default eq if it hasn't been set yet
|
||||
if ( !kernel_unit )
|
||||
treble_eq( -8.0 );
|
||||
|
||||
volume_unit_ = new_unit;
|
||||
double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
|
||||
|
||||
if ( factor > 0.0 )
|
||||
{
|
||||
int shift = 0;
|
||||
|
||||
// if unit is really small, might need to attenuate kernel
|
||||
while ( factor < 2.0 )
|
||||
{
|
||||
shift++;
|
||||
factor *= 2.0;
|
||||
}
|
||||
|
||||
if ( shift )
|
||||
{
|
||||
kernel_unit >>= shift;
|
||||
assert( kernel_unit > 0 ); // fails if volume unit is too low
|
||||
|
||||
// keep values positive to avoid round-towards-zero of sign-preserving
|
||||
// right shift for negative values
|
||||
long offset = 0x8000 + (1 << (shift - 1));
|
||||
long offset2 = 0x8000 >> shift;
|
||||
for ( int i = impulses_size(); i--; )
|
||||
impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2);
|
||||
adjust_impulse();
|
||||
}
|
||||
}
|
||||
delta_factor = (int) floor( factor + 0.5 );
|
||||
//printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
long Blip_Buffer::read_samples( blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo )
|
||||
{
|
||||
long count = samples_avail();
|
||||
if ( count > max_samples )
|
||||
count = max_samples;
|
||||
|
||||
if ( count )
|
||||
{
|
||||
int const bass = BLIP_READER_BASS( *this );
|
||||
BLIP_READER_BEGIN( reader, *this );
|
||||
|
||||
if ( !stereo )
|
||||
{
|
||||
for ( blip_long n = count; n; --n )
|
||||
{
|
||||
blip_long s = BLIP_READER_READ( reader );
|
||||
if ( (blip_sample_t) s != s )
|
||||
s = 0x7FFF - (s >> 24);
|
||||
*out++ = (blip_sample_t) s;
|
||||
BLIP_READER_NEXT( reader, bass );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( blip_long n = count; n; --n )
|
||||
{
|
||||
blip_long s = BLIP_READER_READ( reader );
|
||||
if ( (blip_sample_t) s != s )
|
||||
s = 0x7FFF - (s >> 24);
|
||||
*out = (blip_sample_t) s;
|
||||
out += 2;
|
||||
BLIP_READER_NEXT( reader, bass );
|
||||
}
|
||||
}
|
||||
BLIP_READER_END( reader, *this );
|
||||
|
||||
remove_samples( count );
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
|
||||
{
|
||||
if ( buffer_size_ == silent_buf_size )
|
||||
{
|
||||
assert( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
|
||||
|
||||
int const sample_shift = blip_sample_bits - 16;
|
||||
int prev = 0;
|
||||
while ( count-- )
|
||||
{
|
||||
blip_long s = (blip_long) *in++ << sample_shift;
|
||||
*out += s - prev;
|
||||
prev = s;
|
||||
++out;
|
||||
}
|
||||
*out -= prev;
|
||||
}
|
||||
|
|
@ -0,0 +1,498 @@
|
|||
// Band-limited sound synthesis buffer
|
||||
// Various changes and hacks for use in Mednafen.
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define blip_inline inline __attribute__((always_inline))
|
||||
#else
|
||||
#define blip_inline inline
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Blip_Buffer 0.4.1
|
||||
#ifndef BLIP_BUFFER_H
|
||||
#define BLIP_BUFFER_H
|
||||
|
||||
// Internal
|
||||
typedef int32_t blip_long;
|
||||
typedef uint32_t blip_ulong;
|
||||
typedef int64_t blip_s64;
|
||||
typedef uint64_t blip_u64;
|
||||
|
||||
// Time unit at source clock rate
|
||||
typedef blip_long blip_time_t;
|
||||
|
||||
// Output samples are 16-bit signed, with a range of -32768 to 32767
|
||||
typedef short blip_sample_t;
|
||||
enum { blip_sample_max = 32767 };
|
||||
|
||||
class Blip_Buffer {
|
||||
public:
|
||||
typedef const char* blargg_err_t;
|
||||
|
||||
// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
|
||||
// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
|
||||
// isn't enough memory, returns error without affecting current buffer setup.
|
||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
|
||||
|
||||
// Set number of source time units per second
|
||||
void clock_rate( long );
|
||||
|
||||
// End current time frame of specified duration and make its samples available
|
||||
// (along with any still-unread samples) for reading with read_samples(). Begins
|
||||
// a new time frame at the end of the current frame.
|
||||
void end_frame( blip_time_t time );
|
||||
|
||||
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
|
||||
// the buffer. Returns number of samples actually read and removed. If stereo is
|
||||
// true, increments 'dest' one extra time after writing each sample, to allow
|
||||
// easy interleving of two channels into a stereo output buffer.
|
||||
long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
|
||||
|
||||
// Additional optional features
|
||||
|
||||
// Current output sample rate
|
||||
long sample_rate() const;
|
||||
|
||||
// Length of buffer, in milliseconds
|
||||
int length() const;
|
||||
|
||||
// Number of source time units per second
|
||||
long clock_rate() const;
|
||||
|
||||
// Set frequency high-pass filter frequency, where higher values reduce bass more
|
||||
void bass_freq( int frequency );
|
||||
|
||||
// Number of samples delay from synthesis to samples read out
|
||||
int output_latency() const;
|
||||
|
||||
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
|
||||
// false, just clears out any samples waiting rather than the entire buffer.
|
||||
void clear( int entire_buffer = 1 );
|
||||
|
||||
// Number of samples available for reading with read_samples()
|
||||
long samples_avail() const;
|
||||
|
||||
// Remove 'count' samples from those waiting to be read
|
||||
void remove_samples( long count );
|
||||
|
||||
// Experimental features
|
||||
|
||||
// Count number of clocks needed until 'count' samples will be available.
|
||||
// If buffer can't even hold 'count' samples, returns number of clocks until
|
||||
// buffer becomes full.
|
||||
blip_time_t count_clocks( long count ) const;
|
||||
|
||||
// Number of raw samples that can be mixed within frame of specified duration.
|
||||
long count_samples( blip_time_t duration ) const;
|
||||
|
||||
// Mix 'count' samples from 'buf' into buffer.
|
||||
void mix_samples( blip_sample_t const* buf, long count );
|
||||
|
||||
// not documented yet
|
||||
void set_modified() { modified_ = 1; }
|
||||
int clear_modified() { int b = modified_; modified_ = 0; return b; }
|
||||
typedef blip_u64 blip_resampled_time_t;
|
||||
void remove_silence( long count );
|
||||
blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
|
||||
blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
|
||||
blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
|
||||
public:
|
||||
Blip_Buffer();
|
||||
~Blip_Buffer();
|
||||
|
||||
// Deprecated
|
||||
typedef blip_resampled_time_t resampled_time_t;
|
||||
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
|
||||
blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
|
||||
private:
|
||||
// noncopyable
|
||||
Blip_Buffer( const Blip_Buffer& );
|
||||
Blip_Buffer& operator = ( const Blip_Buffer& );
|
||||
public:
|
||||
typedef blip_time_t buf_t_;
|
||||
blip_u64 factor_;
|
||||
blip_resampled_time_t offset_;
|
||||
buf_t_* buffer_;
|
||||
blip_long buffer_size_;
|
||||
blip_long reader_accum_;
|
||||
int bass_shift_;
|
||||
private:
|
||||
long sample_rate_;
|
||||
long clock_rate_;
|
||||
int bass_freq_;
|
||||
int length_;
|
||||
int modified_;
|
||||
friend class Blip_Reader;
|
||||
};
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define BLIP_BUFFER_ACCURACY 32
|
||||
#define BLIP_PHASE_BITS 8
|
||||
|
||||
// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
|
||||
// but reduce maximum buffer size.
|
||||
//#ifndef BLIP_BUFFER_ACCURACY
|
||||
// #define BLIP_BUFFER_ACCURACY 16
|
||||
//#endif
|
||||
|
||||
// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
|
||||
// noticeable broadband noise when synthesizing high frequency square waves.
|
||||
// Affects size of Blip_Synth objects since they store the waveform directly.
|
||||
//#ifndef BLIP_PHASE_BITS
|
||||
// #if BLIP_BUFFER_FAST
|
||||
// #define BLIP_PHASE_BITS 8
|
||||
// #else
|
||||
// #define BLIP_PHASE_BITS 6
|
||||
// #endif
|
||||
//#endif
|
||||
|
||||
// Internal
|
||||
typedef blip_u64 blip_resampled_time_t;
|
||||
int const blip_widest_impulse_ = 16;
|
||||
int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
|
||||
int const blip_res = 1 << BLIP_PHASE_BITS;
|
||||
class blip_eq_t;
|
||||
|
||||
class Blip_Synth_Fast_ {
|
||||
public:
|
||||
Blip_Buffer* buf;
|
||||
int last_amp;
|
||||
int delta_factor;
|
||||
|
||||
void volume_unit( double );
|
||||
Blip_Synth_Fast_();
|
||||
void treble_eq( blip_eq_t const& ) { }
|
||||
};
|
||||
|
||||
class Blip_Synth_ {
|
||||
public:
|
||||
Blip_Buffer* buf;
|
||||
int last_amp;
|
||||
int delta_factor;
|
||||
|
||||
void volume_unit( double );
|
||||
Blip_Synth_( short* impulses, int width );
|
||||
void treble_eq( blip_eq_t const& );
|
||||
private:
|
||||
double volume_unit_;
|
||||
short* const impulses;
|
||||
int const width;
|
||||
blip_long kernel_unit;
|
||||
int impulses_size() const { return blip_res / 2 * width + 1; }
|
||||
void adjust_impulse();
|
||||
};
|
||||
|
||||
// Quality level. Start with blip_good_quality.
|
||||
const int blip_med_quality = 8;
|
||||
const int blip_good_quality = 12;
|
||||
const int blip_high_quality = 16;
|
||||
|
||||
// Range specifies the greatest expected change in amplitude. Calculate it
|
||||
// by finding the difference between the maximum and minimum expected
|
||||
// amplitudes (max - min).
|
||||
template<int quality,int range>
|
||||
class Blip_Synth {
|
||||
public:
|
||||
// Set overall volume of waveform
|
||||
void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
|
||||
|
||||
// Configure low-pass filter (see blip_buffer.txt)
|
||||
void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
|
||||
|
||||
// Get/set Blip_Buffer used for output
|
||||
Blip_Buffer* output() const { return impl.buf; }
|
||||
void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
|
||||
|
||||
// Update amplitude of waveform at given time. Using this requires a separate
|
||||
// Blip_Synth for each waveform.
|
||||
void update( blip_time_t time, int amplitude );
|
||||
|
||||
// Low-level interface
|
||||
|
||||
// Add an amplitude transition of specified delta, optionally into specified buffer
|
||||
// rather than the one set with output(). Delta can be positive or negative.
|
||||
// The actual change in amplitude is delta * (volume / range)
|
||||
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
|
||||
void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
|
||||
|
||||
// Works directly in terms of fractional output samples. Contact author for more info.
|
||||
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
|
||||
|
||||
// Same as offset(), except code is inlined for higher performance
|
||||
void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
|
||||
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
|
||||
}
|
||||
void offset_inline( blip_time_t t, int delta ) const {
|
||||
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
|
||||
}
|
||||
|
||||
private:
|
||||
#if BLIP_BUFFER_FAST
|
||||
Blip_Synth_Fast_ impl;
|
||||
#else
|
||||
Blip_Synth_ impl;
|
||||
typedef short imp_t;
|
||||
imp_t impulses [blip_res * (quality / 2) + 1];
|
||||
public:
|
||||
Blip_Synth() : impl( impulses, quality ) { }
|
||||
#endif
|
||||
};
|
||||
|
||||
// Low-pass equalization parameters
|
||||
class blip_eq_t {
|
||||
public:
|
||||
// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
|
||||
// treble, small positive values (0 to 5.0) increase treble.
|
||||
blip_eq_t( double treble_db = 0 );
|
||||
|
||||
// See blip_buffer.txt
|
||||
blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
|
||||
|
||||
private:
|
||||
double treble;
|
||||
long rolloff_freq;
|
||||
long sample_rate;
|
||||
long cutoff_freq;
|
||||
void generate( float* out, int count ) const;
|
||||
friend class Blip_Synth_;
|
||||
};
|
||||
|
||||
int const blip_sample_bits = 30;
|
||||
|
||||
// Dummy Blip_Buffer to direct sound output to, for easy muting without
|
||||
// having to stop sound code.
|
||||
class Silent_Blip_Buffer : public Blip_Buffer {
|
||||
buf_t_ buf [blip_buffer_extra_ + 1];
|
||||
public:
|
||||
// The following cannot be used (an assertion will fail if attempted):
|
||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
|
||||
blip_time_t count_clocks( long count ) const;
|
||||
void mix_samples( blip_sample_t const* buf, long count );
|
||||
|
||||
Silent_Blip_Buffer();
|
||||
};
|
||||
|
||||
#if defined (__GNUC__) || _MSC_VER >= 1100
|
||||
#define BLIP_RESTRICT __restrict
|
||||
#else
|
||||
#define BLIP_RESTRICT
|
||||
#endif
|
||||
|
||||
// Optimized reading from Blip_Buffer, for use in custom sample output
|
||||
|
||||
// Begin reading from buffer. Name should be unique to the current block.
|
||||
#define BLIP_READER_BEGIN( name, blip_buffer ) \
|
||||
const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
|
||||
blip_long name##_reader_accum = (blip_buffer).reader_accum_
|
||||
|
||||
// Get value to pass to BLIP_READER_NEXT()
|
||||
#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
|
||||
|
||||
// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
|
||||
// code at the cost of having no bass control
|
||||
int const blip_reader_default_bass = 9;
|
||||
|
||||
// Current sample
|
||||
#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
|
||||
|
||||
// Current raw sample in full internal resolution
|
||||
#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
|
||||
|
||||
// Advance to next sample
|
||||
#define BLIP_READER_NEXT( name, bass ) \
|
||||
(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
|
||||
|
||||
// End reading samples from buffer. The number of samples read must now be removed
|
||||
// using Blip_Buffer::remove_samples().
|
||||
#define BLIP_READER_END( name, blip_buffer ) \
|
||||
(void) ((blip_buffer).reader_accum_ = name##_reader_accum)
|
||||
|
||||
|
||||
// Compatibility with older version
|
||||
const long blip_unscaled = 65535;
|
||||
const int blip_low_quality = blip_med_quality;
|
||||
const int blip_best_quality = blip_high_quality;
|
||||
|
||||
// Deprecated; use BLIP_READER macros as follows:
|
||||
// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
|
||||
// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
|
||||
// r.read() -> BLIP_READER_READ( r )
|
||||
// r.read_raw() -> BLIP_READER_READ_RAW( r )
|
||||
// r.next( bass ) -> BLIP_READER_NEXT( r, bass )
|
||||
// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )
|
||||
// r.end( buf ) -> BLIP_READER_END( r, buf )
|
||||
class Blip_Reader {
|
||||
public:
|
||||
int begin( Blip_Buffer& );
|
||||
blip_long read() const { return accum >> (blip_sample_bits - 16); }
|
||||
blip_long read_raw() const { return accum; }
|
||||
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
|
||||
void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }
|
||||
|
||||
private:
|
||||
const Blip_Buffer::buf_t_* buf;
|
||||
blip_long accum;
|
||||
};
|
||||
|
||||
// End of public interface
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
template<int quality,int range>
|
||||
blip_inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
|
||||
int delta, Blip_Buffer* blip_buf ) const
|
||||
{
|
||||
// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
|
||||
// need for a longer buffer as set by set_sample_rate().
|
||||
assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
|
||||
delta *= impl.delta_factor;
|
||||
blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
|
||||
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
|
||||
|
||||
#if BLIP_BUFFER_FAST
|
||||
blip_long left = buf [0] + delta;
|
||||
|
||||
// Kind of crappy, but doing shift after multiply results in overflow.
|
||||
// Alternate way of delaying multiply by delta_factor results in worse
|
||||
// sub-sample resolution.
|
||||
blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
|
||||
left -= right;
|
||||
right += buf [1];
|
||||
|
||||
buf [0] = left;
|
||||
buf [1] = right;
|
||||
#else
|
||||
|
||||
int const fwd = (blip_widest_impulse_ - quality) / 2;
|
||||
int const rev = fwd + quality - 2;
|
||||
int const mid = quality / 2 - 1;
|
||||
|
||||
imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
|
||||
|
||||
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
|
||||
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
|
||||
|
||||
// straight forward implementation resulted in better code on GCC for x86
|
||||
|
||||
#define ADD_IMP( out, in ) \
|
||||
buf [out] += (blip_long) imp [blip_res * (in)] * delta
|
||||
|
||||
#define BLIP_FWD( i ) {\
|
||||
ADD_IMP( fwd + i, i );\
|
||||
ADD_IMP( fwd + 1 + i, i + 1 );\
|
||||
}
|
||||
#define BLIP_REV( r ) {\
|
||||
ADD_IMP( rev - r, r + 1 );\
|
||||
ADD_IMP( rev + 1 - r, r );\
|
||||
}
|
||||
|
||||
BLIP_FWD( 0 )
|
||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
||||
{
|
||||
ADD_IMP( fwd + mid - 1, mid - 1 );
|
||||
ADD_IMP( fwd + mid , mid );
|
||||
imp = impulses + phase;
|
||||
}
|
||||
if ( quality > 12 ) BLIP_REV( 6 )
|
||||
if ( quality > 8 ) BLIP_REV( 4 )
|
||||
BLIP_REV( 2 )
|
||||
|
||||
ADD_IMP( rev , 1 );
|
||||
ADD_IMP( rev + 1, 0 );
|
||||
|
||||
#else
|
||||
|
||||
// for RISC processors, help compiler by reading ahead of writes
|
||||
|
||||
#define BLIP_FWD( i ) {\
|
||||
blip_long t0 = i0 * delta + buf [fwd + i];\
|
||||
blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
|
||||
i0 = imp [blip_res * (i + 2)];\
|
||||
buf [fwd + i] = t0;\
|
||||
buf [fwd + 1 + i] = t1;\
|
||||
}
|
||||
#define BLIP_REV( r ) {\
|
||||
blip_long t0 = i0 * delta + buf [rev - r];\
|
||||
blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
|
||||
i0 = imp [blip_res * (r - 1)];\
|
||||
buf [rev - r] = t0;\
|
||||
buf [rev + 1 - r] = t1;\
|
||||
}
|
||||
|
||||
blip_long i0 = *imp;
|
||||
BLIP_FWD( 0 )
|
||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
||||
{
|
||||
blip_long t0 = i0 * delta + buf [fwd + mid - 1];
|
||||
blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];
|
||||
imp = impulses + phase;
|
||||
i0 = imp [blip_res * mid];
|
||||
buf [fwd + mid - 1] = t0;
|
||||
buf [fwd + mid ] = t1;
|
||||
}
|
||||
if ( quality > 12 ) BLIP_REV( 6 )
|
||||
if ( quality > 8 ) BLIP_REV( 4 )
|
||||
BLIP_REV( 2 )
|
||||
|
||||
blip_long t0 = i0 * delta + buf [rev ];
|
||||
blip_long t1 = *imp * delta + buf [rev + 1];
|
||||
buf [rev ] = t0;
|
||||
buf [rev + 1] = t1;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef BLIP_FWD
|
||||
#undef BLIP_REV
|
||||
|
||||
template<int quality,int range>
|
||||
#if BLIP_BUFFER_FAST
|
||||
blip_inline
|
||||
#endif
|
||||
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
|
||||
{
|
||||
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
|
||||
}
|
||||
|
||||
template<int quality,int range>
|
||||
#if BLIP_BUFFER_FAST
|
||||
blip_inline
|
||||
#endif
|
||||
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
|
||||
{
|
||||
int delta = amp - impl.last_amp;
|
||||
impl.last_amp = amp;
|
||||
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
|
||||
}
|
||||
|
||||
blip_inline blip_eq_t::blip_eq_t( double t ) :
|
||||
treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
|
||||
blip_inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
|
||||
treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
|
||||
|
||||
blip_inline int Blip_Buffer::length() const { return length_; }
|
||||
blip_inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
|
||||
blip_inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
|
||||
blip_inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
|
||||
blip_inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
|
||||
blip_inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
|
||||
|
||||
blip_inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
|
||||
{
|
||||
buf = blip_buf.buffer_;
|
||||
accum = blip_buf.reader_accum_;
|
||||
return blip_buf.bass_shift_;
|
||||
}
|
||||
|
||||
int const blip_max_length = 0;
|
||||
int const blip_default_length = 250;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,208 @@
|
|||
/* Cygne
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Dox dox@space.pl
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include <ctype.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
//uint8 wsEEPROM[2048];
|
||||
//static uint8 iEEPROM[0x400];
|
||||
static const uint8 iEEPROM_Init[0x400] =
|
||||
{
|
||||
255,255,255,255,255,255,192,255,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,127,0,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
0,252,255,1,255,253,255,253,255,253,255,253,
|
||||
255,253,255,253,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
0,0,3,3,0,0,0,64,128,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
135,5,140,9,5,12,139,12,144,0,0,2,
|
||||
0,76,165,0,128,0,0,0,255,127,255,127,
|
||||
255,127,255,127,255,127,255,127,255,127,255,127,
|
||||
255,127,255,127,255,127,255,127,255,127,255,127,
|
||||
255,127,255,127,255,127,255,127,255,127,255,127,
|
||||
255,127,255,127,255,127,255,127,255,127,255,127,
|
||||
255,127,255,127,255,127,255,127,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
0,0,6,6,6,6,6,0,0,0,0,0,
|
||||
1,128,15,0,1,1,1,15,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
'C'-54,'Y'-54,'G'-54,'N'-54,'E'-54,0,0,0,0,0,0,0,0,0,0,
|
||||
0,32,1,1,33,1,4,0,1,
|
||||
0,152,60,127,74,1,53,1,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255
|
||||
};
|
||||
|
||||
//static uint8 iEEPROM_Command, EEPROM_Command;
|
||||
//static uint16 iEEPROM_Address, EEPROM_Address;
|
||||
|
||||
uint8 EEPROM::Read(uint32 A)
|
||||
{
|
||||
switch(A)
|
||||
{
|
||||
default: Debug::printf("Read: %04x\n", A); break;
|
||||
|
||||
case 0xBA: return(iEEPROM[(iEEPROM_Address << 1) & 0x3FF]);
|
||||
case 0xBB: return(iEEPROM[((iEEPROM_Address << 1) | 1) & 0x3FF]);
|
||||
case 0xBC: return(iEEPROM_Address >> 0);
|
||||
case 0xBD: return(iEEPROM_Address >> 8);
|
||||
case 0xBE:
|
||||
if(iEEPROM_Command & 0x20) return iEEPROM_Command|2;
|
||||
if(iEEPROM_Command & 0x10) return iEEPROM_Command|1;
|
||||
return iEEPROM_Command | 3;
|
||||
|
||||
|
||||
case 0xC4: return(wsEEPROM[(EEPROM_Address << 1) & (eeprom_size - 1)]);
|
||||
case 0xC5: return(wsEEPROM[((EEPROM_Address << 1) | 1) & (eeprom_size - 1)]);
|
||||
case 0xC6: return(EEPROM_Address >> 0);
|
||||
case 0xC7: return(EEPROM_Address >> 8);
|
||||
case 0xC8: if(EEPROM_Command & 0x20) return EEPROM_Command|2;
|
||||
if(EEPROM_Command & 0x10) return EEPROM_Command|1;
|
||||
return EEPROM_Command | 3;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void EEPROM::Write(uint32 A, uint8 V)
|
||||
{
|
||||
switch(A)
|
||||
{
|
||||
case 0xBA: iEEPROM[(iEEPROM_Address << 1) & 0x3FF] = V; break;
|
||||
case 0xBB: iEEPROM[((iEEPROM_Address << 1) | 1) & 0x3FF] = V; break;
|
||||
case 0xBC: iEEPROM_Address &= 0xFF00; iEEPROM_Address |= (V << 0); break;
|
||||
case 0xBD: iEEPROM_Address &= 0x00FF; iEEPROM_Address |= (V << 8); break;
|
||||
case 0xBE: iEEPROM_Command = V; break;
|
||||
|
||||
case 0xC4: wsEEPROM[(EEPROM_Address << 1) & (eeprom_size - 1)] = V; break;
|
||||
case 0xC5: wsEEPROM[((EEPROM_Address << 1) | 1) & (eeprom_size - 1)] = V; break;
|
||||
|
||||
case 0xC6: EEPROM_Address &= 0xFF00; EEPROM_Address |= (V << 0); break;
|
||||
case 0xC7: EEPROM_Address &= 0x00FF; EEPROM_Address |= (V << 8); break;
|
||||
case 0xC8: EEPROM_Command = V; break;
|
||||
}
|
||||
}
|
||||
|
||||
void EEPROM::Reset()
|
||||
{
|
||||
iEEPROM_Command = EEPROM_Command = 0;
|
||||
iEEPROM_Address = EEPROM_Address = 0;
|
||||
}
|
||||
|
||||
void EEPROM::Init(const char *Name, const uint16 BYear, const uint8 BMonth, const uint8 BDay, const uint8 Sex, const uint8 Blood)
|
||||
{
|
||||
std::memset(wsEEPROM, 0, 2048);
|
||||
std::memcpy(iEEPROM, iEEPROM_Init, 0x400);
|
||||
|
||||
for(unsigned int x = 0; x < 16; x++)
|
||||
{
|
||||
uint8 zechar = 0;
|
||||
|
||||
if(x < std::strlen(Name))
|
||||
{
|
||||
char tc = toupper(Name[x]);
|
||||
if(tc == ' ') zechar = 0;
|
||||
else if(tc >= '0' && tc <= '9') zechar = tc - '0' + 0x1;
|
||||
else if(tc >= 'A' && tc <= 'Z') zechar = tc - 'A' + 0xB;
|
||||
else if(tc >= 'a' && tc <= 'z') zechar = tc - 'a' + 0xB + 26;
|
||||
}
|
||||
iEEPROM[0x360 + x] = zechar;
|
||||
}
|
||||
|
||||
#define mBCD16(value) ( (((((value)%100) / 10) <<4)|((value)%10)) | ((((((value / 100)%100) / 10) <<4)|((value / 100)%10))<<8) )
|
||||
#define INT16_TO_BCD(A) ((((((A) % 100) / 10) * 16 + ((A) % 10))) | (((((((A) / 100) % 100) / 10) * 16 + (((A) / 100) % 10))) << 8)) // convert INT16 --> BCD
|
||||
|
||||
uint16 bcd_BYear = INT16_TO_BCD(BYear);
|
||||
|
||||
iEEPROM[0x370] = (bcd_BYear >> 8) & 0xFF;
|
||||
iEEPROM[0x371] = (bcd_BYear >> 0) & 0xFF;
|
||||
iEEPROM[0x372] = mBCD(BMonth);
|
||||
iEEPROM[0x373] = mBCD(BDay);
|
||||
iEEPROM[0x374] = Sex;
|
||||
iEEPROM[0x375] = Blood;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef __WSWAN_EEPROM_H
|
||||
#define __WSWAN_EEPROM_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
|
||||
class EEPROM
|
||||
{
|
||||
public:
|
||||
uint8 Read(uint32 A);
|
||||
void Write(uint32 A, uint8 V);
|
||||
void Reset();
|
||||
void Init(const char *Name, const uint16 BYear, const uint8 BMonth, const uint8 BDay, const uint8 Sex, const uint8 Blood);
|
||||
|
||||
private:
|
||||
uint8 wsEEPROM[2048];
|
||||
uint8 iEEPROM[0x400];
|
||||
uint8 iEEPROM_Command, EEPROM_Command;
|
||||
uint16 iEEPROM_Address, EEPROM_Address;
|
||||
uint32 eeprom_size;
|
||||
|
||||
public:
|
||||
System *sys;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,601 @@
|
|||
/* Cygne
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Dox dox@space.pl
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
//#include <mednafen/video.h>
|
||||
//#include <trio/trio.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
GFX::GFX()
|
||||
{
|
||||
SetPixelFormat();
|
||||
}
|
||||
|
||||
void GFX::Init()
|
||||
{
|
||||
LayerEnabled = 7; // BG, FG, sprites
|
||||
}
|
||||
|
||||
void GFX::PaletteRAMWrite(uint32 ws_offset, uint8 data)
|
||||
{
|
||||
ws_offset=(ws_offset&0xfffe)-0xfe00;
|
||||
wsCols[(ws_offset>>1)>>4][(ws_offset>>1)&15] = sys->memory.wsRAM[ws_offset+0xfe00] | ((sys->memory.wsRAM[ws_offset+0xfe01]&0x0f) << 8);
|
||||
}
|
||||
|
||||
void GFX::Write(uint32 A, uint8 V)
|
||||
{
|
||||
if(A >= 0x1C && A <= 0x1F)
|
||||
{
|
||||
wsColors[(A - 0x1C) * 2 + 0] = 0xF - (V & 0xf);
|
||||
wsColors[(A - 0x1C) * 2 + 1] = 0xF - (V >> 4);
|
||||
}
|
||||
else if(A >= 0x20 && A <= 0x3F)
|
||||
{
|
||||
wsMonoPal[(A - 0x20) >> 1][((A & 0x1) << 1) + 0] = V&7;
|
||||
wsMonoPal[(A - 0x20) >> 1][((A & 0x1) << 1) | 1] = (V>>4)&7;
|
||||
}
|
||||
else switch(A)
|
||||
{
|
||||
case 0x00: DispControl = V; break;
|
||||
case 0x01: BGColor = V; break;
|
||||
case 0x03: LineCompare = V; break;
|
||||
case 0x04: SPRBase = V & 0x3F; break;
|
||||
case 0x05: SpriteStart = V; break;
|
||||
case 0x06: SpriteCount = V; break;
|
||||
case 0x07: FGBGLoc = V; break;
|
||||
case 0x08: FGx0 = V; break;
|
||||
case 0x09: FGy0 = V; break;
|
||||
case 0x0A: FGx1 = V; break;
|
||||
case 0x0B: FGy1 = V; break;
|
||||
case 0x0C: SPRx0 = V; break;
|
||||
case 0x0D: SPRy0 = V; break;
|
||||
case 0x0E: SPRx1 = V; break;
|
||||
case 0x0F: SPRy1 = V; break;
|
||||
case 0x10: BGXScroll = V; break;
|
||||
case 0x11: BGYScroll = V; break;
|
||||
case 0x12: FGXScroll = V; break;
|
||||
case 0x13: FGYScroll = V; break;
|
||||
|
||||
case 0x14: LCDControl = V; break; // if((!(wsIO[0x14]&1))&&(data&1)) { wsLine=0; }break; /* LCD off ??*/
|
||||
case 0x15: LCDIcons = V; break;
|
||||
|
||||
case 0x60: VideoMode = V;
|
||||
SetVideo(V>>5, false);
|
||||
//printf("VideoMode: %02x, %02x\n", V, V >> 5);
|
||||
break;
|
||||
|
||||
case 0xa2: if((V & 0x01) && !(BTimerControl & 0x01))
|
||||
HBCounter = HBTimerPeriod;
|
||||
if((V & 0x04) && !(BTimerControl & 0x04))
|
||||
VBCounter = VBTimerPeriod;
|
||||
BTimerControl = V;
|
||||
//printf("%04x:%02x\n", A, V);
|
||||
break;
|
||||
case 0xa4: HBTimerPeriod &= 0xFF00; HBTimerPeriod |= (V << 0); /*printf("%04x:%02x, %d\n", A, V, wsLine);*/ break;
|
||||
case 0xa5: HBTimerPeriod &= 0x00FF; HBTimerPeriod |= (V << 8); HBCounter = HBTimerPeriod; /*printf("%04x:%02x, %d\n", A, V, wsLine);*/ break;
|
||||
case 0xa6: VBTimerPeriod &= 0xFF00; VBTimerPeriod |= (V << 0); /*printf("%04x:%02x, %d\n", A, V, wsLine);*/ break;
|
||||
case 0xa7: VBTimerPeriod &= 0x00FF; VBTimerPeriod |= (V << 8); VBCounter = VBTimerPeriod; /*printf("%04x:%02x, %d\n", A, V, wsLine);*/ break;
|
||||
//default: printf("%04x:%02x\n", A, V); break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 GFX::Read(uint32 A)
|
||||
{
|
||||
if(A >= 0x1C && A <= 0x1F)
|
||||
{
|
||||
uint8 ret = 0;
|
||||
|
||||
ret |= 0xF - wsColors[(A - 0x1C) * 2 + 0];
|
||||
ret |= (0xF - wsColors[(A - 0x1C) * 2 + 1]) << 4;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
else if(A >= 0x20 && A <= 0x3F)
|
||||
{
|
||||
uint8 ret = wsMonoPal[(A - 0x20) >> 1][((A & 0x1) << 1) + 0] | (wsMonoPal[(A - 0x20) >> 1][((A & 0x1) << 1) | 1] << 4);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
else switch(A)
|
||||
{
|
||||
case 0x00: return(DispControl);
|
||||
case 0x01: return(BGColor);
|
||||
case 0x02: return(wsLine);
|
||||
case 0x03: return(LineCompare);
|
||||
case 0x04: return(SPRBase);
|
||||
case 0x05: return(SpriteStart);
|
||||
case 0x06: return(SpriteCount);
|
||||
case 0x07: return(FGBGLoc);
|
||||
case 0x08: return(FGx0); break;
|
||||
case 0x09: return(FGy0); break;
|
||||
case 0x0A: return(FGx1); break;
|
||||
case 0x0B: return(FGy1); break;
|
||||
case 0x0C: return(SPRx0); break;
|
||||
case 0x0D: return(SPRy0); break;
|
||||
case 0x0E: return(SPRx1); break;
|
||||
case 0x0F: return(SPRy1); break;
|
||||
case 0x10: return(BGXScroll);
|
||||
case 0x11: return(BGYScroll);
|
||||
case 0x12: return(FGXScroll);
|
||||
case 0x13: return(FGYScroll);
|
||||
case 0x14: return(LCDControl);
|
||||
case 0x15: return(LCDIcons);
|
||||
case 0x60: return(VideoMode);
|
||||
case 0xa0: return(sys->wsc ? 0x87 : 0x86);
|
||||
case 0xa2: return(BTimerControl);
|
||||
case 0xa4: return((HBTimerPeriod >> 0) & 0xFF);
|
||||
case 0xa5: return((HBTimerPeriod >> 8) & 0xFF);
|
||||
case 0xa6: return((VBTimerPeriod >> 0) & 0xFF);
|
||||
case 0xa7: return((VBTimerPeriod >> 8) & 0xFF);
|
||||
case 0xa8: /*printf("%04x\n", A);*/ return((HBCounter >> 0) & 0xFF);
|
||||
case 0xa9: /*printf("%04x\n", A);*/ return((HBCounter >> 8) & 0xFF);
|
||||
case 0xaa: /*printf("%04x\n", A);*/ return((VBCounter >> 0) & 0xFF);
|
||||
case 0xab: /*printf("%04x\n", A);*/ return((VBCounter >> 8) & 0xFF);
|
||||
default: return(0);
|
||||
//default: printf("GfxRead: %04x\n", A); return(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool GFX::ExecuteLine(uint32 *surface, bool skip)
|
||||
{
|
||||
//static const void* const WEP_Tab[3] = { &&WEP0, &&WEP1, &&WEP2 }; // The things we do for debugger step mode save states! If we ever add more entries, remember to change the mask stuff in StateAction
|
||||
bool ret;
|
||||
|
||||
// weppy = 0;
|
||||
//WEP0: ;
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
if(wsLine < 144)
|
||||
{
|
||||
if(!skip)
|
||||
Scanline(surface + wsLine * 224);
|
||||
}
|
||||
|
||||
sys->memory.CheckSoundDMA();
|
||||
|
||||
// Update sprite data table
|
||||
if(wsLine == 142)
|
||||
{
|
||||
SpriteCountCache = SpriteCount;
|
||||
|
||||
if(SpriteCountCache > 0x80)
|
||||
SpriteCountCache = 0x80;
|
||||
|
||||
memcpy(SpriteTable, &sys->memory.wsRAM[(SPRBase << 9) + (SpriteStart << 2)], SpriteCountCache << 2);
|
||||
}
|
||||
|
||||
if(wsLine == 144)
|
||||
{
|
||||
ret = TRUE;
|
||||
sys->interrupt.DoInterrupt(WSINT_VBLANK);
|
||||
//printf("VBlank: %d\n", wsLine);
|
||||
}
|
||||
|
||||
|
||||
if(HBCounter && (BTimerControl & 0x01))
|
||||
{
|
||||
HBCounter--;
|
||||
if(!HBCounter)
|
||||
{
|
||||
// Loop mode?
|
||||
if(BTimerControl & 0x02)
|
||||
HBCounter = HBTimerPeriod;
|
||||
sys->interrupt.DoInterrupt(WSINT_HBLANK_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
// weppy = 1;
|
||||
sys->cpu.execute(224);
|
||||
// goto *WEP_Tab[weppy];
|
||||
//WEP1: ;
|
||||
|
||||
wsLine = (wsLine + 1) % 159;
|
||||
if(wsLine == LineCompare)
|
||||
{
|
||||
sys->interrupt.DoInterrupt(WSINT_LINE_HIT);
|
||||
//printf("Line hit: %d\n", wsLine);
|
||||
}
|
||||
|
||||
// weppy = 2;
|
||||
sys->cpu.execute(32);
|
||||
// goto *WEP_Tab[weppy];
|
||||
//WEP2: ;
|
||||
|
||||
sys->rtc.Clock(256);
|
||||
|
||||
if(!wsLine)
|
||||
{
|
||||
if(VBCounter && (BTimerControl & 0x04))
|
||||
{
|
||||
VBCounter--;
|
||||
if(!VBCounter)
|
||||
{
|
||||
if(BTimerControl & 0x08) // Loop mode?
|
||||
VBCounter = VBTimerPeriod;
|
||||
|
||||
sys->interrupt.DoInterrupt(WSINT_VBLANK_TIMER);
|
||||
}
|
||||
}
|
||||
wsLine = 0;
|
||||
}
|
||||
|
||||
// weppy = 0;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void GFX::SetLayerEnableMask(uint64 mask)
|
||||
{
|
||||
LayerEnabled = mask;
|
||||
}
|
||||
|
||||
void GFX::SetPixelFormat()
|
||||
{
|
||||
for(int r = 0; r < 16; r++)
|
||||
for(int g = 0; g < 16; g++)
|
||||
for(int b = 0; b < 16; b++)
|
||||
{
|
||||
uint32 neo_r, neo_g, neo_b;
|
||||
|
||||
neo_r = r * 17;
|
||||
neo_g = g * 17;
|
||||
neo_b = b * 17;
|
||||
|
||||
ColorMap[(r << 8) | (g << 4) | (b << 0)] = 0xff000000 | neo_r << 16 | neo_g << 8 | neo_b << 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
uint32 neo_r, neo_g, neo_b;
|
||||
|
||||
neo_r = (i) * 17;
|
||||
neo_g = (i) * 17;
|
||||
neo_b = (i) * 17;
|
||||
|
||||
ColorMapG[i] = 0xff000000 | neo_r << 16 | neo_g << 8 | neo_b << 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GFX::Scanline(uint32 *target)
|
||||
{
|
||||
uint32 start_tile_n,map_a,startindex,adrbuf,b1,b2,j,t,l;
|
||||
char ys2;
|
||||
uint8 b_bg[256];
|
||||
uint8 b_bg_pal[256];
|
||||
const uint8 *ram = sys->memory.wsRAM;
|
||||
|
||||
if(!wsVMode)
|
||||
memset(b_bg, wsColors[BGColor&0xF]&0xF, 256);
|
||||
else
|
||||
{
|
||||
memset(&b_bg[0], BGColor & 0xF, 256);
|
||||
memset(&b_bg_pal[0], (BGColor>>4) & 0xF, 256);
|
||||
}
|
||||
start_tile_n=(wsLine+BGYScroll)&0xff;/*First line*/
|
||||
map_a=(((uint32)(FGBGLoc&0xF))<<11)+((start_tile_n&0xfff8)<<3);
|
||||
startindex = BGXScroll >> 3; /*First tile in row*/
|
||||
adrbuf = 7-(BGXScroll&7); /*Pixel in tile*/
|
||||
|
||||
if((DispControl & 0x01) && (LayerEnabled & 0x01)) /*BG layer*/
|
||||
{
|
||||
for(t=0;t<29;t++)
|
||||
{
|
||||
b1=ram[map_a+(startindex<<1)];
|
||||
b2=ram[map_a+(startindex<<1)+1];
|
||||
uint32 palette=(b2>>1)&15;
|
||||
b2=(b2<<8)|b1;
|
||||
GetTile(b2&0x1ff,start_tile_n&7,b2&0x8000,b2&0x4000,b2&0x2000);
|
||||
|
||||
if(wsVMode)
|
||||
{
|
||||
if(wsVMode & 0x2)
|
||||
{
|
||||
for(int x = 0; x < 8; x++)
|
||||
if(wsTileRow[x])
|
||||
{
|
||||
b_bg[adrbuf + x] = wsTileRow[x];
|
||||
b_bg_pal[adrbuf + x] = palette;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int x = 0; x < 8; x++)
|
||||
if(wsTileRow[x] || !(palette & 0x4))
|
||||
{
|
||||
b_bg[adrbuf + x] = wsTileRow[x];
|
||||
b_bg_pal[adrbuf + x] = palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int x = 0; x < 8; x++)
|
||||
if(wsTileRow[x] || !(palette & 4))
|
||||
{
|
||||
b_bg[adrbuf + x] = wsColors[wsMonoPal[palette][wsTileRow[x]]];
|
||||
}
|
||||
}
|
||||
adrbuf += 8;
|
||||
startindex=(startindex + 1)&31;
|
||||
} // end for(t = 0 ...
|
||||
} // End BG layer drawing
|
||||
|
||||
if((DispControl & 0x02) && (LayerEnabled & 0x02))/*FG layer*/
|
||||
{
|
||||
uint8 windowtype = DispControl&0x30;
|
||||
bool in_window[256 + 8*2];
|
||||
|
||||
if(windowtype)
|
||||
{
|
||||
memset(in_window, 0, sizeof(in_window));
|
||||
|
||||
if(windowtype == 0x20) // Display FG only inside window
|
||||
{
|
||||
if((wsLine >= FGy0) && (wsLine < FGy1))
|
||||
for(j = FGx0; j <= FGx1 && j < 224; j++)
|
||||
in_window[7 + j] = 1;
|
||||
}
|
||||
else if(windowtype == 0x30) // Display FG only outside window
|
||||
{
|
||||
for(j = 0; j < 224; j++)
|
||||
{
|
||||
if(!(j >= FGx0 && j < FGx1) || !((wsLine >= FGy0) && (wsLine < FGy1)))
|
||||
in_window[7 + j] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::puts("Bad windowtype??");
|
||||
}
|
||||
}
|
||||
else
|
||||
memset(in_window, 1, sizeof(in_window));
|
||||
|
||||
start_tile_n=(wsLine+FGYScroll)&0xff;
|
||||
map_a=(((uint32)((FGBGLoc>>4)&0xF))<<11)+((start_tile_n>>3)<<6);
|
||||
startindex = FGXScroll >> 3;
|
||||
adrbuf = 7-(FGXScroll&7);
|
||||
|
||||
for(t=0; t<29; t++)
|
||||
{
|
||||
b1=ram[map_a+(startindex<<1)];
|
||||
b2=ram[map_a+(startindex<<1)+1];
|
||||
uint32 palette=(b2>>1)&15;
|
||||
b2=(b2<<8)|b1;
|
||||
GetTile(b2&0x1ff,start_tile_n&7,b2&0x8000,b2&0x4000,b2&0x2000);
|
||||
|
||||
if(wsVMode)
|
||||
{
|
||||
if(wsVMode & 0x2)
|
||||
for(int x = 0; x < 8; x++)
|
||||
{
|
||||
if(wsTileRow[x] && in_window[adrbuf + x])
|
||||
{
|
||||
b_bg[adrbuf + x] = wsTileRow[x] | 0x10;
|
||||
b_bg_pal[adrbuf + x] = palette;
|
||||
}
|
||||
}
|
||||
else
|
||||
for(int x = 0; x < 8; x++)
|
||||
{
|
||||
if((wsTileRow[x] || !(palette & 0x4)) && in_window[adrbuf + x])
|
||||
{
|
||||
b_bg[adrbuf + x] = wsTileRow[x] | 0x10;
|
||||
b_bg_pal[adrbuf + x] = palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int x = 0; x < 8; x++)
|
||||
if((wsTileRow[x] || !(palette & 4)) && in_window[adrbuf + x])
|
||||
{
|
||||
b_bg[adrbuf + x] = wsColors[wsMonoPal[palette][wsTileRow[x]]] | 0x10;
|
||||
}
|
||||
}
|
||||
adrbuf += 8;
|
||||
startindex=(startindex + 1)&31;
|
||||
} // end for(t = 0 ...
|
||||
|
||||
} // end FG drawing
|
||||
|
||||
if((DispControl & 0x04) && SpriteCountCache && (LayerEnabled & 0x04))/*Sprites*/
|
||||
{
|
||||
int xs,ts,as,ys,ysx,h;
|
||||
bool in_window[256 + 8*2];
|
||||
|
||||
if(DispControl & 0x08)
|
||||
{
|
||||
memset(in_window, 0, sizeof(in_window));
|
||||
if((wsLine >= SPRy0) && (wsLine < SPRy1))
|
||||
for(j = SPRx0; j < SPRx1 && j < 256; j++)
|
||||
in_window[7 + j] = 1;
|
||||
}
|
||||
else
|
||||
memset(in_window, 1, sizeof(in_window));
|
||||
|
||||
for(h = SpriteCountCache - 1; h >= 0; h--)
|
||||
{
|
||||
ts = SpriteTable[h][0];
|
||||
as = SpriteTable[h][1];
|
||||
ysx = SpriteTable[h][2];
|
||||
ys2 = (int8)SpriteTable[h][2];
|
||||
xs = SpriteTable[h][3];
|
||||
|
||||
if(xs >= 249) xs -= 256;
|
||||
|
||||
if(ysx > 150)
|
||||
ys = ys2;
|
||||
else
|
||||
ys = ysx;
|
||||
|
||||
ys = wsLine - ys;
|
||||
|
||||
if(ys >= 0 && ys < 8 && xs < 224)
|
||||
{
|
||||
uint32 palette = ((as >> 1) & 0x7);
|
||||
|
||||
ts |= (as&1) << 8;
|
||||
GetTile(ts, ys, as & 0x80, as & 0x40, 0);
|
||||
|
||||
if(wsVMode)
|
||||
{
|
||||
if(wsVMode & 0x2)
|
||||
{
|
||||
for(int x = 0; x < 8; x++)
|
||||
if(wsTileRow[x])
|
||||
{
|
||||
if((as & 0x20) || !(b_bg[xs + x + 7] & 0x10))
|
||||
{
|
||||
bool drawthis = 0;
|
||||
|
||||
if(!(DispControl & 0x08))
|
||||
drawthis = TRUE;
|
||||
else if((as & 0x10) && !in_window[7 + xs + x])
|
||||
drawthis = TRUE;
|
||||
else if(!(as & 0x10) && in_window[7 + xs + x])
|
||||
drawthis = TRUE;
|
||||
|
||||
if(drawthis)
|
||||
{
|
||||
b_bg[xs + x + 7] = wsTileRow[x] | (b_bg[xs + x + 7] & 0x10);
|
||||
b_bg_pal[xs + x + 7] = 8 + palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int x = 0; x < 8; x++)
|
||||
if(wsTileRow[x] || !(palette & 0x4))
|
||||
{
|
||||
if((as & 0x20) || !(b_bg[xs + x + 7] & 0x10))
|
||||
{
|
||||
bool drawthis = 0;
|
||||
|
||||
if(!(DispControl & 0x08))
|
||||
drawthis = TRUE;
|
||||
else if((as & 0x10) && !in_window[7 + xs + x])
|
||||
drawthis = TRUE;
|
||||
else if(!(as & 0x10) && in_window[7 + xs + x])
|
||||
drawthis = TRUE;
|
||||
|
||||
if(drawthis)
|
||||
{
|
||||
b_bg[xs + x + 7] = wsTileRow[x] | (b_bg[xs + x + 7] & 0x10);
|
||||
b_bg_pal[xs + x + 7] = 8 + palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int x = 0; x < 8; x++)
|
||||
if(wsTileRow[x] || !(palette & 4))
|
||||
{
|
||||
if((as & 0x20) || !(b_bg[xs + x + 7] & 0x10))
|
||||
{
|
||||
bool drawthis = 0;
|
||||
|
||||
if(!(DispControl & 0x08))
|
||||
drawthis = TRUE;
|
||||
else if((as & 0x10) && !in_window[7 + xs + x])
|
||||
drawthis = TRUE;
|
||||
else if(!(as & 0x10) && in_window[7 + xs + x])
|
||||
drawthis = TRUE;
|
||||
|
||||
if(drawthis)
|
||||
//if((as & 0x10) || in_window[7 + xs + x])
|
||||
{
|
||||
b_bg[xs + x + 7] = wsColors[wsMonoPal[8 + palette][wsTileRow[x]]] | (b_bg[xs + x + 7] & 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End sprite drawing
|
||||
|
||||
if(wsVMode)
|
||||
{
|
||||
for(l=0;l<224;l++)
|
||||
target[l] = ColorMap[wsCols[b_bg_pal[l+7]][b_bg[(l+7)]&0xf]];
|
||||
}
|
||||
else
|
||||
{
|
||||
for(l=0;l<224;l++)
|
||||
target[l] = ColorMapG[(b_bg[l+7])&15];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GFX::Reset()
|
||||
{
|
||||
//weppy = 0;
|
||||
wsLine=145; // all frames same length
|
||||
SetVideo(0,TRUE);
|
||||
|
||||
memset(SpriteTable, 0, sizeof(SpriteTable));
|
||||
SpriteCountCache = 0;
|
||||
DispControl = 0;
|
||||
BGColor = 0;
|
||||
LineCompare = 0xBB;
|
||||
SPRBase = 0;
|
||||
|
||||
SpriteStart = 0;
|
||||
SpriteCount = 0;
|
||||
FGBGLoc = 0;
|
||||
|
||||
FGx0 = 0;
|
||||
FGy0 = 0;
|
||||
FGx1 = 0;
|
||||
FGy1 = 0;
|
||||
SPRx0 = 0;
|
||||
SPRy0 = 0;
|
||||
SPRx1 = 0;
|
||||
SPRy1 = 0;
|
||||
|
||||
BGXScroll = BGYScroll = 0;
|
||||
FGXScroll = FGYScroll = 0;
|
||||
LCDControl = 0;
|
||||
LCDIcons = 0;
|
||||
|
||||
BTimerControl = 0;
|
||||
HBTimerPeriod = 0;
|
||||
VBTimerPeriod = 0;
|
||||
|
||||
HBCounter = 0;
|
||||
VBCounter = 0;
|
||||
|
||||
|
||||
for(int u0=0;u0<16;u0++)
|
||||
for(int u1=0;u1<16;u1++)
|
||||
wsCols[u0][u1]=0;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef __WSWAN_GFX_H
|
||||
#define __WSWAN_GFX_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
class GFX
|
||||
{
|
||||
public:
|
||||
GFX();
|
||||
|
||||
// TCACHE ====================================
|
||||
void InvalidByAddr(uint32);
|
||||
void SetVideo(int, bool);
|
||||
void MakeTiles();
|
||||
void GetTile(uint32 number,uint32 line,int flipv,int fliph,int bank);
|
||||
// TCACHE/====================================
|
||||
void Scanline(uint32 *target);
|
||||
void SetPixelFormat();
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
void Write(uint32 A, uint8 V);
|
||||
uint8 Read(uint32 A);
|
||||
void PaletteRAMWrite(uint32 ws_offset, uint8 data);
|
||||
|
||||
bool ExecuteLine(uint32 *surface, bool skip);
|
||||
|
||||
void SetLayerEnableMask(uint64 mask);
|
||||
|
||||
private:
|
||||
// TCACHE ====================================
|
||||
uint8 tiles[256][256][2][8];
|
||||
uint8 wsTCache[512*64];
|
||||
uint8 wsTCache2[512*64];
|
||||
uint8 wsTCacheFlipped[512*64];
|
||||
uint8 wsTCacheFlipped2[512*64];
|
||||
uint8 wsTCacheUpdate[512];
|
||||
uint8 wsTCacheUpdate2[512];
|
||||
uint8 wsTileRow[8];
|
||||
int wsVMode; // doesn't belong here?
|
||||
// TCACHE/====================================
|
||||
uint32 wsMonoPal[16][4];
|
||||
uint32 wsColors[8];
|
||||
uint32 wsCols[16][16];
|
||||
|
||||
uint32 ColorMapG[16];
|
||||
uint32 ColorMap[16*16*16];
|
||||
uint32 LayerEnabled;
|
||||
|
||||
uint8 wsLine; /*current scanline*/
|
||||
|
||||
uint8 SpriteTable[0x80][4];
|
||||
uint32 SpriteCountCache;
|
||||
uint8 DispControl;
|
||||
uint8 BGColor;
|
||||
uint8 LineCompare;
|
||||
uint8 SPRBase;
|
||||
uint8 SpriteStart, SpriteCount;
|
||||
uint8 FGBGLoc;
|
||||
uint8 FGx0, FGy0, FGx1, FGy1;
|
||||
uint8 SPRx0, SPRy0, SPRx1, SPRy1;
|
||||
|
||||
uint8 BGXScroll, BGYScroll;
|
||||
uint8 FGXScroll, FGYScroll;
|
||||
uint8 LCDControl, LCDIcons;
|
||||
|
||||
uint8 BTimerControl;
|
||||
uint16 HBTimerPeriod;
|
||||
uint16 VBTimerPeriod;
|
||||
|
||||
uint16 HBCounter, VBCounter;
|
||||
uint8 VideoMode;
|
||||
|
||||
public:
|
||||
System *sys;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ?
|
||||
//extern uint32 dx_r,dx_g,dx_b,dx_sr,dx_sg,dx_sb;
|
||||
//extern uint32 dx_bits,dx_pitch,cmov,dx_linewidth_blit,dx_buffer_line;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
#include "system.h"
|
||||
//#include <trio/trio.h>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
void Interrupt::Recalc()
|
||||
{
|
||||
IOn_Cache = FALSE;
|
||||
IOn_Which = 0;
|
||||
IVector_Cache = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
if(IStatus & IEnable & (1 << i))
|
||||
{
|
||||
IOn_Cache = TRUE;
|
||||
IOn_Which = i;
|
||||
IVector_Cache = (IVectorBase + i) * 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Interrupt::DebugForce(unsigned int level)
|
||||
{
|
||||
sys->cpu.interrupt((IVectorBase + level) * 4, TRUE);
|
||||
}
|
||||
|
||||
void Interrupt::DoInterrupt(int which)
|
||||
{
|
||||
if(IEnable & (1 << which))
|
||||
IStatus |= 1 << which;
|
||||
|
||||
//printf("Interrupt: %d\n", which);
|
||||
Recalc();
|
||||
}
|
||||
|
||||
void Interrupt::Write(uint32 A, uint8 V)
|
||||
{
|
||||
//printf("Write: %04x %02x\n", A, V);
|
||||
switch(A)
|
||||
{
|
||||
case 0xB0: IVectorBase = V; Recalc(); break;
|
||||
case 0xB2: IEnable = V; IStatus &= IEnable; Recalc(); break;
|
||||
case 0xB6: /*printf("IStatus: %02x\n", V);*/ IStatus &= ~V; Recalc(); break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 Interrupt::Read(uint32 A)
|
||||
{
|
||||
//printf("Read: %04x\n", A);
|
||||
switch(A)
|
||||
{
|
||||
case 0xB0: return(IVectorBase);
|
||||
case 0xB2: return(IEnable);
|
||||
case 0xB6: return(1 << IOn_Which); //return(IStatus);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Interrupt::Check()
|
||||
{
|
||||
if(IOn_Cache)
|
||||
{
|
||||
sys->cpu.interrupt(IVector_Cache, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void Interrupt::Reset()
|
||||
{
|
||||
IEnable = 0x00;
|
||||
IStatus = 0x00;
|
||||
IVectorBase = 0x00;
|
||||
Recalc();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef __WSWAN_INTERRUPT_H
|
||||
#define __WSWAN_INTERRUPT_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
WSINT_SERIAL_SEND = 0,
|
||||
WSINT_KEY_PRESS,
|
||||
WSINT_RTC_ALARM,
|
||||
WSINT_SERIAL_RECV,
|
||||
WSINT_LINE_HIT,
|
||||
WSINT_VBLANK_TIMER,
|
||||
WSINT_VBLANK,
|
||||
WSINT_HBLANK_TIMER
|
||||
};
|
||||
|
||||
class Interrupt
|
||||
{
|
||||
public:
|
||||
void DoInterrupt(int);
|
||||
void Write(uint32 A, uint8 V);
|
||||
uint8 Read(uint32 A);
|
||||
void Check();
|
||||
void Reset();
|
||||
void DebugForce(unsigned int level);
|
||||
|
||||
private:
|
||||
uint8 IStatus;
|
||||
uint8 IEnable;
|
||||
uint8 IVectorBase;
|
||||
|
||||
bool IOn_Cache;
|
||||
uint32 IOn_Which;
|
||||
uint32 IVector_Cache;
|
||||
|
||||
private:
|
||||
void Recalc();
|
||||
public:
|
||||
System *sys;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,94 @@
|
|||
/* Cygne
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Dox dox@space.pl
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
//#include <mednafen/md5.h>
|
||||
//#include <mednafen/mempatcher.h>
|
||||
//#include <mednafen/player.h>
|
||||
|
||||
//#include <fcntl.h>
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
#include <math.h>
|
||||
//#include <zlib.h>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
#if 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
using namespace MDFN_IEN_WSWAN;
|
||||
|
||||
MDFNGI EmulatedWSwan =
|
||||
{
|
||||
"wswan",
|
||||
"WonderSwan",
|
||||
KnownExtensions,
|
||||
MODPRIO_INTERNAL_HIGH,
|
||||
#ifdef WANT_DEBUGGER
|
||||
&DBGInfo,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
&InputInfo,
|
||||
Load,
|
||||
TestMagic,
|
||||
NULL,
|
||||
NULL,
|
||||
CloseGame,
|
||||
WSwan_SetLayerEnableMask,
|
||||
"Background\0Foreground\0Sprites\0",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
StateAction,
|
||||
Emulate,
|
||||
SetInput,
|
||||
DoSimpleCommand,
|
||||
WSwanSettings,
|
||||
MDFN_MASTERCLOCK_FIXED(3072000),
|
||||
0,
|
||||
FALSE, // Multires possible?
|
||||
|
||||
224, // lcm_width
|
||||
144, // lcm_height
|
||||
NULL, // Dummy
|
||||
|
||||
224, // Nominal width
|
||||
144, // Nominal height
|
||||
|
||||
224, // Framebuffer width
|
||||
144, // Framebuffer height
|
||||
|
||||
2, // Number of output sound channels
|
||||
};
|
||||
*/
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef _STATE_H
|
||||
#define _STATE_H
|
||||
|
||||
#endif
|
|
@ -0,0 +1,201 @@
|
|||
#ifndef __MDFN_TYPES
|
||||
#define __MDFN_TYPES
|
||||
|
||||
#define __STDC_LIMIT_MACROS 1
|
||||
|
||||
// Make sure this file is included BEFORE a few common standard C header files(stdio.h, errno.h, math.h, AND OTHERS, but this is not an exhaustive check, nor
|
||||
// should it be), so that any defines in config.h that change header file behavior will work properly.
|
||||
#if defined(EOF) || defined(EACCES) || defined(F_LOCK) || defined(NULL) || defined(O_APPEND) || defined(M_LOG2E)
|
||||
#error "Wrong include order for types.h"
|
||||
#endif
|
||||
|
||||
// Yes, yes, I know: There's a better place for including config.h than here, but I'm tired, and this should work fine. :b
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
|
||||
#if !defined(HAVE_NATIVE64BIT) && (SIZEOF_VOID_P >= 8 || defined(__x86_64__))
|
||||
#define HAVE_NATIVE64BIT 1
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define MDFN_MAKE_GCCV(maj,min,pl) (((maj)*100*100) + ((min) * 100) + (pl))
|
||||
#define MDFN_GCC_VERSION MDFN_MAKE_GCCV(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
#define INLINE inline __attribute__((always_inline))
|
||||
#define NO_INLINE __attribute__((noinline))
|
||||
|
||||
//
|
||||
// Just avoid using fastcall with gcc before 4.1.0, as it(and similar regparm)
|
||||
// tend to generate bad code on the older versions(between about 3.1.x and 4.0.x, at least)
|
||||
//
|
||||
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12236
|
||||
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=7574
|
||||
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17025
|
||||
//
|
||||
#if MDFN_GCC_VERSION >= MDFN_MAKE_GCCV(4,1,0)
|
||||
#if defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
|
||||
#define MDFN_FASTCALL __attribute__((fastcall))
|
||||
#else
|
||||
#define MDFN_FASTCALL
|
||||
#endif
|
||||
#else
|
||||
#define MDFN_FASTCALL
|
||||
#endif
|
||||
|
||||
#define MDFN_ALIGN(n) __attribute__ ((aligned (n)))
|
||||
#define MDFN_FORMATSTR(a,b,c) __attribute__ ((format (a, b, c)));
|
||||
#define MDFN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
|
||||
#define MDFN_NOWARN_UNUSED __attribute__((unused))
|
||||
|
||||
#define MDFN_UNLIKELY(n) __builtin_expect((n) != 0, 0)
|
||||
#define MDFN_LIKELY(n) __builtin_expect((n) != 0, 1)
|
||||
|
||||
#if MDFN_GCC_VERSION >= MDFN_MAKE_GCCV(4,3,0)
|
||||
#define MDFN_COLD __attribute__((cold))
|
||||
#else
|
||||
#define MDFN_COLD
|
||||
#endif
|
||||
|
||||
#undef MDFN_MAKE_GCCV
|
||||
#undef MDFN_GCC_VERSION
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#pragma message("Compiling with MSVC, untested")
|
||||
|
||||
#define INLINE __forceinline
|
||||
#define NO_INLINE __declspec(noinline)
|
||||
|
||||
#define MDFN_FASTCALL __fastcall
|
||||
|
||||
#define MDFN_ALIGN(n) __declspec(align(n))
|
||||
|
||||
#define MDFN_FORMATSTR(a,b,c)
|
||||
|
||||
#define MDFN_WARN_UNUSED_RESULT
|
||||
|
||||
#define MDFN_NOWARN_UNUSED
|
||||
|
||||
#define MDFN_UNLIKELY(n) ((n) != 0)
|
||||
#define MDFN_LIKELY(n) ((n) != 0)
|
||||
|
||||
#define MDFN_COLD
|
||||
#else
|
||||
#error "Not compiling with GCC nor MSVC"
|
||||
#define INLINE inline
|
||||
#define NO_INLINE
|
||||
|
||||
#define MDFN_FASTCALL
|
||||
|
||||
#define MDFN_ALIGN(n) // hence the #error.
|
||||
|
||||
#define MDFN_FORMATSTR(a,b,c)
|
||||
|
||||
#define MDFN_WARN_UNUSED_RESULT
|
||||
|
||||
#define MDFN_NOWARN_UNUSED
|
||||
|
||||
#define MDFN_UNLIKELY(n) ((n) != 0)
|
||||
#define MDFN_LIKELY(n) ((n) != 0)
|
||||
|
||||
#define MDFN_COLD
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
uint8 High;
|
||||
uint8 Low;
|
||||
#else
|
||||
uint8 Low;
|
||||
uint8 High;
|
||||
#endif
|
||||
} Union8;
|
||||
uint16 Val16;
|
||||
};
|
||||
} Uuint16;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_FIRST
|
||||
Uuint16 High;
|
||||
Uuint16 Low;
|
||||
#else
|
||||
Uuint16 Low;
|
||||
Uuint16 High;
|
||||
#endif
|
||||
} Union16;
|
||||
uint32 Val32;
|
||||
};
|
||||
} Uuint32;
|
||||
|
||||
|
||||
#if PSS_STYLE==2
|
||||
|
||||
#define PSS "\\"
|
||||
#define MDFN_PS '\\'
|
||||
|
||||
#elif PSS_STYLE==1
|
||||
|
||||
#define PSS "/"
|
||||
#define MDFN_PS '/'
|
||||
|
||||
#elif PSS_STYLE==3
|
||||
|
||||
#define PSS "\\"
|
||||
#define MDFN_PS '\\'
|
||||
|
||||
#elif PSS_STYLE==4
|
||||
|
||||
#define PSS ":"
|
||||
#define MDFN_PS ':'
|
||||
|
||||
#endif
|
||||
|
||||
typedef uint32 UTF32; /* at least 32 bits */
|
||||
typedef uint16 UTF16; /* at least 16 bits */
|
||||
typedef uint8 UTF8; /* typically 8 bits */
|
||||
typedef unsigned char Boolean; /* 0 or 1 */
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#undef require
|
||||
#define require( expr ) assert( expr )
|
||||
|
||||
#if !defined(MSB_FIRST) && !defined(LSB_FIRST)
|
||||
#error "Define MSB_FIRST or LSB_FIRST!"
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,390 @@
|
|||
/* Cygne
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Dox dox@space.pl
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
//extern uint16 WSButtonStatus;
|
||||
|
||||
void Memory::Write20(uint32 A, uint8 V)
|
||||
{
|
||||
uint32 offset, bank;
|
||||
|
||||
offset = A & 0xffff;
|
||||
bank = (A>>16) & 0xF;
|
||||
|
||||
if(!bank) /*RAM*/
|
||||
{
|
||||
sys->sound.CheckRAMWrite(offset);
|
||||
wsRAM[offset] = V;
|
||||
|
||||
sys->gfx.InvalidByAddr(offset);
|
||||
|
||||
if(offset>=0xfe00) /*WSC palettes*/
|
||||
sys->gfx.PaletteRAMWrite(offset, V);
|
||||
}
|
||||
else if(bank == 1) /* SRAM */
|
||||
{
|
||||
if(sram_size)
|
||||
{
|
||||
wsSRAM[(offset | (BankSelector[1] << 16)) & (sram_size - 1)] = V;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8 Memory::Read20(uint32 A)
|
||||
{
|
||||
uint32 offset, bank;
|
||||
|
||||
offset = A & 0xFFFF;
|
||||
bank = (A >> 16) & 0xF;
|
||||
|
||||
switch(bank)
|
||||
{
|
||||
case 0: return wsRAM[offset];
|
||||
case 1: if(sram_size)
|
||||
{
|
||||
return wsSRAM[(offset | (BankSelector[1] << 16)) & (sram_size - 1)];
|
||||
}
|
||||
else
|
||||
return(0);
|
||||
|
||||
case 2:
|
||||
case 3: return wsCartROM[offset+((BankSelector[bank]&((rom_size>>16)-1))<<16)];
|
||||
|
||||
default:
|
||||
{
|
||||
uint8 bank_num = ((BankSelector[0] & 0xF) << 4) | (bank & 0xf);
|
||||
bank_num &= (rom_size >> 16) - 1;
|
||||
return(wsCartROM[(bank_num << 16) | offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::CheckDMA()
|
||||
{
|
||||
if(DMAControl & 0x80)
|
||||
{
|
||||
while(DMALength)
|
||||
{
|
||||
Write20(DMADest, Read20(DMASource));
|
||||
|
||||
DMASource++; // = ((DMASource + 1) & 0xFFFF) | (DMASource & 0xFF0000);
|
||||
//if(!(DMASource & 0xFFFF)) puts("Warning: DMA source bank crossed.");
|
||||
DMADest = ((DMADest + 1) & 0xFFFF) | (DMADest & 0xFF0000);
|
||||
DMALength--;
|
||||
}
|
||||
}
|
||||
DMAControl &= ~0x80;
|
||||
}
|
||||
|
||||
void Memory::CheckSoundDMA()
|
||||
{
|
||||
if(SoundDMAControl & 0x80)
|
||||
{
|
||||
if(SoundDMALength)
|
||||
{
|
||||
uint8 zebyte = Read20(SoundDMASource);
|
||||
|
||||
if(SoundDMAControl & 0x08)
|
||||
zebyte ^= 0x80;
|
||||
|
||||
if(SoundDMAControl & 0x10)
|
||||
sys->sound.Write(0x95, zebyte); // Pick a port, any port?!
|
||||
else
|
||||
sys->sound.Write(0x89, zebyte);
|
||||
|
||||
SoundDMASource++; // = ((SoundDMASource + 1) & 0xFFFF) | (SoundDMASource & 0xFF0000);
|
||||
//if(!(SoundDMASource & 0xFFFF)) puts("Warning: Sound DMA source bank crossed.");
|
||||
SoundDMALength--;
|
||||
}
|
||||
if(!SoundDMALength)
|
||||
SoundDMAControl &= ~0x80;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 Memory::readport(uint32 number)
|
||||
{
|
||||
number &= 0xFF;
|
||||
|
||||
if(number >= 0x80 && number <= 0x9F)
|
||||
return(sys->sound.Read(number));
|
||||
else if(number <= 0x3F || (number >= 0xA0 && number <= 0xAF) || (number == 0x60))
|
||||
return(sys->gfx.Read(number));
|
||||
else if((number >= 0xBA && number <= 0xBE) || (number >= 0xC4 && number <= 0xC8))
|
||||
return(sys->eeprom.Read(number));
|
||||
else if(number >= 0xCA && number <= 0xCB)
|
||||
return(sys->rtc.Read(number));
|
||||
else switch(number)
|
||||
{
|
||||
//default: printf("Read: %04x\n", number); break;
|
||||
case 0x40: return(DMASource >> 0);
|
||||
case 0x41: return(DMASource >> 8);
|
||||
case 0x42: return(DMASource >> 16);
|
||||
|
||||
case 0x43: return(DMADest >> 16);
|
||||
case 0x44: return(DMADest >> 0);
|
||||
case 0x45: return(DMADest >> 8);
|
||||
|
||||
case 0x46: return(DMALength >> 0);
|
||||
case 0x47: return(DMALength >> 8);
|
||||
|
||||
case 0x48: return(DMAControl);
|
||||
|
||||
case 0xB0:
|
||||
case 0xB2:
|
||||
case 0xB6: return(sys->interrupt.Read(number));
|
||||
|
||||
case 0xC0: return(BankSelector[0] | 0x20);
|
||||
case 0xC1: return(BankSelector[1]);
|
||||
case 0xC2: return(BankSelector[2]);
|
||||
case 0xC3: return(BankSelector[3]);
|
||||
|
||||
case 0x4a: return(SoundDMASource >> 0);
|
||||
case 0x4b: return(SoundDMASource >> 8);
|
||||
case 0x4c: return(SoundDMASource >> 16);
|
||||
case 0x4e: return(SoundDMALength >> 0);
|
||||
case 0x4f: return(SoundDMALength >> 8);
|
||||
case 0x52: return(SoundDMAControl);
|
||||
|
||||
case 0xB1: return(CommData);
|
||||
|
||||
case 0xb3:
|
||||
{
|
||||
uint8 ret = CommControl & 0xf0;
|
||||
|
||||
if(CommControl & 0x80)
|
||||
ret |= 0x4; // Send complete
|
||||
|
||||
return(ret);
|
||||
}
|
||||
case 0xb5:
|
||||
{
|
||||
uint8 ret = (ButtonWhich << 4) | ButtonReadLatch;
|
||||
return(ret);
|
||||
}
|
||||
}
|
||||
|
||||
if(number >= 0xC8)
|
||||
return language ? 0xD1 : 0xD0;
|
||||
//return(0xD0 | language); // is this right?
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Memory::writeport(uint32 IOPort, uint8 V)
|
||||
{
|
||||
IOPort &= 0xFF;
|
||||
|
||||
if(IOPort >= 0x80 && IOPort <= 0x9F)
|
||||
{
|
||||
sys->sound.Write(IOPort, V);
|
||||
}
|
||||
else if((IOPort >= 0x00 && IOPort <= 0x3F) || (IOPort >= 0xA0 && IOPort <= 0xAF) || (IOPort == 0x60))
|
||||
{
|
||||
sys->gfx.Write(IOPort, V);
|
||||
}
|
||||
else if((IOPort >= 0xBA && IOPort <= 0xBE) || (IOPort >= 0xC4 && IOPort <= 0xC8))
|
||||
sys->eeprom.Write(IOPort, V);
|
||||
else if(IOPort >= 0xCA && IOPort <= 0xCB)
|
||||
sys->rtc.Write(IOPort, V);
|
||||
else switch(IOPort)
|
||||
{
|
||||
//default: printf("%04x %02x\n", IOPort, V); break;
|
||||
|
||||
case 0x40: DMASource &= 0xFFFF00; DMASource |= (V << 0); break;
|
||||
case 0x41: DMASource &= 0xFF00FF; DMASource |= (V << 8); break;
|
||||
case 0x42: DMASource &= 0x00FFFF; DMASource |= ((V & 0x0F) << 16); break;
|
||||
|
||||
case 0x43: DMADest &= 0x00FFFF; DMADest |= ((V & 0x0F) << 16); break;
|
||||
case 0x44: DMADest &= 0xFFFF00; DMADest |= (V << 0); break;
|
||||
case 0x45: DMADest &= 0xFF00FF; DMADest |= (V << 8); break;
|
||||
|
||||
case 0x46: DMALength &= 0xFF00; DMALength |= (V << 0); break;
|
||||
case 0x47: DMALength &= 0x00FF; DMALength |= (V << 8); break;
|
||||
|
||||
case 0x48: DMAControl = V;
|
||||
//if(V&0x80)
|
||||
// printf("DMA%02x: %08x %08x %08x\n", V, DMASource, DMADest, DMALength);
|
||||
CheckDMA();
|
||||
break;
|
||||
|
||||
case 0x4a: SoundDMASource &= 0xFFFF00; SoundDMASource |= (V << 0); break;
|
||||
case 0x4b: SoundDMASource &= 0xFF00FF; SoundDMASource |= (V << 8); break;
|
||||
case 0x4c: SoundDMASource &= 0x00FFFF; SoundDMASource |= (V << 16); break;
|
||||
//case 0x4d: break; // Unused?
|
||||
case 0x4e: SoundDMALength &= 0xFF00; SoundDMALength |= (V << 0); break;
|
||||
case 0x4f: SoundDMALength &= 0x00FF; SoundDMALength |= (V << 8); break;
|
||||
//case 0x50: break; // Unused?
|
||||
//case 0x51: break; // Unused?
|
||||
case 0x52: SoundDMAControl = V;
|
||||
//if(V & 0x80) printf("Sound DMA: %02x, %08x %08x\n", V, SoundDMASource, SoundDMALength);
|
||||
break;
|
||||
|
||||
case 0xB0:
|
||||
case 0xB2:
|
||||
case 0xB6: sys->interrupt.Write(IOPort, V); break;
|
||||
|
||||
case 0xB1: CommData = V; break;
|
||||
case 0xB3: CommControl = V & 0xF0; break;
|
||||
|
||||
case 0xb5: ButtonWhich = V >> 4;
|
||||
ButtonReadLatch = 0;
|
||||
|
||||
if(ButtonWhich & 0x4) /*buttons*/
|
||||
ButtonReadLatch |= ((WSButtonStatus >> 8) << 1) & 0xF;
|
||||
|
||||
if(ButtonWhich & 0x2) /* H/X cursors */
|
||||
ButtonReadLatch |= WSButtonStatus & 0xF;
|
||||
|
||||
if(ButtonWhich & 0x1) /* V/Y cursors */
|
||||
ButtonReadLatch |= (WSButtonStatus >> 4) & 0xF;
|
||||
break;
|
||||
|
||||
case 0xC0: BankSelector[0] = V & 0xF; break;
|
||||
case 0xC1: BankSelector[1] = V; break;
|
||||
case 0xC2: BankSelector[2] = V; break;
|
||||
case 0xC3: BankSelector[3] = V; break;
|
||||
}
|
||||
}
|
||||
|
||||
Memory::~Memory()
|
||||
{
|
||||
if (wsCartROM)
|
||||
{
|
||||
std::free(wsCartROM);
|
||||
wsCartROM = 0;
|
||||
}
|
||||
if (wsSRAM)
|
||||
{
|
||||
std::free(wsSRAM);
|
||||
wsSRAM = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void Memory::Kill()
|
||||
{
|
||||
if((sram_size || eeprom_size) && !SkipSL)
|
||||
{
|
||||
|
||||
std::vector<PtrLengthPair> EvilRams;
|
||||
|
||||
if(eeprom_size)
|
||||
EvilRams.push_back(PtrLengthPair(wsEEPROM, eeprom_size));
|
||||
|
||||
if(sram_size)
|
||||
EvilRams.push_back(PtrLengthPair(wsSRAM, sram_size));
|
||||
|
||||
MDFN_DumpToFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), 6, EvilRams);
|
||||
|
||||
}
|
||||
|
||||
if(wsSRAM)
|
||||
{
|
||||
free(wsSRAM);
|
||||
wsSRAM = NULL;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void Memory::Init(bool SkipSaveLoad, const Settings &settings)
|
||||
{
|
||||
char tmpname[17];
|
||||
std::memcpy(tmpname, settings.name, 16);
|
||||
tmpname[16] = 0;
|
||||
|
||||
|
||||
language = settings.language;
|
||||
SkipSL = SkipSaveLoad;
|
||||
|
||||
|
||||
// WSwan_EEPROMInit() will also clear wsEEPROM
|
||||
sys->eeprom.Init(tmpname, settings.byear, settings.bmonth, settings.bday, settings.sex, settings.blood);
|
||||
|
||||
if(sram_size)
|
||||
{
|
||||
wsSRAM = (uint8*)malloc(sram_size);
|
||||
memset(wsSRAM, 0, sram_size);
|
||||
}
|
||||
|
||||
/* TODO: SAVERAM
|
||||
if((sram_size || eeprom_size) && !SkipSL)
|
||||
{
|
||||
gzFile savegame_fp;
|
||||
|
||||
savegame_fp = gzopen(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav").c_str(), "rb");
|
||||
if(savegame_fp)
|
||||
{
|
||||
if(eeprom_size)
|
||||
gzread(savegame_fp, wsEEPROM, eeprom_size);
|
||||
if(sram_size)
|
||||
gzread(savegame_fp, wsSRAM, sram_size);
|
||||
gzclose(savegame_fp);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//MDFNMP_AddRAM(wsRAMSize, 0x00000, wsRAM); // 65536
|
||||
|
||||
//if(sram_size)
|
||||
// MDFNMP_AddRAM(sram_size, 0x10000, wsSRAM);
|
||||
}
|
||||
|
||||
void Memory::Reset()
|
||||
{
|
||||
memset(wsRAM, 0, 65536);
|
||||
|
||||
wsRAM[0x75AC] = 0x41;
|
||||
wsRAM[0x75AD] = 0x5F;
|
||||
wsRAM[0x75AE] = 0x43;
|
||||
wsRAM[0x75AF] = 0x31;
|
||||
wsRAM[0x75B0] = 0x6E;
|
||||
wsRAM[0x75B1] = 0x5F;
|
||||
wsRAM[0x75B2] = 0x63;
|
||||
wsRAM[0x75B3] = 0x31;
|
||||
|
||||
std::memset(BankSelector, 0, sizeof(BankSelector));
|
||||
ButtonWhich = 0;
|
||||
ButtonReadLatch = 0;
|
||||
DMASource = 0;
|
||||
DMADest = 0;
|
||||
DMALength = 0;
|
||||
DMAControl = 0;
|
||||
|
||||
SoundDMASource = 0;
|
||||
SoundDMALength = 0;
|
||||
SoundDMAControl = 0;
|
||||
|
||||
CommControl = 0;
|
||||
CommData = 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef __WSWAN_MEMORY_H
|
||||
#define __WSWAN_MEMORY_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
class Memory
|
||||
{
|
||||
public:
|
||||
~Memory();
|
||||
|
||||
uint8 Read20(uint32);
|
||||
void Write20(uint32 address,uint8 data);
|
||||
|
||||
void Init(bool SkipSaveLoad, const Settings &settings);
|
||||
//void Kill();
|
||||
|
||||
void CheckSoundDMA();
|
||||
void Reset();
|
||||
void writeport(uint32 IOPort, uint8 V);
|
||||
uint8 readport(uint32 number);
|
||||
uint32 GetRegister(const unsigned int id, char *special, const uint32 special_len);
|
||||
void SetRegister(const unsigned int id, uint32 value);
|
||||
|
||||
private:
|
||||
bool SkipSL; // Skip save and load
|
||||
|
||||
public:
|
||||
uint8 wsRAM[65536];
|
||||
uint8 *wsCartROM;
|
||||
uint32 rom_size;
|
||||
uint32 sram_size;
|
||||
uint32 eeprom_size;
|
||||
|
||||
uint16 WSButtonStatus; // bitfield of buttons, indeed
|
||||
|
||||
private:
|
||||
uint8 *wsSRAM; // = NULL;
|
||||
|
||||
|
||||
uint8 ButtonWhich, ButtonReadLatch;
|
||||
|
||||
uint32 DMASource, DMADest;
|
||||
uint16 DMALength;
|
||||
uint8 DMAControl;
|
||||
|
||||
uint32 SoundDMASource;
|
||||
uint16 SoundDMALength;
|
||||
uint8 SoundDMAControl;
|
||||
|
||||
uint8 BankSelector[4];
|
||||
|
||||
uint8 CommControl, CommData;
|
||||
|
||||
bool language;
|
||||
|
||||
|
||||
public:
|
||||
System *sys;
|
||||
private:
|
||||
void CheckDMA();
|
||||
|
||||
};
|
||||
|
||||
|
||||
//extern uint8 wsRAM[65536];
|
||||
//extern uint8 *wsCartROM;
|
||||
//extern uint32 eeprom_size;
|
||||
//extern uint8 wsEEPROM[2048];
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
MEMORY_GSREG_ROMBBSLCT = 0,
|
||||
MEMORY_GSREG_BNK1SLCT,
|
||||
MEMORY_GSREG_BNK2SLCT,
|
||||
MEMORY_GSREG_BNK3SLCT,
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,138 @@
|
|||
------------------------------------------------------------------------
|
||||
r26 | 2009-10-02 13:36:47 +0400 | 2 lines
|
||||
|
||||
[Issue 5] Change <stdint.h> to "stdint.h" to let compiler search for it in local directory.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r25 | 2009-09-17 23:46:49 +0400 | 2 lines
|
||||
|
||||
[Issue 4] Fix incorrect int8_t behaviour if compiled with /J flag.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r24 | 2009-05-13 14:53:48 +0400 | 2 lines
|
||||
|
||||
Forgot about #ifdef __cplusplus guard around 'extern "C"', so inclusion to C files has been broken.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r23 | 2009-05-12 01:27:45 +0400 | 3 lines
|
||||
|
||||
[Issue 2] Always wrap <wcharîàž with external "C" {}.
|
||||
It turns out that not only Visual Studio 6 requires this, but also newer versions when compiling for ARM.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r22 | 2009-05-11 22:22:15 +0400 | 3 lines
|
||||
|
||||
[Issue 3] Visual Studio 6 and Embedded Visual C++ 4 doesn't realize that, e.g. char has the same size as __int8 so we give up on __intX for them.
|
||||
his should close Issue 3 in issue tracker.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r21 | 2008-07-17 09:47:22 +0400 | 4 lines
|
||||
|
||||
Get rid of these compiler warnings when compiling for 32-bit:
|
||||
warning C4311: 'type cast' : pointer truncation from 'void *' to 'uintptr_t'
|
||||
warning C4312: 'type cast' : conversion from 'uintptr_t' to 'const void *' of greater size
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r20 | 2007-10-09 16:54:27 +0400 | 2 lines
|
||||
|
||||
Better C99 conformance: macros for format specifiers should only be included in C++ implementations if __STDC_FORMAT_MACROS is defined before <inttypes.h> is included.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r19 | 2007-07-04 02:14:40 +0400 | 3 lines
|
||||
|
||||
Explicitly cast to appropriate type INT8_MIN, INT16_MIN, INT32_MIN and INT64_MIN constants.
|
||||
Due to their unusual definition in Visual Studio headers (-_Ix_MAX-1) they are propagated to int and thus do not have expected type, causing VS6 strict compiler to claim about type inconsistency.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r18 | 2007-06-26 16:53:23 +0400 | 2 lines
|
||||
|
||||
Better handling of (U)INTx_C macros - now they generate constants of exact width.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r17 | 2007-03-29 20:16:14 +0400 | 2 lines
|
||||
|
||||
Fix typo: Miscrosoft -> Microsoft.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r16 | 2007-02-24 17:32:58 +0300 | 4 lines
|
||||
|
||||
Remove <BaseTsd.h> include, as it is not present in Visual Studio 2005 Epxress Edition and required only for INT_PTR and UINT_PTR types.
|
||||
|
||||
'intptr_t' and 'uintptr_t' types now defined explicitly with #ifdef _WIN64.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r15 | 2007-02-11 20:53:05 +0300 | 2 lines
|
||||
|
||||
More correct fix for compilation under VS6.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r14 | 2007-02-11 20:04:32 +0300 | 2 lines
|
||||
|
||||
Bugfix: fix compiling under VS6, when stdint.h enclosed in 'extern "C" {}'.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r13 | 2006-12-13 16:53:11 +0300 | 2 lines
|
||||
|
||||
Make _inline modifier for imaxdiv default option. Use STATIC_IMAXDIV to make it static.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r12 | 2006-12-13 16:42:24 +0300 | 2 lines
|
||||
|
||||
Error message changed: VC6 supported from now.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r11 | 2006-12-13 16:39:33 +0300 | 2 lines
|
||||
|
||||
All (U)INT* types changed to (unsigned) __int*. This should make stdint.h compatible with VC6.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r10 | 2006-12-13 16:20:57 +0300 | 3 lines
|
||||
|
||||
Added INLINE_IMAXDIV define switch.
|
||||
If INLINE_IMAXDIV is defined imaxdiv() have static modifier. If not - it is _inline.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r9 | 2006-12-13 15:53:52 +0300 | 2 lines
|
||||
|
||||
Error message for non-MSC compiler changed.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r8 | 2006-12-13 12:47:48 +0300 | 2 lines
|
||||
|
||||
Added #ifndef for SIZE_MAX (it is defined in limits.h on MSVSC 8).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r7 | 2006-12-13 01:08:02 +0300 | 2 lines
|
||||
|
||||
License chaged to BSD-derivative.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r6 | 2006-12-13 00:53:20 +0300 | 2 lines
|
||||
|
||||
Added <wchar.h> include to avoid warnings when it is included after stdint.h.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r5 | 2006-12-12 00:58:05 +0300 | 2 lines
|
||||
|
||||
BUGFIX: Definitions of INTPTR_MIN, INTPTR_MAX and UINTPTR_MAX for WIN32 and WIN64 was mixed up.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r4 | 2006-12-12 00:51:55 +0300 | 2 lines
|
||||
|
||||
Rise #error if _MSC_VER is not defined. I.e. compiler other then Microsoft Visual C++ is used.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r3 | 2006-12-11 22:54:14 +0300 | 2 lines
|
||||
|
||||
Added <limits.h> include to stdint.h.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r2 | 2006-12-11 21:39:27 +0300 | 2 lines
|
||||
|
||||
Initial check in.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
r1 | 2006-12-11 21:30:23 +0300 | 1 line
|
||||
|
||||
Initial directory structure.
|
||||
------------------------------------------------------------------------
|
|
@ -0,0 +1,305 @@
|
|||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// The fscanf macros for signed integers are:
|
||||
#define SCNd8 "d"
|
||||
#define SCNi8 "i"
|
||||
#define SCNdLEAST8 "d"
|
||||
#define SCNiLEAST8 "i"
|
||||
#define SCNdFAST8 "d"
|
||||
#define SCNiFAST8 "i"
|
||||
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNdFAST16 "hd"
|
||||
#define SCNiFAST16 "hi"
|
||||
|
||||
#define SCNd32 "ld"
|
||||
#define SCNi32 "li"
|
||||
#define SCNdLEAST32 "ld"
|
||||
#define SCNiLEAST32 "li"
|
||||
#define SCNdFAST32 "ld"
|
||||
#define SCNiFAST32 "li"
|
||||
|
||||
#define SCNd64 "I64d"
|
||||
#define SCNi64 "I64i"
|
||||
#define SCNdLEAST64 "I64d"
|
||||
#define SCNiLEAST64 "I64i"
|
||||
#define SCNdFAST64 "I64d"
|
||||
#define SCNiFAST64 "I64i"
|
||||
|
||||
#define SCNdMAX "I64d"
|
||||
#define SCNiMAX "I64i"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNdPTR "I64d"
|
||||
# define SCNiPTR "I64i"
|
||||
#else // _WIN64 ][
|
||||
# define SCNdPTR "ld"
|
||||
# define SCNiPTR "li"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// The fscanf macros for unsigned integers are:
|
||||
#define SCNo8 "o"
|
||||
#define SCNu8 "u"
|
||||
#define SCNx8 "x"
|
||||
#define SCNX8 "X"
|
||||
#define SCNoLEAST8 "o"
|
||||
#define SCNuLEAST8 "u"
|
||||
#define SCNxLEAST8 "x"
|
||||
#define SCNXLEAST8 "X"
|
||||
#define SCNoFAST8 "o"
|
||||
#define SCNuFAST8 "u"
|
||||
#define SCNxFAST8 "x"
|
||||
#define SCNXFAST8 "X"
|
||||
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNxLEAST16 "hx"
|
||||
#define SCNXLEAST16 "hX"
|
||||
#define SCNoFAST16 "ho"
|
||||
#define SCNuFAST16 "hu"
|
||||
#define SCNxFAST16 "hx"
|
||||
#define SCNXFAST16 "hX"
|
||||
|
||||
#define SCNo32 "lo"
|
||||
#define SCNu32 "lu"
|
||||
#define SCNx32 "lx"
|
||||
#define SCNX32 "lX"
|
||||
#define SCNoLEAST32 "lo"
|
||||
#define SCNuLEAST32 "lu"
|
||||
#define SCNxLEAST32 "lx"
|
||||
#define SCNXLEAST32 "lX"
|
||||
#define SCNoFAST32 "lo"
|
||||
#define SCNuFAST32 "lu"
|
||||
#define SCNxFAST32 "lx"
|
||||
#define SCNXFAST32 "lX"
|
||||
|
||||
#define SCNo64 "I64o"
|
||||
#define SCNu64 "I64u"
|
||||
#define SCNx64 "I64x"
|
||||
#define SCNX64 "I64X"
|
||||
#define SCNoLEAST64 "I64o"
|
||||
#define SCNuLEAST64 "I64u"
|
||||
#define SCNxLEAST64 "I64x"
|
||||
#define SCNXLEAST64 "I64X"
|
||||
#define SCNoFAST64 "I64o"
|
||||
#define SCNuFAST64 "I64u"
|
||||
#define SCNxFAST64 "I64x"
|
||||
#define SCNXFAST64 "I64X"
|
||||
|
||||
#define SCNoMAX "I64o"
|
||||
#define SCNuMAX "I64u"
|
||||
#define SCNxMAX "I64x"
|
||||
#define SCNXMAX "I64X"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNoPTR "I64o"
|
||||
# define SCNuPTR "I64u"
|
||||
# define SCNxPTR "I64x"
|
||||
# define SCNXPTR "I64X"
|
||||
#else // _WIN64 ][
|
||||
# define SCNoPTR "lo"
|
||||
# define SCNuPTR "lu"
|
||||
# define SCNxPTR "lx"
|
||||
# define SCNXPTR "lX"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
|
@ -0,0 +1,247 @@
|
|||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2008 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
|
@ -0,0 +1,98 @@
|
|||
/* Cygne
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Dox dox@space.pl
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include <ctime>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
/*
|
||||
static uint64 CurrentTime;
|
||||
static uint32 ClockCycleCounter;
|
||||
static uint8 wsCA15;
|
||||
static uint8 Command, Data;
|
||||
*/
|
||||
|
||||
void RTC::Write(uint32 A, uint8 V)
|
||||
{
|
||||
switch(A)
|
||||
{
|
||||
case 0xca:
|
||||
if(V==0x15)
|
||||
wsCA15=0;
|
||||
Command = V;
|
||||
break;
|
||||
case 0xcb: Data = V; break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint8 RTC::Read(uint32 A)
|
||||
{
|
||||
switch(A)
|
||||
{
|
||||
case 0xca : return (Command|0x80);
|
||||
case 0xcb :
|
||||
if(Command == 0x15)
|
||||
{
|
||||
time_t long_time = CurrentTime;
|
||||
struct tm *newtime = gmtime( &long_time );
|
||||
|
||||
switch(wsCA15)
|
||||
{
|
||||
case 0: wsCA15++;return mBCD(newtime->tm_year-100);
|
||||
case 1: wsCA15++;return mBCD(newtime->tm_mon);
|
||||
case 2: wsCA15++;return mBCD(newtime->tm_mday);
|
||||
case 3: wsCA15++;return mBCD(newtime->tm_wday);
|
||||
case 4: wsCA15++;return mBCD(newtime->tm_hour);
|
||||
case 5: wsCA15++;return mBCD(newtime->tm_min);
|
||||
case 6: wsCA15=0;return mBCD(newtime->tm_sec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return Data | 0x80;
|
||||
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void RTC::Reset()
|
||||
{
|
||||
time_t happy_time = time(NULL);
|
||||
|
||||
CurrentTime = mktime(localtime(&happy_time));
|
||||
ClockCycleCounter = 0;
|
||||
wsCA15 = 0;
|
||||
}
|
||||
|
||||
void RTC::Clock(uint32 cycles)
|
||||
{
|
||||
ClockCycleCounter += cycles;
|
||||
while(ClockCycleCounter >= 3072000)
|
||||
{
|
||||
ClockCycleCounter -= 3072000;
|
||||
CurrentTime++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __WSWAN_RTC_H
|
||||
#define __WSWAN_RTC_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
class RTC
|
||||
{
|
||||
public:
|
||||
void Write(uint32 A, uint8 V);
|
||||
uint8 Read(uint32 A);
|
||||
void Reset();
|
||||
void Clock(uint32 cycles);
|
||||
|
||||
private:
|
||||
uint64 CurrentTime;
|
||||
uint32 ClockCycleCounter;
|
||||
uint8 wsCA15;
|
||||
uint8 Command, Data;
|
||||
public:
|
||||
System *sys;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,386 @@
|
|||
/* Mednafen - Multi-system Emulator
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
Noise emulation is almost certainly wrong wrong wrong. Testing on a real system is needed to determine LFSR(assuming it uses an LFSR) taps.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
#define MK_SAMPLE_CACHE \
|
||||
{ \
|
||||
int sample; \
|
||||
sample = (((ram[((SampleRAMPos << 6) + (sample_pos[ch] >> 1) + (ch << 4)) ] >> ((sample_pos[ch] & 1) ? 4 : 0)) & 0x0F)) - 0x8; \
|
||||
sample_cache[ch][0] = sample * ((volume[ch] >> 4) & 0x0F); \
|
||||
sample_cache[ch][1] = sample * ((volume[ch] >> 0) & 0x0F); \
|
||||
}
|
||||
|
||||
#define MK_SAMPLE_CACHE_NOISE \
|
||||
{ \
|
||||
int sample; \
|
||||
sample = ((nreg & 1) ? 0xF : 0x0) - 0x8; \
|
||||
sample_cache[ch][0] = sample * ((volume[ch] >> 4) & 0x0F); \
|
||||
sample_cache[ch][1] = sample * ((volume[ch] >> 0) & 0x0F); \
|
||||
}
|
||||
|
||||
|
||||
#define SYNCSAMPLE(wt) \
|
||||
{ \
|
||||
int32 left = sample_cache[ch][0], right = sample_cache[ch][1]; \
|
||||
WaveSynth.offset_inline(wt, left - last_val[ch][0], sbuf[0]); \
|
||||
WaveSynth.offset_inline(wt, right - last_val[ch][1], sbuf[1]); \
|
||||
last_val[ch][0] = left; \
|
||||
last_val[ch][1] = right; \
|
||||
}
|
||||
|
||||
#define SYNCSAMPLE_NOISE(wt) \
|
||||
{ \
|
||||
int32 left = sample_cache[ch][0], right = sample_cache[ch][1]; \
|
||||
NoiseSynth.offset_inline(wt, left - last_val[ch][0], sbuf[0]); \
|
||||
NoiseSynth.offset_inline(wt, right - last_val[ch][1], sbuf[1]); \
|
||||
last_val[ch][0] = left; \
|
||||
last_val[ch][1] = right; \
|
||||
}
|
||||
|
||||
void Sound::Update()
|
||||
{
|
||||
int32 run_time;
|
||||
const uint8 *ram = sys->memory.wsRAM;
|
||||
const uint32 current_ts = sys->cpu.timestamp;
|
||||
|
||||
//printf("%d\n", v30mz_timestamp);
|
||||
//printf("%02x %02x\n", control, noise_control);
|
||||
run_time = current_ts - last_ts;
|
||||
|
||||
for(unsigned int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
// Channel is disabled?
|
||||
if(!(control & (1 << ch)))
|
||||
continue;
|
||||
|
||||
if(ch == 1 && (control & 0x20)) // Direct D/A mode?
|
||||
{
|
||||
int32 neoval = (volume[ch] - 0x80) * voice_volume;
|
||||
|
||||
VoiceSynth.offset(current_ts, neoval - last_v_val, sbuf[0]);
|
||||
VoiceSynth.offset(current_ts, neoval - last_v_val, sbuf[1]);
|
||||
|
||||
last_v_val = neoval;
|
||||
}
|
||||
else if(ch == 2 && (control & 0x40) && sweep_value) // Sweep
|
||||
{
|
||||
uint32 tmp_pt = 2048 - period[ch];
|
||||
uint32 meow_timestamp = current_ts - run_time;
|
||||
uint32 tmp_run_time = run_time;
|
||||
|
||||
while(tmp_run_time)
|
||||
{
|
||||
int32 sub_run_time = tmp_run_time;
|
||||
|
||||
if(sub_run_time > sweep_8192_divider)
|
||||
sub_run_time = sweep_8192_divider;
|
||||
|
||||
sweep_8192_divider -= sub_run_time;
|
||||
if(sweep_8192_divider <= 0)
|
||||
{
|
||||
sweep_8192_divider += 8192;
|
||||
sweep_counter--;
|
||||
if(sweep_counter <= 0)
|
||||
{
|
||||
sweep_counter = sweep_step + 1;
|
||||
period[ch] = (period[ch] + (int8)sweep_value) & 0x7FF;
|
||||
}
|
||||
}
|
||||
|
||||
meow_timestamp += sub_run_time;
|
||||
if(tmp_pt > 4)
|
||||
{
|
||||
period_counter[ch] -= sub_run_time;
|
||||
while(period_counter[ch] <= 0)
|
||||
{
|
||||
sample_pos[ch] = (sample_pos[ch] + 1) & 0x1F;
|
||||
|
||||
MK_SAMPLE_CACHE;
|
||||
SYNCSAMPLE(meow_timestamp + period_counter[ch]);
|
||||
period_counter[ch] += tmp_pt;
|
||||
}
|
||||
}
|
||||
tmp_run_time -= sub_run_time;
|
||||
}
|
||||
}
|
||||
else if(ch == 3 && (noise_control & 0x10)) //(control & 0x80)) // Noise
|
||||
{
|
||||
uint32 tmp_pt = 2048 - period[ch];
|
||||
|
||||
period_counter[ch] -= run_time;
|
||||
while(period_counter[ch] <= 0)
|
||||
{
|
||||
// Yay, random numbers, so let's use totally wrong numbers to make them!
|
||||
const int bstab1[8] = { 14, 13, 12, 14, 12, 13, 14, 14 };
|
||||
const int bstab2[8] = { 13, 12, 9, 12, 1, 1, 5, 11 };
|
||||
//const int bstab1[8] = { 14, 13, 12, 14, 10, 9, 8, 13 };
|
||||
//const int bstab2[8] = { 13, 12, 9, 12, 1, 6, 4, 11 };
|
||||
nreg = (~((nreg << 1) | ( ((nreg >> bstab1[noise_control & 0x7]) & 1) ^ ((nreg >> bstab2[noise_control & 0x7]) & 1)))) & 0x7FFF;
|
||||
if(control & 0x80)
|
||||
{
|
||||
MK_SAMPLE_CACHE_NOISE;
|
||||
SYNCSAMPLE_NOISE(current_ts + period_counter[ch]);
|
||||
}
|
||||
else if(tmp_pt > 4)
|
||||
{
|
||||
sample_pos[ch] = (sample_pos[ch] + 1) & 0x1F;
|
||||
MK_SAMPLE_CACHE;
|
||||
SYNCSAMPLE(current_ts + period_counter[ch]);
|
||||
}
|
||||
period_counter[ch] += tmp_pt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 tmp_pt = 2048 - period[ch];
|
||||
|
||||
if(tmp_pt > 4)
|
||||
{
|
||||
period_counter[ch] -= run_time;
|
||||
while(period_counter[ch] <= 0)
|
||||
{
|
||||
sample_pos[ch] = (sample_pos[ch] + 1) & 0x1F;
|
||||
|
||||
MK_SAMPLE_CACHE;
|
||||
SYNCSAMPLE(current_ts + period_counter[ch]); // - period_counter[ch]);
|
||||
period_counter[ch] += tmp_pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int32 tmphv = HyperVoice;
|
||||
|
||||
if(tmphv - last_hv_val)
|
||||
{
|
||||
WaveSynth.offset_inline(current_ts, tmphv - last_hv_val, sbuf[0]);
|
||||
WaveSynth.offset_inline(current_ts, tmphv - last_hv_val, sbuf[1]);
|
||||
last_hv_val = tmphv;
|
||||
}
|
||||
}
|
||||
last_ts = current_ts;
|
||||
}
|
||||
|
||||
void Sound::Write(uint32 A, uint8 V)
|
||||
{
|
||||
Update();
|
||||
|
||||
if(A >= 0x80 && A <= 0x87)
|
||||
{
|
||||
int ch = (A - 0x80) >> 1;
|
||||
|
||||
if(A & 1)
|
||||
period[ch] = (period[ch] & 0x00FF) | ((V & 0x07) << 8);
|
||||
else
|
||||
period[ch] = (period[ch] & 0x0700) | ((V & 0xFF) << 0);
|
||||
}
|
||||
else if(A >= 0x88 && A <= 0x8B)
|
||||
{
|
||||
volume[A - 0x88] = V;
|
||||
}
|
||||
else if(A == 0x8C)
|
||||
sweep_value = V;
|
||||
else if(A == 0x8D)
|
||||
{
|
||||
sweep_step = V;
|
||||
sweep_counter = sweep_step + 1;
|
||||
sweep_8192_divider = 8192;
|
||||
}
|
||||
else if(A == 0x8E)
|
||||
{
|
||||
noise_control = V;
|
||||
if(V & 0x8) nreg = 1;
|
||||
//printf("NOISECONTROL: %02x\n", V);
|
||||
}
|
||||
else if(A == 0x90)
|
||||
{
|
||||
for(int n = 0; n < 4; n++)
|
||||
if(!(control & (1 << n)) && (V & (1 << n)))
|
||||
{
|
||||
period_counter[n] = 0;
|
||||
sample_pos[n] = 0x1F;
|
||||
}
|
||||
control = V;
|
||||
//printf("Sound Control: %02x\n", V);
|
||||
}
|
||||
else if(A == 0x91)
|
||||
{
|
||||
output_control = V & 0xF;
|
||||
//printf("%02x, %02x\n", V, (V >> 1) & 3);
|
||||
}
|
||||
else if(A == 0x92)
|
||||
nreg = (nreg & 0xFF00) | (V << 0);
|
||||
else if(A == 0x93)
|
||||
nreg = (nreg & 0x00FF) | ((V & 0x7F) << 8);
|
||||
else if(A == 0x94)
|
||||
{
|
||||
voice_volume = V & 0xF;
|
||||
//printf("%02x\n", V);
|
||||
}
|
||||
else switch(A)
|
||||
{
|
||||
case 0x8F: SampleRAMPos = V; break;
|
||||
case 0x95: HyperVoice = V; break; // Pick a port, any port?!
|
||||
//default: printf("%04x:%02x\n", A, V); break;
|
||||
}
|
||||
Update();
|
||||
}
|
||||
|
||||
uint8 Sound::Read(uint32 A)
|
||||
{
|
||||
Update();
|
||||
|
||||
if(A >= 0x80 && A <= 0x87)
|
||||
{
|
||||
int ch = (A - 0x80) >> 1;
|
||||
|
||||
if(A & 1)
|
||||
return(period[ch] >> 8);
|
||||
else
|
||||
return(period[ch]);
|
||||
}
|
||||
else if(A >= 0x88 && A <= 0x8B)
|
||||
return(volume[A - 0x88]);
|
||||
else switch(A)
|
||||
{
|
||||
default: /*printf("SoundRead: %04x\n", A);*/ return(0);
|
||||
case 0x8C: return(sweep_value);
|
||||
case 0x8D: return(sweep_step);
|
||||
case 0x8E: return(noise_control);
|
||||
case 0x8F: return(SampleRAMPos);
|
||||
case 0x90: return(control);
|
||||
case 0x91: return(output_control | 0x80);
|
||||
case 0x92: return((nreg >> 0) & 0xFF);
|
||||
case 0x93: return((nreg >> 8) & 0xFF);
|
||||
case 0x94: return(voice_volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32 Sound::Flush(int16 *SoundBuf, const int32 MaxSoundFrames)
|
||||
{
|
||||
int32 FrameCount = 0;
|
||||
|
||||
Update();
|
||||
|
||||
if(SoundBuf)
|
||||
{
|
||||
for(int y = 0; y < 2; y++)
|
||||
{
|
||||
sbuf[y]->end_frame(sys->cpu.timestamp);
|
||||
FrameCount = sbuf[y]->read_samples(SoundBuf + y, MaxSoundFrames, true);
|
||||
}
|
||||
}
|
||||
|
||||
last_ts = 0;
|
||||
|
||||
return(FrameCount);
|
||||
}
|
||||
|
||||
// Call before wsRAM is updated
|
||||
void Sound::CheckRAMWrite(uint32 A)
|
||||
{
|
||||
if((A >> 6) == SampleRAMPos)
|
||||
Update();
|
||||
}
|
||||
|
||||
void Sound::Init()
|
||||
{
|
||||
}
|
||||
|
||||
Sound::Sound()
|
||||
{
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
sbuf[i] = new Blip_Buffer();
|
||||
|
||||
sbuf[i]->set_sample_rate(0 ? 0 : 44100, 60);
|
||||
sbuf[i]->clock_rate((long)(3072000));
|
||||
sbuf[i]->bass_freq(20);
|
||||
}
|
||||
|
||||
double eff_volume = 1.0 / 4;
|
||||
|
||||
WaveSynth.volume(eff_volume);
|
||||
NoiseSynth.volume(eff_volume);
|
||||
VoiceSynth.volume(eff_volume);
|
||||
|
||||
SetRate(44100);
|
||||
}
|
||||
|
||||
Sound::~Sound()
|
||||
{
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
if(sbuf[i])
|
||||
{
|
||||
delete sbuf[i];
|
||||
sbuf[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Sound::SetRate(uint32 rate)
|
||||
{
|
||||
for(int i = 0; i < 2; i++)
|
||||
sbuf[i]->set_sample_rate(rate?rate:44100, 60);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void Sound::Reset()
|
||||
{
|
||||
std::memset(period, 0, sizeof(period));
|
||||
std::memset(volume, 0, sizeof(volume));
|
||||
voice_volume = 0;
|
||||
sweep_step = 0;
|
||||
sweep_value = 0;
|
||||
noise_control = 0;
|
||||
control = 0;
|
||||
output_control = 0;
|
||||
|
||||
sweep_8192_divider = 8192;
|
||||
sweep_counter = 0;
|
||||
SampleRAMPos = 0;
|
||||
std::memset(period_counter, 0, sizeof(period_counter));
|
||||
std::memset(sample_pos, 0, sizeof(sample_pos));
|
||||
nreg = 1;
|
||||
|
||||
std::memset(sample_cache, 0, sizeof(sample_cache));
|
||||
std::memset(last_val, 0, sizeof(last_val));
|
||||
last_v_val = 0;
|
||||
|
||||
HyperVoice = 0;
|
||||
last_hv_val = 0;
|
||||
|
||||
for(int y = 0; y < 2; y++)
|
||||
sbuf[y]->clear();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef __WSWAN_SOUND_H
|
||||
#define __WSWAN_SOUND_H
|
||||
|
||||
#include "system.h"
|
||||
#include <blip/Blip_Buffer.h>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
class Sound
|
||||
{
|
||||
public:
|
||||
Sound();
|
||||
~Sound();
|
||||
|
||||
int32 Flush(int16 *SoundBuf, const int32 MaxSoundFrames);
|
||||
|
||||
void Init();
|
||||
void Kill();
|
||||
void SetMultiplier(double multiplier);
|
||||
bool SetRate(uint32 rate);
|
||||
|
||||
void Write(uint32, uint8);
|
||||
uint8 Read(uint32);
|
||||
void Reset();
|
||||
void CheckRAMWrite(uint32 A);
|
||||
|
||||
private:
|
||||
Blip_Synth<blip_good_quality, 256> WaveSynth;
|
||||
Blip_Synth<blip_med_quality, 256> NoiseSynth;
|
||||
Blip_Synth<blip_good_quality, 256 * 15> VoiceSynth;
|
||||
|
||||
Blip_Buffer *sbuf[2]; // = { NULL };
|
||||
|
||||
uint16 period[4];
|
||||
uint8 volume[4]; // left volume in upper 4 bits, right in lower 4 bits
|
||||
uint8 voice_volume;
|
||||
|
||||
uint8 sweep_step, sweep_value;
|
||||
uint8 noise_control;
|
||||
uint8 control;
|
||||
uint8 output_control;
|
||||
|
||||
int32 sweep_8192_divider;
|
||||
uint8 sweep_counter;
|
||||
uint8 SampleRAMPos;
|
||||
|
||||
int32 sample_cache[4][2];
|
||||
|
||||
int32 last_v_val;
|
||||
|
||||
uint8 HyperVoice;
|
||||
int32 last_hv_val;
|
||||
|
||||
int32 period_counter[4];
|
||||
int32 last_val[4][2]; // Last outputted value, l&r
|
||||
uint8 sample_pos[4];
|
||||
uint16 nreg;
|
||||
uint32 last_ts;
|
||||
|
||||
private:
|
||||
void Update();
|
||||
|
||||
public:
|
||||
System *sys;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
===================================================================================
|
||||
Cygne WIN v 2.1a (c) Dox 2002 dox@space.pl
|
||||
===================================================================================
|
||||
|
||||
NEC cpu core by Bryan McPhail,Oliver Bergmann, Fabrice Frances and David Hedley
|
||||
Zlib by Jean-loup Gailly and Mark Adler
|
||||
|
||||
===================================================================================
|
||||
*/
|
||||
|
||||
const uint8 startio[256]={
|
||||
0x00,//0
|
||||
0x00,//1
|
||||
0x9d,//2
|
||||
0xbb,//3
|
||||
0x00,//4
|
||||
0x00,//5
|
||||
0x00,//6
|
||||
0x26,//7
|
||||
0xfe,//8
|
||||
0xde,//9
|
||||
0xf9,//a
|
||||
0xfb,//b
|
||||
0xdb,//c
|
||||
0xd7,//d
|
||||
0x7f,//e
|
||||
0xf5,//f
|
||||
0x00,//10
|
||||
0x00,//11
|
||||
0x00,//12
|
||||
0x00,//13
|
||||
0x01,//14
|
||||
0x00,//15
|
||||
0x9e,//16
|
||||
0x9b,//17
|
||||
0x00,//18
|
||||
0x00,//19
|
||||
0x00,//1a
|
||||
0x00,//1b
|
||||
0x99,//1c
|
||||
0xfd,//1d
|
||||
0xb7,//1e
|
||||
0xdf,//1f
|
||||
0x30,//20
|
||||
0x57,//21
|
||||
0x75,//22
|
||||
0x76,//23
|
||||
0x15,//24
|
||||
0x73,//25
|
||||
0x77,//26
|
||||
0x77,//27
|
||||
0x20,//28
|
||||
0x75,//29
|
||||
0x50,//2a
|
||||
0x36,//2b
|
||||
0x70,//2c
|
||||
0x67,//2d
|
||||
0x50,//2e
|
||||
0x77,//2f
|
||||
0x57,//30
|
||||
0x54,//31
|
||||
0x75,//32
|
||||
0x77,//33
|
||||
0x75,//34
|
||||
0x17,//35
|
||||
0x37,//36
|
||||
0x73,//37
|
||||
0x50,//38
|
||||
0x57,//39
|
||||
0x60,//3a
|
||||
0x77,//3b
|
||||
0x70,//3c
|
||||
0x77,//3d
|
||||
0x10,//3e
|
||||
0x73,//3f
|
||||
0x00,//40
|
||||
0x00,//41
|
||||
0x00,//42
|
||||
0x00,//43
|
||||
0x00,//44
|
||||
0x00,//45
|
||||
0x00,//46
|
||||
0x00,//47
|
||||
0x00,//48
|
||||
0x00,//49
|
||||
0x00,//4a
|
||||
0x00,//4b
|
||||
0x00,//4c
|
||||
0x00,//4d
|
||||
0x00,//4e
|
||||
0x00,//4f
|
||||
0x00,//50
|
||||
0x00,//51
|
||||
0x00,//52
|
||||
0x00,//53
|
||||
0x00,//54
|
||||
0x00,//55
|
||||
0x00,//56
|
||||
0x00,//57
|
||||
0x00,//58
|
||||
0x00,//59
|
||||
0x00,//5a
|
||||
0x00,//5b
|
||||
0x00,//5c
|
||||
0x00,//5d
|
||||
0x00,//5e
|
||||
0x00,//5f
|
||||
0x0a,//60
|
||||
0x00,//61
|
||||
0x00,//62
|
||||
0x00,//63
|
||||
0x00,//64
|
||||
0x00,//65
|
||||
0x00,//66
|
||||
0x00,//67
|
||||
0x00,//68
|
||||
0x00,//69
|
||||
0x00,//6a
|
||||
0x0f,//6b
|
||||
0x00,//6c
|
||||
0x00,//6d
|
||||
0x00,//6e
|
||||
0x00,//6f
|
||||
0x00,//70
|
||||
0x00,//71
|
||||
0x00,//72
|
||||
0x00,//73
|
||||
0x00,//74
|
||||
0x00,//75
|
||||
0x00,//76
|
||||
0x00,//77
|
||||
0x00,//78
|
||||
0x00,//79
|
||||
0x00,//7a
|
||||
0x00,//7b
|
||||
0x00,//7c
|
||||
0x00,//7d
|
||||
0x00,//7e
|
||||
0x00,//7f
|
||||
0x00,//80
|
||||
0x00,//81
|
||||
0x00,//82
|
||||
0x00,//83
|
||||
0x00,//84
|
||||
0x00,//85
|
||||
0x00,//86
|
||||
0x00,//87
|
||||
0x00,//88
|
||||
0x00,//89
|
||||
0x00,//8a
|
||||
0x00,//8b
|
||||
0x00,//8c
|
||||
0x1f,//8d 1d ?
|
||||
0x00,//8e
|
||||
0x00,//8f
|
||||
0x00,//90
|
||||
0x00,//91
|
||||
0x00,//92
|
||||
0x00,//93
|
||||
0x00,//94
|
||||
0x00,//95
|
||||
0x00,//96
|
||||
0x00,//97
|
||||
0x00,//98
|
||||
0x00,//99
|
||||
0x00,//9a
|
||||
0x00,//9b
|
||||
0x00,//9c
|
||||
0x00,//9d
|
||||
0x03,//9e
|
||||
0x00,//9f
|
||||
0x87-2,//a0
|
||||
0x00,//a1
|
||||
0x00,//a2
|
||||
0x00,//a3
|
||||
0x0,//a4 2b
|
||||
0x0,//a5 7f
|
||||
0x4f,//a6
|
||||
0xff,//a7 cf ?
|
||||
0x00,//a8
|
||||
0x00,//a9
|
||||
0x00,//aa
|
||||
0x00,//ab
|
||||
0x00,//ac
|
||||
0x00,//ad
|
||||
0x00,//ae
|
||||
0x00,//af
|
||||
0x00,//b0
|
||||
0xdb,//b1
|
||||
0x00,//b2
|
||||
0x00,//b3
|
||||
0x00,//b4
|
||||
0x40,//b5
|
||||
0x00,//b6
|
||||
0x00,//b7
|
||||
0x00,//b8
|
||||
0x00,//b9
|
||||
0x01,//ba
|
||||
0x00,//bb
|
||||
0x42,//bc
|
||||
0x00,//bd
|
||||
0x83,//be
|
||||
0x00,//bf
|
||||
0x2f,//c0
|
||||
0x3f,//c1
|
||||
0xff,//c2
|
||||
0xff,//c3
|
||||
0x00,//c4
|
||||
0x00,//c5
|
||||
0x00,//c6
|
||||
0x00,//c7
|
||||
|
||||
0xd1,//c8?
|
||||
0xd1,//c9
|
||||
0xd1,//ca
|
||||
0xd1,//cb
|
||||
0xd1,//cc
|
||||
0xd1,//cd
|
||||
0xd1,//ce
|
||||
0xd1,//cf
|
||||
0xd1,//d0
|
||||
0xd1,//d1
|
||||
0xd1,//d2
|
||||
0xd1,//d3
|
||||
0xd1,//d4
|
||||
0xd1,//d5
|
||||
0xd1,//d6
|
||||
0xd1,//d7
|
||||
0xd1,//d8
|
||||
0xd1,//d9
|
||||
0xd1,//da
|
||||
0xd1,//db
|
||||
0xd1,//dc
|
||||
0xd1,//dd
|
||||
0xd1,//de
|
||||
0xd1,//df
|
||||
0xd1,//e0
|
||||
0xd1,//e1
|
||||
0xd1,//e2
|
||||
0xd1,//e3
|
||||
0xd1,//e4
|
||||
0xd1,//e5
|
||||
0xd1,//e6
|
||||
0xd1,//e7
|
||||
0xd1,//e8
|
||||
0xd1,//e9
|
||||
0xd1,//ea
|
||||
0xd1,//eb
|
||||
0xd1,//ec
|
||||
0xd1,//ed
|
||||
0xd1,//ee
|
||||
0xd1,//ef
|
||||
0xd1,//f0
|
||||
0xd1,//f1
|
||||
0xd1,//f2
|
||||
0xd1,//f3
|
||||
0xd1,//f4
|
||||
0xd1,//f5
|
||||
0xd1,//f6
|
||||
0xd1,//f7
|
||||
0xd1,//f8
|
||||
0xd1,//f9
|
||||
0xd1,//fa
|
||||
0xd1,//fb
|
||||
0xd1,//fc
|
||||
0xd1,//fd
|
||||
0xd1,//fe
|
||||
0xd1};//ff
|
|
@ -0,0 +1,315 @@
|
|||
/* Cygne
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Dox dox@space.pl
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
#define EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
#include "start.inc"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const uint8 id;
|
||||
const char *name;
|
||||
} DLEntry;
|
||||
|
||||
static const DLEntry Developers[] =
|
||||
{
|
||||
{ 0x01, "Bandai" },
|
||||
{ 0x02, "Taito" },
|
||||
{ 0x03, "Tomy" },
|
||||
{ 0x04, "Koei" },
|
||||
{ 0x05, "Data East" },
|
||||
{ 0x06, "Asmik" }, // Asmik Ace?
|
||||
{ 0x07, "Media Entertainment" },
|
||||
{ 0x08, "Nichibutsu" },
|
||||
{ 0x0A, "Coconuts Japan" },
|
||||
{ 0x0B, "Sammy" },
|
||||
{ 0x0C, "Sunsoft" },
|
||||
{ 0x0D, "Mebius" },
|
||||
{ 0x0E, "Banpresto" },
|
||||
{ 0x10, "Jaleco" },
|
||||
{ 0x11, "Imagineer" },
|
||||
{ 0x12, "Konami" },
|
||||
{ 0x16, "Kobunsha" },
|
||||
{ 0x17, "Bottom Up" },
|
||||
{ 0x18, "Naxat" }, // Mechanic Arms? Media Entertainment? Argh!
|
||||
{ 0x19, "Sunrise" },
|
||||
{ 0x1A, "Cyberfront" },
|
||||
{ 0x1B, "Megahouse" },
|
||||
{ 0x1D, "Interbec" },
|
||||
{ 0x1E, "NAC" },
|
||||
{ 0x1F, "Emotion" }, // Bandai Visual??
|
||||
{ 0x20, "Athena" },
|
||||
{ 0x21, "KID" },
|
||||
{ 0x24, "Omega Micott" },
|
||||
{ 0x25, "Upstar" },
|
||||
{ 0x26, "Kadokawa/Megas" },
|
||||
{ 0x27, "Cocktail Soft" },
|
||||
{ 0x28, "Squaresoft" },
|
||||
{ 0x2B, "TomCreate" },
|
||||
{ 0x2D, "Namco" },
|
||||
{ 0x2F, "Gust" },
|
||||
{ 0x36, "Capcom" },
|
||||
};
|
||||
|
||||
void System::Reset()
|
||||
{
|
||||
cpu.reset();
|
||||
memory.Reset();
|
||||
gfx.Reset();
|
||||
sound.Reset();
|
||||
interrupt.Reset();
|
||||
rtc.Reset();
|
||||
eeprom.Reset();
|
||||
|
||||
for(int u0=0;u0<0xc9;u0++)
|
||||
{
|
||||
if(u0 != 0xC4 && u0 != 0xC5 && u0 != 0xBA && u0 != 0xBB)
|
||||
memory.writeport(u0,startio[u0]);
|
||||
}
|
||||
|
||||
cpu.set_reg(NEC_SS,0);
|
||||
cpu.set_reg(NEC_SP,0x2000);
|
||||
}
|
||||
|
||||
|
||||
void System::Advance(uint16 buttons, bool novideo, uint32 *surface, int16 *soundbuff, int &soundbuffsize)
|
||||
{
|
||||
|
||||
memory.WSButtonStatus = buttons;
|
||||
while (!gfx.ExecuteLine(surface, novideo))
|
||||
{
|
||||
}
|
||||
|
||||
soundbuffsize = sound.Flush(soundbuff, soundbuffsize);
|
||||
|
||||
// cycles elapsed in the frame can be read here
|
||||
// how is this OK to reset? it's only used by the sound code, so once the sound for the frame has
|
||||
// been collected, it's OK to zero. indeed, it should be done as there's no rollover protection
|
||||
cpu.timestamp = 0;
|
||||
|
||||
}
|
||||
|
||||
// Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
// Rounds up to the nearest power of 2.
|
||||
static INLINE uint64 round_up_pow2(uint64 v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v |= v >> 32;
|
||||
v++;
|
||||
|
||||
v += (v == 0);
|
||||
|
||||
return(v);
|
||||
}
|
||||
|
||||
bool System::Load(const uint8 *data, int length, const Settings &settings)
|
||||
{
|
||||
uint32 real_rom_size;
|
||||
|
||||
if(length < 65536)
|
||||
{
|
||||
Debug::puts("Rom image is too small (<64K)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!memcmp(data + length - 0x20, "WSRF", 4))
|
||||
{
|
||||
Debug::puts("WSRF files not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
real_rom_size = (length + 0xFFFF) & ~0xFFFF;
|
||||
memory.rom_size = round_up_pow2(real_rom_size);
|
||||
|
||||
memory.wsCartROM = (uint8 *)std::calloc(1, memory.rom_size);
|
||||
|
||||
|
||||
if(real_rom_size < memory.rom_size)
|
||||
memset(memory.wsCartROM, 0xFF, memory.rom_size - real_rom_size);
|
||||
|
||||
memcpy(memory.wsCartROM + (memory.rom_size - real_rom_size), data, length);
|
||||
|
||||
|
||||
uint8 header[10];
|
||||
memcpy(header, memory.wsCartROM + memory.rom_size - 10, 10);
|
||||
|
||||
{
|
||||
const char *developer_name = "???";
|
||||
for(unsigned int x = 0; x < sizeof(Developers) / sizeof(DLEntry); x++)
|
||||
{
|
||||
if(Developers[x].id == header[0])
|
||||
{
|
||||
developer_name = Developers[x].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Debug::printf("Developer: %s (0x%02x)\n", developer_name, header[0]);
|
||||
}
|
||||
|
||||
memory.sram_size = 0;
|
||||
memory.eeprom_size = 0;
|
||||
|
||||
switch(header[5])
|
||||
{
|
||||
case 0x01: memory.sram_size = 8*1024; break;
|
||||
case 0x02: memory.sram_size = 32*1024; break;
|
||||
case 0x03: memory.sram_size = 16 * 65536; break;
|
||||
case 0x04: memory.sram_size = 32 * 65536; break; // Dicing Knight!
|
||||
|
||||
case 0x10: memory.eeprom_size = 128; break;
|
||||
case 0x20: memory.eeprom_size = 2*1024; break;
|
||||
case 0x50: memory.eeprom_size = 1024; break;
|
||||
}
|
||||
|
||||
//printf("%02x\n", header[5]);
|
||||
|
||||
if(memory.eeprom_size)
|
||||
Debug::printf("EEPROM: %d bytes\n", memory.eeprom_size);
|
||||
|
||||
if(memory.sram_size)
|
||||
Debug::printf("Battery-backed RAM: %d bytes\n", memory.sram_size);
|
||||
|
||||
Debug::printf("Recorded Checksum: 0x%04x\n", header[8] | (header[9] << 8));
|
||||
{
|
||||
uint16 real_crc = 0;
|
||||
for(unsigned int i = 0; i < memory.rom_size - 2; i++)
|
||||
real_crc += memory.wsCartROM[i];
|
||||
Debug::printf("Real Checksum: 0x%04x\n", real_crc);
|
||||
}
|
||||
|
||||
if((header[8] | (header[9] << 8)) == 0x8de1 && (header[0]==0x01)&&(header[2]==0x27)) /* Detective Conan */
|
||||
{
|
||||
Debug::printf("Activating Detective Conan Hack\n");
|
||||
/* WS cpu is using cache/pipeline or there's protected ROM bank where pointing CS */
|
||||
memory.wsCartROM[0xfffe8]=0xea;
|
||||
memory.wsCartROM[0xfffe9]=0x00;
|
||||
memory.wsCartROM[0xfffea]=0x00;
|
||||
memory.wsCartROM[0xfffeb]=0x00;
|
||||
memory.wsCartROM[0xfffec]=0x20;
|
||||
}
|
||||
|
||||
|
||||
if(header[6] & 0x1)
|
||||
{
|
||||
//MDFNGameInfo->rotated = MDFN_ROTATE90;
|
||||
}
|
||||
|
||||
|
||||
//MDFNMP_Init(16384, (1 << 20) / 1024);
|
||||
|
||||
cpu.init();
|
||||
|
||||
// TODO: control WSC setting
|
||||
// TODO: rip out skipsaveload code
|
||||
|
||||
memory.Init(false, settings);
|
||||
|
||||
gfx.Init();
|
||||
//MDFNGameInfo->fps = (uint32)((uint64)3072000 * 65536 * 256 / (159*256));
|
||||
|
||||
sound.Init();
|
||||
|
||||
gfx.MakeTiles();
|
||||
|
||||
Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *System::operator new(std::size_t size)
|
||||
{
|
||||
void *p = ::operator new(size);
|
||||
std::memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
System::System()
|
||||
:wsc(1)
|
||||
{
|
||||
gfx.sys = this;
|
||||
memory.sys = this;
|
||||
eeprom.sys = this;
|
||||
rtc.sys = this;
|
||||
sound.sys = this;
|
||||
cpu.sys = this;
|
||||
interrupt.sys = this;
|
||||
}
|
||||
|
||||
System::~System()
|
||||
{
|
||||
}
|
||||
|
||||
// maybe change?
|
||||
int Debug::puts ( const char * str )
|
||||
{
|
||||
return std::puts(str);
|
||||
}
|
||||
int Debug::printf ( const char * format, ... )
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vprintf(format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EXPORT System *bizswan_new()
|
||||
{
|
||||
return new System();
|
||||
}
|
||||
|
||||
EXPORT void bizswan_delete(System *s)
|
||||
{
|
||||
delete s;
|
||||
}
|
||||
|
||||
EXPORT void bizswan_reset(System *s)
|
||||
{
|
||||
s->Reset();
|
||||
}
|
||||
|
||||
EXPORT void bizswan_advance(System *s, uint16 buttons, bool novideo, uint32 *surface, int16 *soundbuff, int *soundbuffsize)
|
||||
{
|
||||
s->Advance(buttons, novideo, surface, soundbuff, *soundbuffsize);
|
||||
}
|
||||
|
||||
EXPORT int bizswan_load(System *s, const uint8 *data, int length, const Settings *settings)
|
||||
{
|
||||
return s->Load(data, length, *settings);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
class System;
|
||||
struct Settings;
|
||||
}
|
||||
|
||||
#include "wswan.h"
|
||||
#include "gfx.h"
|
||||
#include "memory.h"
|
||||
#include "eeprom.h"
|
||||
#include "rtc.h"
|
||||
#include "sound.h"
|
||||
#include "v30mz.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
class System
|
||||
{
|
||||
public:
|
||||
System();
|
||||
~System();
|
||||
|
||||
static void* operator new(std::size_t size);
|
||||
|
||||
void Reset();
|
||||
void Advance(uint16 buttons, bool novideo, uint32 *surface, int16 *soundbuff, int &soundbuffsize);
|
||||
bool Load(const uint8 *data, int length, const Settings &s);
|
||||
|
||||
public:
|
||||
GFX gfx;
|
||||
Memory memory;
|
||||
EEPROM eeprom;
|
||||
RTC rtc;
|
||||
Sound sound;
|
||||
V30MZ cpu;
|
||||
Interrupt interrupt;
|
||||
public:
|
||||
int wsc; // 1 = 1; /*color/mono*/
|
||||
|
||||
};
|
||||
|
||||
struct Settings
|
||||
{
|
||||
uint16 byear; // birth year, 0000-9999
|
||||
uint8 bmonth; // birth month, 1-12
|
||||
uint8 bday; // birth day, 1-31
|
||||
char name[17]; // up to 16 chars long, most chars don't work (conversion from ascii is internal)
|
||||
uint8 language; // 0 = J, 1 = E; only affects "Digimon Tamers - Battle Spirit"
|
||||
uint8 sex; // sex, 1 = male, 2 = female
|
||||
uint8 blood; // 1 = a, 2 = b, 3 = o, 4 = ab
|
||||
bool rotateinput; // true to rotate input and dpads, sync setting because of this
|
||||
};
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
int puts ( const char * str );
|
||||
int printf ( const char * format, ... );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,290 @@
|
|||
/* Cygne
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Dox dox@space.pl
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
void GFX::InvalidByAddr(uint32 ws_offset)
|
||||
{
|
||||
if(wsVMode && (ws_offset>=0x4000)&&(ws_offset<0x8000))
|
||||
{
|
||||
wsTCacheUpdate[(ws_offset-0x4000)>>5]=FALSE; /*invalidate tile*/
|
||||
return;
|
||||
}
|
||||
else if((ws_offset>=0x2000)&&(ws_offset<0x4000))
|
||||
{
|
||||
wsTCacheUpdate[(ws_offset-0x2000)>>4]=FALSE; /*invalidate tile*/
|
||||
return;
|
||||
}
|
||||
|
||||
if(wsVMode && (ws_offset>=0x8000)&&(ws_offset<0xc000))
|
||||
{
|
||||
wsTCacheUpdate2[(ws_offset-0x8000)>>5]=FALSE; /*invalidate tile*/
|
||||
return;
|
||||
}
|
||||
else if((ws_offset>=0x4000)&&(ws_offset<0x6000))
|
||||
{
|
||||
wsTCacheUpdate2[(ws_offset-0x4000)>>4]=FALSE; /*invalidate tile*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GFX::SetVideo(int number,bool force)
|
||||
{
|
||||
if((number!=wsVMode)||(force))
|
||||
{
|
||||
wsVMode=number;
|
||||
std::memset(wsTCacheUpdate,0,512);
|
||||
std::memset(wsTCacheUpdate2,0,512);
|
||||
}
|
||||
}
|
||||
|
||||
void GFX::MakeTiles()
|
||||
{
|
||||
int x,y,b0,b1,b2,b3,b4,b5,b6,b7;
|
||||
for(x=0;x<256;x++)
|
||||
for(y=0;y<256;y++)
|
||||
{
|
||||
b0=(x&128)>>7;b1=(x&64)>>6;b2=(x&32)>>5;b3=(x&16)>>4;b4=(x&8)>>3;b5=(x&4)>>2;b6=(x&2)>>1;b7=(x&1);
|
||||
b0|=(y&128)>>6;b1|=(y&64)>>5;b2|=(y&32)>>4;b3|=(y&16)>>3;b4|=(y&8)>>2;b5|=(y&4)>>1;b6|=(y&2);b7|=(y&1)<<1;
|
||||
tiles[x][y][0][0]=b0;
|
||||
tiles[x][y][0][1]=b1;
|
||||
tiles[x][y][0][2]=b2;
|
||||
tiles[x][y][0][3]=b3;
|
||||
tiles[x][y][0][4]=b4;
|
||||
tiles[x][y][0][5]=b5;
|
||||
tiles[x][y][0][6]=b6;
|
||||
tiles[x][y][0][7]=b7;
|
||||
tiles[x][y][1][0]=b7;
|
||||
tiles[x][y][1][1]=b6;
|
||||
tiles[x][y][1][2]=b5;
|
||||
tiles[x][y][1][3]=b4;
|
||||
tiles[x][y][1][4]=b3;
|
||||
tiles[x][y][1][5]=b2;
|
||||
tiles[x][y][1][6]=b1;
|
||||
tiles[x][y][1][7]=b0;
|
||||
}
|
||||
}
|
||||
|
||||
void GFX::GetTile(uint32 number,uint32 line,int flipv,int fliph,int bank)
|
||||
{
|
||||
uint32 t_adr,t_index,i;
|
||||
uint8 byte0,byte1,byte2,byte3;
|
||||
const uint8 *ram = sys->memory.wsRAM;
|
||||
|
||||
if((!bank)||(!(wsVMode &0x07)))
|
||||
{
|
||||
if(!wsTCacheUpdate[number])
|
||||
{
|
||||
wsTCacheUpdate[number]=true;
|
||||
switch(wsVMode)
|
||||
{
|
||||
case 7:
|
||||
t_adr=0x4000+(number<<5);
|
||||
t_index=number<<6;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
byte0=ram[t_adr++];
|
||||
byte1=ram[t_adr++];
|
||||
byte2=ram[t_adr++];
|
||||
byte3=ram[t_adr++];
|
||||
wsTCache[t_index]=byte0>>4;
|
||||
wsTCacheFlipped[t_index++]=byte3&15;
|
||||
wsTCache[t_index]=byte0&15;
|
||||
wsTCacheFlipped[t_index++]=byte3>>4;
|
||||
wsTCache[t_index]=byte1>>4;
|
||||
wsTCacheFlipped[t_index++]=byte2&15;
|
||||
wsTCache[t_index]=byte1&15;
|
||||
wsTCacheFlipped[t_index++]=byte2>>4;
|
||||
wsTCache[t_index]=byte2>>4;
|
||||
wsTCacheFlipped[t_index++]=byte1&15;
|
||||
wsTCache[t_index]=byte2&15;
|
||||
wsTCacheFlipped[t_index++]=byte1>>4;
|
||||
wsTCache[t_index]=byte3>>4;
|
||||
wsTCacheFlipped[t_index++]=byte0&15;
|
||||
wsTCache[t_index]=byte3&15;
|
||||
wsTCacheFlipped[t_index++]=byte0>>4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
t_adr=0x4000+(number<<5);
|
||||
t_index=number<<6;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
byte0=ram[t_adr++];
|
||||
byte1=ram[t_adr++];
|
||||
byte2=ram[t_adr++];
|
||||
byte3=ram[t_adr++];
|
||||
wsTCache[t_index]=((byte0>>7)&1)|(((byte1>>7)&1)<<1)|(((byte2>>7)&1)<<2)|(((byte3>>7)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0)&1)|(((byte1)&1)<<1)|(((byte2)&1)<<2)|(((byte3)&1)<<3);
|
||||
wsTCache[t_index]=((byte0>>6)&1)|(((byte1>>6)&1)<<1)|(((byte2>>6)&1)<<2)|(((byte3>>6)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0>>1)&1)|(((byte1>>1)&1)<<1)|(((byte2>>1)&1)<<2)|(((byte3>>1)&1)<<3);
|
||||
wsTCache[t_index]=((byte0>>5)&1)|(((byte1>>5)&1)<<1)|(((byte2>>5)&1)<<2)|(((byte3>>5)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0>>2)&1)|(((byte1>>2)&1)<<1)|(((byte2>>2)&1)<<2)|(((byte3>>2)&1)<<3);
|
||||
wsTCache[t_index]=((byte0>>4)&1)|(((byte1>>4)&1)<<1)|(((byte2>>4)&1)<<2)|(((byte3>>4)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0>>3)&1)|(((byte1>>3)&1)<<1)|(((byte2>>3)&1)<<2)|(((byte3>>3)&1)<<3);
|
||||
wsTCache[t_index]=((byte0>>3)&1)|(((byte1>>3)&1)<<1)|(((byte2>>3)&1)<<2)|(((byte3>>3)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0>>4)&1)|(((byte1>>4)&1)<<1)|(((byte2>>4)&1)<<2)|(((byte3>>4)&1)<<3);
|
||||
wsTCache[t_index]=((byte0>>2)&1)|(((byte1>>2)&1)<<1)|(((byte2>>2)&1)<<2)|(((byte3>>2)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0>>5)&1)|(((byte1>>5)&1)<<1)|(((byte2>>5)&1)<<2)|(((byte3>>5)&1)<<3);
|
||||
wsTCache[t_index]=((byte0>>1)&1)|(((byte1>>1)&1)<<1)|(((byte2>>1)&1)<<2)|(((byte3>>1)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0>>6)&1)|(((byte1>>6)&1)<<1)|(((byte2>>6)&1)<<2)|(((byte3>>6)&1)<<3);
|
||||
wsTCache[t_index]=((byte0)&1)|(((byte1)&1)<<1)|(((byte2)&1)<<2)|(((byte3)&1)<<3);
|
||||
wsTCacheFlipped[t_index++]=((byte0>>7)&1)|(((byte1>>7)&1)<<1)|(((byte2>>7)&1)<<2)|(((byte3>>7)&1)<<3);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
t_adr=0x2000+(number<<4);
|
||||
t_index=number<<6;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
byte0=ram[t_adr++];
|
||||
byte1=ram[t_adr++];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][0];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][0];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][1];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][1];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][2];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][2];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][3];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][3];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][4];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][4];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][5];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][5];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][6];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][6];
|
||||
wsTCache[t_index]=tiles[byte0][byte1][0][7];
|
||||
wsTCacheFlipped[t_index++]=tiles[byte0][byte1][1][7];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(flipv)
|
||||
line=7-line;
|
||||
if(fliph)
|
||||
memcpy(&wsTileRow[0],&wsTCacheFlipped[(number<<6)|(line<<3)],8);
|
||||
else
|
||||
memcpy(&wsTileRow[0],&wsTCache[(number<<6)|(line<<3)],8);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
if(!wsTCacheUpdate2[number])
|
||||
{
|
||||
wsTCacheUpdate2[number]=TRUE;
|
||||
switch(wsVMode)
|
||||
{
|
||||
case 7:
|
||||
t_adr=0x8000+(number<<5);
|
||||
t_index=number<<6;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
byte0=ram[t_adr++];
|
||||
byte1=ram[t_adr++];
|
||||
byte2=ram[t_adr++];
|
||||
byte3=ram[t_adr++];
|
||||
wsTCache2[t_index]=byte0>>4;
|
||||
wsTCacheFlipped2[t_index++]=byte3&15;
|
||||
wsTCache2[t_index]=byte0&15;
|
||||
wsTCacheFlipped2[t_index++]=byte3>>4;
|
||||
wsTCache2[t_index]=byte1>>4;
|
||||
wsTCacheFlipped2[t_index++]=byte2&15;
|
||||
wsTCache2[t_index]=byte1&15;
|
||||
wsTCacheFlipped2[t_index++]=byte2>>4;
|
||||
wsTCache2[t_index]=byte2>>4;
|
||||
wsTCacheFlipped2[t_index++]=byte1&15;
|
||||
wsTCache2[t_index]=byte2&15;
|
||||
wsTCacheFlipped2[t_index++]=byte1>>4;
|
||||
wsTCache2[t_index]=byte3>>4;
|
||||
wsTCacheFlipped2[t_index++]=byte0&15;
|
||||
wsTCache2[t_index]=byte3&15;
|
||||
wsTCacheFlipped2[t_index++]=byte0>>4;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
t_adr=0x8000+(number<<5);
|
||||
t_index=number<<6;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
byte0=ram[t_adr++];
|
||||
byte1=ram[t_adr++];
|
||||
byte2=ram[t_adr++];
|
||||
byte3=ram[t_adr++];
|
||||
wsTCache2[t_index]=((byte0>>7)&1)|(((byte1>>7)&1)<<1)|(((byte2>>7)&1)<<2)|(((byte3>>7)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0)&1)|(((byte1)&1)<<1)|(((byte2)&1)<<2)|(((byte3)&1)<<3);
|
||||
wsTCache2[t_index]=((byte0>>6)&1)|(((byte1>>6)&1)<<1)|(((byte2>>6)&1)<<2)|(((byte3>>6)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0>>1)&1)|(((byte1>>1)&1)<<1)|(((byte2>>1)&1)<<2)|(((byte3>>1)&1)<<3);
|
||||
wsTCache2[t_index]=((byte0>>5)&1)|(((byte1>>5)&1)<<1)|(((byte2>>5)&1)<<2)|(((byte3>>5)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0>>2)&1)|(((byte1>>2)&1)<<1)|(((byte2>>2)&1)<<2)|(((byte3>>2)&1)<<3);
|
||||
wsTCache2[t_index]=((byte0>>4)&1)|(((byte1>>4)&1)<<1)|(((byte2>>4)&1)<<2)|(((byte3>>4)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0>>3)&1)|(((byte1>>3)&1)<<1)|(((byte2>>3)&1)<<2)|(((byte3>>3)&1)<<3);
|
||||
wsTCache2[t_index]=((byte0>>3)&1)|(((byte1>>3)&1)<<1)|(((byte2>>3)&1)<<2)|(((byte3>>3)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0>>4)&1)|(((byte1>>4)&1)<<1)|(((byte2>>4)&1)<<2)|(((byte3>>4)&1)<<3);
|
||||
wsTCache2[t_index]=((byte0>>2)&1)|(((byte1>>2)&1)<<1)|(((byte2>>2)&1)<<2)|(((byte3>>2)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0>>5)&1)|(((byte1>>5)&1)<<1)|(((byte2>>5)&1)<<2)|(((byte3>>5)&1)<<3);
|
||||
wsTCache2[t_index]=((byte0>>1)&1)|(((byte1>>1)&1)<<1)|(((byte2>>1)&1)<<2)|(((byte3>>1)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0>>6)&1)|(((byte1>>6)&1)<<1)|(((byte2>>6)&1)<<2)|(((byte3>>6)&1)<<3);
|
||||
wsTCache2[t_index]=((byte0)&1)|(((byte1)&1)<<1)|(((byte2)&1)<<2)|(((byte3)&1)<<3);
|
||||
wsTCacheFlipped2[t_index++]=((byte0>>7)&1)|(((byte1>>7)&1)<<1)|(((byte2>>7)&1)<<2)|(((byte3>>7)&1)<<3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
t_adr=0x4000+(number<<4);
|
||||
t_index=number<<6;
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
byte0=ram[t_adr++];
|
||||
byte1=ram[t_adr++];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][0];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][0];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][1];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][1];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][2];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][2];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][3];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][3];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][4];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][4];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][5];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][5];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][6];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][6];
|
||||
wsTCache2[t_index]=tiles[byte0][byte1][0][7];
|
||||
wsTCacheFlipped2[t_index++]=tiles[byte0][byte1][1][7];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(flipv)
|
||||
line=7-line;
|
||||
if(fliph)
|
||||
memcpy(&wsTileRow[0],&wsTCacheFlipped2[(number<<6)|(line<<3)],8);
|
||||
else
|
||||
memcpy(&wsTileRow[0],&wsTCache2[(number<<6)|(line<<3)],8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
#define RegWord(ModRM) I.regs.w[Mod_RM.reg.w[ModRM]]
|
||||
#define RegByte(ModRM) I.regs.b[Mod_RM.reg.b[ModRM]]
|
||||
|
||||
#define GetRMWord(ModRM) \
|
||||
((ModRM) >= 0xc0 ? I.regs.w[Mod_RM.RM.w[ModRM]] : ( (this->*GetEA[ModRM])(), ReadWord( EA ) ))
|
||||
|
||||
#define PutbackRMWord(ModRM,val) \
|
||||
{ \
|
||||
if (ModRM >= 0xc0) I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
|
||||
else WriteWord(EA,val); \
|
||||
}
|
||||
|
||||
#define GetnextRMWord ReadWord((EA&0xf0000)|((EA+2)&0xffff))
|
||||
|
||||
#define PutRMWord(ModRM,val) \
|
||||
{ \
|
||||
if (ModRM >= 0xc0) \
|
||||
I.regs.w[Mod_RM.RM.w[ModRM]]=val; \
|
||||
else { \
|
||||
(this->*GetEA[ModRM])(); \
|
||||
WriteWord( EA ,val); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PutImmRMWord(ModRM) \
|
||||
{ \
|
||||
uint16 val; \
|
||||
if (ModRM >= 0xc0) \
|
||||
FETCHuint16(I.regs.w[Mod_RM.RM.w[ModRM]]) \
|
||||
else { \
|
||||
(this->*GetEA[ModRM])(); \
|
||||
FETCHuint16(val) \
|
||||
WriteWord( EA , val); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GetRMByte(ModRM) \
|
||||
((ModRM) >= 0xc0 ? I.regs.b[Mod_RM.RM.b[ModRM]] : ReadByte( (this->*GetEA[ModRM])() ))
|
||||
|
||||
#define PutRMByte(ModRM,val) \
|
||||
{ \
|
||||
if (ModRM >= 0xc0) \
|
||||
I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
|
||||
else \
|
||||
WriteByte( (this->*GetEA[ModRM])() ,val); \
|
||||
}
|
||||
|
||||
#define PutImmRMByte(ModRM) \
|
||||
{ \
|
||||
if (ModRM >= 0xc0) \
|
||||
I.regs.b[Mod_RM.RM.b[ModRM]]=FETCH; \
|
||||
else { \
|
||||
(this->*GetEA[ModRM])(); \
|
||||
WriteByte( EA , FETCH ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PutbackRMByte(ModRM,val) \
|
||||
{ \
|
||||
if (ModRM >= 0xc0) \
|
||||
I.regs.b[Mod_RM.RM.b[ModRM]]=val; \
|
||||
else \
|
||||
WriteByte(EA,val); \
|
||||
}
|
||||
|
||||
#define DEF_br8 \
|
||||
uint32 ModRM = FETCH,src,dst; \
|
||||
src = RegByte(ModRM); \
|
||||
dst = GetRMByte(ModRM)
|
||||
|
||||
#define DEF_wr16 \
|
||||
uint32 ModRM = FETCH,src,dst; \
|
||||
src = RegWord(ModRM); \
|
||||
dst = GetRMWord(ModRM)
|
||||
|
||||
#define DEF_r8b \
|
||||
uint32 ModRM = FETCH,src,dst; \
|
||||
dst = RegByte(ModRM); \
|
||||
src = GetRMByte(ModRM)
|
||||
|
||||
#define DEF_r16w \
|
||||
uint32 ModRM = FETCH,src,dst; \
|
||||
dst = RegWord(ModRM); \
|
||||
src = GetRMWord(ModRM)
|
||||
|
||||
#define DEF_ald8 \
|
||||
uint32 src = FETCH; \
|
||||
uint32 dst = I.regs.b[AL]
|
||||
|
||||
#define DEF_axd16 \
|
||||
uint32 src = FETCH; \
|
||||
uint32 dst = I.regs.w[AW]; \
|
||||
src += (FETCH << 8)
|
|
@ -0,0 +1,252 @@
|
|||
#define cpu_readop sys->memory.Read20
|
||||
//cpu_readmem20
|
||||
#define cpu_readop_arg sys->memory.Read20
|
||||
//cpu_readmem20
|
||||
#define cpu_readmem20 sys->memory.Read20
|
||||
#define cpu_writemem20 sys->memory.Write20
|
||||
#define cpu_readport sys->memory.readport
|
||||
#define cpu_writeport sys->memory.writeport
|
||||
|
||||
#define NEC_NMI_INT_VECTOR 2
|
||||
|
||||
/* parameter x = result, y = source 1, z = source 2 */
|
||||
|
||||
#define SetTF(x) (I.TF = (x))
|
||||
#define SetIF(x) (I.IF = (x))
|
||||
#define SetDF(x) (I.DF = (x))
|
||||
|
||||
#define SetCFB(x) (I.CarryVal = (x) & 0x100)
|
||||
#define SetCFW(x) (I.CarryVal = (x) & 0x10000)
|
||||
|
||||
#define SetAF(x,y,z) (I.AuxVal = ((x) ^ ((y) ^ (z))) & 0x10)
|
||||
|
||||
|
||||
|
||||
|
||||
#define SetSF(x) (I.SignVal = (x))
|
||||
#define SetZF(x) (I.ZeroVal = (x))
|
||||
#define SetPF(x) (I.ParityVal = (x))
|
||||
|
||||
#define SetSZPF_Byte(x) (I.SignVal=I.ZeroVal=I.ParityVal=(int8)(x))
|
||||
#define SetSZPF_Word(x) (I.SignVal=I.ZeroVal=I.ParityVal=(int16)(x))
|
||||
|
||||
#define SetOFW_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000)
|
||||
#define SetOFB_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x80)
|
||||
#define SetOFW_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000)
|
||||
#define SetOFB_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x80)
|
||||
|
||||
#define ADDB { uint32 res=dst+src; SetCFB(res); SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(uint8)res; }
|
||||
#define ADDW { uint32 res=dst+src; SetCFW(res); SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(uint16)res; }
|
||||
|
||||
#define SUBB { uint32 res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(uint8)res; }
|
||||
#define SUBW { uint32 res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(uint16)res; }
|
||||
|
||||
#define ORB dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
|
||||
#define ORW dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
|
||||
|
||||
#define ANDB dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
|
||||
#define ANDW dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
|
||||
|
||||
#define XORB dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst)
|
||||
#define XORW dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst)
|
||||
|
||||
#define CF (I.CarryVal!=0)
|
||||
#define SF (I.SignVal<0)
|
||||
#define ZF (I.ZeroVal==0)
|
||||
#define PF parity_table[(uint8)I.ParityVal]
|
||||
#define AF (I.AuxVal!=0)
|
||||
#define FLAG_O (I.OverVal!=0)
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
#define SegBase(Seg) (I.sregs[Seg] << 4)
|
||||
|
||||
#define DefaultBase(Seg) ((seg_prefix && (Seg==DS0 || Seg==SS)) ? prefix_base : I.sregs[Seg] << 4)
|
||||
|
||||
#define GetMemB(Seg,Off) ((uint8)cpu_readmem20((DefaultBase(Seg)+(Off))))
|
||||
#define GetMemW(Seg,Off) ((uint16) cpu_readmem20((DefaultBase(Seg)+(Off))) + (cpu_readmem20((DefaultBase(Seg)+((Off)+1)))<<8) )
|
||||
|
||||
#define PutMemB(Seg,Off,x) { cpu_writemem20((DefaultBase(Seg)+(Off)),(x)); }
|
||||
#define PutMemW(Seg,Off,x) { PutMemB(Seg,Off,(x)&0xff); PutMemB(Seg,(Off)+1,(uint8)((x)>>8)); }
|
||||
|
||||
/* Todo: Remove these later - plus readword could overflow */
|
||||
#define ReadByte(ea) ((uint8)cpu_readmem20((ea)))
|
||||
#define ReadWord(ea) (cpu_readmem20((ea))+(cpu_readmem20(((ea)+1))<<8))
|
||||
#define WriteByte(ea,val) { cpu_writemem20((ea),val); }
|
||||
#define WriteWord(ea,val) { cpu_writemem20((ea),(uint8)(val)); cpu_writemem20(((ea)+1),(val)>>8); }
|
||||
|
||||
#define read_port(port) cpu_readport(port)
|
||||
#define write_port(port,val) cpu_writeport(port,val)
|
||||
|
||||
#define FETCH (cpu_readop_arg((I.sregs[PS]<<4)+I.pc++))
|
||||
#define FETCHOP (cpu_readop((I.sregs[PS]<<4)+I.pc++))
|
||||
#define FETCHuint16(var) { var=cpu_readop_arg((((I.sregs[PS]<<4)+I.pc)))+(cpu_readop_arg((((I.sregs[PS]<<4)+I.pc+1)))<<8); I.pc+=2; }
|
||||
#define PUSH(val) { I.regs.w[SP]-=2; WriteWord((((I.sregs[SS]<<4)+I.regs.w[SP])),val); }
|
||||
#define POP(var) { var = ReadWord((((I.sregs[SS]<<4)+I.regs.w[SP]))); I.regs.w[SP]+=2; }
|
||||
#define PEEK(addr) ((uint8)cpu_readop_arg(addr))
|
||||
#define PEEKOP(addr) ((uint8)cpu_readop(addr))
|
||||
|
||||
#define GetModRM uint32 ModRM=cpu_readop_arg((I.sregs[PS]<<4)+I.pc++)
|
||||
|
||||
/* Cycle count macros:
|
||||
CLK - cycle count is the same on all processors
|
||||
CLKM - cycle count for reg/mem instructions
|
||||
|
||||
|
||||
Prefetch & buswait time is not emulated.
|
||||
Extra cycles for PUSH'ing or POP'ing registers to odd addresses is not emulated.
|
||||
*/
|
||||
|
||||
#define _REAL_CLK(cycles) { ICount -= cycles; timestamp += cycles; }
|
||||
#define CLK _REAL_CLK
|
||||
//#define CLK(cycles) { _REAL_CLK(cycles); if(ws_CheckDMA(cycles)) _REAL_CLK(1); }
|
||||
|
||||
#define CLKM(mcount, ccount) { if(ModRM >=0xc0 ) { CLK(ccount);} else {CLK(mcount);} }
|
||||
|
||||
|
||||
#define CompressFlags() (uint16)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \
|
||||
| (SF << 7) | (I.TF << 8) | (I.IF << 9) \
|
||||
| (I.DF << 10) | (FLAG_O << 11) | (0xF002))
|
||||
|
||||
|
||||
#define ExpandFlags(f) \
|
||||
{ \
|
||||
I.CarryVal = (f) & 1; \
|
||||
I.ParityVal = !((f) & 4); \
|
||||
I.AuxVal = (f) & 16; \
|
||||
I.ZeroVal = !((f) & 64); \
|
||||
I.SignVal = (f) & 128 ? -1 : 0; \
|
||||
I.TF = ((f) & 256) == 256; \
|
||||
I.IF = ((f) & 512) == 512; \
|
||||
I.DF = ((f) & 1024) == 1024; \
|
||||
I.OverVal = (f) & 2048; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define IncWordReg(Reg) \
|
||||
unsigned tmp = (unsigned)I.regs.w[Reg]; \
|
||||
unsigned tmp1 = tmp+1; \
|
||||
I.OverVal = (tmp == 0x7fff); \
|
||||
SetAF(tmp1,tmp,1); \
|
||||
SetSZPF_Word(tmp1); \
|
||||
I.regs.w[Reg]=tmp1
|
||||
|
||||
|
||||
|
||||
#define DecWordReg(Reg) \
|
||||
unsigned tmp = (unsigned)I.regs.w[Reg]; \
|
||||
unsigned tmp1 = tmp-1; \
|
||||
I.OverVal = (tmp == 0x8000); \
|
||||
SetAF(tmp1,tmp,1); \
|
||||
SetSZPF_Word(tmp1); \
|
||||
I.regs.w[Reg]=tmp1
|
||||
|
||||
#define JMP(flag) \
|
||||
int tmp = (int)((int8)FETCH); \
|
||||
if (flag) \
|
||||
{ \
|
||||
I.pc = (uint16)(I.pc+tmp); \
|
||||
CLK(3); \
|
||||
ADDBRANCHTRACE(I.sregs[PS], I.pc); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define ADJ4(param1,param2) \
|
||||
if (AF || ((I.regs.b[AL] & 0xf) > 9)) \
|
||||
{ \
|
||||
uint16 tmp; \
|
||||
tmp = I.regs.b[AL] + param1; \
|
||||
I.regs.b[AL] = tmp; \
|
||||
I.AuxVal = 1; \
|
||||
I.CarryVal |= tmp & 0x100; /*if(tmp&0x100){puts("Meow"); }*//* Correct? */ \
|
||||
} \
|
||||
if (CF || (I.regs.b[AL] > 0x9f)) \
|
||||
{ \
|
||||
I.regs.b[AL] += param2; \
|
||||
I.CarryVal = 1; \
|
||||
} \
|
||||
SetSZPF_Byte(I.regs.b[AL])
|
||||
|
||||
#define ADJB(param1,param2) \
|
||||
if (AF || ((I.regs.b[AL] & 0xf) > 9)) \
|
||||
{ \
|
||||
I.regs.b[AL] += param1; \
|
||||
I.regs.b[AH] += param2; \
|
||||
I.AuxVal = 1; \
|
||||
I.CarryVal = 1; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
I.AuxVal = 0; \
|
||||
I.CarryVal = 0; \
|
||||
} \
|
||||
I.regs.b[AL] &= 0x0F
|
||||
|
||||
#define BIT_NOT \
|
||||
if (tmp & (1<<tmp2)) \
|
||||
tmp &= ~(1<<tmp2); \
|
||||
else \
|
||||
tmp |= (1<<tmp2)
|
||||
|
||||
#define XchgAWReg(Reg) \
|
||||
uint16 tmp; \
|
||||
tmp = I.regs.w[Reg]; \
|
||||
I.regs.w[Reg] = I.regs.w[AW]; \
|
||||
I.regs.w[AW] = tmp
|
||||
|
||||
#define ROL_uint8 I.CarryVal = dst & 0x80; dst = (dst << 1)+CF
|
||||
#define ROL_uint16 I.CarryVal = dst & 0x8000; dst = (dst << 1)+CF
|
||||
#define ROR_uint8 I.CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<7)
|
||||
#define ROR_uint16 I.CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<15)
|
||||
#define ROLC_uint8 dst = (dst << 1) + CF; SetCFB(dst)
|
||||
#define ROLC_uint16 dst = (dst << 1) + CF; SetCFW(dst)
|
||||
#define RORC_uint8 dst = (CF<<8)+dst; I.CarryVal = dst & 0x01; dst >>= 1
|
||||
#define RORC_uint16 dst = (CF<<16)+dst; I.CarryVal = dst & 0x01; dst >>= 1
|
||||
#define SHL_uint8(c) dst <<= c; SetCFB(dst); SetSZPF_Byte(dst); PutbackRMByte(ModRM,(uint8)dst)
|
||||
#define SHL_uint16(c) dst <<= c; SetCFW(dst); SetSZPF_Word(dst); PutbackRMWord(ModRM,(uint16)dst)
|
||||
#define SHR_uint8(c) dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(uint8)dst)
|
||||
#define SHR_uint16(c) dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(uint16)dst)
|
||||
#define SHRA_uint8(c) dst = ((int8)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((int8)((uint8)dst)) >> 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(uint8)dst)
|
||||
#define SHRA_uint16(c) dst = ((int16)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((int16)((uint16)dst)) >> 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(uint16)dst)
|
||||
|
||||
#define DIVUB \
|
||||
uresult = I.regs.w[AW]; \
|
||||
uresult2 = uresult % tmp; \
|
||||
if ((uresult /= tmp) > 0xff) { \
|
||||
nec_interrupt(0); break; \
|
||||
} else { \
|
||||
I.regs.b[AL] = uresult; \
|
||||
I.regs.b[AH] = uresult2; \
|
||||
}
|
||||
|
||||
#define DIVB \
|
||||
result = (int16)I.regs.w[AW]; \
|
||||
result2 = result % (int16)((int8)tmp); \
|
||||
if ((result /= (int16)((int8)tmp)) > 0xff) { \
|
||||
nec_interrupt(0); break; \
|
||||
} else { \
|
||||
I.regs.b[AL] = result; \
|
||||
I.regs.b[AH] = result2; \
|
||||
}
|
||||
|
||||
#define DIVUW \
|
||||
uresult = (((uint32)I.regs.w[DW]) << 16) | I.regs.w[AW];\
|
||||
uresult2 = uresult % tmp; \
|
||||
if ((uresult /= tmp) > 0xffff) { \
|
||||
nec_interrupt(0); break; \
|
||||
} else { \
|
||||
I.regs.w[AW]=uresult; \
|
||||
I.regs.w[DW]=uresult2; \
|
||||
}
|
||||
|
||||
#define DIVW \
|
||||
result = ((uint32)I.regs.w[DW] << 16) + I.regs.w[AW]; \
|
||||
result2 = result % (int32)((int16)tmp); \
|
||||
if ((result /= (int32)((int16)tmp)) > 0xffff) { \
|
||||
nec_interrupt(0); break; \
|
||||
} else { \
|
||||
I.regs.w[AW]=result; \
|
||||
I.regs.w[DW]=result2; \
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,166 @@
|
|||
#ifndef __V30MZ_H_
|
||||
#define __V30MZ_H_
|
||||
|
||||
#include "system.h"
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
typedef union
|
||||
{ /* eight general registers */
|
||||
uint16 w[8]; /* viewed as 16 bits registers */
|
||||
uint8 b[16]; /* or as 8 bit registers */
|
||||
} v30mz_basicregs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
v30mz_basicregs_t regs;
|
||||
uint16 sregs[4];
|
||||
|
||||
uint16 pc;
|
||||
|
||||
int32 SignVal;
|
||||
uint32 AuxVal, OverVal, ZeroVal, CarryVal, ParityVal; /* 0 or non-0 valued flags */
|
||||
uint8 TF, IF, DF;
|
||||
} v30mz_regs_t;
|
||||
|
||||
namespace V30MZEnum
|
||||
{
|
||||
|
||||
typedef enum { DS1, PS, SS, DS0 } SREGS;
|
||||
typedef enum { AW, CW, DW, BW, SP, BP, IX, IY } WREGS;
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
typedef enum { AL,AH,CL,CH,DL,DH,BL,BH,SPL,SPH,BPL,BPH,IXL,IXH,IYL,IYH } BREGS;
|
||||
#else
|
||||
typedef enum { AH,AL,CH,CL,DH,DL,BH,BL,SPH,SPL,BPH,BPL,IXH,IXL,IYH,IYL } BREGS;
|
||||
#endif
|
||||
}
|
||||
|
||||
class V30MZ
|
||||
{
|
||||
public:
|
||||
V30MZ();
|
||||
|
||||
void execute(int cycles);
|
||||
void set_reg(int, unsigned);
|
||||
unsigned get_reg(int regnum);
|
||||
void reset();
|
||||
void init();
|
||||
|
||||
void interrupt(uint32 vector, bool IgnoreIF = FALSE);
|
||||
|
||||
private:
|
||||
uint16 old_CS, old_IP;
|
||||
|
||||
public:
|
||||
uint32 timestamp;
|
||||
private:
|
||||
int32 ICount;
|
||||
|
||||
v30mz_regs_t I;
|
||||
bool InHLT;
|
||||
|
||||
uint32 prefix_base; /* base address of the latest prefix segment */
|
||||
char seg_prefix; /* prefix segment indicator */
|
||||
|
||||
uint8 parity_table[256];
|
||||
|
||||
uint32 EA;
|
||||
uint16 EO;
|
||||
uint16 E16;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
V30MZEnum::WREGS w[256];
|
||||
V30MZEnum::BREGS b[256];
|
||||
} reg;
|
||||
struct {
|
||||
V30MZEnum::WREGS w[256];
|
||||
V30MZEnum::BREGS b[256];
|
||||
} RM;
|
||||
} Mod_RM;
|
||||
|
||||
private:
|
||||
//void (*cpu_writemem20)(uint32,uint8);// = NULL;
|
||||
//uint8 (*cpu_readport)(uint32);// = NULL;
|
||||
//void (*cpu_writeport)(uint32, uint8);// = NULL;
|
||||
//uint8 (*cpu_readmem20)(uint32);// = NULL;
|
||||
|
||||
private:
|
||||
void nec_interrupt(unsigned int_num);
|
||||
bool CheckInHLT();
|
||||
void DoOP(uint8 opcode);
|
||||
|
||||
void i_real_pushf();
|
||||
void i_real_popf();
|
||||
|
||||
void i_real_insb();
|
||||
void i_real_insw();
|
||||
void i_real_outsb();
|
||||
void i_real_outsw();
|
||||
void i_real_movsb();
|
||||
void i_real_movsw();
|
||||
void i_real_cmpsb();
|
||||
void i_real_cmpsw();
|
||||
void i_real_stosb();
|
||||
void i_real_stosw();
|
||||
void i_real_lodsb();
|
||||
void i_real_lodsw();
|
||||
void i_real_scasb();
|
||||
void i_real_scasw();
|
||||
|
||||
private:
|
||||
unsigned EA_000();
|
||||
unsigned EA_001();
|
||||
unsigned EA_002();
|
||||
unsigned EA_003();
|
||||
unsigned EA_004();
|
||||
unsigned EA_005();
|
||||
unsigned EA_006();
|
||||
unsigned EA_007();
|
||||
|
||||
unsigned EA_100();
|
||||
unsigned EA_101();
|
||||
unsigned EA_102();
|
||||
unsigned EA_103();
|
||||
unsigned EA_104();
|
||||
unsigned EA_105();
|
||||
unsigned EA_106();
|
||||
unsigned EA_107();
|
||||
|
||||
unsigned EA_200();
|
||||
unsigned EA_201();
|
||||
unsigned EA_202();
|
||||
unsigned EA_203();
|
||||
unsigned EA_204();
|
||||
unsigned EA_205();
|
||||
unsigned EA_206();
|
||||
unsigned EA_207();
|
||||
|
||||
private:
|
||||
void SetupEA();
|
||||
|
||||
typedef unsigned(V30MZ::*EAFPtr)();
|
||||
EAFPtr GetEA[192];
|
||||
|
||||
public:
|
||||
System *sys;
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
NEC_PC=1, NEC_AW, NEC_CW, NEC_DW, NEC_BW, NEC_SP, NEC_BP, NEC_IX, NEC_IY,
|
||||
NEC_FLAGS, NEC_DS1, NEC_PS, NEC_SS, NEC_DS0
|
||||
};
|
||||
|
||||
/* Public variables */
|
||||
//extern int v30mz_ICount;
|
||||
//extern uint32 v30mz_timestamp;
|
||||
|
||||
|
||||
/* Public functions */
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,757 @@
|
|||
___ ___ _
|
||||
/ | \ ___ __/ \__ ___ ___ /\__
|
||||
\ / \ // __>\_ _// __|/ __\/ \
|
||||
\_____/_\__ \ \_/ \___|\___/\_/\_/
|
||||
\____/ 2.4 - 26.12.2003
|
||||
|
||||
1. ABOUT
|
||||
WStech doc v2.4 made by Judge and Dox
|
||||
Special thanks to -anonymous- contributor for some usefull info.
|
||||
|
||||
For more info please visit http://www.pocketdomain.net
|
||||
|
||||
Comments/updates/infos please send to dox@space.pl
|
||||
|
||||
What's new in version 2.4:
|
||||
|
||||
- corect info about Sprite Table, BG Map and FG Map locations
|
||||
(ports $04 and $07 - section 10)
|
||||
Special thanks to mika-n
|
||||
|
||||
2. CPU
|
||||
|
||||
Bandai SPGY-1001 ASWAN 9850KK003
|
||||
NEC V30 MZ - fast version of V30 with internal pipeline (16 bytes prefatch buffer) running at 3.072 MHz.
|
||||
V30 MZ is aprox 4 times faster than V30.
|
||||
The V30MZ performs pipeline processing internally, performing instruction fetch (prefetch), instruction decode, and
|
||||
instruction execution in parallel. For this reason, it is difficult to determine what part of the program is currently being
|
||||
executed by monitoring the output of the address bus for the instruction code fetch.
|
||||
If there are conditional branch instructions, even in case branching does not occur, the address of the branch
|
||||
destination is prefetched (only one time), so that further monitoring of the program is difficult.
|
||||
The V30MZ has 8 prefetch queues (16 bytes).
|
||||
|
||||
There are a few other differences between V30MZ and V30 cpu (unsupported opcodes , different flag handling after mul/div).
|
||||
|
||||
Timing:
|
||||
|
||||
Hblank : 256 CPU cycles
|
||||
Vblank : 159 Hblank = 159*256/3072000 = 75.47Hz
|
||||
|
||||
|
||||
3. MEMORY
|
||||
|
||||
20 bit addressing space = 1 Megabyte. Memory is splitted into 64KB blocks (segments/banks).
|
||||
|
||||
Segments:
|
||||
|
||||
0 - RAM - 16 KB (WS) / 64 KB (WSC) internal RAM (see below)
|
||||
|
||||
1 - SRAM (cart) SRAM is BSI device BS62LV256TC - 256K(32Kx8) Static RAM - TSOP 0 - 70 c, 70 ns (http://www.bsi.com.tw/product/bs62lv256.pdf)
|
||||
|
||||
2 - ROM Bank (initial bank = last)
|
||||
3 - ROM Bank (lnitial bank = last)
|
||||
|
||||
4 - ROM Bank (initial bank = last - 11)
|
||||
5 - ROM Bank (initial bank = last - 10)
|
||||
6 - ROM Bank (initial bank = last - 9)
|
||||
7 - ROM Bank (initial bank = last - 8)
|
||||
8 - ROM Bank (initial bank = last - 7)
|
||||
9 - ROM Bank (initial bank = last - 6)
|
||||
A - ROM Bank (initial bank = last - 5)
|
||||
B - ROM Bank (initial bank = last - 4)
|
||||
C - ROM Bank (initial bank = last - 3)
|
||||
D - ROM Bank (initial bank = last - 2)
|
||||
E - ROM Bank (initial bank = last - 1)
|
||||
F - ROM Bank (initial bank = last)
|
||||
|
||||
Segments 2-$F are switchable using ports :
|
||||
|
||||
$C2 - Segment 2 (value written to port is ROM Bank number ($FF means last ROM bank (last 64 kbytes of ROM file) , $FE = last - 1 .. etc)
|
||||
$C3 - Segment 3 (same as above)
|
||||
$C0 - Segments 4-$F - bits 0,1,2 and 3 of port $C0 are bits 4,5,6 and 7 of ROM bank number in segments 4-$F . Bits 0-3
|
||||
are taken form segment number ( for example , IO[$C0]=$4E -> segment 9 contains ROM bank $E9).
|
||||
|
||||
RAM Map :
|
||||
|
||||
$0000 - $1FFF WS/WSC
|
||||
$2000 - $3FFF 4 Col Tiles WS/WSC
|
||||
-------------
|
||||
$4000 - $7FFF 16 Col Tiles Bank 0 WSC only
|
||||
$8000 - $BFFF 16 Col Tiles Bank 1 WSC only
|
||||
$C000 - $FDFF WSC only
|
||||
$FE00 - $FFFF Palettes (WSC) WSC only
|
||||
|
||||
Some games required initialized (?) part of RAM, for example:
|
||||
|
||||
$75AC = $41 = "A"
|
||||
$75AD = $5F = "_"
|
||||
$75AE = $43 = "C"
|
||||
$75AF = $31 = "1"
|
||||
$75B0 = $6E = "n"
|
||||
$75B1 = $5F = "_"
|
||||
$75B2 = $63 = "c"
|
||||
$75B3 = $31 = "1"
|
||||
|
||||
4. VIDEO
|
||||
|
||||
Screen size - 224 x 144 pixels (28 x 18 tiles)
|
||||
Tile size - 8 x 8 dots , 16 bytes/tile (4 col modes) or 32 bytes/tile (16 col modes)
|
||||
Map size - 256 x 256 pixels (32 x 32 tiles)
|
||||
Layers - Two layers - Background and Foreground (top layer)
|
||||
Maps locations - Selectable using port $07
|
||||
Tiles locations - Fixed, two banks - one at $4000 , second at $8000
|
||||
Map format - Each position in the map is defined by one word:
|
||||
bits 0 - 8 - Tile number (0-511)
|
||||
bits 9 - 12 - Palette number (0-15)
|
||||
bit 13 - WS = unused / WSC = tile bank
|
||||
bit 14 - Horizontal flip
|
||||
bit 15 - Vertical flip
|
||||
Tile formats - Depends on video mode (port $60)
|
||||
Sprites - Max 128 sprites , limited to max 32 on scanline
|
||||
sprite format:
|
||||
byte 0,1 - bits
|
||||
0 - 8 - Tile number (0-511)
|
||||
9 - 11 - Palette number (0-7) + 8 -> (8-15)
|
||||
12 - Sprite window clipping on/off
|
||||
13 - Priority with respect to the layers
|
||||
0 - appear between the 2 background and foreground layers
|
||||
1 - appear on top of both layers
|
||||
14 - Horizontal flip
|
||||
15 - Vertical flip
|
||||
byte 2 - Y position on the screen
|
||||
byte 3 - X position on the screen
|
||||
|
||||
Sprite table is buffered durning frame display.
|
||||
Probably up to scanline 140 (1238-144?)
|
||||
|
||||
Colors - Wonderswan (Mono) is capable of showing 16 shades of gray(only 8 can be selected at any one time)
|
||||
These 8 shades form a pool from which the palette definition can select shades. There are 16 palettes.
|
||||
All 16 palettes are used by BG and FG layers , the last 8 are used also by sprites.
|
||||
Which 8 colors are used for palette generation is defined by ports 1C and 1E- port 1C
|
||||
defines palette colors 0 - 3, port 1E defines 4 - 7. Each palette selection is 4 bits in
|
||||
size:
|
||||
1C : 11110000
|
||||
1D : 33332222
|
||||
1E : 55554444
|
||||
1F : 77776666
|
||||
|
||||
(where color 15 is the darkest one)
|
||||
|
||||
Ports 20 - 3E are used to define the palettes themselves.
|
||||
20 : x111x000 - palette #0
|
||||
21 : x333x222
|
||||
|
||||
In color video modes each color is defined using one word,
|
||||
where bits:
|
||||
0 - 3 Blue
|
||||
4 - 7 Green
|
||||
8 - 11 Red
|
||||
12 - 14 unused
|
||||
Color palettes are stored in the RAM (segment 0) , at address $FE00
|
||||
|
||||
Scrolling - Each of layers can be scrolled horizontal or vertical using ports $10 - $13
|
||||
|
||||
Transparency - Wonderswan - if bit 3 on palette number is set - color 0 of that palette is transparent
|
||||
Wonderswan color - color 0 of each palette is transparent
|
||||
Windows - There are two windows - rectangular areas for disabling /enabling FG layer (FG window) or sprites(Sprite window)
|
||||
|
||||
5. SOUND
|
||||
|
||||
4 Audio channels.
|
||||
Each channel can play short samples ( 4 bit , 16 bytes ( 32 sampels = 2 samples in byte (bits 0-3 and 4-7))
|
||||
with selectable frequency = 3,072 *10e6 / ((2048 - N) x 32 ) Hz , where N = 11 bit value.
|
||||
Location of that samples is unknown.
|
||||
|
||||
Volume of each audio channle is controlled by writing two 4 bit values ( for left/right output
|
||||
channel) into ports $88 - $8B. Master volume is controlled by port $91
|
||||
(2 bit value = first 'used' bit in master volume output (11 bit wide) , D/A converter can
|
||||
read only 8 bits , starting from bit set in port $91 , for example if first 'used' bit
|
||||
is set to 2 , D/A using bits 2,3,4,5,6,7,8,9 for audio output)
|
||||
|
||||
Additional (selectable) functions :
|
||||
- channel 2 - voice - can play 8 bit samples writing frequently data to ch2 volume I/O port
|
||||
- channel 3 - sweep - two parameters:
|
||||
- step = 2.667 x (N + 1) ms , where N = 5 bit value
|
||||
- value - signed byte (-128 - 127)
|
||||
- channel 4 - noise - 7 selectable noise generators (probably I/O port $8E)
|
||||
|
||||
For detailed info please check ports $80 - $91 in section I/O Ports.
|
||||
|
||||
There's also Audio DMA (please chec ports $4a - $52).
|
||||
Transfer rate is 12KHz (HBlank).
|
||||
I/O ports $4A-$4B and $4E-$4F are autupdated durning data transfer .
|
||||
|
||||
6. ROM HEADER
|
||||
|
||||
Header taking last 10 bytes of each ROM file.
|
||||
Bytes :
|
||||
0 - Developer ID
|
||||
1 - Minimum support system
|
||||
00 - WS Mono
|
||||
01 - WS Color
|
||||
2 - Cart ID number for developer defined at byte 0
|
||||
3 - ??
|
||||
4 - ROM Size
|
||||
01 - ?
|
||||
02 - 4Mbit
|
||||
03 - 8Mbit
|
||||
04 - 16Mbit
|
||||
05 - ?
|
||||
06 - 32Mbit
|
||||
07 - ?
|
||||
08 - 64Mbit
|
||||
09 - 128Mbit
|
||||
5 - SRAM/EEPROM Size
|
||||
00 - 0k
|
||||
01 - 64k SRAM
|
||||
02 - 256k SRAM
|
||||
03 - 1M SRAM (Taikyoku Igo Heisei Kiin)
|
||||
04 - 2M SRAM (WonderWitch)
|
||||
10 - 1k EEPROM
|
||||
20 - 16k EEPROM
|
||||
50 - 8k EEPROM
|
||||
6 - Additional capabilities(?)
|
||||
- bit 0 - 1 - vertical position , 1 - horizontal position
|
||||
- bit 2 - always 1
|
||||
|
||||
7 - 1 - RTC (Real Time Clock)
|
||||
8,9 - Checksum = sum of all ROM bytes except two last ones ( where checksum is stored)
|
||||
|
||||
7. INTERRUPTS
|
||||
The Wonderswan CPU recognizes 7 interrupts from the hardware, these are:
|
||||
7 - HBlank Timer
|
||||
6 - VBlank
|
||||
5 - VBlank Timer
|
||||
4 - Drawing line detection
|
||||
3 - Serial Recieve
|
||||
2 - RTC Alarm (cartridge)
|
||||
1 - Key press
|
||||
0 - Serial Send
|
||||
|
||||
Whether the CPU should indeed take action when one of these interrupts come in
|
||||
is determined by port B2. The above mentioned interrupts correspond with the bit
|
||||
numbers of port B2. When an interrupt occurs the corresponding bit of port B6 gets
|
||||
set to 1 and, if enabled, an interrupt to the CPU is generated. This bit of port B6
|
||||
will have to be cleared through code when the interrupt has been handled.
|
||||
|
||||
Example:
|
||||
The Wonderswan is set to react to VBlank begin interrupts. Then bit 7 of B6 is set high
|
||||
and keeps the interrupt line high until the CPU is able to take action upon this interrupt.
|
||||
A typical VBlank interrupt routine is as follows:
|
||||
<push registers>
|
||||
<do some useful work>
|
||||
out B6,40
|
||||
<pop registers>
|
||||
iret
|
||||
|
||||
The mentioned interrupts do not correspond with the same interrupt numbers for the vectors
|
||||
in the vector table. The base for the actual interrupt numbers is set through port B0. If B0
|
||||
is set to 20h then a VBlank begin interrupt routine must be set at vector 26h. (Base is 20h
|
||||
and VBlank begin interrupt is 6)
|
||||
|
||||
8. CONTROLS - It's easy to check buttons status reading/writing port $B5(see below).
|
||||
There's required some delay between writing and reading port $B5 ( few NOP-s)
|
||||
|
||||
9. Internal EEPROM Communication(?) and 'owner' info structure
|
||||
I/O Ports in range 0xBA -0xBE seems to be used for serial reading of internal
|
||||
WS EEPROM (for example - 'owner' info).
|
||||
|
||||
0xBA (Word) - Data
|
||||
0xBC (Word) - Address (calculated probably Modulo EEPROM size (unknown))
|
||||
0xBE (Byte) - Communication (?)
|
||||
bit 4 set before reading data
|
||||
bit 1 set by hardware , when data is ready to read
|
||||
|
||||
Example :
|
||||
|
||||
mov ax, $1B9
|
||||
out $BC, ax
|
||||
mov al, $10
|
||||
out $BE, al
|
||||
xor dx, dx
|
||||
miniloop:
|
||||
inc dx
|
||||
cmp dl, 32
|
||||
jnc bad_data
|
||||
in al, $BE
|
||||
and al, 1
|
||||
jz miniloop
|
||||
in ax, $BA ; Month and Day of birth
|
||||
|
||||
|
||||
'Owner' info structure :
|
||||
|
||||
- Name - 16 bytes ( 0 = Space, 1 = '0' ... 0xA = '9', 0xB = 'A'... )
|
||||
- Year of birth - 2 bytes (BCD)
|
||||
- Month of birth - 1 byte (BCD)
|
||||
- Day of birth - 1 byte (BCD)
|
||||
- Sex - 1 byte (1 - male , 2 - female)
|
||||
- Blood - 1 byte (1 - A, 2 - B, 3 - 0, 4 - AB)
|
||||
|
||||
|
||||
Struct size - 22 bytes = 11 reads,
|
||||
Address range = 0x1B0 - 0x1BA
|
||||
|
||||
10. I/O PORTS (port number /initial value / description)
|
||||
|
||||
- $00 - $00 - Display control
|
||||
bit 0 - background layer on/off
|
||||
bit 1 - foreground layer on/off
|
||||
bit 2 - sprites on/off
|
||||
bit 3 - sprite window on/off (window coords defined in ports $0C - $0F)
|
||||
bit 4,5 - fg win inside on/off (window coords defined in ports $08 - $0B)
|
||||
Meaning of bits 4 and 5 :
|
||||
5 4
|
||||
---
|
||||
0 0 FG layer is displayed inside and outside FG window area
|
||||
0 1 ??
|
||||
1 0 FG layer is displayed only inside window
|
||||
1 1 FG layer is displayed outside window
|
||||
- $01 - $00 - Determines the background color
|
||||
bit 0-3 - background color
|
||||
bit 4-7 - background palette (WSC only)
|
||||
- $02 - ??? - Current Line (0 - 158) (159 ???)
|
||||
- $03 - $BB - Line compare (for drawning line detection interrupt)
|
||||
- $04 - $00 - Determines the base address for the sprite table.
|
||||
To get the address of the table, shift this value left 9 times
|
||||
and clear MSB. (bits 0..5 are effective to determines the base,
|
||||
bits 6,7 are unknown)
|
||||
0 0xxxxxx0 00000000
|
||||
(Sprite Attribute Table Base can move from $00000-$07E00 with 512 bytes step)
|
||||
- $05 - $00 - Determines the number of the sprite to start drawing with
|
||||
- $06 - $00 - Determines the number of the sprite to stop drawing.
|
||||
- $07 - $26 - Determines the location of the foreground and background screens in RAM.
|
||||
Format:
|
||||
bits 7-0 : ?fff?bbb
|
||||
bit 7 - Unknown
|
||||
bits 6-4 - Determines foreground location (address is 00fff000 00000000)
|
||||
bit 3-? - Unknown
|
||||
bits 2-0 - Determines background location (address is 00bbb000 00000000)
|
||||
Back Ground Tile Map Base can move from $00000-$03800 (2048 bytes step)
|
||||
- $08 - $FE - x0 of FG window (x0,y0) = top left corner, (x1,y1) = bottom right corner
|
||||
- $09 - $DE - y0 of FG window
|
||||
- $0A - $F9 - x1 of FG window
|
||||
- $0B - $FB - y1 of FG window
|
||||
- $0C - $DB - x0 of SPR window
|
||||
- $0D - $D7 - y0 of SPR window
|
||||
- $0E - $7F - x1 of SPR window
|
||||
- $0F - $F5 - y1 of SPR window
|
||||
- $10 - $00 - Background layer X scroll register
|
||||
- $11 - $00 - Background layer Y scroll register
|
||||
- $12 - $00 - Foreground layer X scroll register
|
||||
- $13 - $00 - Foreground layer Y scroll register
|
||||
- $14 - $01 - LCD Control (???)
|
||||
bit 0 - 1 - LCD on
|
||||
0 - LCD off
|
||||
- $15 - $00 - LCD Icons
|
||||
bit 0 - LCD Sleep
|
||||
bit 1 - Vertical Position
|
||||
bit 2 - Horizontal Position
|
||||
bit 3 - Dot 1
|
||||
bit 4 - Dot 2
|
||||
bit 5 - Dot 3
|
||||
bit 6 - Not Used ?
|
||||
bit 7 - Not Used ?
|
||||
- $16 - $9E - ???
|
||||
- $17 - $9B - ???
|
||||
- $18 - $00 - ???
|
||||
- $19 - $00 - ???
|
||||
- $1A - $00 - ???
|
||||
- $1B - $00 - ???
|
||||
- $1C - $99 - PALCOL10
|
||||
- $1D - $FD - PALCOL32
|
||||
- $1E - $B7 - PALCOL54
|
||||
- $1F - $DF - PALCOL76
|
||||
- $20 - $30 - PAL00
|
||||
- $21 - $57 - PAL01
|
||||
- $22 - $75 - PAL10
|
||||
- $23 - $76 - PAL11
|
||||
- $24 - $15 - PAL20
|
||||
- $25 - $73 - PAL21
|
||||
- $26 - $77 - PAL30
|
||||
- $27 - $77 - PAL31
|
||||
- $28 - $20 - PAL40
|
||||
- $29 - $75 - PAL41
|
||||
- $2A - $50 - PAL50
|
||||
- $2B - $36 - PAL51
|
||||
- $2C - $70 - PAL60
|
||||
- $2D - $67 - PAL61
|
||||
- $2E - $50 - PAL70
|
||||
- $2F - $77 - PAL70
|
||||
- $30 - $57 - PAL00
|
||||
- $31 - $54 - PAL01
|
||||
- $32 - $75 - PAL10
|
||||
- $33 - $77 - PAL11
|
||||
- $34 - $75 - PAL20
|
||||
- $35 - $17 - PAL21
|
||||
- $36 - $37 - PAL30
|
||||
- $37 - $73 - PAL31
|
||||
- $38 - $50 - PAL40
|
||||
- $39 - $57 - PAL41
|
||||
- $3A - $60 - PAL50
|
||||
- $3B - $77 - PAL51
|
||||
- $3C - $70 - PAL60
|
||||
- $3D - $77 - PAL61
|
||||
- $3E - $10 - PAL70
|
||||
- $3F - $73 - PAL70
|
||||
- $40 - $00 - DMA (?) copy source address
|
||||
- $41 - $00 - ^^^
|
||||
- $42 - $00 - copy source bank
|
||||
- $43 - $00 - copy destination bank
|
||||
- $44 - $00 - copy destination address
|
||||
- $45 - $00 - ^^^
|
||||
- $46 - $00 - size of copied data (in bytes)
|
||||
- $47 - $00 - ^^^
|
||||
- $48 - $00 - bit 7 = 1 -> copy start
|
||||
(bit 7=0 when data transfer is finished)
|
||||
DMA(?) isn't immediate and not stopping
|
||||
the main cpu operations (like gbc GDMA)
|
||||
ports $40-$48 are updated durning copy process
|
||||
- $49 - $00 - ???
|
||||
|
||||
- $4A - $00 - sound DMA source address
|
||||
- $4B - $00 - ^^^
|
||||
- $4C - $00 - DMA source memory segment bank
|
||||
- $4D - $00 - ???
|
||||
- $4E - $00 - DMA transfer size (in bytes)
|
||||
- $4F - $00 - ^^^
|
||||
- $50 - $00 - ???
|
||||
- $51 - $00 - ???
|
||||
- $52 - $00 - bit 7 = 1 -> DMA start
|
||||
- $53 - $00 - ???
|
||||
- $54 - $00 - ???
|
||||
- $55 - $00 - ???
|
||||
- $56 - $00 - ???
|
||||
- $57 - $00 - ???
|
||||
- $58 - $00 - ???
|
||||
- $59 - $00 - ???
|
||||
- $5A - $00 - ???
|
||||
- $5B - $00 - ???
|
||||
- $5C - $00 - ???
|
||||
- $5D - $00 - ???
|
||||
- $5E - $00 - ???
|
||||
- $5F - $00 - ???
|
||||
- $60 - $0A - video mode
|
||||
Meaning of bits 5-7:
|
||||
765
|
||||
---
|
||||
111 16 col/tile 'packed' mode - tiles like in Genesis, 16 col/tile
|
||||
110 16 col/tile 'layered' mode - tiles like in GameGear, 16 col/tile
|
||||
010 4 col/tile - the same as mono (below) but using color palettes, 4 cols/tile, one tile = 16 bytes, WSC only
|
||||
000 4 col/tile mono - tiles like in GameBoy,
|
||||
[bit 7 = 16/4 color/tile , bit 6 - color/mono mode, bit 5 - 'packed' mode on/off]
|
||||
- $61 - $00 - ???
|
||||
- $62 - $00 - ???
|
||||
- $63 - $00 - ???
|
||||
- $64 - $00 - ???
|
||||
- $65 - $00 - ???
|
||||
- $66 - $00 - ???
|
||||
- $67 - $00 - ???
|
||||
- $68 - $00 - ???
|
||||
- $69 - $00 - ???
|
||||
- $6A - $00 - ???
|
||||
- $6B - $0F - ???
|
||||
- $6C - $00 - ???
|
||||
- $6D - $00 - ???
|
||||
- $6E - $00 - ???
|
||||
- $6F - $00 - ???
|
||||
- $70 - $00 - ???
|
||||
- $71 - $00 - ???
|
||||
- $72 - $00 - ???
|
||||
- $73 - $00 - ???
|
||||
- $74 - $00 - ???
|
||||
- $75 - $00 - ???
|
||||
- $76 - $00 - ???
|
||||
- $77 - $00 - ???
|
||||
- $78 - $00 - ???
|
||||
- $79 - $00 - ???
|
||||
- $7A - $00 - ???
|
||||
- $7B - $00 - ???
|
||||
- $7C - $00 - ???
|
||||
- $7D - $00 - ???
|
||||
- $7E - $00 - ???
|
||||
- $7F - $00 - ???
|
||||
- $80 - $00 - Audio 1 Freq
|
||||
- $81 - $00 - ^^^
|
||||
- $82 - $00 - Audio 2 Freq
|
||||
- $83 - $00 - ^^^
|
||||
- $84 - $00 - Audio 3 Freq
|
||||
- $85 - $00 - ^^^
|
||||
- $86 - $00 - Audio 4 Freq
|
||||
- $87 - $00 - ^^^
|
||||
- $88 - $00 - Audio 1 volume
|
||||
- $89 - $00 - Audio 2 volume
|
||||
- $8A - $00 - Audio 3 volume
|
||||
- $8B - $00 - Audio 4 volume
|
||||
- $8C - $00 - ?? Sweep value
|
||||
- $8D - $1F - ?? Sweep step
|
||||
- $8E - $00 - Noise control
|
||||
Bits :
|
||||
0 - Noise generator type
|
||||
1 - ^^^
|
||||
2 - ^^^
|
||||
3 - Reset
|
||||
4 - Enable
|
||||
5 - ???
|
||||
6 - ???
|
||||
7 - ???
|
||||
- $8F - $00 - Sample location
|
||||
To get the address of samples, shift this value left 6 times.
|
||||
0 00xxxxxx xx000000
|
||||
- $90 - $00 - Audio control
|
||||
Bits:
|
||||
0 - Audio 1 on/off
|
||||
1 - Audio 2 on/off
|
||||
2 - Audio 3 on/off
|
||||
3 - Audio 4 on/off
|
||||
4 - ???
|
||||
5 - Audio 2 Voice
|
||||
6 - Audio 3 Sweep
|
||||
7 - Audio 4 Noise
|
||||
- $91 - $00 - Audio Output
|
||||
Bits :
|
||||
0 - Mono
|
||||
1 - Output Volume
|
||||
2 - ^^^
|
||||
3 - External Stereo
|
||||
4 - ???
|
||||
5 - ???
|
||||
6 - ???
|
||||
7 - External Speaker (set by hardware)
|
||||
- $92 - $00 - Noise Counter Shift Register (15 bits)
|
||||
- $93 - $00 - ^^^
|
||||
- $94 - $00 - Volume (4 bit)
|
||||
- $95 - $00 - ???
|
||||
- $96 - $00 - ???
|
||||
- $97 - $00 - ???
|
||||
- $98 - $00 - ???
|
||||
- $99 - $00 - ???
|
||||
- $9A - $00 - ???
|
||||
- $9B - $00 - ???
|
||||
- $9C - $00 - ???
|
||||
- $9D - $00 - ???
|
||||
- $9E - $03 - ???
|
||||
- $9F - $00 - ???
|
||||
- $A0 - $87 - Hardware type
|
||||
bit 1 - 1 - color
|
||||
0 - mono
|
||||
- $A1 - $00 - ???
|
||||
- $A2 - $0C - Timer Control
|
||||
bit 0 - Hblank Timer on/off
|
||||
bit 1 - Hblank Timer Mode
|
||||
0 - One Shot
|
||||
1 - Auto Preset
|
||||
bit 2 - Vblank Timer(1/75s) on/off
|
||||
bit 3 - Vblank Timer Mode
|
||||
0 - One Shot
|
||||
1 - Auto Preset
|
||||
- $A3 - $00 - ???
|
||||
- $A4 - $00 - Hblank Timer 'frequency'
|
||||
0 = no HBLANK Interrupt
|
||||
n = HBLANK Interrupt every n lines (???)
|
||||
- $A5 - $00 - ^^^
|
||||
- $A6 - $4F - Vblank Timer 'frequency'
|
||||
- $A7 - $FF - ^^^
|
||||
- $A8 - $00 - Hblank Counter - 1/12000s
|
||||
- $A9 - $00 - Hblank Counter - 1/(12000>>8)s
|
||||
- $AA - $00 - Vblank Counter - 1/75s
|
||||
- $AB - $00 - Vblank Counter - 1/(75>>8)s
|
||||
- $AC - $00 - ???
|
||||
- $AD - $00 - ???
|
||||
- $AE - $00 - ???
|
||||
- $AF - $00 - ???
|
||||
- $B0 - $00 - Interrupt Base
|
||||
- $B1 - $DB - Communication byte
|
||||
- $B2 - $00 - Interrupt enable
|
||||
bit 7 - HBlank Timer
|
||||
bit 6 - VBlank begin
|
||||
bit 5 - VBlank Timer
|
||||
bit 4 - Drawing line detection
|
||||
bit 3 - Serial receive
|
||||
bit 2 - RTC Alarm
|
||||
bit 1 - Key press
|
||||
bit 0 - Serial transmit
|
||||
- $B3 - $00 - Communication direction
|
||||
bit 7 - Recieve data interrupt generation
|
||||
bit 6 - Connection Speed
|
||||
0 - 9600 bps
|
||||
1 - 38400 bps
|
||||
bit 5 - Send data interrupt generation
|
||||
bit 4 - ???
|
||||
bit 3 - ???
|
||||
bit 2 - Send Complete
|
||||
bit 1 - Error
|
||||
bit 0 - Recieve Complete
|
||||
|
||||
write $00-$7f = read $00
|
||||
write $80-$bf = read $84
|
||||
write $c0-$cf = read $c4
|
||||
- $B4 - $00 - ???
|
||||
- $B5 - $40 - Controls
|
||||
bits 4-7 : read/write - Select line of inputs to read
|
||||
0001 - read vertical cursors
|
||||
0010 - read hozizontal cursors
|
||||
0100 - read buttons
|
||||
bits 0-3 : read only - Read the current state of the input lines (positive logic) after having written 10h,20h, or 40h.
|
||||
Meaning of the bits when reading cursors:
|
||||
bit 0 - cursor up
|
||||
bit 1 - cursor right
|
||||
bit 2 - cursor down
|
||||
bit 3 - cursor left
|
||||
Meaning of the bits when reading buttons:
|
||||
bit 0 - ???
|
||||
bit 1 - START
|
||||
bit 2 - A
|
||||
bit 3 - B
|
||||
- $B6 - $00 - Interrupt Acknowledge
|
||||
bit 7 - HBlank Timer
|
||||
bit 6 - VBlank begin
|
||||
bit 5 - VBlank Timer
|
||||
bit 4 - Drawing line detection
|
||||
bit 3 - Serial receive
|
||||
bit 2 - RTC Alarm
|
||||
bit 1 - Key press
|
||||
bit 0 - Serial transmit
|
||||
- $B7 - $00 - ???
|
||||
- $B8 - $00 - ???
|
||||
- $B9 - $00 - ???
|
||||
- $BA - $01 - Internal EEPROM (?) Data
|
||||
- $BB - $00 - ^^^
|
||||
- $BC - $42 - Internal EEPROM (?) Address (calculated probably Modulo EEPROM (1kbit?) size (mirroring for read/write))
|
||||
- $BD - $00 - ^^^
|
||||
- $BE - $83 - Internal EEPROM (?) Command
|
||||
bit 7 - Initialize ?
|
||||
bit 6 - Protect ?
|
||||
bit 5 - Write
|
||||
bit 4 - Read
|
||||
bit 3 - ???
|
||||
bit 2 - ???
|
||||
bit 1 - Write Complete (Read only)
|
||||
bit 0 - Read Complete (Read only)
|
||||
- $BF - $00 - ???
|
||||
- $C0 - $2F - ROM Bank Base Selector for segments 4-$F
|
||||
- $C1 - $3F - SRAM Bank selector (???)
|
||||
- $C2 - $FF - BNK2SLCT - ROM Bank selector for segment 2
|
||||
- $C3 - $FF - BNK3SLCT - ROM Bank selector for segment 3
|
||||
- $C4 - $00 - EEPROM Data
|
||||
- $C5 - $00 - ^^^
|
||||
- $C6 - $00 - 1kbit EEPROM (16bit*64) :
|
||||
- bits 0-5 - address
|
||||
- bits 6-7 - command :
|
||||
0 - Extended Comand Address bits 4-5
|
||||
0 - Write Disable
|
||||
1 - Write All
|
||||
2 - Erase All
|
||||
3 - Write Enable
|
||||
1 - Write
|
||||
2 - Read
|
||||
3 - Erase
|
||||
- 16 kbit EEPROM (16bit*1024) - bits 0-7 - address (low)
|
||||
- $C7 - $00 - 1kbit EEPROM (16bit*64) :
|
||||
bit 0 - Start
|
||||
- 16 kbit EEPROM (16bit*1024) :
|
||||
- bits 0-1 - address (high)
|
||||
- bits 2-3 - command :
|
||||
0 - Extended Comand Address bits 0-1
|
||||
0 - Write Disable
|
||||
1 - Write All
|
||||
2 - Erase All
|
||||
3 - Write Enable
|
||||
1 - Write
|
||||
2 - Read
|
||||
3 - Erase
|
||||
- bit 4 - Start
|
||||
- $C8 - $D1 - EEPROM Command :
|
||||
bit 7 - Initialize ???
|
||||
bit 6 - Protect ???
|
||||
bit 5 - Write
|
||||
bit 4 - Read
|
||||
bit 3 - ???
|
||||
bit 2 - ???
|
||||
bit 1 - Write Complete (Read only)
|
||||
bit 0 - Read Complete (Read only)
|
||||
- $C9 - $D1 - ???
|
||||
- $CA - $D1 - RTC Command
|
||||
Write :
|
||||
- $10 - Reset
|
||||
- $12 - ??? Alarm ???
|
||||
- $13 - ???
|
||||
- $14 - Set Time
|
||||
- $15 - Get Time
|
||||
Read:
|
||||
- bit 7 - Ack [HACK = 1]
|
||||
- $CB - $D1 - RTC Data
|
||||
Write :
|
||||
Sometimes $40 , and wait for bit 7 = 1
|
||||
After Command ($CA):
|
||||
- $14 - 7 writes (all BCD):
|
||||
- Year ( + 2000)
|
||||
- Month
|
||||
- Day
|
||||
- Day Of Week
|
||||
- Hour
|
||||
- Min
|
||||
- Sec
|
||||
Read
|
||||
After Command ($CA) :
|
||||
- $13 - bit 7 - Ack [HACK = 1]
|
||||
- $15 - 7 reads (all BCD)
|
||||
- Year ( + 2000)
|
||||
- Month
|
||||
- Day
|
||||
- Day Of Week
|
||||
- Hour
|
||||
- Min
|
||||
- Sec
|
||||
- $CC - $D1 - ???
|
||||
- $CD - $D1 - ???
|
||||
- $CE - $D1 - ???
|
||||
- $CF - $D1 - ???
|
||||
- $D0 - $D1 - ???
|
||||
- $D1 - $D1 - ???
|
||||
- $D2 - $D1 - ???
|
||||
- $D3 - $D1 - ???
|
||||
- $D4 - $D1 - ???
|
||||
- $D5 - $D1 - ???
|
||||
- $D6 - $D1 - ???
|
||||
- $D7 - $D1 - ???
|
||||
- $D8 - $D1 - ???
|
||||
- $D9 - $D1 - ???
|
||||
- $DA - $D1 - ???
|
||||
- $DB - $D1 - ???
|
||||
- $DC - $D1 - ???
|
||||
- $DD - $D1 - ???
|
||||
- $DE - $D1 - ???
|
||||
- $DF - $D1 - ???
|
||||
- $E0 - $D1 - ???
|
||||
- $E1 - $D1 - ???
|
||||
- $E2 - $D1 - ???
|
||||
- $E3 - $D1 - ???
|
||||
- $E4 - $D1 - ???
|
||||
- $E5 - $D1 - ???
|
||||
- $E6 - $D1 - ???
|
||||
- $E7 - $D1 - ???
|
||||
- $E8 - $D1 - ???
|
||||
- $E9 - $D1 - ???
|
||||
- $EA - $D1 - ???
|
||||
- $EB - $D1 - ???
|
||||
- $EC - $D1 - ???
|
||||
- $ED - $D1 - ???
|
||||
- $EE - $D1 - ???
|
||||
- $EF - $D1 - ???
|
||||
- $F0 - $D1 - ???
|
||||
- $F1 - $D1 - ???
|
||||
- $F2 - $D1 - ???
|
||||
- $F3 - $D1 - ???
|
||||
- $F4 - $D1 - ???
|
||||
- $F5 - $D1 - ???
|
||||
- $F6 - $D1 - ???
|
||||
- $F7 - $D1 - ???
|
||||
- $F8 - $D1 - ???
|
||||
- $F9 - $D1 - ???
|
||||
- $FA - $D1 - ???
|
||||
- $FB - $D1 - ???
|
||||
- $FC - $D1 - ???
|
||||
- $FD - $D1 - ???
|
||||
- $FE - $D1 - ???
|
||||
- $FF - $D1 - ???
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef __WSWAN_H
|
||||
#define __WSWAN_H
|
||||
|
||||
#include <mednafen/types.h>
|
||||
#include <mednafen/state.h>
|
||||
|
||||
#include "interrupt.h"
|
||||
|
||||
namespace MDFN_IEN_WSWAN
|
||||
{
|
||||
|
||||
#define mBCD(value) (((value)/10)<<4)|((value)%10)
|
||||
|
||||
//extern uint32 rom_size;
|
||||
//extern int wsc;
|
||||
|
||||
/*
|
||||
enum
|
||||
{
|
||||
WSWAN_SEX_MALE = 1,
|
||||
WSWAN_SEX_FEMALE = 2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WSWAN_BLOOD_A = 1,
|
||||
WSWAN_BLOOD_B = 2,
|
||||
WSWAN_BLOOD_O = 3,
|
||||
WSWAN_BLOOD_AB = 4
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue