diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index 5f989de38a..a93abaefc7 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -23,6 +23,7 @@ using BizHawk.Emulation.Cores.Sega.Saturn; using BizHawk.Emulation.Cores.Sony.PSP; using BizHawk.Emulation.Cores.Sony.PSX; using BizHawk.Emulation.DiscSystem; +using BizHawk.Emulation.Cores.WonderSwan; namespace BizHawk.Client.Common { @@ -413,6 +414,9 @@ namespace BizHawk.Client.Common case "N64": nextEmulator = new N64(nextComm, game, rom.RomData, GetCoreSyncSettings()); break; + case "WSWAN": + nextEmulator = new WonderSwan(nextComm, rom.RomData); + break; case "DEBUG": if (VersionInfo.INTERIM) { diff --git a/BizHawk.Emulation.Common/Database/Database.cs b/BizHawk.Emulation.Common/Database/Database.cs index 6510129f01..01e5c62e19 100644 --- a/BizHawk.Emulation.Common/Database/Database.cs +++ b/BizHawk.Emulation.Common/Database/Database.cs @@ -324,6 +324,11 @@ namespace BizHawk.Emulation.Common case ".DEBUG": game.System = "DEBUG"; break; + + case ".WS": + case ".WSC": + game.System = "WSWAN"; + break; } game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' '); diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index abe1a599d5..fedf87a821 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -470,6 +470,8 @@ + + diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/BizSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/BizSwan.cs new file mode 100644 index 0000000000..81e10ed943 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/BizSwan.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.WonderSwan +{ + public static class BizSwan + { + const CallingConvention cc = CallingConvention.Cdecl; + const string dd = "bizswan.dll"; + + [DllImport(dd, CallingConvention = cc)] + public static extern IntPtr bizswan_new(); + + [DllImport(dd, CallingConvention = cc)] + public static extern void bizswan_delete(IntPtr core); + + [DllImport(dd, CallingConvention = cc)] + public static extern void bizswan_reset(IntPtr core); + + [DllImport(dd, CallingConvention = cc)] + public static extern void bizswan_advance(IntPtr core, Buttons buttons, bool novideo, int[] surface, short[] soundbuff, ref int soundbuffsize); + + [DllImport(dd, CallingConvention = cc)] + public static extern bool bizswan_load(IntPtr core, byte[] data, int length, [In] ref Settings settings); + + [Flags] + public enum Buttons : ushort + { + UpX = 0x0001, + DownX = 0x0002, + LeftX = 0x0004, + RightX = 0x0008, + UpY = 0x0010, + DownY = 0x0020, + LeftY = 0x0040, + RightY = 0x0080, + Start = 0x0100, + B = 0x0200, + A = 0x0400, + } + + public enum Language : byte + { + Japanese = 0, + English = 1 + } + + public enum Bloodtype : byte + { + A = 1, + B = 2, + O = 3, + AB = 4 + } + + public enum Gender : byte + { + Male = 1, + Female = 2 + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct Settings + { + public ushort byear; + public byte bmonth; + public byte bday; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public byte[] name; + public Language language; + public Gender sex; + public Bloodtype blood; + [MarshalAs(UnmanagedType.U1)] + public bool rotateinput; + + public void SetName(string newname) + { + byte[] data = Encoding.ASCII.GetBytes(newname); + name = new byte[17]; + Buffer.BlockCopy(data, 0, name, 0, Math.Min(data.Length, name.Length)); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs new file mode 100644 index 0000000000..54bea55575 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -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 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 + } +} diff --git a/output/dll/bizswan.dll b/output/dll/bizswan.dll new file mode 100644 index 0000000000..5000718d63 Binary files /dev/null and b/output/dll/bizswan.dll differ diff --git a/wonderswan/bizswan/bizswan.sln b/wonderswan/bizswan/bizswan.sln new file mode 100644 index 0000000000..742e57fa9b --- /dev/null +++ b/wonderswan/bizswan/bizswan.sln @@ -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 diff --git a/wonderswan/bizswan/bizswan.vcxproj b/wonderswan/bizswan/bizswan.vcxproj new file mode 100644 index 0000000000..fd15924816 --- /dev/null +++ b/wonderswan/bizswan/bizswan.vcxproj @@ -0,0 +1,110 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {F92A3734-EAE1-44D9-B474-FF80AE039790} + bizswan + + + + DynamicLibrary + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + + + + + + + + + + + + + Level3 + Disabled + $(ProjectDir)\..;$(ProjectDir)\..\msvc + _WINDLL;%(PreprocessorDefinitions);LSB_FIRST + + + true + + + copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\..\output\dll\$(TargetFileName) + + + + + Level3 + MaxSpeed + true + true + $(ProjectDir)\..;$(ProjectDir)\..\msvc + _WINDLL;%(PreprocessorDefinitions);LSB_FIRST + + + true + true + true + + + copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\..\output\dll\$(TargetFileName) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wonderswan/bizswan/bizswan.vcxproj.filters b/wonderswan/bizswan/bizswan.vcxproj.filters new file mode 100644 index 0000000000..97d6f1b7b6 --- /dev/null +++ b/wonderswan/bizswan/bizswan.vcxproj.filters @@ -0,0 +1,122 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {d0b85f88-6eca-4fa8-bf29-4d75ff7471fe} + + + {fc621339-f39c-496f-8085-9f3bf7e64a80} + + + {f7aba5a2-698c-4085-a191-b0ffd3522298} + + + {4fb57465-2aae-4d75-87de-a2669a0570b4} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\blip + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\msvc + + + Header Files\msvc + + + Header Files\mednafen + + + Header Files\mednafen + + + Header Files\blip + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/wonderswan/blip/Blip_Buffer.cpp b/wonderswan/blip/Blip_Buffer.cpp new file mode 100644 index 0000000000..f04a1fc599 --- /dev/null +++ b/wonderswan/blip/Blip_Buffer.cpp @@ -0,0 +1,457 @@ +// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ + +#include "Blip_Buffer.h" + +#include +#include +#include +#include +#include +#include + +/* 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; +} + diff --git a/wonderswan/blip/Blip_Buffer.h b/wonderswan/blip/Blip_Buffer.h new file mode 100644 index 0000000000..a8e90ee053 --- /dev/null +++ b/wonderswan/blip/Blip_Buffer.h @@ -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 +#include + +// 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 +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 + +template +blip_inline void Blip_Synth::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 +#if BLIP_BUFFER_FAST + blip_inline +#endif +void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const +{ + offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); +} + +template +#if BLIP_BUFFER_FAST + blip_inline +#endif +void Blip_Synth::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 diff --git a/wonderswan/eeprom.cpp b/wonderswan/eeprom.cpp new file mode 100644 index 0000000000..087915403e --- /dev/null +++ b/wonderswan/eeprom.cpp @@ -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 +#include + +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; + } + +} diff --git a/wonderswan/eeprom.h b/wonderswan/eeprom.h new file mode 100644 index 0000000000..26d5e7b4f5 --- /dev/null +++ b/wonderswan/eeprom.h @@ -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 diff --git a/wonderswan/gfx.cpp b/wonderswan/gfx.cpp new file mode 100644 index 0000000000..d34f238a2e --- /dev/null +++ b/wonderswan/gfx.cpp @@ -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 +//#include +#include + +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; + + } + +} diff --git a/wonderswan/gfx.h b/wonderswan/gfx.h new file mode 100644 index 0000000000..3974a4b8d1 --- /dev/null +++ b/wonderswan/gfx.h @@ -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 diff --git a/wonderswan/interrupt.cpp b/wonderswan/interrupt.cpp new file mode 100644 index 0000000000..bff9d854fc --- /dev/null +++ b/wonderswan/interrupt.cpp @@ -0,0 +1,77 @@ +#include "system.h" +//#include + +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(); + } + +} diff --git a/wonderswan/interrupt.h b/wonderswan/interrupt.h new file mode 100644 index 0000000000..6c41e18205 --- /dev/null +++ b/wonderswan/interrupt.h @@ -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 diff --git a/wonderswan/main.cpp b/wonderswan/main.cpp new file mode 100644 index 0000000000..e36fa1b575 --- /dev/null +++ b/wonderswan/main.cpp @@ -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 +//#include +//#include + +//#include +//#include +//#include +#include +//#include + +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 +}; +*/ diff --git a/wonderswan/mednafen/state.h b/wonderswan/mednafen/state.h new file mode 100644 index 0000000000..d39a3ad865 --- /dev/null +++ b/wonderswan/mednafen/state.h @@ -0,0 +1,4 @@ +#ifndef _STATE_H +#define _STATE_H + +#endif diff --git a/wonderswan/mednafen/types.h b/wonderswan/mednafen/types.h new file mode 100644 index 0000000000..320aab5069 --- /dev/null +++ b/wonderswan/mednafen/types.h @@ -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 +#endif + +#include +#include + +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 diff --git a/wonderswan/memory.cpp b/wonderswan/memory.cpp new file mode 100644 index 0000000000..847798ae35 --- /dev/null +++ b/wonderswan/memory.cpp @@ -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 +#include +#include +#include + + +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 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; + } + +} diff --git a/wonderswan/memory.h b/wonderswan/memory.h new file mode 100644 index 0000000000..779685768e --- /dev/null +++ b/wonderswan/memory.h @@ -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 diff --git a/wonderswan/msvc/changelog.txt b/wonderswan/msvc/changelog.txt new file mode 100644 index 0000000000..cf0539c253 --- /dev/null +++ b/wonderswan/msvc/changelog.txt @@ -0,0 +1,138 @@ +------------------------------------------------------------------------ +r26 | 2009-10-02 13:36:47 +0400 | 2 lines + +[Issue 5] Change 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 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 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 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 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. +------------------------------------------------------------------------ diff --git a/wonderswan/msvc/inttypes.h b/wonderswan/msvc/inttypes.h new file mode 100644 index 0000000000..25542771f5 --- /dev/null +++ b/wonderswan/msvc/inttypes.h @@ -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_ ] diff --git a/wonderswan/msvc/stdint.h b/wonderswan/msvc/stdint.h new file mode 100644 index 0000000000..59d067302f --- /dev/null +++ b/wonderswan/msvc/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap 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 +#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 +#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_ ] diff --git a/wonderswan/rtc.cpp b/wonderswan/rtc.cpp new file mode 100644 index 0000000000..643a140637 --- /dev/null +++ b/wonderswan/rtc.cpp @@ -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 + +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++; + } + } + +} diff --git a/wonderswan/rtc.h b/wonderswan/rtc.h new file mode 100644 index 0000000000..d4319e2c43 --- /dev/null +++ b/wonderswan/rtc.h @@ -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 diff --git a/wonderswan/sound.cpp b/wonderswan/sound.cpp new file mode 100644 index 0000000000..90300a61e9 --- /dev/null +++ b/wonderswan/sound.cpp @@ -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 + + +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(); + } + +} diff --git a/wonderswan/sound.h b/wonderswan/sound.h new file mode 100644 index 0000000000..e0c9cddd04 --- /dev/null +++ b/wonderswan/sound.h @@ -0,0 +1,71 @@ +#ifndef __WSWAN_SOUND_H +#define __WSWAN_SOUND_H + +#include "system.h" +#include + +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 WaveSynth; + Blip_Synth NoiseSynth; + Blip_Synth 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 diff --git a/wonderswan/start.inc b/wonderswan/start.inc new file mode 100644 index 0000000000..54a871f986 --- /dev/null +++ b/wonderswan/start.inc @@ -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 diff --git a/wonderswan/system.cpp b/wonderswan/system.cpp new file mode 100644 index 0000000000..d314822362 --- /dev/null +++ b/wonderswan/system.cpp @@ -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 +#include +#include +#include + +#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); + } + +} diff --git a/wonderswan/system.h b/wonderswan/system.h new file mode 100644 index 0000000000..9638b83d66 --- /dev/null +++ b/wonderswan/system.h @@ -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 + +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 diff --git a/wonderswan/tcache.cpp b/wonderswan/tcache.cpp new file mode 100644 index 0000000000..661dcb4f3c --- /dev/null +++ b/wonderswan/tcache.cpp @@ -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 + +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); + } + } + +} diff --git a/wonderswan/v30mz-ea.inc b/wonderswan/v30mz-ea.inc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wonderswan/v30mz-modrm.inc b/wonderswan/v30mz-modrm.inc new file mode 100644 index 0000000000..e0496c4441 --- /dev/null +++ b/wonderswan/v30mz-modrm.inc @@ -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) diff --git a/wonderswan/v30mz-private.h b/wonderswan/v30mz-private.h new file mode 100644 index 0000000000..261b7b0c98 --- /dev/null +++ b/wonderswan/v30mz-private.h @@ -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<> 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; \ + } + diff --git a/wonderswan/v30mz.cpp b/wonderswan/v30mz.cpp new file mode 100644 index 0000000000..490d308527 --- /dev/null +++ b/wonderswan/v30mz.cpp @@ -0,0 +1,1035 @@ +/**************************************************************************** + +NEC V30MZ emulator + +Stripped out non-V30MZ clock counts and code. + +Small changes made by dox@space.pl (Corrected bug in NEG instruction , different AUX flag handling in some opcodes) + +(Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based +on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code +on the i286 emulator by Fabrice Frances which had initial work based on +David Hedley's pcemu(!). + +****************************************************************************/ + +/* This NEC V30MZ emulator may be used for purposes both commercial and noncommercial if you give the author, Bryan McPhail, +a small credit somewhere(such as in the documentation for an executable package). +*/ + +/* +TODO: +Implement bus lock fully(prevent interrupts from occuring during a REP sequence, I think...), taking into account +HLT emulation to prevent deadlocks! + +Implement better prefix emulation. It's extremely kludgey right now. + +Implement prefetch/pipeline emulation. +*/ + +#include "system.h" +#include +#include "v30mz-private.h" + +using namespace MDFN_IEN_WSWAN::V30MZEnum; + +namespace MDFN_IEN_WSWAN +{ +#define ADDBRANCHTRACE(x,y) { } +#define ADDBRANCHTRACE_INT(x,y) { } +#define SETOLDCSIP() { } + +#include "v30mz-modrm.inc" + + unsigned V30MZ::EA_000() { EO=I.regs.w[BW]+I.regs.w[IX]; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_001() { EO=I.regs.w[BW]+I.regs.w[IY]; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_002() { EO=I.regs.w[BP]+I.regs.w[IX]; EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_003() { EO=I.regs.w[BP]+I.regs.w[IY]; EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_004() { EO=I.regs.w[IX]; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_005() { EO=I.regs.w[IY]; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_006() { EO=FETCH; EO+=FETCH<<8; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_007() { EO=I.regs.w[BW]; EA=DefaultBase(DS0)+EO; return EA; } + + unsigned V30MZ::EA_100() { EO=(I.regs.w[BW]+I.regs.w[IX]+(int8)FETCH); EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_101() { EO=(I.regs.w[BW]+I.regs.w[IY]+(int8)FETCH); EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_102() { EO=(I.regs.w[BP]+I.regs.w[IX]+(int8)FETCH); EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_103() { EO=(I.regs.w[BP]+I.regs.w[IY]+(int8)FETCH); EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_104() { EO=(I.regs.w[IX]+(int8)FETCH); EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_105() { EO=(I.regs.w[IY]+(int8)FETCH); EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_106() { EO=(I.regs.w[BP]+(int8)FETCH); EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_107() { EO=(I.regs.w[BW]+(int8)FETCH); EA=DefaultBase(DS0)+EO; return EA; } + + unsigned V30MZ::EA_200() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IX]+(int16)E16; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_201() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IY]+(int16)E16; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_202() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IX]+(int16)E16; EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_203() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IY]+(int16)E16; EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_204() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IX]+(int16)E16; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_205() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IY]+(int16)E16; EA=DefaultBase(DS0)+EO; return EA; } + unsigned V30MZ::EA_206() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+(int16)E16; EA=DefaultBase(SS)+EO; return EA; } + unsigned V30MZ::EA_207() { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+(int16)E16; EA=DefaultBase(DS0)+EO; return EA; } + + void V30MZ::SetupEA() + { + for (int i = 0; i < 64; i += 8) + { + GetEA[i + 0] = &V30MZ::EA_000; + GetEA[i + 1] = &V30MZ::EA_001; + GetEA[i + 2] = &V30MZ::EA_002; + GetEA[i + 3] = &V30MZ::EA_003; + GetEA[i + 4] = &V30MZ::EA_004; + GetEA[i + 5] = &V30MZ::EA_005; + GetEA[i + 6] = &V30MZ::EA_006; + GetEA[i + 7] = &V30MZ::EA_007; + } + for (int i = 64; i < 128; i += 8) + { + GetEA[i + 0] = &V30MZ::EA_100; + GetEA[i + 1] = &V30MZ::EA_101; + GetEA[i + 2] = &V30MZ::EA_102; + GetEA[i + 3] = &V30MZ::EA_103; + GetEA[i + 4] = &V30MZ::EA_104; + GetEA[i + 5] = &V30MZ::EA_105; + GetEA[i + 6] = &V30MZ::EA_106; + GetEA[i + 7] = &V30MZ::EA_107; + } + for (int i = 128; i < 192; i += 8) + { + GetEA[i + 0] = &V30MZ::EA_200; + GetEA[i + 1] = &V30MZ::EA_201; + GetEA[i + 2] = &V30MZ::EA_202; + GetEA[i + 3] = &V30MZ::EA_203; + GetEA[i + 4] = &V30MZ::EA_204; + GetEA[i + 5] = &V30MZ::EA_205; + GetEA[i + 6] = &V30MZ::EA_206; + GetEA[i + 7] = &V30MZ::EA_207; + } + } + + INLINE void V30MZ::i_real_pushf() + { + PUSH( CompressFlags() ); + CLK(2); + } + + INLINE void V30MZ::i_real_popf() + { + uint32 tmp; + POP(tmp); + ExpandFlags(tmp); + CLK(3); + } + + /***************************************************************************/ + + V30MZ::V30MZ() + { + SetupEA(); + } + + void V30MZ::init() + { + + } + + void V30MZ::reset() + { + const BREGS reg_name[8] = { AL, CL, DL, BL, AH, CH, DH, BH }; + + ICount = 0; + timestamp = 0; + + std::memset(&I, 0, sizeof(I)); + + I.sregs[PS] = 0xffff; + + + for(unsigned int i = 0; i < 256; i++) + { + unsigned int c = 0; + + for (unsigned int j = i; j > 0; j >>= 1) + if (j & 1) c++; + + parity_table[i] = !(c & 1); + } + + I.ZeroVal = I.ParityVal = 1; + + for(unsigned int i = 0; i < 256; i++) + { + Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3]; + Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ; + } + + for(unsigned int i = 0xc0; i < 0x100; i++) + { + Mod_RM.RM.w[i] = (WREGS)( i & 7 ); + Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7]; + } + + prefix_base = 0; + seg_prefix = 0; + InHLT = 0; + } + + void V30MZ::interrupt(uint32 vector, bool IgnoreIF) + { + InHLT = FALSE; // This is correct! Standby mode is always exited when there is an INT signal, regardless of whether interrupt are disabled. + if(I.IF || IgnoreIF) + { + uint32 dest_seg, dest_off; + + PUSH( CompressFlags() ); + I.TF = I.IF = 0; + dest_off = ReadWord(vector); + dest_seg = ReadWord(vector+2); + PUSH(I.sregs[PS]); + PUSH(I.pc); + I.pc = (uint16)dest_off; + I.sregs[PS] = (uint16)dest_seg; + ADDBRANCHTRACE_INT(I.sregs[PS], I.pc); + CLK(32); + } + } + + void V30MZ::nec_interrupt(unsigned int_num) + { + uint32 dest_seg, dest_off; + + if (int_num == -1) + return; + + i_real_pushf(); + I.TF = I.IF = 0; + + + dest_off = ReadWord((int_num)*4); + dest_seg = ReadWord((int_num)*4+2); + + PUSH(I.sregs[PS]); + PUSH(I.pc); + I.pc = (uint16)dest_off; + I.sregs[PS] = (uint16)dest_seg; + ADDBRANCHTRACE(I.sregs[PS], I.pc); + } + + bool V30MZ::CheckInHLT() + { + if(InHLT) + { + sys->interrupt.Check(); + if(InHLT) + { + int32 tmp = ICount; + + if(tmp > 0) + CLK(tmp); + return(1); + } + } + return(0); + } + + + /****************************************************************************/ + /* OPCODES */ + /****************************************************************************/ + + INLINE void V30MZ::i_real_insb() + { + PutMemB(DS1,I.regs.w[IY], read_port(I.regs.w[DW])); + I.regs.w[IY]+= -2 * I.DF + 1; + CLK(6); + } + + INLINE void V30MZ::i_real_insw() + { + PutMemB(DS1,I.regs.w[IY],read_port(I.regs.w[DW])); + PutMemB(DS1,(I.regs.w[IY]+1)&0xffff,read_port((I.regs.w[DW]+1)&0xffff)); + I.regs.w[IY]+= -4 * I.DF + 2; + CLK(6); + } + + INLINE void V30MZ::i_real_outsb() + { + write_port(I.regs.w[DW],GetMemB(DS0,I.regs.w[IX])); + I.regs.w[IX]+= -2 * I.DF + 1; + CLK(7); + } + + INLINE void V30MZ::i_real_outsw() + { + write_port(I.regs.w[DW],GetMemB(DS0,I.regs.w[IX])); + write_port((I.regs.w[DW]+1)&0xffff,GetMemB(DS0,(I.regs.w[IX]+1)&0xffff)); + I.regs.w[IX]+= -4 * I.DF + 2; + CLK(7); + } + + INLINE void V30MZ::i_real_movsb() + { + uint32 tmp = GetMemB(DS0,I.regs.w[IX]); + PutMemB(DS1,I.regs.w[IY], tmp); + I.regs.w[IY] += -2 * I.DF + 1; + I.regs.w[IX] += -2 * I.DF + 1; + CLK(5); + } + + INLINE void V30MZ::i_real_movsw() + { + uint32 tmp = GetMemW(DS0,I.regs.w[IX]); PutMemW(DS1,I.regs.w[IY], tmp); I.regs.w[IY] += -4 * I.DF + 2; + I.regs.w[IX] += -4 * I.DF + 2; CLK(5); + } + + INLINE void V30MZ::i_real_cmpsb() + { + uint32 src = GetMemB(DS1, I.regs.w[IY]); uint32 dst = GetMemB(DS0, I.regs.w[IX]); SUBB; I.regs.w[IY] += -2 * I.DF + 1; + I.regs.w[IX] += -2 * I.DF + 1; CLK(6); + } + + INLINE void V30MZ::i_real_cmpsw() + { + uint32 src = GetMemW(DS1, I.regs.w[IY]); uint32 dst = GetMemW(DS0, I.regs.w[IX]); SUBW; I.regs.w[IY] += -4 * I.DF + 2; + I.regs.w[IX] += -4 * I.DF + 2; CLK(6); + } + + INLINE void V30MZ::i_real_stosb() + { + PutMemB(DS1,I.regs.w[IY],I.regs.b[AL]); I.regs.w[IY] += -2 * I.DF + 1; CLK(3); + } + + INLINE void V30MZ::i_real_stosw() + { + PutMemW(DS1,I.regs.w[IY],I.regs.w[AW]); I.regs.w[IY] += -4 * I.DF + 2; CLK(3); + } + + INLINE void V30MZ::i_real_lodsb() + { + I.regs.b[AL] = GetMemB(DS0,I.regs.w[IX]); I.regs.w[IX] += -2 * I.DF + 1; CLK(3); + } + + INLINE void V30MZ::i_real_lodsw() + { + I.regs.w[AW] = GetMemW(DS0,I.regs.w[IX]); I.regs.w[IX] += -4 * I.DF + 2; CLK(3); + } + + INLINE void V30MZ::i_real_scasb() + { + uint32 src = GetMemB(DS1, I.regs.w[IY]); uint32 dst = I.regs.b[AL]; SUBB; + I.regs.w[IY] += -2 * I.DF + 1; CLK(4); + } + + INLINE void V30MZ::i_real_scasw() + { + uint32 src = GetMemW(DS1, I.regs.w[IY]); uint32 dst = I.regs.w[AW]; SUBW; + I.regs.w[IY] += -4 * I.DF + 2; CLK(4); + } + + void V30MZ::DoOP(uint8 opcode) + { + //#define OP(num,func_name) static void func_name() +#define OP(num, func_name) case num: + //#define OP_RANGE(num1, num2, func_name) case num1 ... num2: + +#define OP_EPILOGUE break + + switch(opcode) + { + default: + Debug::printf("Invalid op: %02x\n", opcode); + CLK(10); + break; + + OP( 0x00, i_add_br8 ) { DEF_br8; ADDB; PutbackRMByte(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x01, i_add_wr16 ) { DEF_wr16; ADDW; PutbackRMWord(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x02, i_add_r8b ) { DEF_r8b; ADDB; RegByte(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x03, i_add_r16w ) { DEF_r16w; ADDW; RegWord(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x04, i_add_ald8 ) { DEF_ald8; ADDB; I.regs.b[AL]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x05, i_add_axd16) { DEF_axd16; ADDW; I.regs.w[AW]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x06, i_push_ds1 ) { PUSH(I.sregs[DS1]); CLK(2); } OP_EPILOGUE; + OP( 0x07, i_pop_ds1 ) { POP(I.sregs[DS1]); CLK(3); } OP_EPILOGUE; + + OP( 0x08, i_or_br8 ) { DEF_br8; ORB; PutbackRMByte(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x09, i_or_wr16 ) { DEF_wr16; ORW; PutbackRMWord(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x0a, i_or_r8b ) { DEF_r8b; ORB; RegByte(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x0b, i_or_r16w ) { DEF_r16w; ORW; RegWord(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x0c, i_or_ald8 ) { DEF_ald8; ORB; I.regs.b[AL]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x0d, i_or_axd16 ) { DEF_axd16; ORW; I.regs.w[AW]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x0e, i_push_cs ) { PUSH(I.sregs[PS]); CLK(2); } OP_EPILOGUE; + + OP( 0x10, i_adc_br8 ) { DEF_br8; src+=CF; ADDB; PutbackRMByte(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x11, i_adc_wr16 ) { DEF_wr16; src+=CF; ADDW; PutbackRMWord(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x12, i_adc_r8b ) { DEF_r8b; src+=CF; ADDB; RegByte(ModRM)=dst; CLKM(2, 1); } OP_EPILOGUE; + OP( 0x13, i_adc_r16w ) { DEF_r16w; src+=CF; ADDW; RegWord(ModRM)=dst; CLKM(2, 1); } OP_EPILOGUE; + OP( 0x14, i_adc_ald8 ) { DEF_ald8; src+=CF; ADDB; I.regs.b[AL]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x15, i_adc_axd16) { DEF_axd16; src+=CF; ADDW; I.regs.w[AW]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x16, i_push_ss ) { PUSH(I.sregs[SS]); CLK(2); } OP_EPILOGUE; + OP( 0x17, i_pop_ss ) { POP(I.sregs[SS]); CLK(3); } OP_EPILOGUE; + + OP( 0x18, i_sbb_br8 ) { DEF_br8; src+=CF; SUBB; PutbackRMByte(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x19, i_sbb_wr16 ) { DEF_wr16; src+=CF; SUBW; PutbackRMWord(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x1a, i_sbb_r8b ) { DEF_r8b; src+=CF; SUBB; RegByte(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x1b, i_sbb_r16w ) { DEF_r16w; src+=CF; SUBW; RegWord(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x1c, i_sbb_ald8 ) { DEF_ald8; src+=CF; SUBB; I.regs.b[AL]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x1d, i_sbb_axd16) { DEF_axd16; src+=CF; SUBW; I.regs.w[AW]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x1e, i_push_ds ) { PUSH(I.sregs[DS0]); CLK(2); } OP_EPILOGUE; + OP( 0x1f, i_pop_ds ) { POP(I.sregs[DS0]); CLK(3); } OP_EPILOGUE; + + OP( 0x20, i_and_br8 ) { DEF_br8; ANDB; PutbackRMByte(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x21, i_and_wr16 ) { DEF_wr16; ANDW; PutbackRMWord(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x22, i_and_r8b ) { DEF_r8b; ANDB; RegByte(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x23, i_and_r16w ) { DEF_r16w; ANDW; RegWord(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x24, i_and_ald8 ) { DEF_ald8; ANDB; I.regs.b[AL]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x25, i_and_axd16) { DEF_axd16; ANDW; I.regs.w[AW]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x26, i_ds1 ) { seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; CLK(1); DoOP(FETCHOP); seg_prefix=FALSE; } OP_EPILOGUE; + OP( 0x27, i_daa ) { ADJ4(6,0x60); CLK(10); } OP_EPILOGUE; + + OP( 0x28, i_sub_br8 ) { DEF_br8; SUBB; PutbackRMByte(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x29, i_sub_wr16 ) { DEF_wr16; SUBW; PutbackRMWord(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x2a, i_sub_r8b ) { DEF_r8b; SUBB; RegByte(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x2b, i_sub_r16w ) { DEF_r16w; SUBW; RegWord(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x2c, i_sub_ald8 ) { DEF_ald8; SUBB; I.regs.b[AL]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x2d, i_sub_axd16) { DEF_axd16; SUBW; I.regs.w[AW]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x2e, i_ps ) { seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; CLK(1); DoOP(FETCHOP); seg_prefix=FALSE; } OP_EPILOGUE; + OP( 0x2f, i_das ) { ADJ4(-6,-0x60); CLK(10); } OP_EPILOGUE; + + OP( 0x30, i_xor_br8 ) { DEF_br8; XORB; PutbackRMByte(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x31, i_xor_wr16 ) { DEF_wr16; XORW; PutbackRMWord(ModRM,dst); CLKM(3,1); } OP_EPILOGUE; + OP( 0x32, i_xor_r8b ) { DEF_r8b; XORB; RegByte(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x33, i_xor_r16w ) { DEF_r16w; XORW; RegWord(ModRM)=dst; CLKM(2,1); } OP_EPILOGUE; + OP( 0x34, i_xor_ald8 ) { DEF_ald8; XORB; I.regs.b[AL]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x35, i_xor_axd16) { DEF_axd16; XORW; I.regs.w[AW]=dst; CLK(1); } OP_EPILOGUE; + OP( 0x36, i_ss ) { seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; CLK(1); DoOP(FETCHOP); seg_prefix=FALSE; } OP_EPILOGUE; + OP( 0x37, i_aaa ) { ADJB(6,1); CLK(9); } OP_EPILOGUE; + + OP( 0x38, i_cmp_br8 ) { DEF_br8; SUBB; CLKM(2,1); } OP_EPILOGUE; + OP( 0x39, i_cmp_wr16 ) { DEF_wr16; SUBW; CLKM(2,1); } OP_EPILOGUE; + OP( 0x3a, i_cmp_r8b ) { DEF_r8b; SUBB; CLKM(2,1); } OP_EPILOGUE; + OP( 0x3b, i_cmp_r16w ) { DEF_r16w; SUBW; CLKM(2,1); } OP_EPILOGUE; + OP( 0x3c, i_cmp_ald8 ) { DEF_ald8; SUBB; CLK(1); } OP_EPILOGUE; + OP( 0x3d, i_cmp_axd16) { DEF_axd16; SUBW; CLK(1); } OP_EPILOGUE; + OP( 0x3e, i_ds0 ) { seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; CLK(1); DoOP(FETCHOP); seg_prefix=FALSE; } OP_EPILOGUE; + OP( 0x3f, i_aas ) { ADJB(-6,-1); CLK(9); } OP_EPILOGUE; + + OP( 0x40, i_inc_ax ) { IncWordReg(AW); CLK(1); } OP_EPILOGUE; + OP( 0x41, i_inc_cx ) { IncWordReg(CW); CLK(1); } OP_EPILOGUE; + OP( 0x42, i_inc_dx ) { IncWordReg(DW); CLK(1); } OP_EPILOGUE; + OP( 0x43, i_inc_bx ) { IncWordReg(BW); CLK(1); } OP_EPILOGUE; + OP( 0x44, i_inc_sp ) { IncWordReg(SP); CLK(1); } OP_EPILOGUE; + OP( 0x45, i_inc_bp ) { IncWordReg(BP); CLK(1); } OP_EPILOGUE; + OP( 0x46, i_inc_si ) { IncWordReg(IX); CLK(1); } OP_EPILOGUE; + OP( 0x47, i_inc_di ) { IncWordReg(IY); CLK(1); } OP_EPILOGUE; + + OP( 0x48, i_dec_ax ) { DecWordReg(AW); CLK(1); } OP_EPILOGUE; + OP( 0x49, i_dec_cx ) { DecWordReg(CW); CLK(1); } OP_EPILOGUE; + OP( 0x4a, i_dec_dx ) { DecWordReg(DW); CLK(1); } OP_EPILOGUE; + OP( 0x4b, i_dec_bx ) { DecWordReg(BW); CLK(1); } OP_EPILOGUE; + OP( 0x4c, i_dec_sp ) { DecWordReg(SP); CLK(1); } OP_EPILOGUE; + OP( 0x4d, i_dec_bp ) { DecWordReg(BP); CLK(1); } OP_EPILOGUE; + OP( 0x4e, i_dec_si ) { DecWordReg(IX); CLK(1); } OP_EPILOGUE; + OP( 0x4f, i_dec_di ) { DecWordReg(IY); CLK(1); } OP_EPILOGUE; + + OP( 0x50, i_push_ax ) { PUSH(I.regs.w[AW]); CLK(1); } OP_EPILOGUE; + OP( 0x51, i_push_cx ) { PUSH(I.regs.w[CW]); CLK(1); } OP_EPILOGUE; + OP( 0x52, i_push_dx ) { PUSH(I.regs.w[DW]); CLK(1); } OP_EPILOGUE; + OP( 0x53, i_push_bx ) { PUSH(I.regs.w[BW]); CLK(1); } OP_EPILOGUE; + OP( 0x54, i_push_sp ) { PUSH(I.regs.w[SP]); CLK(1); } OP_EPILOGUE; + OP( 0x55, i_push_bp ) { PUSH(I.regs.w[BP]); CLK(1); } OP_EPILOGUE; + OP( 0x56, i_push_si ) { PUSH(I.regs.w[IX]); CLK(1); } OP_EPILOGUE; + OP( 0x57, i_push_di ) { PUSH(I.regs.w[IY]); CLK(1); } OP_EPILOGUE; + + OP( 0x58, i_pop_ax ) { POP(I.regs.w[AW]); CLK(1); } OP_EPILOGUE; + OP( 0x59, i_pop_cx ) { POP(I.regs.w[CW]); CLK(1); } OP_EPILOGUE; + OP( 0x5a, i_pop_dx ) { POP(I.regs.w[DW]); CLK(1); } OP_EPILOGUE; + OP( 0x5b, i_pop_bx ) { POP(I.regs.w[BW]); CLK(1); } OP_EPILOGUE; + OP( 0x5c, i_pop_sp ) { POP(I.regs.w[SP]); CLK(1); } OP_EPILOGUE; + OP( 0x5d, i_pop_bp ) { POP(I.regs.w[BP]); CLK(1); } OP_EPILOGUE; + OP( 0x5e, i_pop_si ) { POP(I.regs.w[IX]); CLK(1); } OP_EPILOGUE; + OP( 0x5f, i_pop_di ) { POP(I.regs.w[IY]); CLK(1); } OP_EPILOGUE; + + OP( 0x60, i_pusha ) { + unsigned tmp=I.regs.w[SP]; + PUSH(I.regs.w[AW]); + PUSH(I.regs.w[CW]); + PUSH(I.regs.w[DW]); + PUSH(I.regs.w[BW]); + PUSH(tmp); + PUSH(I.regs.w[BP]); + PUSH(I.regs.w[IX]); + PUSH(I.regs.w[IY]); + CLK(9); + } OP_EPILOGUE; + + OP( 0x61, i_popa ) { + unsigned tmp; + POP(I.regs.w[IY]); + POP(I.regs.w[IX]); + POP(I.regs.w[BP]); + POP(tmp); + POP(I.regs.w[BW]); + POP(I.regs.w[DW]); + POP(I.regs.w[CW]); + POP(I.regs.w[AW]); + CLK(8); + } OP_EPILOGUE; + + OP( 0x62, i_chkind ) + { + uint32 low,high,tmp; + + GetModRM; + + low = GetRMWord(ModRM); + high = GetnextRMWord; + tmp = RegWord(ModRM); + + CLK(13); + if (tmphigh) + { + nec_interrupt(5); + } + } OP_EPILOGUE; + + OP( 0x68, i_push_d16 ) { uint32 tmp; FETCHuint16(tmp); PUSH(tmp); CLK(1); } OP_EPILOGUE; + OP( 0x69, i_imul_d16 ) { uint32 tmp; DEF_r16w; FETCHuint16(tmp); dst = (int32)((int16)src)*(int32)((int16)tmp); I.CarryVal = I.OverVal = (((int32)dst) >> 15 != 0) && (((int32)dst) >> 15 != -1); RegWord(ModRM)=(uint16)dst; CLKM(4,3);} OP_EPILOGUE; + OP( 0x6a, i_push_d8 ) { uint32 tmp = (uint16)((int16)((int8)FETCH)); PUSH(tmp); CLK(1); } OP_EPILOGUE; + OP( 0x6b, i_imul_d8 ) { uint32 src2; DEF_r16w; src2= (uint16)((int16)((int8)FETCH)); dst = (int32)((int16)src)*(int32)((int16)src2); I.CarryVal = I.OverVal = (((int32)dst) >> 15 != 0) && (((int32)dst) >> 15 != -1); RegWord(ModRM)=(uint16)dst; CLKM(4,3); } OP_EPILOGUE; + OP( 0x6c, i_insb ) { i_real_insb(); } OP_EPILOGUE; + OP( 0x6d, i_insw ) { i_real_insw(); } OP_EPILOGUE; + OP( 0x6e, i_outsb ) { i_real_outsb(); } OP_EPILOGUE; + OP( 0x6f, i_outsw ) { i_real_outsw(); } OP_EPILOGUE; + + OP( 0x70, i_jo ) { JMP( FLAG_O); CLK(1); } OP_EPILOGUE; + OP( 0x71, i_jno ) { JMP(!FLAG_O); CLK(1); } OP_EPILOGUE; + OP( 0x72, i_jc ) { JMP( CF); CLK(1); } OP_EPILOGUE; + OP( 0x73, i_jnc ) { JMP(!CF); CLK(1); } OP_EPILOGUE; + OP( 0x74, i_jz ) { JMP( ZF); CLK(1); } OP_EPILOGUE; + OP( 0x75, i_jnz ) { JMP(!ZF); CLK(1); } OP_EPILOGUE; + OP( 0x76, i_jce ) { JMP(CF || ZF); CLK(1); } OP_EPILOGUE; + OP( 0x77, i_jnce ) { JMP(!(CF || ZF)); CLK(1); } OP_EPILOGUE; + OP( 0x78, i_js ) { JMP( SF); CLK(1); } OP_EPILOGUE; + OP( 0x79, i_jns ) { JMP(!SF); CLK(1); } OP_EPILOGUE; + OP( 0x7a, i_jp ) { JMP( PF); CLK(1); } OP_EPILOGUE; + OP( 0x7b, i_jnp ) { JMP(!PF); CLK(1); } OP_EPILOGUE; + OP( 0x7c, i_jl ) { JMP((SF!=FLAG_O)&&(!ZF)); CLK(1); } OP_EPILOGUE; + OP( 0x7d, i_jnl ) { JMP((ZF)||(SF==FLAG_O)); CLK(1); } OP_EPILOGUE; + OP( 0x7e, i_jle ) { JMP((ZF)||(SF!=FLAG_O)); CLK(1); } OP_EPILOGUE; + OP( 0x7f, i_jnle ) { JMP((SF==FLAG_O)&&(!ZF)); CLK(1); } OP_EPILOGUE; + + OP( 0x80, i_80pre ) { uint32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = FETCH; + CLKM(3, 1); + switch (ModRM & 0x38) { + case 0x00: ADDB; PutbackRMByte(ModRM,dst); break; + case 0x08: ORB; PutbackRMByte(ModRM,dst); break; + case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break; + case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break; + case 0x20: ANDB; PutbackRMByte(ModRM,dst); break; + case 0x28: SUBB; PutbackRMByte(ModRM,dst); break; + case 0x30: XORB; PutbackRMByte(ModRM,dst); break; + case 0x38: SUBB; break; /* CMP */ + } + } OP_EPILOGUE; + + OP( 0x81, i_81pre ) { uint32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = FETCH; src+= (FETCH << 8); + CLKM(3, 1); + switch (ModRM & 0x38) { + case 0x00: ADDW; PutbackRMWord(ModRM,dst); break; + case 0x08: ORW; PutbackRMWord(ModRM,dst); break; + case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break; + case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break; + case 0x20: ANDW; PutbackRMWord(ModRM,dst); break; + case 0x28: SUBW; PutbackRMWord(ModRM,dst); break; + case 0x30: XORW; PutbackRMWord(ModRM,dst); break; + case 0x38: SUBW; break; /* CMP */ + } + } OP_EPILOGUE; + + OP( 0x82, i_82pre ) { uint32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = (uint8)((int8)FETCH); + CLKM(3,1); + switch (ModRM & 0x38) { + case 0x00: ADDB; PutbackRMByte(ModRM,dst); break; + case 0x08: ORB; PutbackRMByte(ModRM,dst); break; + case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break; + case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break; + case 0x20: ANDB; PutbackRMByte(ModRM,dst); break; + case 0x28: SUBB; PutbackRMByte(ModRM,dst); break; + case 0x30: XORB; PutbackRMByte(ModRM,dst); break; + case 0x38: SUBB; break; /* CMP */ + } + } OP_EPILOGUE; + + OP( 0x83, i_83pre ) { uint32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = (uint16)((int16)((int8)FETCH)); + CLKM(3,1); + switch (ModRM & 0x38) { + case 0x00: ADDW; PutbackRMWord(ModRM,dst); break; + case 0x08: ORW; PutbackRMWord(ModRM,dst); break; + case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break; + case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break; + case 0x20: ANDW; PutbackRMWord(ModRM,dst); break; + case 0x28: SUBW; PutbackRMWord(ModRM,dst); break; + case 0x30: XORW; PutbackRMWord(ModRM,dst); break; + case 0x38: SUBW; break; /* CMP */ + } + } OP_EPILOGUE; + + OP( 0x84, i_test_br8 ) { DEF_br8; ANDB; CLKM(2,1); } OP_EPILOGUE; + OP( 0x85, i_test_wr16 ) { DEF_wr16; ANDW; CLKM(2,1); } OP_EPILOGUE; + OP( 0x86, i_xchg_br8 ) { DEF_br8; RegByte(ModRM)=dst; PutbackRMByte(ModRM,src); CLKM(5,3); } OP_EPILOGUE; + OP( 0x87, i_xchg_wr16 ) { DEF_wr16; RegWord(ModRM)=dst; PutbackRMWord(ModRM,src); CLKM(5,3); } OP_EPILOGUE; + + OP( 0x88, i_mov_br8 ) { uint8 src; GetModRM; src = RegByte(ModRM); PutRMByte(ModRM,src); CLK(1); } OP_EPILOGUE; + OP( 0x89, i_mov_wr16 ) { uint16 src; GetModRM; src = RegWord(ModRM); PutRMWord(ModRM,src); CLK(1); } OP_EPILOGUE; + OP( 0x8a, i_mov_r8b ) { uint8 src; GetModRM; src = GetRMByte(ModRM); RegByte(ModRM)=src; CLK(1); } OP_EPILOGUE; + OP( 0x8b, i_mov_r16w ) { uint16 src; GetModRM; src = GetRMWord(ModRM); RegWord(ModRM)=src; CLK(1); } OP_EPILOGUE; + OP( 0x8c, i_mov_wsreg ) { GetModRM; PutRMWord(ModRM,I.sregs[(ModRM & 0x38) >> 3]); CLK(1); } OP_EPILOGUE; + OP( 0x8d, i_lea ) { uint16 ModRM = FETCH; if(ModRM >= 192) { Debug::printf("LEA Error: %02x\n", ModRM);} else { (void)(this->*GetEA[ModRM])(); } RegWord(ModRM)=EO; CLK(1); } OP_EPILOGUE; + OP( 0x8e, i_mov_sregw ) { uint16 src; GetModRM; src = GetRMWord(ModRM); CLKM(3,2); + switch (ModRM & 0x38) { + case 0x00: I.sregs[DS1] = src; break; /* mov ds1,ew */ + case 0x08: I.sregs[PS] = src; break; /* mov cs,ew */ + case 0x10: I.sregs[SS] = src; break; /* mov ss,ew */ + case 0x18: I.sregs[DS0] = src; break; /* mov ds0,ew */ + } + } OP_EPILOGUE; + + OP( 0x8f, i_popw ) { uint16 tmp; GetModRM; POP(tmp); PutRMWord(ModRM,tmp); CLKM(3,1); } OP_EPILOGUE; + OP( 0x90, i_nop ) { CLK(3); } OP_EPILOGUE; + + OP( 0x91, i_xchg_axcx ) { XchgAWReg(CW); CLK(3); } OP_EPILOGUE; + OP( 0x92, i_xchg_axdx ) { XchgAWReg(DW); CLK(3); } OP_EPILOGUE; + OP( 0x93, i_xchg_axbx ) { XchgAWReg(BW); CLK(3); } OP_EPILOGUE; + OP( 0x94, i_xchg_axsp ) { XchgAWReg(SP); CLK(3); } OP_EPILOGUE; + OP( 0x95, i_xchg_axbp ) { XchgAWReg(BP); CLK(3); } OP_EPILOGUE; + OP( 0x96, i_xchg_axsi ) { XchgAWReg(IX); CLK(3); } OP_EPILOGUE; + OP( 0x97, i_xchg_axdi ) { XchgAWReg(IY); CLK(3); } OP_EPILOGUE; + + // AKA CVTBW + OP( 0x98, i_cbw ) { I.regs.b[AH] = (I.regs.b[AL] & 0x80) ? 0xff : 0; CLK(1); } OP_EPILOGUE; + + // AKA CVTWL + OP( 0x99, i_cwd ) { I.regs.w[DW] = (I.regs.b[AH] & 0x80) ? 0xffff : 0; CLK(1); } OP_EPILOGUE; + + OP( 0x9a, i_call_far ) { uint32 tmp, tmp2; FETCHuint16(tmp); FETCHuint16(tmp2); PUSH(I.sregs[PS]); PUSH(I.pc); I.pc = (uint16)tmp; I.sregs[PS] = (uint16)tmp2; ADDBRANCHTRACE(I.sregs[PS], I.pc); CLK(10); } OP_EPILOGUE; + OP( 0x9b, i_poll ) { Debug::puts("POLL"); } OP_EPILOGUE; + OP( 0x9c, i_pushf ) { i_real_pushf(); } OP_EPILOGUE; + OP( 0x9d, i_popf ) { i_real_popf(); } OP_EPILOGUE; + OP( 0x9e, i_sahf ) { uint32 tmp = (CompressFlags() & 0xff00) | (I.regs.b[AH] & 0xd5); ExpandFlags(tmp); CLK(4); } OP_EPILOGUE; + OP( 0x9f, i_lahf ) { I.regs.b[AH] = CompressFlags() & 0xff; CLK(2); } OP_EPILOGUE; + + OP( 0xa0, i_mov_aldisp ) { uint32 addr; FETCHuint16(addr); I.regs.b[AL] = GetMemB(DS0, addr); CLK(1); } OP_EPILOGUE; + OP( 0xa1, i_mov_axdisp ) { uint32 addr; FETCHuint16(addr); I.regs.b[AL] = GetMemB(DS0, addr); I.regs.b[AH] = GetMemB(DS0, (addr+1)&0xffff); CLK(1); } OP_EPILOGUE; + OP( 0xa2, i_mov_dispal ) { uint32 addr; FETCHuint16(addr); PutMemB(DS0, addr, I.regs.b[AL]); CLK(1); } OP_EPILOGUE; + OP( 0xa3, i_mov_dispax ) { uint32 addr; FETCHuint16(addr); PutMemB(DS0, addr, I.regs.b[AL]); PutMemB(DS0, (addr+1)&0xffff, I.regs.b[AH]); CLK(1); } OP_EPILOGUE; + + OP( 0xa4, i_movsb ) { i_real_movsb(); } OP_EPILOGUE; + OP( 0xa5, i_movsw ) { i_real_movsw(); } OP_EPILOGUE; + OP( 0xa6, i_cmpsb ) { i_real_cmpsb(); } OP_EPILOGUE; + OP( 0xa7, i_cmpsw ) { i_real_cmpsw(); } OP_EPILOGUE; + + OP( 0xa8, i_test_ald8 ) { DEF_ald8; ANDB; CLK(1); } OP_EPILOGUE; + OP( 0xa9, i_test_axd16 ) { DEF_axd16; ANDW; CLK(1); } OP_EPILOGUE; + + OP( 0xaa, i_stosb ) { i_real_stosb(); } OP_EPILOGUE; + OP( 0xab, i_stosw ) { i_real_stosw(); } OP_EPILOGUE; + OP( 0xac, i_lodsb ) { i_real_lodsb(); } OP_EPILOGUE; + OP( 0xad, i_lodsw ) { i_real_lodsw(); } OP_EPILOGUE; + OP( 0xae, i_scasb ) { i_real_scasb(); } OP_EPILOGUE; + OP( 0xaf, i_scasw ) { i_real_scasw(); } OP_EPILOGUE; + + OP( 0xb0, i_mov_ald8 ) { I.regs.b[AL] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb1, i_mov_cld8 ) { I.regs.b[CL] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb2, i_mov_dld8 ) { I.regs.b[DL] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb3, i_mov_bld8 ) { I.regs.b[BL] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb4, i_mov_ahd8 ) { I.regs.b[AH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb5, i_mov_chd8 ) { I.regs.b[CH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb6, i_mov_dhd8 ) { I.regs.b[DH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb7, i_mov_bhd8 ) { I.regs.b[BH] = FETCH; CLK(1); } OP_EPILOGUE; + + OP( 0xb8, i_mov_axd16 ) { I.regs.b[AL] = FETCH; I.regs.b[AH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xb9, i_mov_cxd16 ) { I.regs.b[CL] = FETCH; I.regs.b[CH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xba, i_mov_dxd16 ) { I.regs.b[DL] = FETCH; I.regs.b[DH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xbb, i_mov_bxd16 ) { I.regs.b[BL] = FETCH; I.regs.b[BH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xbc, i_mov_spd16 ) { I.regs.b[SPL] = FETCH; I.regs.b[SPH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xbd, i_mov_bpd16 ) { I.regs.b[BPL] = FETCH; I.regs.b[BPH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xbe, i_mov_sid16 ) { I.regs.b[IXL] = FETCH; I.regs.b[IXH] = FETCH; CLK(1); } OP_EPILOGUE; + OP( 0xbf, i_mov_did16 ) { I.regs.b[IYL] = FETCH; I.regs.b[IYH] = FETCH; CLK(1); } OP_EPILOGUE; + + OP( 0xc0, i_rotshft_bd8 ) { + uint32 src, dst; uint8 c; + GetModRM; src = (unsigned)GetRMByte(ModRM); dst=src; + c=FETCH; + c&=0x1f; + CLKM(5,3); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_uint8; c--; } while (c>0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x08: do { ROR_uint8; c--; } while (c>0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x10: do { ROLC_uint8; c--; } while (c>0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x18: do { RORC_uint8; c--; } while (c>0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x20: SHL_uint8(c); I.AuxVal = 1; break;// + case 0x28: SHR_uint8(c); I.AuxVal = 1; break;// + case 0x30: break; + case 0x38: SHRA_uint8(c); break; + } + } OP_EPILOGUE; + + OP( 0xc1, i_rotshft_wd8 ) { + uint32 src, dst; uint8 c; + GetModRM; src = (unsigned)GetRMWord(ModRM); dst=src; + c=FETCH; + c&=0x1f; + CLKM(5,3); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x08: do { ROR_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x10: do { ROLC_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x18: do { RORC_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x20: SHL_uint16(c); I.AuxVal = 1; break; + case 0x28: SHR_uint16(c); I.AuxVal = 1; break; + case 0x30: break; + case 0x38: SHRA_uint16(c); break; + } + } OP_EPILOGUE; + + OP( 0xc2, i_ret_d16 ) { uint32 count = FETCH; count += FETCH << 8; POP(I.pc); I.regs.w[SP]+=count; CLK(6); ADDBRANCHTRACE(I.sregs[PS], I.pc); } OP_EPILOGUE; + OP( 0xc3, i_ret ) { POP(I.pc); CLK(6); ADDBRANCHTRACE(I.sregs[PS], I.pc); } OP_EPILOGUE; + OP( 0xc4, i_les_dw ) { GetModRM; uint16 tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[DS1] = GetnextRMWord; CLK(6); } OP_EPILOGUE; + OP( 0xc5, i_lds_dw ) { GetModRM; uint16 tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[DS0] = GetnextRMWord; CLK(6); } OP_EPILOGUE; + OP( 0xc6, i_mov_bd8 ) { GetModRM; PutImmRMByte(ModRM); CLK(1); } OP_EPILOGUE; + OP( 0xc7, i_mov_wd16 ) { GetModRM; PutImmRMWord(ModRM); CLK(1); } OP_EPILOGUE; + + // NEC calls it "PREPARE" + OP( 0xc8, i_enter ) { + uint32 nb = FETCH; + uint32 i,level; + + CLK(19); + nb += FETCH << 8; + + level = FETCH; + level &= 0x1F; // Only lower 5 bits are valid on V30MZ + + PUSH(I.regs.w[BP]); + I.regs.w[BP]=I.regs.w[SP]; + I.regs.w[SP] -= nb; + for (i=1;i0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x08: do { ROR_uint8; c--; } while (c>0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x10: do { ROLC_uint8; c--; } while (c>0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x18: do { RORC_uint8; c--; } while (c>0); PutbackRMByte(ModRM,(uint8)dst); break; + case 0x20: SHL_uint8(c); I.AuxVal = 1; break; + case 0x28: SHR_uint8(c); I.AuxVal = 1;break; + case 0x30: break; + case 0x38: SHRA_uint8(c); break; + } + } OP_EPILOGUE; + + OP( 0xd3, i_rotshft_wcl ) { + uint32 src, dst; uint8 c; GetModRM; src = (uint32)GetRMWord(ModRM); dst=src; + c=I.regs.b[CL]; + c&=0x1f; + CLKM(5,3); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x08: do { ROR_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x10: do { ROLC_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x18: do { RORC_uint16; c--; } while (c>0); PutbackRMWord(ModRM,(uint16)dst); break; + case 0x20: SHL_uint16(c); I.AuxVal = 1; break; + case 0x28: SHR_uint16(c); I.AuxVal = 1; break; + case 0x30: break; + case 0x38: SHRA_uint16(c); break; + } + } OP_EPILOGUE; + + OP( 0xd4, i_aam ) { uint32 mult=FETCH; mult=0; I.regs.b[AH] = I.regs.b[AL] / 10; I.regs.b[AL] %= 10; SetSZPF_Word(I.regs.w[AW]); CLK(17); } OP_EPILOGUE; + OP( 0xd5, i_aad ) { uint32 mult=FETCH; mult=0; I.regs.b[AL] = I.regs.b[AH] * 10 + I.regs.b[AL]; I.regs.b[AH] = 0; SetSZPF_Byte(I.regs.b[AL]); CLK(6); } OP_EPILOGUE; + OP( 0xd6, i_setalc ) { I.regs.b[AL] = (CF)?0xff:0x00; CLK(3); } OP_EPILOGUE; + OP( 0xd7, i_trans ) { uint32 dest = (I.regs.w[BW]+I.regs.b[AL])&0xffff; I.regs.b[AL] = GetMemB(DS0, dest); CLK(5); } OP_EPILOGUE; + + // + OP( 0xd8, i_fpo) + OP( 0xd9, i_fpo) + OP( 0xda, i_fpo) + OP( 0xdb, i_fpo) + OP( 0xdc, i_fpo) + OP( 0xdd, i_fpo) + OP( 0xde, i_fpo) + OP( 0xdf, i_fpo) + /*OP_RANGE(0xd8, 0xdf, i_fpo)*/ { /*printf("FPO1, Op:%02x\n", opcode);*/ GetModRM; CLK(1); } OP_EPILOGUE; + + OP( 0xe0, i_loopne ) { int8 disp = (int8)FETCH; I.regs.w[CW]--; if (!ZF && I.regs.w[CW]) { I.pc = (uint16)(I.pc+disp); CLK(6); ADDBRANCHTRACE(I.sregs[PS], I.pc); } else CLK(3); } OP_EPILOGUE; + OP( 0xe1, i_loope ) { int8 disp = (int8)FETCH; I.regs.w[CW]--; if ( ZF && I.regs.w[CW]) { I.pc = (uint16)(I.pc+disp); CLK(6); ADDBRANCHTRACE(I.sregs[PS], I.pc); } else CLK(3); } OP_EPILOGUE; + OP( 0xe2, i_loop ) { int8 disp = (int8)FETCH; I.regs.w[CW]--; if (I.regs.w[CW]) { I.pc = (uint16)(I.pc+disp); CLK(5); ADDBRANCHTRACE(I.sregs[PS], I.pc); } else CLK(2); } OP_EPILOGUE; + OP( 0xe3, i_jcxz ) { int8 disp = (int8)FETCH; if (I.regs.w[CW] == 0) { I.pc = (uint16)(I.pc+disp); CLK(4); ADDBRANCHTRACE(I.sregs[PS], I.pc); } else CLK(1); } OP_EPILOGUE; + OP( 0xe4, i_inal ) { uint8 port = FETCH; I.regs.b[AL] = read_port(port); CLK(6); } OP_EPILOGUE; + OP( 0xe5, i_inax ) { uint8 port = FETCH; I.regs.b[AL] = read_port(port); I.regs.b[AH] = read_port(port+1); CLK(6); } OP_EPILOGUE; + OP( 0xe6, i_outal ) { uint8 port = FETCH; write_port(port, I.regs.b[AL]); CLK(6); } OP_EPILOGUE; + OP( 0xe7, i_outax ) { uint8 port = FETCH; write_port(port, I.regs.b[AL]); write_port(port+1, I.regs.b[AH]); CLK(6); } OP_EPILOGUE; + + OP( 0xe8, i_call_d16 ) { uint32 tmp; FETCHuint16(tmp); PUSH(I.pc); I.pc = (uint16)(I.pc+(int16)tmp); ADDBRANCHTRACE(I.sregs[PS], I.pc); CLK(5); } OP_EPILOGUE; + OP( 0xe9, i_jmp_d16 ) { uint32 tmp; FETCHuint16(tmp); I.pc = (uint16)(I.pc+(int16)tmp); ADDBRANCHTRACE(I.sregs[PS], I.pc); CLK(4); } OP_EPILOGUE; + OP( 0xea, i_jmp_far ) { uint32 tmp,tmp1; FETCHuint16(tmp); FETCHuint16(tmp1); I.sregs[PS] = (uint16)tmp1; I.pc = (uint16)tmp; ; ADDBRANCHTRACE(I.sregs[PS], I.pc); CLK(7); } OP_EPILOGUE; + OP( 0xeb, i_jmp_d8 ) { int tmp = (int)((int8)FETCH); CLK(4);I.pc = (uint16)(I.pc+tmp); ADDBRANCHTRACE(I.sregs[PS], I.pc); } OP_EPILOGUE; + + OP( 0xec, i_inaldx ) { I.regs.b[AL] = read_port(I.regs.w[DW]); CLK(6);} OP_EPILOGUE; + OP( 0xed, i_inaxdx ) { uint32 port = I.regs.w[DW]; I.regs.b[AL] = read_port(port); I.regs.b[AH] = read_port(port+1); CLK(6); } OP_EPILOGUE; + + OP( 0xee, i_outdxal ) { write_port(I.regs.w[DW], I.regs.b[AL]); CLK(6); } OP_EPILOGUE; + OP( 0xef, i_outdxax ) { uint32 port = I.regs.w[DW]; write_port(port, I.regs.b[AL]); write_port(port+1, I.regs.b[AH]); CLK(6); } OP_EPILOGUE; + + // NEC calls it "BUSLOCK" + OP( 0xf0, i_lock ) { CLK(1); DoOP(FETCHOP); } OP_EPILOGUE; + + // We put CHK_ICOUNT *after* the first iteration has completed, to match real behavior. +#define CHK_ICOUNT(cond) if(ICount < 0 && (cond)) { I.pc -= seg_prefix ? 3 : 2; break; } + + OP( 0xf2, i_repne ) + { + uint32 next = FETCHOP; + + switch(next) { /* Segments */ + case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; next = FETCHOP; CLK(2); break; + case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; next = FETCHOP; CLK(2); break; + case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break; + case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; next = FETCHOP; CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(5); if (I.regs.w[CW]) do { i_real_insb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0x6d: CLK(5); if (I.regs.w[CW]) do { i_real_insw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0x6e: CLK(5); if (I.regs.w[CW]) do { i_real_outsb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0x6f: CLK(5); if (I.regs.w[CW]) do { i_real_outsw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xa4: CLK(5); if (I.regs.w[CW]) do { i_real_movsb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xa5: CLK(5); if (I.regs.w[CW]) do { i_real_movsw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xa6: CLK(5); if (I.regs.w[CW]) do { i_real_cmpsb(); I.regs.w[CW]--; CLK(3); CHK_ICOUNT(I.regs.w[CW] && ZF == 0); /* 6 + 3 = 9 */ } while (I.regs.w[CW]>0 && ZF==0); break; + case 0xa7: CLK(5); if (I.regs.w[CW]) do { i_real_cmpsw(); I.regs.w[CW]--; CLK(3); CHK_ICOUNT(I.regs.w[CW] && ZF == 0); /* 6 + 3 = 9 */ } while (I.regs.w[CW]>0 && ZF==0); break; + case 0xaa: CLK(5); if (I.regs.w[CW]) do { i_real_stosb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xab: CLK(5); if (I.regs.w[CW]) do { i_real_stosw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xac: CLK(5); if (I.regs.w[CW]) do { i_real_lodsb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xad: CLK(5); if (I.regs.w[CW]) do { i_real_lodsw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xae: CLK(5); if (I.regs.w[CW]) do { i_real_scasb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW] && ZF == 0); } while (I.regs.w[CW]>0 && ZF==0); break; + case 0xaf: CLK(5); if (I.regs.w[CW]) do { i_real_scasw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW] && ZF == 0); } while (I.regs.w[CW]>0 && ZF==0); break; + default: DoOP(next); break; + } + seg_prefix=FALSE; + } OP_EPILOGUE; + + OP( 0xf3, i_repe) + { + uint32 next = FETCHOP; + + switch(next) { /* Segments */ + case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[DS1]<<4; next = FETCHOP; CLK(2); break; + case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[PS]<<4; next = FETCHOP; CLK(2); break; + case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break; + case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS0]<<4; next = FETCHOP; CLK(2); break; + } + switch(next) { + case 0x6c: CLK(5); if (I.regs.w[CW]) do { i_real_insb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0x6d: CLK(5); if (I.regs.w[CW]) do { i_real_insw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0x6e: CLK(5); if (I.regs.w[CW]) do { i_real_outsb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0x6f: CLK(5); if (I.regs.w[CW]) do { i_real_outsw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xa4: CLK(5); if (I.regs.w[CW]) do { i_real_movsb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xa5: CLK(5); if (I.regs.w[CW]) do { i_real_movsw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xa6: CLK(5); if (I.regs.w[CW]) do { i_real_cmpsb(); I.regs.w[CW]--; CLK(3); CHK_ICOUNT(I.regs.w[CW] && ZF == 1); /* 6 + 3 = 9 */ } while (I.regs.w[CW]>0 && ZF==1); break; + case 0xa7: CLK(5); if (I.regs.w[CW]) do { i_real_cmpsw(); I.regs.w[CW]--; CLK(3); CHK_ICOUNT(I.regs.w[CW] && ZF == 1);/* 6 + 3 = 9 */ } while (I.regs.w[CW]>0 && ZF==1); break; + case 0xaa: CLK(5); if (I.regs.w[CW]) do { i_real_stosb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xab: CLK(5); if (I.regs.w[CW]) do { i_real_stosw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xac: CLK(5); if (I.regs.w[CW]) do { i_real_lodsb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xad: CLK(5); if (I.regs.w[CW]) do { i_real_lodsw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW]); } while (I.regs.w[CW]>0); break; + case 0xae: CLK(5); if (I.regs.w[CW]) do { i_real_scasb(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW] && ZF == 1); } while (I.regs.w[CW]>0 && ZF==1); break; + case 0xaf: CLK(5); if (I.regs.w[CW]) do { i_real_scasw(); I.regs.w[CW]--; CHK_ICOUNT(I.regs.w[CW] && ZF == 1); } while (I.regs.w[CW]>0 && ZF==1); break; + default: DoOP(next); break; + } + seg_prefix=FALSE; + } OP_EPILOGUE; + + OP( 0xf4, i_hlt ) { InHLT = TRUE; CheckInHLT(); } OP_EPILOGUE; + + OP( 0xf5, i_cmc ) { I.CarryVal = !CF; CLK(4); } OP_EPILOGUE; + OP( 0xf6, i_f6pre ) { uint32 tmp; uint32 uresult,uresult2; int32 result,result2; + GetModRM; tmp = GetRMByte(ModRM); + switch (ModRM & 0x38) { + case 0x00: tmp &= FETCH; I.CarryVal = I.OverVal = I.AuxVal=0; SetSZPF_Byte(tmp); CLKM(2,1); break; /* TEST */ + case 0x08: break; + case 0x10: PutbackRMByte(ModRM,~tmp); CLKM(3,1); break; /* NOT */ + + case 0x18: I.CarryVal=(tmp!=0);tmp=(~tmp)+1; SetSZPF_Byte(tmp); PutbackRMByte(ModRM,tmp&0xff); CLKM(3,1); break; /* NEG */ + case 0x20: uresult = I.regs.b[AL]*tmp; I.regs.w[AW]=(uint16)uresult; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); CLKM(4,3); break; /* MULU */ + case 0x28: result = (int16)((int8)I.regs.b[AL])*(int16)((int8)tmp); I.regs.w[AW]=(uint16)result; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); CLKM(4,3); break; /* MUL */ + case 0x30: if (tmp) { DIVUB; } else nec_interrupt(0); CLKM(16,15); break; + case 0x38: if (tmp) { DIVB; } else nec_interrupt(0); CLKM(18,17); break; + } + } OP_EPILOGUE; + + OP( 0xf7, i_f7pre ) { uint32 tmp,tmp2; uint32 uresult,uresult2; int32 result,result2; + GetModRM; tmp = GetRMWord(ModRM); + switch (ModRM & 0x38) { + case 0x00: FETCHuint16(tmp2); tmp &= tmp2; I.CarryVal = I.OverVal = I.AuxVal=0; SetSZPF_Word(tmp); CLKM(2,1); break; /* TEST */ + case 0x08: break; + case 0x10: PutbackRMWord(ModRM,~tmp); CLKM(3,1); break; /* NOT */ + case 0x18: I.CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Word(tmp); PutbackRMWord(ModRM,tmp&0xffff); CLKM(3,1); break; /* NEG */ + case 0x20: uresult = I.regs.w[AW]*tmp; I.regs.w[AW]=uresult&0xffff; I.regs.w[DW]=((uint32)uresult)>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); CLKM(4,3); break; /* MULU */ + case 0x28: result = (int32)((int16)I.regs.w[AW])*(int32)((int16)tmp); I.regs.w[AW]=result&0xffff; I.regs.w[DW]=result>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); CLKM(4,3); break; /* MUL */ + case 0x30: if (tmp) { DIVUW; } else nec_interrupt(0); CLKM(24,23); break; + case 0x38: if (tmp) { DIVW; } else nec_interrupt(0); CLKM(25,24); break; + } + } OP_EPILOGUE; + + OP( 0xf8, i_clc ) { I.CarryVal = 0; CLK(4); } OP_EPILOGUE; + OP( 0xf9, i_stc ) { I.CarryVal = 1; CLK(4); } OP_EPILOGUE; + OP( 0xfa, i_di ) { SetIF(0); CLK(4); } OP_EPILOGUE; + OP( 0xfb, i_ei ) { SetIF(1); CLK(4); } OP_EPILOGUE; + OP( 0xfc, i_cld ) { SetDF(0); CLK(4); } OP_EPILOGUE; + OP( 0xfd, i_std ) { SetDF(1); CLK(4); } OP_EPILOGUE; + OP( 0xfe, i_fepre ) { uint32 tmp, tmp1; GetModRM; tmp=GetRMByte(ModRM); + switch(ModRM & 0x38) { + case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7f); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(uint8)tmp1); CLKM(3,1); break; /* INC */ + case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x80); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(uint8)tmp1); CLKM(3,1); break; /* DEC */ + } + } OP_EPILOGUE; + + OP( 0xff, i_ffpre ) { uint32 tmp, tmp1; GetModRM; tmp=GetRMWord(ModRM); + switch(ModRM & 0x38) { + case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7fff); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(uint16)tmp1); CLKM(3,1); break; /* INC */ + case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x8000); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(uint16)tmp1); CLKM(3,1); break; /* DEC */ + case 0x10: PUSH(I.pc); I.pc = (uint16)tmp; ADDBRANCHTRACE(I.sregs[PS], I.pc); CLKM(6,5); break; /* CALL */ + case 0x18: tmp1 = I.sregs[PS]; I.sregs[PS] = GetnextRMWord; PUSH(tmp1); PUSH(I.pc); I.pc = tmp; ADDBRANCHTRACE(I.sregs[PS], I.pc); CLKM(12,1); break; /* CALL FAR */ + case 0x20: I.pc = tmp; ADDBRANCHTRACE(I.sregs[PS], I.pc); CLKM(5,4); break; /* JMP */ + case 0x28: I.pc = tmp; I.sregs[PS] = GetnextRMWord; ADDBRANCHTRACE(I.sregs[PS], I.pc); CLKM(10,1); break; /* JMP FAR */ + case 0x30: PUSH(tmp); CLKM(2,1); break; + } + } OP_EPILOGUE; + } // End switch statement + + + } // End func + + + /*****************************************************************************/ + + + unsigned V30MZ::get_reg(int regnum) + { + switch( regnum ) + { + case NEC_PC: return I.pc; + case NEC_SP: return I.regs.w[SP]; + case NEC_FLAGS: return CompressFlags(); + case NEC_AW: return I.regs.w[AW]; + case NEC_CW: return I.regs.w[CW]; + case NEC_DW: return I.regs.w[DW]; + case NEC_BW: return I.regs.w[BW]; + case NEC_BP: return I.regs.w[BP]; + case NEC_IX: return I.regs.w[IX]; + case NEC_IY: return I.regs.w[IY]; + case NEC_DS1: return I.sregs[DS1]; + case NEC_PS: return I.sregs[PS]; + case NEC_SS: return I.sregs[SS]; + case NEC_DS0: return I.sregs[DS0]; + } + return 0; + } + + void nec_set_irq_line(int irqline, int state); + + void V30MZ::set_reg(int regnum, unsigned val) + { + switch( regnum ) + { + case NEC_PC: I.pc = val; break; + case NEC_SP: I.regs.w[SP] = val; break; + case NEC_FLAGS: ExpandFlags(val); break; + case NEC_AW: I.regs.w[AW] = val; break; + case NEC_CW: I.regs.w[CW] = val; break; + case NEC_DW: I.regs.w[DW] = val; break; + case NEC_BW: I.regs.w[BW] = val; break; + case NEC_BP: I.regs.w[BP] = val; break; + case NEC_IX: I.regs.w[IX] = val; break; + case NEC_IY: I.regs.w[IY] = val; break; + case NEC_DS1: I.sregs[DS1] = val; break; + case NEC_PS: I.sregs[PS] = val; break; + case NEC_SS: I.sregs[SS] = val; break; + case NEC_DS0: I.sregs[DS0] = val; break; + } + } + + void V30MZ::execute(int cycles) + { + ICount += cycles; + if(InHLT) + { + SETOLDCSIP(); + sys->interrupt.Check(); + if(InHLT) + { + int32 tmp = ICount; + if(tmp > 0) + CLK(tmp); + return; + } + } + + while(ICount > 0) + { + SETOLDCSIP(); + sys->interrupt.Check(); + DoOP(FETCHOP); + } + + } + +} diff --git a/wonderswan/v30mz.h b/wonderswan/v30mz.h new file mode 100644 index 0000000000..761b28b721 --- /dev/null +++ b/wonderswan/v30mz.h @@ -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 diff --git a/wonderswan/wstech24.txt b/wonderswan/wstech24.txt new file mode 100644 index 0000000000..6c4a5c30f7 --- /dev/null +++ b/wonderswan/wstech24.txt @@ -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: + + + out B6,40 + + 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 - ??? diff --git a/wonderswan/wswan.h b/wonderswan/wswan.h new file mode 100644 index 0000000000..c92937dc16 --- /dev/null +++ b/wonderswan/wswan.h @@ -0,0 +1,34 @@ +#ifndef __WSWAN_H +#define __WSWAN_H + +#include +#include + +#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