mednafen 0.9.34.1 "cygne" (wonderswan)

This commit is contained in:
goyuken 2014-05-30 05:09:54 +00:00
parent 2053349e31
commit c306e61d5b
40 changed files with 7952 additions and 0 deletions

View File

@ -23,6 +23,7 @@ using BizHawk.Emulation.Cores.Sega.Saturn;
using BizHawk.Emulation.Cores.Sony.PSP; using BizHawk.Emulation.Cores.Sony.PSP;
using BizHawk.Emulation.Cores.Sony.PSX; using BizHawk.Emulation.Cores.Sony.PSX;
using BizHawk.Emulation.DiscSystem; using BizHawk.Emulation.DiscSystem;
using BizHawk.Emulation.Cores.WonderSwan;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -413,6 +414,9 @@ namespace BizHawk.Client.Common
case "N64": case "N64":
nextEmulator = new N64(nextComm, game, rom.RomData, GetCoreSyncSettings<N64>()); nextEmulator = new N64(nextComm, game, rom.RomData, GetCoreSyncSettings<N64>());
break; break;
case "WSWAN":
nextEmulator = new WonderSwan(nextComm, rom.RomData);
break;
case "DEBUG": case "DEBUG":
if (VersionInfo.INTERIM) if (VersionInfo.INTERIM)
{ {

View File

@ -324,6 +324,11 @@ namespace BizHawk.Emulation.Common
case ".DEBUG": case ".DEBUG":
game.System = "DEBUG"; game.System = "DEBUG";
break; break;
case ".WS":
case ".WSC":
game.System = "WSWAN";
break;
} }
game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' '); game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' ');

View File

@ -470,6 +470,8 @@
<Compile Include="Consoles\Sony\PSP\PSP.cs" /> <Compile Include="Consoles\Sony\PSP\PSP.cs" />
<Compile Include="Consoles\Sony\PSX\LibMednahawkDll.cs" /> <Compile Include="Consoles\Sony\PSX\LibMednahawkDll.cs" />
<Compile Include="Consoles\Sony\PSX\Octoshock.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\Diassembler.cs" />
<Compile Include="CPUs\68000\Instructions\BitArithemetic.cs" /> <Compile Include="CPUs\68000\Instructions\BitArithemetic.cs" />
<Compile Include="CPUs\68000\Instructions\DataMovement.cs" /> <Compile Include="CPUs\68000\Instructions\DataMovement.cs" />

View File

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

View File

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

BIN
output/dll/bizswan.dll Normal file

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

208
wonderswan/eeprom.cpp Normal file
View File

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

32
wonderswan/eeprom.h Normal file
View File

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

601
wonderswan/gfx.cpp Normal file
View File

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

91
wonderswan/gfx.h Normal file
View File

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

77
wonderswan/interrupt.cpp Normal file
View File

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

48
wonderswan/interrupt.h Normal file
View File

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

94
wonderswan/main.cpp Normal file
View File

@ -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
};
*/

View File

@ -0,0 +1,4 @@
#ifndef _STATE_H
#define _STATE_H
#endif

201
wonderswan/mednafen/types.h Normal file
View File

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

390
wonderswan/memory.cpp Normal file
View File

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

85
wonderswan/memory.h Normal file
View File

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

View File

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

305
wonderswan/msvc/inttypes.h Normal file
View File

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

247
wonderswan/msvc/stdint.h Normal file
View File

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

98
wonderswan/rtc.cpp Normal file
View File

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

28
wonderswan/rtc.h Normal file
View File

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

386
wonderswan/sound.cpp Normal file
View File

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

71
wonderswan/sound.h Normal file
View File

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

269
wonderswan/start.inc Normal file
View File

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

315
wonderswan/system.cpp Normal file
View File

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

68
wonderswan/system.h Normal file
View File

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

290
wonderswan/tcache.cpp Normal file
View File

@ -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
wonderswan/v30mz-ea.inc Normal file
View File

View File

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

252
wonderswan/v30mz-private.h Normal file
View File

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

1035
wonderswan/v30mz.cpp Normal file

File diff suppressed because it is too large Load Diff

166
wonderswan/v30mz.h Normal file
View File

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

757
wonderswan/wstech24.txt Normal file
View File

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

34
wonderswan/wswan.h Normal file
View File

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