diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibPizza.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibPizza.cs deleted file mode 100644 index e8306aea35..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibPizza.cs +++ /dev/null @@ -1,43 +0,0 @@ -using BizHawk.Common.BizInvoke; -using BizHawk.Emulation.Cores.Waterbox; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy -{ - public abstract class LibPizza : LibWaterboxCore, ICustomSaveram - { - [Flags] - public enum Buttons : uint - { - A = 0x01, - B = 0x02, - SELECT = 0x04, - START = 0x08, - RIGHT = 0x10, - LEFT = 0x20, - UP = 0x40, - DOWN = 0x80 - } - [StructLayout(LayoutKind.Sequential)] - public new class FrameInfo : LibWaterboxCore.FrameInfo - { - public long Time; - public Buttons Keys; - } - [BizImport(CC)] - public abstract bool Init(byte[] rom, int romlen, bool sgb, byte[] spc, int spclen); - [BizImport(CC)] - public abstract bool IsCGB(); - [BizImport(CC)] - public abstract int GetSaveramSize(); - [BizImport(CC)] - public abstract void PutSaveram(byte[] data, int size); - [BizImport(CC)] - public abstract void GetSaveram(byte[] data, int size); - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs deleted file mode 100644 index 90fecb3b99..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Pizza.cs +++ /dev/null @@ -1,169 +0,0 @@ -using BizHawk.Common; -using BizHawk.Common.BizInvoke; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Waterbox; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy -{ - [Core("Pizza Boy", "Davide Berra", true, true, "c7bc6ee376028b3766de8d7a02e60ab794841f45", - "https://github.com/davideberra/emu-pizza/", false)] - public class Pizza : WaterboxCore - { - private LibPizza _pizza; - private readonly bool _sgb; - - [CoreConstructor("SGB")] - public Pizza(byte[] rom, CoreComm comm) - : this(rom, comm, true) - { } - - [CoreConstructor("GB")] - public Pizza(CoreComm comm, byte[] rom) - : this(rom, comm, false) - { } - - public Pizza(byte[] rom, CoreComm comm, bool sgb) - : base(comm, new Configuration - { - DefaultWidth = 160, - DefaultHeight = 144, - MaxWidth = 256, - MaxHeight = 224, - MaxSamples = 1024, - DefaultFpsNumerator = TICKSPERSECOND, - DefaultFpsDenominator = TICKSPERFRAME - }) - { - if (sgb && (rom[0x143] & 0xc0) == 0xc0) - { - throw new CGBNotSupportedException(); - } - - _pizza = PreInit(new PeRunnerOptions - { - Filename = "pizza.wbx", - SbrkHeapSizeKB = 128, - InvisibleHeapSizeKB = 16, - SealedHeapSizeKB = 5 * 1024, - PlainHeapSizeKB = 16, - MmapHeapSizeKB = 0 - }); - - var spc = sgb - ? Util.DecompressGzipFile(new MemoryStream(Properties.Resources.SgbCartPresent_SPC)) - : new byte[0]; - _sgb = sgb; - if (!_pizza.Init(rom, rom.Length, _sgb, spc, spc.Length)) - { - throw new InvalidOperationException("Core rejected the rom!"); - } - - PostInit(); - - if (_sgb) - { - VsyncNumerator = TICKSPERSECOND_SGB; - BufferWidth = 256; - BufferHeight = 224; - } - InitializeRtc(new DateTime(2010, 1, 1)); // TODO: connect to syncsettings - Console.WriteLine("Pizza Initialized: CGB {0} SGB {1}", IsCGBMode(), IsSGBMode()); - } - - /// - /// the nominal length of one frame - /// - private const int TICKSPERFRAME = 35112; - - /// - /// number of ticks per second (GB, CGB) - /// - private const int TICKSPERSECOND = 2097152; - - /// - /// number of ticks per second (SGB) - /// - private const int TICKSPERSECOND_SGB = 2147727; - - #region Controller - - private static readonly ControllerDefinition _gbDefinition; - private static readonly ControllerDefinition _sgbDefinition; - public override ControllerDefinition ControllerDefinition => _sgb ? _sgbDefinition : _gbDefinition; - - private static ControllerDefinition CreateControllerDefinition(int p) - { - var ret = new ControllerDefinition { Name = "Gameboy Controller" }; - for (int i = 0; i < p; i++) - { - ret.BoolButtons.AddRange( - new[] { "Up", "Down", "Left", "Right", "A", "B", "Select", "Start" } - .Select(s => $"P{i + 1} {s}")); - } - return ret; - } - - static Pizza() - { - _gbDefinition = CreateControllerDefinition(1); - _sgbDefinition = CreateControllerDefinition(4); - } - - private LibPizza.Buttons GetButtons(IController c) - { - LibPizza.Buttons b = 0; - for (int i = _sgb ? 4 : 1; i > 0; i--) - { - if (c.IsPressed($"P{i} Up")) - b |= LibPizza.Buttons.UP; - if (c.IsPressed($"P{i} Down")) - b |= LibPizza.Buttons.DOWN; - if (c.IsPressed($"P{i} Left")) - b |= LibPizza.Buttons.LEFT; - if (c.IsPressed($"P{i} Right")) - b |= LibPizza.Buttons.RIGHT; - if (c.IsPressed($"P{i} A")) - b |= LibPizza.Buttons.A; - if (c.IsPressed($"P{i} B")) - b |= LibPizza.Buttons.B; - if (c.IsPressed($"P{i} Select")) - b |= LibPizza.Buttons.SELECT; - if (c.IsPressed($"P{i} Start")) - b |= LibPizza.Buttons.START; - if (i != 1) - b = (LibPizza.Buttons)((uint)b << 8); - } - return b; - } - - #endregion - - LibPizza.FrameInfo _tmp; // TODO: clean this up so it's not so hacky - - protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound) - { - return _tmp = new LibPizza.FrameInfo - { - Time = GetRtcTime(false), - Keys = GetButtons(controller) - }; - } - - protected override void FrameAdvancePost() - { - //Console.WriteLine(_tmp.Cycles); - _tmp = null; - } - - public bool IsCGBMode() => _pizza.IsCGB(); - public bool IsSGBMode() => _sgb; - - public override string SystemId => _sgb ? "SGB" : "GB"; - } -} diff --git a/output/dll/pizza.wbx.gz b/output/dll/pizza.wbx.gz deleted file mode 100644 index 3df3e57b0f..0000000000 Binary files a/output/dll/pizza.wbx.gz and /dev/null differ diff --git a/waterbox/pizza/.vscode/settings.json b/waterbox/pizza/.vscode/settings.json deleted file mode 100644 index d5073385ae..0000000000 --- a/waterbox/pizza/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ - "editor.insertSpaces": false, - "editor.tabSize": 4, - "editor.detectIndentation": false -} \ No newline at end of file diff --git a/waterbox/pizza/Makefile b/waterbox/pizza/Makefile deleted file mode 100644 index 4893bc03f3..0000000000 --- a/waterbox/pizza/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -CC = x86_64-nt64-midipix-gcc -CPP = x86_64-nt64-midipix-g++ - -FLAGS:=-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \ - -fomit-frame-pointer -fvisibility=hidden \ - -O3 -flto - -CCFLAGS:=$(FLAGS) -Ilib \ - -I../emulibc \ - -std=c99 \ - -DLSB_FIRST -D_GNU_SOURCE - -CPPFLAGS:=$(FLAGS) -DSPC_NO_COPY_STATE_FUNCS - -TARGET = pizza.wbx - -LDFLAGS = -Wl,--dynamicbase,--export-all-symbols - -ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -C_SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.c') -CPP_SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.cpp') -SRCS:=$(C_SRCS) $(CPP_SRCS) -OBJ_DIR:=$(ROOT_DIR)/obj - -__OBJS:=$(SRCS:.c=.o) -_OBJS:=$(__OBJS:.cpp=.opp) -OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS)) - -$(OBJ_DIR)/%.o: %.c - @mkdir -p $(@D) - @$(CC) -c -o $@ $< $(CCFLAGS) - -$(OBJ_DIR)/%.opp: %.cpp - @mkdir -p $(@D) - @$(CPP) -c -o $@ $< $(CPPFLAGS) - -all: $(TARGET) - -.PHONY: clean all - -$(TARGET).in: $(OBJS) - @$(CPP) -o $@ $(LDFLAGS) $(FLAGS) $(OBJS) ../emulibc/libemuhost.so - -$(TARGET): $(TARGET).in - strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104 -# cp $< $@ - -clean: - rm -rf $(OBJ_DIR) - rm -f $(TARGET).in - rm -f $(TARGET) - -#install: -# $(CP) $(TARGET) $(DEST_$(ARCH)) diff --git a/waterbox/pizza/README.md b/waterbox/pizza/README.md deleted file mode 100644 index edc069a750..0000000000 --- a/waterbox/pizza/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Emu-pizza -A new born Gameboy Classic/Color emulator.... - -Requirements ------------ -Emu-pizza requires libSDL2 to compile and run Space Invaders and Gameboy games. To install it - -on an APT based distro: -``` -sudo apt-get install libsdl2-dev -``` - -on a YUM based distro: -``` -sudo yum install SDL2-devel -``` - -Compile -------- -``` -make -``` - -Usage ------ -``` -emu-pizza [gameboy rom] -``` - -Gameboy keys -------------------- -* Arrows -- Arrows (rly?) -* Enter -- Start -* Space -- Select -* Z/X -- A/B buttons -* Q -- Exit - -Supported ROMS --------------- -* Almost totality of Gameboy roms - -Todo ----- -* Serial cable emulation - -Credits -------- - -Thanks to [Emulator 101](http://www.emulator101.com), the source of all my current knowledge on 8080 emulation diff --git a/waterbox/pizza/blip_buf/blip_buf.c b/waterbox/pizza/blip_buf/blip_buf.c deleted file mode 100644 index 1bd3377e92..0000000000 --- a/waterbox/pizza/blip_buf/blip_buf.c +++ /dev/null @@ -1,344 +0,0 @@ -/* blip_buf 1.1.0. http://www.slack.net/~ant/ */ - -#include "blip_buf.h" - -#include -#include -#include -#include - -/* Library Copyright (C) 2003-2009 Shay Green. This library 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 -library 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 */ - -#if defined (BLARGG_TEST) && BLARGG_TEST - #include "blargg_test.h" -#endif - -/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000. -Avoids constants that don't fit in 32 bits. */ -#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF - typedef unsigned long fixed_t; - enum { pre_shift = 32 }; - -#elif defined(ULLONG_MAX) - typedef unsigned long long fixed_t; - enum { pre_shift = 32 }; - -#else - typedef unsigned fixed_t; - enum { pre_shift = 0 }; - -#endif - -enum { time_bits = pre_shift + 20 }; - -static fixed_t const time_unit = (fixed_t) 1 << time_bits; - -enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */ -enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */ - -enum { half_width = 8 }; -enum { buf_extra = half_width*2 + end_frame_extra }; -enum { phase_bits = 5 }; -enum { phase_count = 1 << phase_bits }; -enum { delta_bits = 15 }; -enum { delta_unit = 1 << delta_bits }; -enum { frac_bits = time_bits - pre_shift }; - -/* We could eliminate avail and encode whole samples in offset, but that would -limit the total buffered samples to blip_max_frame. That could only be -increased by decreasing time_bits, which would reduce resample ratio accuracy. -*/ - -/** Sample buffer that resamples to output rate and accumulates samples -until they're read out */ -struct blip_t -{ - fixed_t factor; - fixed_t offset; - int avail; - int size; - int integrator; -}; - -typedef int buf_t; - -/* probably not totally portable */ -#define SAMPLES( buf ) ((buf_t*) ((buf) + 1)) - -/* Arithmetic (sign-preserving) right shift */ -#define ARITH_SHIFT( n, shift ) \ - ((n) >> (shift)) - -enum { max_sample = +32767 }; -enum { min_sample = -32768 }; - -#define CLAMP( n ) \ - {\ - if ( (short) n != n )\ - n = ARITH_SHIFT( n, 16 ) ^ max_sample;\ - } - -static void check_assumptions( void ) -{ - int n; - - #if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF - #error "int must be at least 32 bits" - #endif - - assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */ - - n = max_sample * 2; - CLAMP( n ); - assert( n == max_sample ); - - n = min_sample * 2; - CLAMP( n ); - assert( n == min_sample ); - - assert( blip_max_ratio <= time_unit ); - assert( blip_max_frame <= (fixed_t) -1 >> time_bits ); -} - -blip_t* blip_new( int size ) -{ - blip_t* m; - assert( size >= 0 ); - - m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) ); - if ( m ) - { - m->factor = time_unit / blip_max_ratio; - m->size = size; - blip_clear( m ); - check_assumptions(); - } - return m; -} - -void blip_delete( blip_t* m ) -{ - if ( m != NULL ) - { - /* Clear fields in case user tries to use after freeing */ - memset( m, 0, sizeof *m ); - free( m ); - } -} - -void blip_set_rates( blip_t* m, double clock_rate, double sample_rate ) -{ - double factor = time_unit * sample_rate / clock_rate; - m->factor = (fixed_t) factor; - - /* Fails if clock_rate exceeds maximum, relative to sample_rate */ - assert( 0 <= factor - m->factor && factor - m->factor < 1 ); - - /* Avoid requiring math.h. Equivalent to - m->factor = (int) ceil( factor ) */ - if ( m->factor < factor ) - m->factor++; - - /* At this point, factor is most likely rounded up, but could still - have been rounded down in the floating-point calculation. */ -} - -void blip_clear( blip_t* m ) -{ - /* We could set offset to 0, factor/2, or factor-1. 0 is suitable if - factor is rounded up. factor-1 is suitable if factor is rounded down. - Since we don't know rounding direction, factor/2 accommodates either, - with the slight loss of showing an error in half the time. Since for - a 64-bit factor this is years, the halving isn't a problem. */ - - m->offset = m->factor / 2; - m->avail = 0; - m->integrator = 0; - memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) ); -} - -int blip_clocks_needed( const blip_t* m, int samples ) -{ - fixed_t needed; - - /* Fails if buffer can't hold that many more samples */ - assert( samples >= 0 && m->avail + samples <= m->size ); - - needed = (fixed_t) samples * time_unit; - if ( needed < m->offset ) - return 0; - - return (needed - m->offset + m->factor - 1) / m->factor; -} - -void blip_end_frame( blip_t* m, unsigned t ) -{ - fixed_t off = t * m->factor + m->offset; - m->avail += off >> time_bits; - m->offset = off & (time_unit - 1); - - /* Fails if buffer size was exceeded */ - assert( m->avail <= m->size ); -} - -int blip_samples_avail( const blip_t* m ) -{ - return m->avail; -} - -static void remove_samples( blip_t* m, int count ) -{ - buf_t* buf = SAMPLES( m ); - int remain = m->avail + buf_extra - count; - m->avail -= count; - - memmove( &buf [0], &buf [count], remain * sizeof buf [0] ); - memset( &buf [remain], 0, count * sizeof buf [0] ); -} - -int blip_read_samples( blip_t* m, short out [], int count, int stereo ) -{ - assert( count >= 0 ); - - if ( count > m->avail ) - count = m->avail; - - if ( count ) - { - int const step = stereo ? 2 : 1; - buf_t const* in = SAMPLES( m ); - buf_t const* end = in + count; - int sum = m->integrator; - do - { - /* Eliminate fraction */ - int s = ARITH_SHIFT( sum, delta_bits ); - - sum += *in++; - - CLAMP( s ); - - *out = s; - out += step; - - /* High-pass filter */ - sum -= s << (delta_bits - bass_shift); - } - while ( in != end ); - m->integrator = sum; - - remove_samples( m, count ); - } - - return count; -} - -/* Things that didn't help performance on x86: - __attribute__((aligned(128))) - #define short int - restrict -*/ - -/* Sinc_Generator( 0.9, 0.55, 4.5 ) */ -static short const bl_step [phase_count + 1] [half_width] = -{ -{ 43, -115, 350, -488, 1136, -914, 5861,21022}, -{ 44, -118, 348, -473, 1076, -799, 5274,21001}, -{ 45, -121, 344, -454, 1011, -677, 4706,20936}, -{ 46, -122, 336, -431, 942, -549, 4156,20829}, -{ 47, -123, 327, -404, 868, -418, 3629,20679}, -{ 47, -122, 316, -375, 792, -285, 3124,20488}, -{ 47, -120, 303, -344, 714, -151, 2644,20256}, -{ 46, -117, 289, -310, 634, -17, 2188,19985}, -{ 46, -114, 273, -275, 553, 117, 1758,19675}, -{ 44, -108, 255, -237, 471, 247, 1356,19327}, -{ 43, -103, 237, -199, 390, 373, 981,18944}, -{ 42, -98, 218, -160, 310, 495, 633,18527}, -{ 40, -91, 198, -121, 231, 611, 314,18078}, -{ 38, -84, 178, -81, 153, 722, 22,17599}, -{ 36, -76, 157, -43, 80, 824, -241,17092}, -{ 34, -68, 135, -3, 8, 919, -476,16558}, -{ 32, -61, 115, 34, -60, 1006, -683,16001}, -{ 29, -52, 94, 70, -123, 1083, -862,15422}, -{ 27, -44, 73, 106, -184, 1152,-1015,14824}, -{ 25, -36, 53, 139, -239, 1211,-1142,14210}, -{ 22, -27, 34, 170, -290, 1261,-1244,13582}, -{ 20, -20, 16, 199, -335, 1301,-1322,12942}, -{ 18, -12, -3, 226, -375, 1331,-1376,12293}, -{ 15, -4, -19, 250, -410, 1351,-1408,11638}, -{ 13, 3, -35, 272, -439, 1361,-1419,10979}, -{ 11, 9, -49, 292, -464, 1362,-1410,10319}, -{ 9, 16, -63, 309, -483, 1354,-1383, 9660}, -{ 7, 22, -75, 322, -496, 1337,-1339, 9005}, -{ 6, 26, -85, 333, -504, 1312,-1280, 8355}, -{ 4, 31, -94, 341, -507, 1278,-1205, 7713}, -{ 3, 35, -102, 347, -506, 1238,-1119, 7082}, -{ 1, 40, -110, 350, -499, 1190,-1021, 6464}, -{ 0, 43, -115, 350, -488, 1136, -914, 5861} -}; - -/* Shifting by pre_shift allows calculation using unsigned int rather than -possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient. -And by having pre_shift 32, a 32-bit platform can easily do the shift by -simply ignoring the low half. */ - -void blip_add_delta( blip_t* m, unsigned time, int delta ) -{ - unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift); - buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits); - - int const phase_shift = frac_bits - phase_bits; - int phase = fixed >> phase_shift & (phase_count - 1); - short const* in = bl_step [phase]; - short const* rev = bl_step [phase_count - phase]; - - int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1); - int delta2 = (delta * interp) >> delta_bits; - delta -= delta2; - - /* Fails if buffer size was exceeded */ - assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] ); - - out [0] += in[0]*delta + in[half_width+0]*delta2; - out [1] += in[1]*delta + in[half_width+1]*delta2; - out [2] += in[2]*delta + in[half_width+2]*delta2; - out [3] += in[3]*delta + in[half_width+3]*delta2; - out [4] += in[4]*delta + in[half_width+4]*delta2; - out [5] += in[5]*delta + in[half_width+5]*delta2; - out [6] += in[6]*delta + in[half_width+6]*delta2; - out [7] += in[7]*delta + in[half_width+7]*delta2; - - in = rev; - out [ 8] += in[7]*delta + in[7-half_width]*delta2; - out [ 9] += in[6]*delta + in[6-half_width]*delta2; - out [10] += in[5]*delta + in[5-half_width]*delta2; - out [11] += in[4]*delta + in[4-half_width]*delta2; - out [12] += in[3]*delta + in[3-half_width]*delta2; - out [13] += in[2]*delta + in[2-half_width]*delta2; - out [14] += in[1]*delta + in[1-half_width]*delta2; - out [15] += in[0]*delta + in[0-half_width]*delta2; -} - -void blip_add_delta_fast( blip_t* m, unsigned time, int delta ) -{ - unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift); - buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits); - - int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1); - int delta2 = delta * interp; - - /* Fails if buffer size was exceeded */ - assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] ); - - out [7] += delta * delta_unit - delta2; - out [8] += delta2; -} diff --git a/waterbox/pizza/blip_buf/blip_buf.h b/waterbox/pizza/blip_buf/blip_buf.h deleted file mode 100644 index e9a5d4cc3b..0000000000 --- a/waterbox/pizza/blip_buf/blip_buf.h +++ /dev/null @@ -1,72 +0,0 @@ -/** \file -Sample buffer that resamples from input clock rate to output sample rate */ - -/* blip_buf 1.1.0 */ -#ifndef BLIP_BUF_H -#define BLIP_BUF_H - -#ifdef __cplusplus - extern "C" { -#endif - -/** First parameter of most functions is blip_t*, or const blip_t* if nothing -is changed. */ -typedef struct blip_t blip_t; - -/** Creates new buffer that can hold at most sample_count samples. Sets rates -so that there are blip_max_ratio clocks per sample. Returns pointer to new -buffer, or NULL if insufficient memory. */ -blip_t* blip_new( int sample_count ); - -/** Sets approximate input clock rate and output sample rate. For every -clock_rate input clocks, approximately sample_rate samples are generated. */ -void blip_set_rates( blip_t*, double clock_rate, double sample_rate ); - -enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate, -clock_rate must not be greater than sample_rate*blip_max_ratio. */ -blip_max_ratio = 1 << 20 }; - -/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */ -void blip_clear( blip_t* ); - -/** Adds positive/negative delta into buffer at specified clock time. */ -void blip_add_delta( blip_t*, unsigned int clock_time, int delta ); - -/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */ -void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta ); - -/** Length of time frame, in clocks, needed to make sample_count additional -samples available. */ -int blip_clocks_needed( const blip_t*, int sample_count ); - -enum { /** Maximum number of samples that can be generated from one time frame. */ -blip_max_frame = 4000 }; - -/** Makes input clocks before clock_duration available for reading as output -samples. Also begins new time frame at clock_duration, so that clock time 0 in -the new time frame specifies the same clock as clock_duration in the old time -frame specified. Deltas can have been added slightly past clock_duration (up to -however many clocks there are in two output samples). */ -void blip_end_frame( blip_t*, unsigned int clock_duration ); - -/** Number of buffered samples available for reading. */ -int blip_samples_avail( const blip_t* ); - -/** Reads and removes at most 'count' samples and writes them to 'out'. If -'stereo' is true, writes output to every other element of 'out', allowing easy -interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed -samples. Returns number of samples actually read. */ -int blip_read_samples( blip_t*, short out [], int count, int stereo ); - -/** Frees buffer. No effect if NULL is passed. */ -void blip_delete( blip_t* ); - - -/* Deprecated */ -typedef blip_t blip_buffer_t; - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/waterbox/pizza/lib/cartridge.c b/waterbox/pizza/lib/cartridge.c deleted file mode 100644 index 89835aad17..0000000000 --- a/waterbox/pizza/lib/cartridge.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include -#include -#include - -#include "global.h" -#include "mmu.h" -#include "utils.h" - -/* guess what */ -/* return values */ -/* 0: OK */ -/* 1: Can't open/read file */ -/* 2: Unknown cartridge */ - -char cartridge_load(const void *data, size_t sz) -{ - int i, z = 0; - - if (sz < 1 || sz > 1 << 22) - return 1; - - const uint8_t *rom = (const uint8_t *)data; - - /* gameboy color? */ - if (rom[0x143] == 0xC0 || rom[0x143] == 0x80) - { - utils_log("Gameboy Color cartridge\n"); - global_cgb = global_sgb ? 0 : 1; - } - else - { - utils_log("Gameboy Classic cartridge\n"); - global_cgb = 0; - } - - /* get cartridge infos */ - uint8_t mbc = rom[0x147]; - - utils_log("Cartridge code: %02x\n", mbc); - - switch (mbc) - { - case 0x00: - utils_log("ROM ONLY\n"); - break; - case 0x01: - utils_log("MBC1\n"); - break; - case 0x02: - utils_log("MBC1 + RAM\n"); - break; - case 0x03: - utils_log("MBC1 + RAM + BATTERY\n"); - break; - case 0x05: - utils_log("MBC2\n"); - break; - case 0x06: - mmu_init_ram(512); - utils_log("MBC2 + BATTERY\n"); - break; - case 0x10: - utils_log("MBC3 + TIMER + RAM + BATTERY\n"); - break; - case 0x11: - utils_log("MBC3\n"); - break; - case 0x12: - utils_log("MBC3 + RAM\n"); - break; - case 0x13: - utils_log("MBC3 + RAM + BATTERY\n"); - break; - case 0x19: - utils_log("MBC5\n"); - break; - case 0x1A: - utils_log("MBC5 + RAM\n"); - break; - case 0x1B: - utils_log("MBC5 + RAM + BATTERY\n"); - break; - case 0x1C: - global_rumble = 1; - utils_log("MBC5 + RUMBLE\n"); - break; - case 0x1D: - global_rumble = 1; - utils_log("MBC5 + RUMBLE + RAM\n"); - break; - case 0x1E: - global_rumble = 1; - utils_log("MBC5 + RUMBLE + RAM + BATTERY\n"); - break; - - default: - utils_log("Unknown cartridge type: %02x\n", mbc); - return 2; - } - - /* title */ - for (i = 0x134; i < 0x143; i++) - if (rom[i] > 0x40 && rom[i] < 0x5B) - global_cart_name[z++] = rom[i]; - - global_cart_name[z] = '\0'; - - utils_log("%s\n", global_cart_name); - - /* get ROM banks */ - uint8_t byte = rom[0x148]; - - utils_log("ROM: "); - - switch (byte) - { - case 0x00: - utils_log("0 banks\n"); - break; - case 0x01: - utils_log("4 banks\n"); - break; - case 0x02: - utils_log("8 banks\n"); - break; - case 0x03: - utils_log("16 banks\n"); - break; - case 0x04: - utils_log("32 banks\n"); - break; - case 0x05: - utils_log("64 banks\n"); - break; - case 0x06: - utils_log("128 banks\n"); - break; - case 0x07: - utils_log("256 banks\n"); - break; - case 0x52: - utils_log("72 banks\n"); - break; - case 0x53: - utils_log("80 banks\n"); - break; - case 0x54: - utils_log("96 banks\n"); - break; - } - - /* init MMU */ - mmu_init(mbc, byte); - - /* get RAM banks */ - byte = rom[0x149]; - - utils_log("RAM: "); - - switch (byte) - { - case 0x00: - utils_log("NO RAM\n"); - break; - case 0x01: - mmu_init_ram(1 << 11); - utils_log("2 kB\n"); - break; - case 0x02: - /* MBC5 got bigger values */ - if (mbc >= 0x19 && mbc <= 0x1E) - { - mmu_init_ram(1 << 16); - utils_log("64 kB\n"); - } - else - { - mmu_init_ram(1 << 13); - utils_log("8 kB\n"); - } - break; - case 0x03: - mmu_init_ram(1 << 15); - utils_log("32 kB\n"); - break; - case 0x04: - mmu_init_ram(1 << 17); - utils_log("128 kB\n"); - break; - case 0x05: - mmu_init_ram(1 << 16); - utils_log("64 kB\n"); - break; - } - - /* restore saved RAM if it's the case */ - //mmu_restore_ram(file_sav); - - /* restore saved RTC if it's the case */ - //mmu_restore_rtc(file_rtc); - - /* load FULL ROM at 0x0000 address of system memory */ - mmu_load_cartridge(rom, sz); - - return 0; -} - -/*void cartridge_term() -{ - // save persistent data (battery backed RAM and RTC clock) - mmu_save_ram(file_sav); - mmu_save_rtc(file_rtc); -}*/ diff --git a/waterbox/pizza/lib/cartridge.h b/waterbox/pizza/lib/cartridge.h deleted file mode 100644 index ebc95de13c..0000000000 --- a/waterbox/pizza/lib/cartridge.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __CARTRIDGE_HDR__ -#define __CARTRIDGE_HDR__ - -#include - -/* prototypes */ -char cartridge_load(const void* data, size_t sz); - -#endif diff --git a/waterbox/pizza/lib/cycles.c b/waterbox/pizza/lib/cycles.c deleted file mode 100644 index f8a350462e..0000000000 --- a/waterbox/pizza/lib/cycles.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include "cycles.h" -#include "global.h" -#include "gpu.h" -#include "mmu.h" -#include "serial.h" -#include "sound.h" -#include "timer.h" -#include "interrupt.h" -#include "utils.h" - -interrupts_flags_t *cycles_if; - -/* instance of the main struct */ -cycles_t cycles = {0, 0, 0, 0}; - -#define CYCLES_PAUSES 256 - -/* hard sync stuff (for remote connection) */ -uint8_t cycles_hs_mode = 0; - -/* type of next */ -typedef enum { - CYCLES_NEXT_TYPE_CYCLES, - CYCLES_NEXT_TYPE_CYCLES_HS, - CYCLES_NEXT_TYPE_DMA, -} cycles_next_type_enum_e; - -/* closest next and its type */ -uint_fast32_t cycles_very_next; -cycles_next_type_enum_e cycles_next_type; - -/* set hard sync mode. sync is given by the remote peer + local timer */ -void cycles_start_hs() -{ - utils_log("Hard sync mode ON\n"); - - /* boolean set to on */ - cycles_hs_mode = 1; -} - -void cycles_stop_hs() -{ - utils_log("Hard sync mode OFF\n"); - - /* boolean set to on */ - cycles_hs_mode = 0; -} - -/* set double or normal speed */ -void cycles_set_speed(char dbl) -{ - /* set global */ - global_cpu_double_speed = dbl; - - /* update clock */ - if (global_cpu_double_speed) - cycles.clock = 4194304 * 2; - else - cycles.clock = 4194304; - - /* calculate the mask */ - cycles_change_emulation_speed(); -} - -/* set emulation speed */ -void cycles_change_emulation_speed() -{ - cycles.step = ((4194304 / CYCLES_PAUSES) - << global_cpu_double_speed); -} - -void cycles_closest_next() -{ - int_fast32_t diff = cycles.cnt - cycles.next; - - /* init */ - cycles_very_next = cycles.next; - cycles_next_type = CYCLES_NEXT_TYPE_CYCLES; - - int_fast32_t diff_new = cycles.cnt - mmu.dma_next; - - /* DMA? */ - if (diff_new < diff) - { - /* this is the new lowest */ - cycles_very_next = mmu.dma_next; - cycles_next_type = CYCLES_NEXT_TYPE_DMA; - } -} - -/* this function is gonna be called every M-cycle = 4 ticks of CPU */ -void cycles_step() -{ - cycles.cnt += 4; - cycles.sampleclock += 2 >> global_cpu_double_speed; - - /* - while (cycles.cnt >= cycles_very_next) - { - switch (cycles_next_type) - { - case CYCLES_NEXT_TYPE_CYCLES: - - deadline.tv_nsec += 1000000000 / CYCLES_PAUSES; - - if (deadline.tv_nsec > 1000000000) - { - deadline.tv_sec += 1; - deadline.tv_nsec -= 1000000000; - } - - clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, - &deadline, NULL); - - cycles.next += cycles.step; - - if (cycles.cnt % cycles.clock == 0) - cycles.seconds++; - - break; - - case CYCLES_NEXT_TYPE_DMA: - - memcpy(&mmu.memory[0xFE00], &mmu.memory[mmu.dma_address], 160); - - mmu.dma_address = 0x0000; - - mmu.dma_next = 1; - - break; - } - - cycles_closest_next(); - } -*/ - - /* 65536 == cpu clock / CYCLES_PAUSES pauses every second */ - if (cycles.cnt == cycles.next) - { - cycles.next += cycles.step; - } - - /* hard sync next step */ - if (cycles.cnt == cycles.hs_next) - { - /* set cycles for hard sync */ - cycles.hs_next += ((4096 * 4) << global_cpu_double_speed); - - /* hard sync is on? */ - if (cycles_hs_mode) - { - /* send my status and wait for peer status back */ - serial_send_byte(); - - /* wait for reply */ - serial_wait_data(); - - /* verify if we need to trigger an interrupt */ - serial_verify_intr(); - } - } - - /* DMA */ - if (mmu.dma_next == cycles.cnt) - { - memcpy(&mmu.memory[0xFE00], &mmu.memory[mmu.dma_address], 160); - - /* reset address */ - mmu.dma_address = 0x0000; - - /* reset */ - mmu.dma_next = 1; - } - - /* update GPU state */ - if (gpu.next == cycles.cnt) - gpu_step(); - - /* fs clock */ - if (sound.fs_cycles_next == cycles.cnt) - sound_step_fs(); - - /* channel one */ - if (sound.channel_one.duty_cycles_next == cycles.cnt) - sound_step_ch1(); - - /* channel two */ - if (sound.channel_two.duty_cycles_next == cycles.cnt) - sound_step_ch2(); - - /* channel three */ - if (sound.channel_three.cycles_next <= cycles.cnt) - sound_step_ch3(); - - /* channel four */ - if (sound.channel_four.cycles_next == cycles.cnt) - sound_step_ch4(); - - /* update timer state */ - if (cycles.cnt == timer.next) - { - timer.next += 256; - timer.div++; - } - - /* timer is on? */ - if (timer.sub_next == cycles.cnt) - { - timer.sub_next += timer.threshold; - timer.cnt++; - - /* cnt value > 255? trigger an interrupt */ - if (timer.cnt > 255) - { - timer.cnt = timer.mod; - - /* trigger timer interrupt */ - cycles_if->timer = 1; - } - } - - /* update serial state */ - if (serial.next == cycles.cnt) - { - /* nullize serial next */ - serial.next -= 1; - - /* reset counter */ - serial.bits_sent = 0; - - /* gotta reply with 0xff when asking for ff01 */ - serial.data = 0xFF; - - /* reset transfer_start flag to yell I'M DONE */ - serial.transfer_start = 0; - - /* if not connected, trig the fucking interrupt */ - cycles_if->serial_io = 1; - } -} - -/* things to do when vsync kicks in */ -void cycles_vblank() -{ - return; -} - -/* stuff tied to entering into hblank state */ -void cycles_hdma() -{ - /* HDMA (only CGB) */ - if (mmu.hdma_to_transfer) - { - /* hblank transfer */ - if (mmu.hdma_transfer_mode) - { - /* transfer when line is changed and we're into HBLANK phase */ - if (mmu.memory[0xFF44] < 143 && - mmu.hdma_current_line != mmu.memory[0xFF44] && - (mmu.memory[0xFF41] & 0x03) == 0x00) - { - /* update current line */ - mmu.hdma_current_line = mmu.memory[0xFF44]; - - /* copy 0x10 bytes */ - if (mmu.vram_idx) - memcpy(mmu_addr_vram1() + mmu.hdma_dst_address - 0x8000, - &mmu.memory[mmu.hdma_src_address], 0x10); - else - memcpy(mmu_addr_vram0() + mmu.hdma_dst_address - 0x8000, - &mmu.memory[mmu.hdma_src_address], 0x10); - - /* decrease bytes to transfer */ - mmu.hdma_to_transfer -= 0x10; - - /* increase pointers */ - mmu.hdma_dst_address += 0x10; - mmu.hdma_src_address += 0x10; - } - } - } -} - -char cycles_init() -{ - cycles.inited = 1; - - /* interrupt registers */ - cycles_if = mmu_addr(0xFF0F); - - /* init clock and counter */ - cycles.clock = 4194304; - cycles.cnt = 0; - cycles.hs_next = 70224; - - /* mask for pauses cycles fast calc */ - cycles.step = 4194304 / CYCLES_PAUSES; - cycles.next = 4194304 / CYCLES_PAUSES; - - return 0; -} diff --git a/waterbox/pizza/lib/cycles.h b/waterbox/pizza/lib/cycles.h deleted file mode 100644 index 58c7c2bb4c..0000000000 --- a/waterbox/pizza/lib/cycles.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __CYCLES_HDR__ -#define __CYCLES_HDR__ - -#include -#include - -typedef struct cycles_s -{ - /* am i init'ed? */ - uint_fast32_t inited; - - /* ticks counter */ - uint64_t cnt; - - // CPU clock. advances at 4MHz or 8MHz depending on current cgb setting - uint_fast32_t clock; - - /* handy for calculation */ - uint64_t next; - - /* step varying on cpu and emulation speed */ - uint_fast32_t step; - - /* 2 spares */ - uint64_t hs_next; - - // reference clock. advances at 2MHz always - uint64_t sampleclock; -} cycles_t; - -extern cycles_t cycles; - -// extern uint8_t cycles_hs_local_cnt; -// extern uint8_t cycles_hs_peer_cnt; - -/* callback function */ -typedef void (*cycles_send_cb_t)(uint32_t v); - -/* prototypes */ -void cycles_change_emulation_speed(); -void cycles_hdma(); -char cycles_init(); -void cycles_set_speed(char dbl); -void cycles_start_hs(); -void cycles_step(); -void cycles_stop_hs(); -void cycles_vblank(); - -#endif diff --git a/waterbox/pizza/lib/gameboy.c b/waterbox/pizza/lib/gameboy.c deleted file mode 100644 index be64e6436d..0000000000 --- a/waterbox/pizza/lib/gameboy.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include -#include "cartridge.h" -#include "sound.h" -#include "mmu.h" -#include "cycles.h" -#include "gpu.h" -#include "global.h" -#include "input.h" -#include "timer.h" -#include "serial.h" -#include "utils.h" -#include "z80_gameboy_regs.h" -#include "z80_gameboy.h" - -char gameboy_inited = 0; - -void gameboy_init() -{ - /* init z80 */ - z80_init(); - - /* init cycles syncronizer */ - cycles_init(); - - /* init timer */ - timer_init(); - - /* init serial */ - serial_init(); - - /* init sound (this will start audio thread) */ - sound_init(); - - /* reset GPU counters */ - gpu_reset(); - - /* reset to default values */ - mmu_write_no_cyc(0xFF05, 0x00); - mmu_write_no_cyc(0xFF06, 0x00); - mmu_write_no_cyc(0xFF07, 0x00); - mmu_write_no_cyc(0xFF10, 0x80); - mmu_write_no_cyc(0xFF11, 0xBF); - mmu_write_no_cyc(0xFF12, 0xF3); - mmu_write_no_cyc(0xFF14, 0xBF); - mmu_write_no_cyc(0xFF16, 0x3F); - mmu_write_no_cyc(0xFF17, 0x00); - mmu_write_no_cyc(0xFF19, 0xBF); - mmu_write_no_cyc(0xFF1A, 0x7F); - mmu_write_no_cyc(0xFF1B, 0xFF); - mmu_write_no_cyc(0xFF1C, 0x9F); - mmu_write_no_cyc(0xFF1E, 0xBF); - mmu_write_no_cyc(0xFF20, 0xFF); - mmu_write_no_cyc(0xFF21, 0x00); - mmu_write_no_cyc(0xFF22, 0x00); - mmu_write_no_cyc(0xFF23, 0xBF); - mmu_write_no_cyc(0xFF24, 0x77); - mmu_write_no_cyc(0xFF25, 0xF3); - mmu_write_no_cyc(0xFF26, 0xF1); - mmu_write_no_cyc(0xFF40, 0x91); - mmu_write_no_cyc(0xFF41, 0x80); - mmu_write_no_cyc(0xFF42, 0x00); - mmu_write_no_cyc(0xFF43, 0x00); - mmu_write_no_cyc(0xFF44, 0x00); - mmu_write_no_cyc(0xFF45, 0x00); - mmu_write_no_cyc(0xFF47, 0xFC); - mmu_write_no_cyc(0xFF48, 0xFF); - mmu_write_no_cyc(0xFF49, 0xFF); - mmu_write_no_cyc(0xFF4A, 0x00); - mmu_write_no_cyc(0xFF4B, 0x00); - mmu_write_no_cyc(0xFF98, 0xDC); - mmu_write_no_cyc(0xFFFF, 0x00); - mmu_write_no_cyc(0xC000, 0x08); - mmu_write_no_cyc(0xFFFE, 0x69); - - if (global_cgb) - state.a = 0x11; - else - state.a = 0x00; - - state.b = 0x00; - state.c = 0x13; - state.d = 0x00; - state.e = 0xd8; - state.h = 0x01; - state.l = 0x4d; - state.pc = 0x0100; - state.sp = 0xFFFE; - *state.f = 0xB0; - - /* reset counter */ - cycles.cnt = 0; - /* start at normal speed */ - global_cpu_double_speed = 0; - - /* mark as inited */ - gameboy_inited = 1; - - return; -} - -void gameboy_run(uint64_t target) -{ - uint8_t op; - - /* get interrupt flags and interrupt enables */ - uint8_t *int_e; - uint8_t *int_f; - - /* pointers to memory location of interrupt enables/flags */ - int_e = mmu_addr(0xFFFF); - int_f = mmu_addr(0xFF0F); - - /* run stuff! */ - /* mechanism is simple. */ - /* 1) execute instruction 2) update cycles counter 3) check interrupts */ - /* and repeat forever */ - while (cycles.sampleclock < target) - { - /* get op */ - op = mmu_read(state.pc); - - /* print out CPU state if enabled by debug flag */ - if (global_debug) - { - utils_log("OP: %02x F: %02x PC: %04x:%02x:%02x SP: %04x:%02x:%02x ", - op, *state.f & 0xd0, state.pc, - mmu_read_no_cyc(state.pc + 1), - mmu_read_no_cyc(state.pc + 2), state.sp, - mmu_read_no_cyc(state.sp), - mmu_read_no_cyc(state.sp + 1)); - - utils_log("A: %02x BC: %04x DE: %04x HL: %04x FF41: %02x " - "FF44: %02x ENAB: %02x INTE: %02x INTF: %02x\n", - state.a, *state.bc, - *state.de, *state.hl, - mmu_read_no_cyc(0xFF41), - mmu_read_no_cyc(0xFF44), - state.int_enable, - *int_e, *int_f); - } - - /* execute instruction by the GB Z80 version */ - z80_execute(op); - - /* if last op was Interrupt Enable (0xFB) */ - /* we need to check for INTR on next cycle */ - if (op == 0xFB) - continue; - - /* interrupts filtered by enable flags */ - uint8_t int_r = (*int_f & *int_e); - - /* check for interrupts */ - if ((state.int_enable || op == 0x76) && (int_r != 0)) - { - /* discard useless bits */ - if ((int_r & 0x1F) == 0x00) - continue; - - /* beware of instruction that doesn't move PC! */ - /* like HALT (0x76) */ - if (op == 0x76) - { - state.pc++; - - if (state.int_enable == 0) - continue; - } - - /* reset int-enable flag, it will be restored after a RETI op */ - state.int_enable = 0; - - if ((int_r & 0x01) == 0x01) - { - /* vblank interrupt triggers RST 5 */ - - /* reset flag */ - *int_f &= 0xFE; - - /* handle the interrupt */ - z80_intr(0x0040); - } - else if ((int_r & 0x02) == 0x02) - { - /* LCD Stat interrupt */ - - /* reset flag */ - *int_f &= 0xFD; - - /* handle the interrupt! */ - z80_intr(0x0048); - } - else if ((int_r & 0x04) == 0x04) - { - /* timer interrupt */ - - /* reset flag */ - *int_f &= 0xFB; - - /* handle the interrupt! */ - z80_intr(0x0050); - } - else if ((int_r & 0x08) == 0x08) - { - /* serial interrupt */ - - /* reset flag */ - *int_f &= 0xF7; - - /* handle the interrupt! */ - z80_intr(0x0058); - } - } - } -} diff --git a/waterbox/pizza/lib/gameboy.h b/waterbox/pizza/lib/gameboy.h deleted file mode 100644 index 06efa026a8..0000000000 --- a/waterbox/pizza/lib/gameboy.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __GAMEBOY_HDR__ -#define __GAMEBOY_HDR__ - -/* prototypes */ -void gameboy_init(); -void gameboy_run(uint64_t target); -void gameboy_stop(); - -#endif diff --git a/waterbox/pizza/lib/global.c b/waterbox/pizza/lib/global.c deleted file mode 100644 index e14d158dc3..0000000000 --- a/waterbox/pizza/lib/global.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include - -#include "global.h" - -char global_cart_name[256]; -char global_cgb; // if true, in CGB mode -char global_sgb; // if true, in SGB mode -char global_cpu_double_speed; -char global_debug; -char global_rumble; -char global_window; // if true, show window -int global_lagged; -void (*global_input_callback)(void); -int64_t global_currenttime; - -void global_init() -{ - global_window = 1; - global_debug = 0; - global_cgb = 0; - global_sgb = 0; - global_cpu_double_speed = 0; - global_rumble = 0; - global_lagged = 0; - global_input_callback = NULL; - sprintf(global_cart_name, "NOCARTIRDGE"); -} diff --git a/waterbox/pizza/lib/global.h b/waterbox/pizza/lib/global.h deleted file mode 100644 index 06e3cff320..0000000000 --- a/waterbox/pizza/lib/global.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __GLOBAL__ -#define __GLOBAL__ - -#include - -extern char global_window; -extern char global_debug; -extern char global_cgb; -extern char global_sgb; -// extern char global_started; -extern char global_cpu_double_speed; -extern char global_rumble; -extern char global_cart_name[256]; -extern int global_lagged; -extern void (*global_input_callback)(void); -extern int64_t global_currenttime; - -/* prototypes */ -void global_init(); - -#endif diff --git a/waterbox/pizza/lib/gpu.c b/waterbox/pizza/lib/gpu.c deleted file mode 100644 index 44859f824d..0000000000 --- a/waterbox/pizza/lib/gpu.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include - -#include "cycles.h" -#include "gameboy.h" -#include "global.h" -#include "gpu.h" -#include "interrupt.h" -#include "mmu.h" -#include "utils.h" -#include "sgb.h" - -/* Gameboy OAM 4 bytes data */ -typedef struct gpu_oam_s -{ - uint8_t y; - uint8_t x; - uint8_t pattern; - - uint8_t palette_cgb : 3; - uint8_t vram_bank : 1; - uint8_t palette : 1; - uint8_t x_flip : 1; - uint8_t y_flip : 1; - uint8_t priority : 1; - -} gpu_oam_t; - -/* Gameboy Color additional tile attributes */ -typedef struct gpu_cgb_bg_tile_s -{ - uint8_t palette : 3; - uint8_t vram_bank : 1; - uint8_t spare : 1; - uint8_t x_flip : 1; - uint8_t y_flip : 1; - uint8_t priority : 1; - -} gpu_cgb_bg_tile_t; - -/* ordered sprite list */ -typedef struct oam_list_s -{ - int idx; - struct oam_list_s *next; -} oam_list_t; - -/* pointer to interrupt flags (handy) */ -interrupts_flags_t *gpu_if; - -/* internal functions prototypes */ -void gpu_draw_sprite_line(gpu_oam_t *oam, - uint8_t sprites_size, - uint8_t line); -void gpu_draw_window_line(int tile_idx, uint8_t frame_x, - uint8_t frame_y, uint8_t line); - -/* 2 bit to 8 bit color lookup */ -// TODO: hook these up to the same color logic that that the other GB core uses -static const uint32_t gpu_color_lookup[] = {0xffffffff, 0xffaaaaaa, 0xff555555, 0xff000000}; - -/* function to call when frame is ready */ -gpu_frame_ready_cb_t gpu_frame_ready_cb; - -/* global state of GPU */ -gpu_t gpu; - -void gpu_dump_oam() -{ - /* make it point to the first OAM object */ - gpu_oam_t *oam = (gpu_oam_t *)mmu_addr(0xFE00); - - int i; - - for (i = 0; i < 40; i++) - { - if (oam[i].x != 0 && oam[i].y != 0) - printf("OAM X %d Y %d VRAM %d PATTERN %d\n", oam[i].x, oam[i].y, - oam[i].vram_bank, - oam[i].pattern); - } -} - -/* init pointers */ -void gpu_init_pointers() -{ - /* make gpu field points to the related memory area */ - gpu.lcd_ctrl = mmu_addr(0xFF40); - gpu.lcd_status = mmu_addr(0xFF41); - gpu.scroll_y = mmu_addr(0xFF42); - gpu.scroll_x = mmu_addr(0xFF43); - gpu.window_y = mmu_addr(0xFF4A); - gpu.window_x = mmu_addr(0xFF4B); - gpu.ly = mmu_addr(0xFF44); - gpu.lyc = mmu_addr(0xFF45); - gpu_if = mmu_addr(0xFF0F); -} - -/* reset */ -void gpu_reset() -{ - /* init counters */ - gpu.next = 456 << global_cpu_double_speed; - gpu.frame_counter = 0; -} - -/* init GPU states */ -void gpu_init(gpu_frame_ready_cb_t cb) -{ - /* reset gpu structure */ - bzero(&gpu, sizeof(gpu_t)); - - /* init memory pointers */ - gpu_init_pointers(); - - /* init counters */ - gpu.next = 456 << global_cpu_double_speed; - gpu.frame_counter = 0; - - /* step for normal CPU speed */ - gpu.step = 4; - - /* init palette */ - memcpy(gpu.bg_palette, gpu_color_lookup, sizeof(uint32_t) * 4); - memcpy(gpu.obj_palette_0, gpu_color_lookup, sizeof(uint32_t) * 4); - memcpy(gpu.obj_palette_1, gpu_color_lookup, sizeof(uint32_t) * 4); - - /* set callback */ - gpu_frame_ready_cb = cb; -} - -/* turn on/off lcd */ -void gpu_toggle(uint8_t state) -{ - /* from off to on */ - if (state & 0x80) - { - /* LCD turned on */ - gpu.next = cycles.cnt + (456 << global_cpu_double_speed); - *gpu.ly = 0; - (*gpu.lcd_status).mode = 0x00; - (*gpu.lcd_status).ly_coincidence = 0x00; - } - else - { - /* LCD turned off - reset stuff */ - gpu.next = cycles.cnt - 1; // + (80 << global_cpu_double_speed); - *gpu.ly = 0; - (*gpu.lcd_status).mode = 0x00; - } -} - -/* push frame on screen */ -void gpu_draw_frame() -{ - /* increase frame counter */ - gpu.frame_counter++; - - /* is it the case to push samples? */ - /*if ((global_emulation_speed == GLOBAL_EMULATION_SPEED_DOUBLE && - (gpu.frame_counter & 0x0001) != 0) || - (global_emulation_speed == GLOBAL_EMULATION_SPEED_4X && - (gpu.frame_counter & 0x0003) != 0)) - return;*/ - - if (global_sgb) - { - sgb_take_frame(gpu.frame_buffer); - } - - /* call the callback */ - if (gpu_frame_ready_cb) - (*gpu_frame_ready_cb)(); - - /* reset priority matrix */ - bzero(gpu.priority, 160 * 144); - bzero(gpu.palette_idx, 160 * 144); - - return; -} - -/* draw a single line */ -void gpu_draw_line(uint8_t line) -{ - /* avoid mess */ - if (line > 144) - return; - - /* is it the case to push samples? */ - /*if ((global_emulation_speed == GLOBAL_EMULATION_SPEED_DOUBLE && - (gpu.frame_counter & 0x0001) != 0) || - (global_emulation_speed == GLOBAL_EMULATION_SPEED_4X && - (gpu.frame_counter & 0x0003) != 0)) - return;*/ - - int i, t, y, px_start, px_drawn; - uint8_t *tiles_map, tile_subline, palette_idx, x_flip, priority; - uint16_t tiles_addr, tile_n, tile_idx, tile_line; - uint16_t tile_y; - - /* gotta show BG? Answer is always YES in case of Gameboy Color */ - if ((*gpu.lcd_ctrl).bg || global_cgb) - { - gpu_cgb_bg_tile_t *tiles_map_cgb = NULL; - uint8_t *tiles = NULL; - uint32_t *palette; - - if (global_cgb) - { - /* CGB tile map into VRAM0 */ - tiles_map = mmu_addr_vram0() + ((*gpu.lcd_ctrl).bg_tiles_map ? 0x1C00 : 0x1800); - - /* additional attribute table is into VRAM1 */ - tiles_map_cgb = mmu_addr_vram1() + ((*gpu.lcd_ctrl).bg_tiles_map ? 0x1C00 : 0x1800); - } - else - { - /* never flip */ - x_flip = 0; - - /* get tile map offset */ - tiles_map = mmu_addr((*gpu.lcd_ctrl).bg_tiles_map ? 0x9C00 : 0x9800); - - if ((*gpu.lcd_ctrl).bg_tiles) - tiles_addr = 0x8000; - else - tiles_addr = 0x9000; - - /* get absolute address of tiles area */ - tiles = mmu_addr(tiles_addr); - - /* monochrome GB uses a single BG palette */ - palette = gpu.bg_palette; - - /* always priority = 0 */ - priority = 0; - } - - /* calc tile y */ - tile_y = (*(gpu.scroll_y) + line) & 0xFF; - - /* calc first tile idx */ - tile_idx = ((tile_y >> 3) * 32) + (*(gpu.scroll_x) / 8); - - /* tile line because if we reach the end of the line, */ - /* we have to rewind to the first tile of the same line */ - tile_line = ((tile_y >> 3) * 32); - - /* calc first pixel of frame buffer of the current line */ - uint_fast16_t pos_fb = line * 160; - uint_fast16_t pos; - - /* calc tile subline */ - tile_subline = tile_y % 8; - - /* walk through different tiles */ - for (t = 0; t < 21; t++) - { - /* resolv tile data memory area */ - if ((*gpu.lcd_ctrl).bg_tiles == 0) - tile_n = (int8_t)tiles_map[tile_idx]; - else - tile_n = (tiles_map[tile_idx] & 0x00FF); - - /* if color gameboy, resolv which palette is bound */ - if (global_cgb) - { - /* extract palette index (0-31) */ - palette_idx = tiles_map_cgb[tile_idx].palette; - - /* get palette pointer to 4 (16bit) colors */ - palette = &gpu.cgb_palette_bg_rgb888[palette_idx * 4]; - - /* get priority of the tile */ - priority = tiles_map_cgb[tile_idx].priority; - - if (tiles_map_cgb[tile_idx].vram_bank) - tiles = mmu_addr_vram1() + - ((*gpu.lcd_ctrl).bg_tiles ? 0x0000 : 0x1000); - else - tiles = mmu_addr_vram0() + - ((*gpu.lcd_ctrl).bg_tiles ? 0x0000 : 0x1000); - - /* calc subline in case of flip_y */ - if (tiles_map_cgb[tile_idx].y_flip) - tile_subline = 7 - (tile_y % 8); - else - tile_subline = tile_y % 8; - - /* save x_flip */ - x_flip = tiles_map_cgb[tile_idx].x_flip; - } - - /* calc tile data pointer */ - int16_t tile_ptr = (tile_n * 16) + (tile_subline * 2); - - /* pixels are handled in a super shitty way */ - /* bit 0 of the pixel is taken from even position tile bytes */ - /* bit 1 of the pixel is taken from odd position tile bytes */ - - uint8_t pxa[8]; - uint8_t shft; - uint8_t b1 = *(tiles + tile_ptr); - uint8_t b2 = *(tiles + tile_ptr + 1); - - for (y = 0; y < 8; y++) - { - if (x_flip) - shft = (1 << (7 - y)); - else - shft = (1 << y); - - pxa[y] = ((b1 & shft) ? 1 : 0) | - ((b2 & shft) ? 2 : 0); - } - - /* particular cases for first and last tile */ - /* (could be shown just a part) */ - if (t == 0) - { - px_start = (*(gpu.scroll_x) % 8); - - px_drawn = 8 - px_start; - - /* set n pixels */ - for (i = 0; i < px_drawn; i++) - { - pos = pos_fb + (px_drawn - i - 1); - - gpu.priority[pos] = priority; - gpu.palette_idx[pos] = pxa[i]; - gpu.frame_buffer[pos] = palette[pxa[i]]; - } - } - else if (t == 20) - { - px_drawn = *(gpu.scroll_x) % 8; - - /* set n pixels */ - for (i = 0; i < px_drawn; i++) - { - pos = pos_fb + (px_drawn - i - 1); - - gpu.priority[pos] = priority; - gpu.palette_idx[pos] = pxa[i]; - gpu.frame_buffer[pos] = palette[pxa[i + (8 - px_drawn)]]; - } - } - else - { - /* set 8 pixels */ - for (i = 0; i < 8; i++) - { - pos = pos_fb + (7 - i); - - gpu.priority[pos] = priority; - gpu.palette_idx[pos] = pxa[i]; - gpu.frame_buffer[pos] = palette[pxa[i]]; - } - - px_drawn = 8; - } - - /* go to the next tile and rewind in case we reached the 32th */ - tile_idx++; - - /* don't go to the next line, just rewind */ - if (tile_idx == (tile_line + 32)) - tile_idx = tile_line; - - /* go to the next block of 8 pixels of the frame buffer */ - pos_fb += px_drawn; - } - } - - /* gotta show sprites? */ - if ((*gpu.lcd_ctrl).sprites) - { - /* make it point to the first OAM object */ - gpu_oam_t *oam = (gpu_oam_t *)mmu_addr(0xFE00); - - /* calc sprite height */ - uint8_t h = ((*gpu.lcd_ctrl).sprites_size + 1) * 8; - - int sort[40]; - int j = 0; - - /* prepare sorted list of oams */ - for (i = 0; i < 40; i++) - sort[i] = -1; - - for (i = 0; i < 40; i++) - { - /* the sprite intersects the current line? */ - if (oam[i].x != 0 && oam[i].y != 0 && - oam[i].x < 168 && oam[i].y < 160 && - line < (oam[i].y + h - 16) && - line >= (oam[i].y - 16)) - { - /* color GB uses memory position as priority criteria */ - if (global_cgb) - { - sort[j++] = i; - continue; - } - - /* find its position on sort array */ - for (j = 0; j < 40; j++) - { - if (sort[j] == -1) - { - sort[j] = i; - break; - } - - if (global_cgb) - continue; - - if ((oam[i].y < oam[sort[j]].y) || - ((oam[i].y == oam[sort[j]].y) && - (oam[i].x < oam[sort[j]].x))) - { - int z; - - for (z = 40; z > j; z--) - sort[z] = sort[z - 1]; - - sort[j] = i; - break; - } - } - } - } - - /* draw ordered sprite list */ - for (i = 0; i < 40 && sort[i] != -1; i++) - gpu_draw_sprite_line(&oam[sort[i]], - (*gpu.lcd_ctrl).sprites_size, line); - } - - /* wanna show window? */ - if (global_window && (*gpu.lcd_ctrl).window) - { - /* at least the current line is covering the window area? */ - if (line < *(gpu.window_y)) - return; - - /* TODO - reset this in a better place */ - if (line == *(gpu.window_y)) - gpu.window_skipped_lines = 0; - - int z, first_z; - uint8_t tile_pos_x, tile_pos_y; - - /* gotta draw a window? check if it is inside screen coordinates */ - if (*(gpu.window_y) >= 144 || - *(gpu.window_x) >= 160) - { - gpu.window_skipped_lines++; - return; - } - - /* calc the first interesting tile */ - first_z = ((line - *(gpu.window_y) - - gpu.window_skipped_lines) >> - 3) - << 5; - - for (z = first_z; z < first_z + 21; z++) - { - /* calc tile coordinates on frame buffer */ - tile_pos_x = ((z & 0x1F) << 3) + *(gpu.window_x) - 7; - tile_pos_y = ((z >> 5) << 3) + *(gpu.window_y) + - gpu.window_skipped_lines; - - /* gone over the current line? */ - if (tile_pos_y > line) - break; - - if (tile_pos_y < (line - 7)) - continue; - - /* gone over the screen visible X? */ - /* being between last column and first one is valid */ - if (tile_pos_x >= 160 && tile_pos_x < 248) - break; - - /* gone over the screen visible section? stop it */ - if (tile_pos_y >= 144) // || (tile_pos_x >= 160)) - break; - - /* put tile on frame buffer */ - gpu_draw_window_line(z, (uint8_t)tile_pos_x, - (uint8_t)tile_pos_y, line); - } - } -} - -/* draw a tile in x,y coordinates */ -void gpu_draw_window_line(int tile_idx, uint8_t frame_x, - uint8_t frame_y, uint8_t line) -{ - int i, p, y, pos; - int16_t tile_n; - uint8_t *tiles_map; - gpu_cgb_bg_tile_t *tiles_map_cgb = NULL; - uint8_t *tiles, x_flip; - uint32_t *palette; - - if (global_cgb) - { - /* CGB tile map into VRAM0 */ - tiles_map = mmu_addr_vram0() + ((*gpu.lcd_ctrl).window_tiles_map ? 0x1C00 : 0x1800); - - /* additional attribute table is into VRAM1 */ - tiles_map_cgb = mmu_addr_vram1() + ((*gpu.lcd_ctrl).window_tiles_map ? 0x1C00 : 0x1800); - - /* get palette index */ - uint8_t palette_idx = tiles_map_cgb[tile_idx].palette; - x_flip = tiles_map_cgb[tile_idx].x_flip; - - /* get palette pointer to 4 (16bit) colors */ - palette = &gpu.cgb_palette_bg_rgb888[palette_idx * 4]; - - /* attribute table will tell us where is the tile */ - if (tiles_map_cgb[tile_idx].vram_bank) - tiles = mmu_addr_vram1() + - ((*gpu.lcd_ctrl).bg_tiles ? 0x0000 : 0x1000); - else - tiles = mmu_addr_vram0() + - ((*gpu.lcd_ctrl).bg_tiles ? 0x0000 : 0x1000); - } - else - { - /* get tile map offset */ - tiles_map = mmu_addr((*gpu.lcd_ctrl).window_tiles_map ? 0x9C00 : 0x9800); - - /* get tile offset */ - if ((*gpu.lcd_ctrl).bg_tiles) - tiles = mmu_addr(0x8000); - else - tiles = mmu_addr(0x9000); - - /* monochrome GB uses a single BG palette */ - palette = gpu.bg_palette; - - /* never flip */ - x_flip = 0; - } - - /* obtain tile number */ - if ((*gpu.lcd_ctrl).bg_tiles == 0) - tile_n = (int8_t)tiles_map[tile_idx]; - else - tile_n = (tiles_map[tile_idx] & 0x00ff); - - /* calc vertical offset INSIDE the tile */ - p = (line - frame_y) * 2; - - /* calc frame position buffer for 4 pixels */ - uint32_t pos_fb = (line * 160); - - /* calc tile pointer */ - int16_t tile_ptr = (tile_n * 16) + p; - - /* pixels are handled in a super shitty way */ - /* bit 0 of the pixel is taken from even position tile bytes */ - /* bit 1 of the pixel is taken from odd position tile bytes */ - - uint8_t pxa[8]; - uint8_t shft; - - for (y = 0; y < 8; y++) - { - //uint8_t shft = (1 << y); - - if (x_flip) - shft = (1 << (7 - y)); - else - shft = (1 << y); - - pxa[y] = ((*(tiles + tile_ptr) & shft) ? 1 : 0) | - ((*(tiles + tile_ptr + 1) & shft) ? 2 : 0); - } - - /* set 8 pixels (full tile line) */ - for (i = 0; i < 8; i++) - { - /* over the last column? */ - uint8_t x = frame_x + (7 - i); - - if (x > 159) - continue; - - /* calc position on frame buffer */ - pos = pos_fb + x; - - /* can overwrite sprites? depends on pixel priority */ - if (gpu.priority[pos] != 0x02) - gpu.frame_buffer[pos] = palette[pxa[i]]; - } -} - -/* draw a sprite tile in x,y coordinates */ -void gpu_draw_sprite_line(gpu_oam_t *oam, uint8_t sprites_size, uint8_t line) -{ - int_fast32_t x, y, pos, fb_x, off; - uint_fast16_t p, i, j; - uint8_t sprite_bytes; - int16_t tile_ptr; - uint32_t *palette; - uint8_t *tiles; - - /* REMEMBER! position of sprites is relative to the visible screen area */ - /* ... and y is shifted by 16 pixels, x by 8 */ - y = oam->y - 16; - x = oam->x - 8; - - if (x < -7) - return; - - /* first pixel on frame buffer position */ - uint32_t tile_pos_fb = (y * 160) + x; - - /* choose palette */ - if (global_cgb) - { - uint8_t palette_idx = oam->palette_cgb; - - /* get palette pointer to 4 (16bit) colors */ - palette = &gpu.cgb_palette_oam_rgb888[palette_idx * 4]; - - /* tiles are into vram0 */ - if (oam->vram_bank) - tiles = mmu_addr_vram1(); - else - tiles = mmu_addr_vram0(); - } - else - { - /* tiles are int fixed 0x8000 address */ - tiles = mmu_addr(0x8000); - - if (oam->palette) - palette = gpu.obj_palette_1; - else - palette = gpu.obj_palette_0; - } - - /* calc sprite in byte */ - sprite_bytes = 16 * (sprites_size + 1); - - /* walk through 8x8 pixels (2bit per pixel -> 4 pixels per byte) */ - /* 1 line is 8 pixels -> 2 bytes per line */ - for (p = 0; p < sprite_bytes; p += 2) - { - uint8_t tile_y = p / 2; - - if (tile_y + y != line) - continue; - - /* calc frame position buffer for 4 pixels */ - uint32_t pos_fb = (tile_pos_fb + (tile_y * 160)) & 0xFFFF; //% 65536; - - /* calc tile pointer */ - if (oam->y_flip) - tile_ptr = (oam->pattern * 16) + (sprite_bytes - p - 2); - else - tile_ptr = (oam->pattern * 16) + p; - - /* pixels are handled in a super shitty way */ - /* bit 0 of the pixel is taken from even position tile bytes */ - /* bit 1 of the pixel is taken from odd position tile bytes */ - - uint8_t pxa[8]; - - for (j = 0; j < 8; j++) - { - uint8_t shft = (1 << j); - - pxa[j] = ((*(tiles + tile_ptr) & shft) ? 1 : 0) | - ((*(tiles + tile_ptr + 1) & shft) ? 2 : 0); - } - - /* set 8 pixels (full tile line) */ - for (i = 0; i < 8; i++) - { - if (oam->x_flip) - off = i; - else - off = 7 - i; - - /* is it on screen? */ - fb_x = x + off; - - if (fb_x < 0 || fb_x > 160) - continue; - - /* set serial position on frame buffer */ - pos = pos_fb + off; - - /* is it inside the screen? */ - if (pos >= 144 * 160 || pos < 0) - continue; - - if (global_cgb) - { - /* sprite color 0 = transparent */ - if (pxa[i] != 0x00) - { - /* flag clr = sprites always on top of bg and window */ - if ((*gpu.lcd_ctrl).bg == 0) - { - gpu.frame_buffer[pos] = palette[pxa[i]]; - gpu.priority[pos] = 0x02; - } - else - { - if (((gpu.priority[pos] == 0) && - (oam->priority == 0 || - (oam->priority == 1 && - gpu.palette_idx[pos] == 0x00))) || - (gpu.priority[pos] == 1 && - gpu.palette_idx[pos] == 0x00)) - { - gpu.frame_buffer[pos] = palette[pxa[i]]; - gpu.priority[pos] = (oam->priority ? 0x00 : 0x02); - } - } - } - } - else - { - /* push on screen pixels not set to zero (transparent) */ - /* and if the priority is set to one, overwrite just */ - /* bg pixels set to zero */ - if ((pxa[i] != 0x00) && - (oam->priority == 0 || - (oam->priority == 1 && - gpu.frame_buffer[pos] == gpu.bg_palette[0x00]))) - { - gpu.frame_buffer[pos] = palette[pxa[i]]; - gpu.priority[pos] = (oam->priority ? 0x00 : 0x02); - } - } - } - } -} - -/* update GPU internal state given CPU T-states */ -void gpu_step() -{ - char ly_changed = 0; - char mode_changed = 0; - - /* take different action based on current state */ - switch ((*gpu.lcd_status).mode) - { - /* - * during HBLANK (CPU can access VRAM) - */ - case 0: - /* handle HDMA stuff during hblank */ - cycles_hdma(); - - /* - * if current line == 143 (and it's about to turn 144) - * enter mode 01 (VBLANK) - */ - if (*gpu.ly == 143) - { - /* notify mode has changes */ - mode_changed = 1; - - (*gpu.lcd_status).mode = 0x01; - - /* mode one lasts 456 cycles */ - gpu.next = cycles.cnt + - (456 << global_cpu_double_speed); - - /* DRAW! TODO */ - /* CHECK INTERRUPTS! TODO */ - cycles_vblank(); - - /* set VBLANK interrupt flag */ - gpu_if->lcd_vblank = 1; - - /* apply gameshark patches */ - //mmu_apply_gs(); - - /* and finally push it on screen! */ - gpu_draw_frame(); - } - else - { - /* notify mode has changed */ - mode_changed = 1; - - /* enter OAM mode */ - (*gpu.lcd_status).mode = 0x02; - - /* mode 2 needs 80 cycles */ - gpu.next = cycles.cnt + - (80 << global_cpu_double_speed); - } - - /* notify mode has changed */ - ly_changed = 1; - - /* inc current line */ - (*gpu.ly)++; - - // cycles_hblank(*gpu.ly); - - break; - - /* - * during VBLANK (CPU can access VRAM) - */ - case 1: - /* notify ly has changed */ - ly_changed = 1; - - /* inc current line */ - (*gpu.ly)++; - - /* reached the bottom? */ - if ((*gpu.ly) > 153) - { - /* go back to line 0 */ - (*gpu.ly) = 0; - - /* switch to OAM mode */ - (*gpu.lcd_status).mode = 0x02; - - /* */ - gpu.next = - cycles.cnt + (80 << global_cpu_double_speed); - } - else - gpu.next = - cycles.cnt + (456 << global_cpu_double_speed); - - break; - - /* - * during OAM (LCD access FE00-FE90, so CPU cannot) - */ - case 2: - /* reset clock counter */ - gpu.next = - cycles.cnt + (172 << global_cpu_double_speed); - - /* notify mode has changed */ - mode_changed = 1; - - /* switch to VRAM mode */ - (*gpu.lcd_status).mode = 0x03; - - break; - - /* - * during VRAM (LCD access both OAM and VRAM, so CPU cannot) - */ - case 3: - /* reset clock counter */ - gpu.next = - cycles.cnt + (204 << global_cpu_double_speed); - - /* notify mode has changed */ - mode_changed = 1; - - /* go back to HBLANK mode */ - (*gpu.lcd_status).mode = 0x00; - - /* draw line */ - gpu_draw_line(*gpu.ly); - - /* notify cycles */ - // cycles_hblank(*gpu.ly); - - //printf("COLLA %d\n", *gpu.ly); - - break; - } - - /* ly changed? is it the case to trig an interrupt? */ - if (ly_changed) - { - /* check if we gotta trigger an interrupt */ - if ((*gpu.ly) == (*gpu.lyc)) - { - /* set lcd status flags indicating there's a concidence */ - (*gpu.lcd_status).ly_coincidence = 1; - - /* an interrupt is desiderable? */ - if ((*gpu.lcd_status).ir_ly_coincidence) - gpu_if->lcd_ctrl = 1; - } - else - { - /* set lcd status flags indicating there's NOT a concidence */ - (*gpu.lcd_status).ly_coincidence = 0; - } - } - - /* mode changed? is is the case to trig an interrupt? */ - if (mode_changed) - { - if ((*gpu.lcd_status).mode == 0x00 && - (*gpu.lcd_status).ir_mode_00) - gpu_if->lcd_ctrl = 1; - else if ((*gpu.lcd_status).mode == 0x01 && - (*gpu.lcd_status).ir_mode_01) - gpu_if->lcd_ctrl = 1; - else if ((*gpu.lcd_status).mode == 0x02 && - (*gpu.lcd_status).ir_mode_10) - gpu_if->lcd_ctrl = 1; - } -} - -uint8_t gpu_read_reg(uint16_t a) -{ - switch (a) - { - case 0xFF68: - - return (gpu.cgb_palette_bg_autoinc << 7 | gpu.cgb_palette_bg_idx); - - case 0xFF69: - - if ((gpu.cgb_palette_bg_idx & 0x01) == 0x00) - return gpu.cgb_palette_bg[gpu.cgb_palette_bg_idx / 2] & - 0x00ff; - else - return (gpu.cgb_palette_bg[gpu.cgb_palette_bg_idx / 2] & - 0xff00) >> - 8; - - case 0xFF6A: - - return (gpu.cgb_palette_oam_autoinc << 7 | gpu.cgb_palette_oam_idx); - - case 0xFF6B: - - if ((gpu.cgb_palette_oam_idx & 0x01) == 0x00) - return gpu.cgb_palette_oam[gpu.cgb_palette_oam_idx / 2] & - 0x00ff; - else - return (gpu.cgb_palette_oam[gpu.cgb_palette_oam_idx / 2] & - 0xff00) >> - 8; - } - - return 0x00; -} - -static uint32_t makecol(uint16_t c) -{ - // TODO: hook this up to the same color logic that the other cores use - return c >> 7 & 0xf8 | c >> 12 & 0x07 - | c << 6 & 0xf800 | c << 1 & 0x0700 - | c << 19 & 0xf80000 | c << 14 & 0x070000 - | 0xff000000; -} - -void gpu_write_reg(uint16_t a, uint8_t v) -{ - int i; - switch (a) - { - case 0xFF47: - gpu.bg_palette[0] = gpu_color_lookup[v & 0x03]; - gpu.bg_palette[1] = gpu_color_lookup[(v & 0x0c) >> 2]; - gpu.bg_palette[2] = gpu_color_lookup[(v & 0x30) >> 4]; - gpu.bg_palette[3] = gpu_color_lookup[(v & 0xc0) >> 6]; - break; - - case 0xFF48: - gpu.obj_palette_0[0] = gpu_color_lookup[v & 0x03]; - gpu.obj_palette_0[1] = gpu_color_lookup[(v & 0x0c) >> 2]; - gpu.obj_palette_0[2] = gpu_color_lookup[(v & 0x30) >> 4]; - gpu.obj_palette_0[3] = gpu_color_lookup[(v & 0xc0) >> 6]; - break; - - case 0xFF49: - gpu.obj_palette_1[0] = gpu_color_lookup[v & 0x03]; - gpu.obj_palette_1[1] = gpu_color_lookup[(v & 0x0c) >> 2]; - gpu.obj_palette_1[2] = gpu_color_lookup[(v & 0x30) >> 4]; - gpu.obj_palette_1[3] = gpu_color_lookup[(v & 0xc0) >> 6]; - break; - - case 0xFF68: - gpu.cgb_palette_bg_idx = (v & 0x3f); - gpu.cgb_palette_bg_autoinc = ((v & 0x80) == 0x80); - break; - - case 0xFF69: - i = gpu.cgb_palette_bg_idx / 2; - - if ((gpu.cgb_palette_bg_idx & 0x01) == 0x00) - { - gpu.cgb_palette_bg[i] &= 0xff00; - gpu.cgb_palette_bg[i] |= v; - } - else - { - gpu.cgb_palette_bg[i] &= 0x00ff; - gpu.cgb_palette_bg[i] |= (v << 8); - } - - gpu.cgb_palette_bg_rgb888[i] = makecol(gpu.cgb_palette_bg[i]); - - if (gpu.cgb_palette_bg_autoinc) - gpu.cgb_palette_bg_idx = (gpu.cgb_palette_bg_idx + 1) & 0x3f; - - break; - - case 0xFF6A: - gpu.cgb_palette_oam_idx = v & 0x3f; - gpu.cgb_palette_oam_autoinc = ((v & 0x80) == 0x80); - break; - - case 0xFF6B: - i = gpu.cgb_palette_oam_idx / 2; - - if ((gpu.cgb_palette_oam_idx & 0x01) == 0x00) - { - gpu.cgb_palette_oam[i] &= 0xff00; - gpu.cgb_palette_oam[i] |= v; - } - else - { - gpu.cgb_palette_oam[i] &= 0x00ff; - gpu.cgb_palette_oam[i] |= (v << 8); - } - - gpu.cgb_palette_oam_rgb888[i] = makecol(gpu.cgb_palette_oam[i]); - - if (gpu.cgb_palette_oam_autoinc) - gpu.cgb_palette_oam_idx = (gpu.cgb_palette_oam_idx + 1) & 0x3f; - - break; - } -} - -void gpu_set_speed(char speed) -{ - if (speed == 1) - gpu.step = 2; - else - gpu.step = 4; -} diff --git a/waterbox/pizza/lib/gpu.h b/waterbox/pizza/lib/gpu.h deleted file mode 100644 index 1fd8105d4e..0000000000 --- a/waterbox/pizza/lib/gpu.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __GPU_HDR__ -#define __GPU_HDR__ - -#include -#include - -/* callback function */ -typedef void (*gpu_frame_ready_cb_t) (); - -/* prototypes */ -void gpu_dump_oam(); -void gpu_init(gpu_frame_ready_cb_t cb); -void gpu_reset(); -void gpu_set_speed(char speed); -void gpu_step(); -void gpu_toggle(uint8_t state); -void gpu_write_reg(uint16_t a, uint8_t v); -uint8_t gpu_read_reg(uint16_t a); - - -/* Gameboy LCD Control - R/W accessing 0xFF40 address */ -typedef struct gpu_lcd_ctrl_s -{ - uint8_t bg:1; /* 0 = BG off, 1 = BG on */ - uint8_t sprites:1; /* ??? */ - uint8_t sprites_size:1; /* 0 = 8x8, 1 = 8x16 */ - uint8_t bg_tiles_map:1; /* 0 = 9800-9BFF, 1 = 9C00-9FFF */ - uint8_t bg_tiles:1; /* 0 = 8800-97FF, 1 = 8000-8FFF */ - uint8_t window:1; /* 0 = window off, 1 = on */ - uint8_t window_tiles_map:1; /* 0 = 9800-9BFF, 1 = 9C00-9FFF */ - uint8_t display:1; /* 0 = LCD off, 1 = LCD on */ -} gpu_lcd_ctrl_t; - -/* Gameboy LCD Status - R/W accessing 0xFF41 address */ -typedef struct gpu_lcd_status_s -{ - uint8_t mode:2; - uint8_t ly_coincidence:1; - uint8_t ir_mode_00:1; - uint8_t ir_mode_01:1; - uint8_t ir_mode_10:1; - uint8_t ir_ly_coincidence:1; - uint8_t spare:1; -} gpu_lcd_status_t; - -/* RGB color */ -typedef struct rgb_s -{ - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -} rgb_t; - -/* Gameboy GPU status */ -typedef struct gpu_s -{ - gpu_lcd_ctrl_t *lcd_ctrl; - gpu_lcd_status_t *lcd_status; - - /* scroll positions */ - uint8_t *scroll_x; - uint8_t *scroll_y; - - /* window position */ - uint8_t *window_x; - uint8_t *window_y; - - /* current scanline and it's compare values */ - uint8_t *ly; - uint8_t *lyc; - - /* clocks counter */ - uint64_t next; - - /* gpu step span */ - uint_fast32_t step; - - /* window last drawn lines */ - uint8_t window_last_ly; - uint8_t window_skipped_lines; - uint16_t spare; - - /* frame counter */ - uint_fast16_t frame_counter; - - /* BG palette */ - uint32_t bg_palette[4]; - - /* Obj palette 0/1 */ - uint32_t obj_palette_0[4]; - uint32_t obj_palette_1[4]; - - /* CGB palette for background */ - uint32_t cgb_palette_bg_rgb888[0x20]; - uint16_t cgb_palette_bg[0x20]; - uint8_t cgb_palette_bg_idx; - uint8_t cgb_palette_bg_autoinc; - - /* CGB palette for sprites */ - uint32_t cgb_palette_oam_rgb888[0x20]; - uint16_t cgb_palette_oam[0x20]; - uint8_t cgb_palette_oam_idx; - uint8_t cgb_palette_oam_autoinc; - - /* frame buffer */ - uint32_t frame_buffer[160 * 144]; - uint8_t priority[160 * 144]; - uint8_t palette_idx[160 * 144]; -} gpu_t; - -extern gpu_t gpu; - -#endif diff --git a/waterbox/pizza/lib/input.c b/waterbox/pizza/lib/input.c deleted file mode 100644 index 4dfde8d5aa..0000000000 --- a/waterbox/pizza/lib/input.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include "global.h" -#include "utils.h" - -#include - -/* button states */ -static uint8_t input_keys; - -void input_set_keys(uint8_t keys) -{ - // 7......0 - // DULRSsBA - input_keys = keys & 0xff; -} - -uint8_t input_get_keys(uint8_t line) -{ - uint8_t v = line | 0x0f; - - if ((line & 0x30) == 0x20) - { - v ^= input_keys >> 4; - } - - if ((line & 0x30) == 0x10) - { - v ^= input_keys & 0x0f; - } - - return v | 0xc0; -} diff --git a/waterbox/pizza/lib/input.h b/waterbox/pizza/lib/input.h deleted file mode 100644 index 3f678ea009..0000000000 --- a/waterbox/pizza/lib/input.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __INPUT_HDR__ -#define __INPUT_HDR__ - -/* prototypes */ -uint8_t input_get_keys(uint8_t line); -void input_set_keys(uint8_t keys); - -#endif diff --git a/waterbox/pizza/lib/interrupt.h b/waterbox/pizza/lib/interrupt.h deleted file mode 100644 index 0fbc4b0873..0000000000 --- a/waterbox/pizza/lib/interrupt.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __INTERRUPTS_HDR__ -#define __INTERRUPTS_HDR__ - -#include - -typedef struct interrupts_flags_s -{ - uint8_t lcd_vblank:1; - uint8_t lcd_ctrl:1; - uint8_t timer:1; - uint8_t serial_io:1; - uint8_t pins1013:1; - uint8_t spare:3; -} interrupts_flags_t; - -#endif \ No newline at end of file diff --git a/waterbox/pizza/lib/mmu.c b/waterbox/pizza/lib/mmu.c deleted file mode 100644 index 8a8bc9b30b..0000000000 --- a/waterbox/pizza/lib/mmu.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include "cycles.h" -#include "global.h" -#include "gpu.h" -#include "interrupt.h" -#include "input.h" -#include "mmu.h" -#include "sound.h" -#include "serial.h" -#include "timer.h" -#include "utils.h" - -#include -#include -#include -#include -#include "sgb.h" -#include - -/* GAMEBOY MEMORY AREAS - -0x0000 - 0x00FF - BIOS -0x0000 - 0x3FFF - First 16k of game ROM (permanent) -0x4000 - 0x7FFF - ROM banks (switchable) -0x8000 - 0x9FFF - Video RAM (8kb - keeps pixels data) -0xA000 - 0xBFFF - External RAM (switchable, it was on cartridge, - 8kb banks, max 32k, NON volatile) -0xC000 - 0xDFFF - Gameboy RAM -0xE000 - 0xEFFF - ???????????????? -0xFE00 - 0xFF7F - I/O -0xFF80 - 0xFFFE - Temp RAM -0xFFFF - Turn on/off interrupts - -*/ - -/* cartridge memory (max 8MB) */ -uint8_t* cart_memory; - -/* RAM memory area */ -uint8_t *ram; -uint32_t ram_sz; - -/* main struct */ -mmu_t mmu; - -/* function to call when rumble */ -mmu_rumble_cb_t mmu_rumble_cb = NULL; - - -/* return absolute memory address */ -void *mmu_addr(uint16_t a) -{ - return (void *) &mmu.memory[a]; -} - -/* return absolute memory address */ -void *mmu_addr_vram0() -{ - return (void *) &mmu.vram0; -} - -/* return absolute memory address */ -void *mmu_addr_vram1() -{ - return (void *) &mmu.vram1; -} - -/* debug purposes */ -void mmu_dump_all() -{ - int i; - - printf("#### MAIN MEMORY ####\n\n"); - - for (i=0; i<0x10000; i++) - { - if ((i & 0x0f) == 0x00) - printf("\n%04x: ", i); - printf(" %02x", mmu.memory[i]); - } - - if (global_cgb) - { - printf("#### VRAM 0 ####\n\n"); - - for (i=0; i<0x2000; i++) - { - if ((i & 0x0f) == 0x00) - printf("\n%04x: ", i); - printf(" %02x", mmu.vram0[i]); - } - - printf("#### VRAM 1 ####\n\n"); - - for (i=0; i<0x2000; i++) - { - if ((i & 0x0f) == 0x00) - printf("\n%04x: ", i); - printf(" %02x", mmu.vram1[i]); - } - } -} - -/* init (alloc) system state.memory */ -void mmu_init(uint8_t c, uint8_t rn) -{ - mmu.rom_current_bank = 0x01; - mmu.ram_current_bank = 0x00; - - /* set ram to NULL */ - ram = NULL; - - /* save carttype and qty of ROM blocks */ - mmu.carttype = c; - mmu.roms = rn; - - mmu.vram_idx = 0; - mmu.wram_current_bank = 1; - mmu.ram_current_bank = 0; - mmu.ram_external_enabled = 0; - mmu.dma_cycles = 0; - mmu.dma_address = 0; - mmu.rtc_mode = 0; - - /* reset memory */ - bzero(mmu.memory, 65536); -} - -/* init (alloc) system state.memory */ -void mmu_init_ram(uint32_t c) -{ - ram_sz = c; - - ram = malloc(c); - - bzero(ram, c); -} - -/* load data in a certain address */ -void mmu_load(uint8_t *data, size_t sz, uint16_t a) -{ - memcpy(&mmu.memory[a], data, sz); -} - -/* load full cartridge */ -void mmu_load_cartridge(const uint8_t *data, size_t sz) -{ - /* copy max 32k into working memory */ - memcpy(mmu.memory, data, 2 << 14); - - cart_memory = alloc_sealed(1 << 22); - /* copy full cartridge */ - memcpy(cart_memory, data, sz); -} - -/* move 8 bit from s to d */ -void mmu_move(uint16_t d, uint16_t s) -{ - mmu_write(d, mmu_read(s)); -} - -/* read 8 bit data from a memory addres */ -uint8_t mmu_read(uint16_t a) -{ - /* always takes 4 cycles */ - cycles_step(); - - /* 90% of the read is in the ROM area */ - if (a < 0x8000) - return mmu.memory[a]; - - /* test VRAM */ - if (a < 0xA000) - { - if (global_cgb) - { - if (mmu.vram_idx == 0) - return mmu.vram0[a - 0x8000]; - else - return mmu.vram1[a - 0x8000]; - } - - return mmu.memory[a]; - } - - if (a < 0xC000) - { - if (mmu.rtc_mode != 0x00) - { - int64_t diff = mmu.rtc_latch_time - mmu.rtc_time; - - switch (mmu.rtc_mode) - { - case 0x08: - return (diff % 60); - case 0x09: - return ((diff / 60) % 60); - case 0x0A: - return (diff / 3600) % 24; - case 0x0B: - return (diff / (3600 * 24)) & 0x00FF; - case 0x0C: - return ((diff / (3600 * 24)) & 0xFF00) >> 8; - } - } - else - return mmu.memory[a]; - } - - /* RAM */ - if (a < 0xE000) - return mmu.memory[a]; - - /* RAM mirror */ - if (a < 0xFE00) - return mmu.memory[a - 0x2000]; - - switch (a) - { - /* serial registers */ - case 0xFF01: - case 0xFF02: - return serial_read_reg(a); - - /* don't ask me why.... */ - case 0xFF44: - return (mmu.memory[0xFF44] == 153 ? 0 : mmu.memory[0xFF44]); - - /* sound registers */ - case 0xFF10 ... 0xFF3F: - return sound_read_reg(a, mmu.memory[a]); - - /* joypad reading */ - case 0xFF00: - global_lagged = 0; - if (global_input_callback) - global_input_callback(); - return global_sgb ? sgb_read_ff00(cycles.sampleclock) : input_get_keys(mmu.memory[a]); - - /* CGB HDMA transfer */ - case 0xFF55: - - if (!global_cgb) break; - - /* HDMA result */ - if (mmu.hdma_to_transfer) - return (mmu.hdma_to_transfer / 0x10 - 0x01); - else - return 0xFF; - - /* CGB color palette registers */ - case 0xFF68: - case 0xFF69: - case 0xFF6A: - case 0xFF6B: - - if (!global_cgb) break; - - /* color palettes registers */ - return gpu_read_reg(a); - - /* timer registers */ - case 0xFF04 ... 0xFF07: - return timer_read_reg(a); - - } - - return mmu.memory[a]; -} - -/* read 16 bit data from a memory addres */ -unsigned int mmu_read_16(uint16_t a) -{ - return (mmu_read(a) | (mmu_read(a + 1) << 8)); -} - -/* read 8 bit data from a memory addres (not affecting cycles) */ -uint8_t mmu_read_no_cyc(uint16_t a) -{ - if (a >= 0xE000 && a <= 0xFDFF) - return mmu.memory[a - 0x2000]; - - return mmu.memory[a]; -} - -static int has_saveram(void) -{ - return mmu.carttype == 0x03 || - mmu.carttype == 0x06 || - mmu.carttype == 0x09 || - mmu.carttype == 0x0D || - mmu.carttype == 0x0F || - mmu.carttype == 0x10 || - mmu.carttype == 0x13 || - mmu.carttype == 0x17 || - mmu.carttype == 0x1B || - mmu.carttype == 0x1E || - mmu.carttype == 0x22 || - mmu.carttype == 0xFF; -} - -int mmu_saveram_size(void) -{ - return has_saveram() ? ram_sz : 0; -} - -void mmu_restore_saveram(const uint8_t* data, int sz) -{ - if (sz == mmu_saveram_size()) - { - if (ram_sz <= 0x2000) - { - memcpy(&mmu.memory[0xa000], data, ram_sz); - } - else - { - memcpy(ram, data, ram_sz); - if (mmu.ram_external_enabled) - memcpy(&mmu.memory[0xa000], &ram[0x2000 * mmu.ram_current_bank], 0x2000); - } - } -} - -void mmu_save_saveram(uint8_t* dest, int sz) -{ - if (sz == mmu_saveram_size()) - { - if (ram_sz <= 0x2000) - { - memcpy(dest, &mmu.memory[0xa000], ram_sz); - } - else - { - memcpy(dest, ram, ram_sz); - if (mmu.ram_external_enabled) - memcpy(&dest[0x2000 * mmu.ram_current_bank], &mmu.memory[0xa000], 0x2000); - } - } -} - -void mmu_set_rumble_cb(mmu_rumble_cb_t cb) -{ - mmu_rumble_cb = cb; -} - -/* write 16 bit block on a memory address */ -void mmu_write(uint16_t a, uint8_t v) -{ - /* update cycles AFTER memory set */ - cycles_step(); - - /* color gameboy stuff */ - if (global_cgb) - { - /* VRAM write? */ - if (a >= 0x8000 && a < 0xA000) - { - if (mmu.vram_idx == 0) - mmu.vram0[a - 0x8000] = v; - else - mmu.vram1[a - 0x8000] = v; - - return; - } - else - { - /* wanna access to RTC register? */ - if (a >= 0xA000 && a <= 0xBFFF && mmu.rtc_mode != 0x00) - { - int64_t t,s1,s2,m1,m2,h1,h2,d1,d2,days; - - t = global_currenttime; - - /* extract parts in seconds from current and ref times */ - s1 = t % 60; - s2 = mmu.rtc_time % 60; - - m1 = (t - s1) % (60 * 60); - m2 = (mmu.rtc_time - s2) % (60 * 60); - - h1 = (t - m1 - s1) % (60 * 60 * 24); - h2 = (mmu.rtc_time - m2 - s2) % (60 * 60 * 24); - - d1 = t - h1 - m1 - s1; - d2 = mmu.rtc_time - h2 - m2 - s2; - - switch (mmu.rtc_mode) - { - case 0x08: - - /* remove seconds from current time */ - mmu.rtc_time -= s2; - - /* set new seconds */ - mmu.rtc_time += (s1 - v); - - return; - - case 0x09: - - /* remove seconds from current time */ - mmu.rtc_time -= m2; - - /* set new seconds */ - mmu.rtc_time += (m1 - (v * 60)); - - return; - - case 0x0A: - - /* remove seconds from current time */ - mmu.rtc_time -= h2; - - /* set new seconds */ - mmu.rtc_time += (h1 - (v * 60 * 24)); - - return; - - case 0x0B: - - days = (((d1 - d2) / - (60 * 60 * 24)) & 0xFF00) | v; - - /* remove seconds from current time */ - mmu.rtc_time -= d2; - - /* set new seconds */ - mmu.rtc_time += (d1 - (days * 60 * 60 * 24)); - - return; - - case 0x0C: - - days = (((d1 - d2) / - (60 * 60 * 24)) & 0xFEFF) | (v << 8); - - /* remove seconds from current time */ - mmu.rtc_time -= d2; - - /* set new seconds */ - mmu.rtc_time += (d1 - (days * 60 * 60 * 24)); - - return; - } - } - } - - /* switch WRAM */ - if (a == 0xFF70) - { - /* number goes from 1 to 7 */ - uint8_t new = (v & 0x07); - - if (new == 0) - new = 1; - - if (new == mmu.wram_current_bank) - return; - - /* save current bank */ - memcpy(&mmu.wram[0x1000 * mmu.wram_current_bank], - &mmu.memory[0xD000], 0x1000); - - mmu.wram_current_bank = new; - - /* move new ram bank */ - memcpy(&mmu.memory[0xD000], - &mmu.wram[0x1000 * mmu.wram_current_bank], - 0x1000); - - /* save current bank */ - mmu.memory[0xFF70] = new; - - return; - } - - if (a == 0xFF4F) - { - /* extract VRAM index from last bit */ - mmu.vram_idx = (v & 0x01); - - /* save current VRAM bank */ - mmu.memory[0xFF4F] = mmu.vram_idx; - - return; - } - } - - /* wanna write on ROM? */ - if (a < 0x8000) - { - /* return in case of ONLY ROM */ - if (mmu.carttype == 0x00) - return; - - /* TODO - MBC strategies */ - uint8_t b = mmu.rom_current_bank; - - switch (mmu.carttype) - { - /* MBC1 */ - case 0x01: - case 0x02: - case 0x03: - - if (a >= 0x2000 && a <= 0x3FFF) - { - /* reset 5 bits */ - b = mmu.rom_current_bank & 0xE0; - - /* set them with new value */ - b |= v & 0x1F; - - /* doesn't fit on max rom number? */ - if (b > (2 << mmu.roms)) - { - /* filter result to get a value < max rom number */ - b %= (2 << mmu.roms); - } - - /* 0x00 is not valid, switch it to 0x01 */ - if (b == 0x00) - b = 0x01; - } - else if (a >= 0x4000 && a <= 0x5FFF) - { - /* ROM banking? it's about 2 higher bits */ - if (mmu.banking == 0) - { - /* reset 5 bits */ - b = mmu.rom_current_bank & 0x1F; - - /* set them with new value */ - b |= (v << 5); - - /* doesn't fit on max rom number? */ - if (b > (2 << mmu.roms)) - { - /* filter result to get a value < max rom number */ - b %= (2 << mmu.roms); - } - } - else - { - if ((0x2000 * v) < ram_sz) - { - /* save current bank */ - memcpy(&ram[0x2000 * mmu.ram_current_bank], - &mmu.memory[0xA000], 0x2000); - - mmu.ram_current_bank = v; - - /* move new ram bank */ - memcpy(&mmu.memory[0xA000], - &ram[0x2000 * mmu.ram_current_bank], - 0x2000); - } - } - } - else if (a >= 0x6000 && a <= 0x7FFF) - mmu.banking = v; - - break; - - /* MBC2 */ - case 0x05: - case 0x06: - - if (a >= 0x2000 && a <= 0x3FFF) - { - /* use lower nibble to set current bank */ - b = v & 0x0f; - - /*if (b != rom_current_bank) - memcpy(&memory[0x4000], - &cart_memory[b * 0x4000], 0x4000); - - rom_current_bank = b;*/ - } - - break; - - /* MBC3 */ - case 0x10: - case 0x13: - - if (a >= 0x0000 && a <= 0x1FFF) - { - if (v == 0x0A) - { - /* already enabled? */ - if (mmu.ram_external_enabled) - return; - - /* restore external ram bank */ - memcpy(&mmu.memory[0xA000], - &ram[0x2000 * mmu.ram_current_bank], - 0x2000); - - /* set external RAM eanbled flag */ - mmu.ram_external_enabled = 1; - - return; - } - - if (v == 0x00) - { - /* already disabled? */ - if (mmu.ram_external_enabled == 0) - return; - - /* save current bank */ - memcpy(&ram[0x2000 * mmu.ram_current_bank], - &mmu.memory[0xA000], 0x2000); - - /* clear external RAM eanbled flag */ - mmu.ram_external_enabled = 0; - } - } - else if (a >= 0x2000 && a <= 0x3FFF) - { - /* set them with new value */ - b = v & 0x7F; - - /* doesn't fit on max rom number? */ - if (b > (2 << mmu.roms)) - { - /* filter result to get a value < max rom number */ - b %= (2 << mmu.roms); - } - - /* 0x00 is not valid, switch it to 0x01 */ - if (b == 0x00) - b = 0x01; - } - else if (a >= 0x4000 && a <= 0x5FFF) - { - /* 0x00 to 0x07 is referred to RAM bank */ - if (v < 0x08) - { - /* not on RTC mode anymore */ - mmu.rtc_mode = 0x00; - - if ((0x2000 * (v & 0x0f)) < ram_sz) - { - /* save current bank */ - memcpy(&ram[0x2000 * mmu.ram_current_bank], - &mmu.memory[0xA000], 0x2000); - - mmu.ram_current_bank = v & 0x0f; - - /* move new ram bank */ - memcpy(&mmu.memory[0xA000], - &ram[0x2000 * mmu.ram_current_bank], - 0x2000); - } - } - else if (v < 0x0d) - { - /* from 0x08 to 0x0C trigger RTC mode */ - mmu.rtc_mode = v; - } - - } - else if (a >= 0x6000 && a <= 0x7FFF) - { - /* latch clock data. move clock data to RTC registers */ - mmu.rtc_latch_time = global_currenttime; - } - - - break; - - /* MBC5 */ - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - - if (a >= 0x0000 && a <= 0x1FFF) - { - if (v == 0x0A) - { - /* we got external RAM? some stupid game try */ - /* to access it despite it doesn't have it */ - if (ram_sz == 0) - return; - - /* already enabled? */ - if (mmu.ram_external_enabled) - return; - - /* restore external ram bank */ - memcpy(&mmu.memory[0xA000], - &ram[0x2000 * mmu.ram_current_bank], - 0x2000); - - /* set external RAM eanbled flag */ - mmu.ram_external_enabled = 1; - - return; - } - - if (v == 0x00) - { - /* we got external RAM? some stpd game try to do shit */ - if (ram_sz == 0) - return; - - /* already disabled? */ - if (mmu.ram_external_enabled == 0) - return; - - /* save current bank */ - memcpy(&ram[0x2000 * mmu.ram_current_bank], - &mmu.memory[0xA000], 0x2000); - - /* clear external RAM eanbled flag */ - mmu.ram_external_enabled = 0; - } - } - if (a >= 0x2000 && a <= 0x2FFF) - { - /* set them with new value */ - b = (mmu.rom_current_bank & 0xFF00) | v; - - /* doesn't fit on max rom number? */ - if (b > (2 << mmu.roms)) - { - /* filter result to get a value < max rom number */ - b %= (2 << mmu.roms); - } - } - else if (a >= 0x3000 && a <= 0x3FFF) - { - /* set them with new value */ - b = (mmu.rom_current_bank & 0x00FF) | ((v & 0x01) << 8); - - /* doesn't fit on max rom number? */ - if (b > (2 << mmu.roms)) - { - /* filter result to get a value < max rom number */ - b %= (2 << mmu.roms); - } - } - else if (a >= 0x4000 && a <= 0x5FFF) - { - uint8_t mask = 0x0F; - - if (global_rumble) - { - mask = 0x07; - - if (mmu_rumble_cb) - (*mmu_rumble_cb) ((v & 0x08) ? 1 : 0); - - /* check if we want to appizz the motor */ -/* if (v & 0x08) - printf("APPIZZ MOTOR\n"); - else - printf("SPEGN MOTOR\n");*/ - } - - if ((0x2000 * (v & mask)) < ram_sz) - { - /* is externa RAM enabled? */ - if (!mmu.ram_external_enabled) - break; - - /* wanna switch on the same bank? =\ just discard it */ - if ((v & 0x0f) == mmu.ram_current_bank) - break; - - /* save current bank */ - memcpy(&ram[0x2000 * mmu.ram_current_bank], - &mmu.memory[0xA000], 0x2000); - - mmu.ram_current_bank = (v & 0x0f); - - /* move new ram bank */ - memcpy(&mmu.memory[0xA000], - &ram[0x2000 * mmu.ram_current_bank], - 0x2000); - } - } - - break; - - } - - /* need to switch? */ - if (b != mmu.rom_current_bank) - { - /* copy from cartridge rom to GB switchable bank area */ - memcpy(&mmu.memory[0x4000], &cart_memory[b * 0x4000], 0x4000); - - /* save new current bank */ - mmu.rom_current_bank = b; - } - - return; - } - - if (a >= 0xE000) - { - /* changes on sound registers? */ - if (a >= 0xFF10 && a <= 0xFF3F) - { - /* set memory */ - sound_write_reg(a, v); - - return; - } - - /* mirror area */ - if (a >= 0xE000 && a <= 0xFDFF) - { - mmu.memory[a - 0x2000] = v; - return; - } - - /* TODO - put them all */ - switch(a) - { - case 0xFF00: - sgb_write_ff00(v, cycles.sampleclock); - break; - case 0xFF01: - case 0xFF02: - serial_write_reg(a, v); - return; - case 0xFF04 ... 0xFF07: - timer_write_reg(a, v); - return; - } - - /* LCD turned on/off? */ - if (a == 0xFF40) - { - if ((v ^ mmu.memory[0xFF40]) & 0x80) - gpu_toggle(v); - } - - /* only 5 high bits are writable */ - if (a == 0xFF41) - { - mmu.memory[a] = (mmu.memory[a] & 0x07) | (v & 0xf8); - return; - } - - /* palette update */ - if ((a >= 0xFF47 && a <= 0xFF49) || - (a >= 0xFF68 && a <= 0xFF6B)) - gpu_write_reg(a, v); - - /* CGB only registers */ - if (global_cgb) - { - switch (a) - { - case 0xFF4D: - - /* wanna switch speed? */ - if (v & 0x01) - { - global_cpu_double_speed ^= 0x01; - - /* update new clock */ - // cycles_clock = 4194304 << global_double_speed; - cycles_set_speed(1); - sound_set_speed(1); - gpu_set_speed(1); - - /* save into memory i'm working at double speed */ - if (global_cpu_double_speed) - mmu.memory[a] = 0x80; - else - mmu.memory[a] = 0x00; - } - - return; - - case 0xFF52: - - /* high byte of HDMA source address */ - mmu.hdma_src_address &= 0xff00; - - /* lower 4 bits are ignored */ - mmu.hdma_src_address |= (v & 0xf0); - - break; - - case 0xFF51: - - /* low byte of HDMA source address */ - mmu.hdma_src_address &= 0x00ff; - - /* highet 3 bits are ignored (always 100 binary) */ - mmu.hdma_src_address |= (v << 8); - - break; - - case 0xFF54: - - /* high byte of HDMA source address */ - mmu.hdma_dst_address &= 0xff00; - - /* lower 4 bits are ignored */ - mmu.hdma_dst_address |= (v & 0xf0); - - break; - - case 0xFF53: - - /* low byte of HDMA source address */ - mmu.hdma_dst_address &= 0x00ff; - - /* highet 3 bits are ignored (always 100 binary) */ - mmu.hdma_dst_address |= ((v & 0x1f) | 0x80) << 8; - - break; - - case 0xFF55: - - /* wanna stop HBLANK transfer? a zero on 7th bit will do */ - if ((v & 0x80) == 0 && - mmu.hdma_transfer_mode == 0x01 && - mmu.hdma_to_transfer) - { - mmu.hdma_to_transfer = 0x00; - mmu.hdma_transfer_mode = 0x00; - - return; - } - - /* general (0) or hblank (1) ? */ - mmu.hdma_transfer_mode = ((v & 0x80) ? 1 : 0); - - /* calc how many bytes gotta be transferred */ - uint16_t to_transfer = ((v & 0x7f) + 1) * 0x10; - - /* general must be done immediately */ - if (mmu.hdma_transfer_mode == 0) - { - /* copy right now */ - if (mmu.vram_idx) - memcpy(mmu_addr_vram1() + - (mmu.hdma_dst_address - 0x8000), - &mmu.memory[mmu.hdma_src_address], - to_transfer); - else - memcpy(mmu_addr_vram0() + - (mmu.hdma_dst_address - 0x8000), - &mmu.memory[mmu.hdma_src_address], - to_transfer); - - /* reset to_transfer var */ - mmu.hdma_to_transfer = 0; - - /* move forward src and dst addresses =| */ - mmu.hdma_src_address += to_transfer; - mmu.hdma_dst_address += to_transfer; - } - else - { - mmu.hdma_to_transfer = to_transfer; - - /* check if we're already into hblank phase */ - cycles_hdma(); - } - - break; - } - } - - /* finally set memory byte with data */ - mmu.memory[a] = v; - - /* DMA access */ - if (a == 0xFF46) - { - /* calc source address */ - mmu.dma_address = v * 256; - - /* initialize counter, DMA needs 672 ticks */ - mmu.dma_next = cycles.cnt + 4; // 168 / 2; - } - } - else - mmu.memory[a] = v; -} - -/* write 16 bit block on a memory address */ -void mmu_write_16(uint16_t a, uint16_t v) -{ - mmu.memory[a] = (uint8_t) (v & 0x00ff); - mmu.memory[a + 1] = (uint8_t) (v >> 8); - - /* 16 bit write = +8 cycles */ - cycles_step(); - cycles_step(); -} - - -/* write 16 bit block on a memory address (no cycles affected) */ -void mmu_write_no_cyc(uint16_t a, uint8_t v) -{ - mmu.memory[a] = v; -} diff --git a/waterbox/pizza/lib/mmu.h b/waterbox/pizza/lib/mmu.h deleted file mode 100644 index cc36b8e0cc..0000000000 --- a/waterbox/pizza/lib/mmu.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __MMU_HDR__ -#define __MMU_HDR__ - -#include -#include - -typedef struct mmu_s -{ - /* main 64K of memory */ - uint8_t memory[65536]; - - /* vram in standby */ - uint8_t vram0[0x2000]; - uint8_t vram1[0x2000]; - - /* vram current idx */ - uint8_t vram_idx; - uint8_t spare; - uint16_t spare2; - - // cartridge RAM - uint8_t ram_external_enabled; - uint8_t ram_current_bank; - - /* cartridge type */ - uint8_t carttype; - - /* number of switchable roms */ - uint8_t roms; - - /* current ROM bank */ - uint8_t rom_current_bank; - - /* type of banking */ - uint8_t banking; - - /* working RAM (only CGB) */ - uint8_t wram[0x8000]; - - /* current WRAM bank (only CGB) */ - uint8_t wram_current_bank; - uint8_t spare3; - uint16_t spare4; - - /* DMA transfer stuff */ - uint_fast16_t dma_address; - uint_fast16_t dma_cycles; - - /* HDMA transfer stuff */ - uint16_t hdma_src_address; - uint16_t hdma_dst_address; - uint16_t hdma_to_transfer; - uint8_t hdma_transfer_mode; - uint8_t hdma_current_line; - - /* RTC stuff */ - uint8_t rtc_mode; - int64_t rtc_time; - int64_t rtc_latch_time; - - uint64_t dma_next; -} mmu_t; - -extern mmu_t mmu; - -/* callback function */ -typedef void (*mmu_rumble_cb_t)(uint8_t onoff); - -/* functions prototypes */ -void *mmu_addr(uint16_t a); -void *mmu_addr_vram0(); -void *mmu_addr_vram1(); -void mmu_dump_all(); -void mmu_init(uint8_t c, uint8_t rn); -void mmu_init_ram(uint32_t c); -void mmu_load(uint8_t *data, size_t sz, uint16_t a); -void mmu_load_cartridge(const uint8_t *data, size_t sz); -void mmu_move(uint16_t d, uint16_t s); -uint8_t mmu_read_no_cyc(uint16_t a); -uint8_t mmu_read(uint16_t a); -unsigned int mmu_read_16(uint16_t a); -int mmu_saveram_size(void); -void mmu_restore_saveram(const uint8_t *data, int sz); -void mmu_save_saveram(uint8_t *dest, int sz); -void mmu_restore_rtc(char *fn); -void mmu_save_rtc(char *fn); -void mmu_set_rumble_cb(mmu_rumble_cb_t cb); -void mmu_step(); -void mmu_write_no_cyc(uint16_t a, uint8_t v); -void mmu_write(uint16_t a, uint8_t v); -void mmu_write_16(uint16_t a, uint16_t v); - -#endif diff --git a/waterbox/pizza/lib/serial.c b/waterbox/pizza/lib/serial.c deleted file mode 100644 index 497d8a65c1..0000000000 --- a/waterbox/pizza/lib/serial.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include "cycles.h" -#include "interrupt.h" -#include "mmu.h" -#include "serial.h" -#include "utils.h" - -/* main variable */ -serial_t serial; - -/* function to call when frame is ready */ -serial_data_send_cb_t serial_data_send_cb; - -interrupts_flags_t *serial_if; - -/* second message before the first was handled? */ -uint8_t serial_second_set = 0; -uint8_t serial_second_data = 0; -uint8_t serial_second_clock = 0; -uint8_t serial_second_transfer_start = 0; -uint8_t serial_waiting_data = 0; - -void serial_verify_intr() -{ - if (serial.data_recv && serial.data_sent) - { - serial.data_recv = 0; - serial.data_sent = 0; - - /* valid couple of messages for a serial interrupt? */ - if ((serial.data_recv_clock != serial.data_sent_clock) && - serial.data_recv_transfer_start && - serial.data_sent_transfer_start) - { - /* put received data into 0xFF01 (serial.data) */ - /* and notify with an interrupt */ - serial.transfer_start = 0; - serial.data = serial.data_to_recv; - - serial_if->serial_io = 1; - } - - /* a message is already on queue? */ - if (serial_second_set) - { - serial_second_set = 0; - serial.data_recv = 1; - serial.data_to_recv = serial_second_data; - serial.data_recv_clock = serial_second_clock; - serial.data_recv_transfer_start = serial_second_transfer_start; - } - } -} - -void serial_init() -{ - /* pointer to interrupt flags */ - serial_if = mmu_addr(0xFF0F); - - /* init counters */ - serial.bits_sent = 0; - - /* start as not connected */ - serial.peer_connected = 0; -} - -void serial_write_reg(uint16_t a, uint8_t v) -{ - switch (a) - { - case 0xFF01: - serial.data = v; - return; - case 0xFF02: - serial.clock = v & 0x01; - serial.speed = (v & 0x02) ? 0x01 : 0x00; - serial.spare = ((v >> 2) & 0x1F); - serial.transfer_start = (v & 0x80) ? 0x01 : 0x00; - - /* reset? */ - serial.data_sent = 0; - break; - } - - if (serial.transfer_start && - !serial.peer_connected && - serial.clock) - { - if (serial.speed) - serial.next = cycles.cnt + 8 * 8; - else - serial.next = cycles.cnt + 256 * 8; - } -} - -uint8_t serial_read_reg(uint16_t a) -{ - uint8_t v = 0xFF; - - switch (a) - { - case 0xFF01: v = serial.data; break; - case 0xFF02: v = ((serial.clock) ? 0x01 : 0x00) | - ((serial.speed) ? 0x02 : 0x00) | - (serial.spare << 2) | - ((serial.transfer_start) ? 0x80 : 0x00); - } - - return v; -} - -void serial_recv_byte(uint8_t v, uint8_t clock, uint8_t transfer_start) -{ - /* second message during same span time? */ - if (serial.data_recv) - { - /* store it. handle it later */ - serial_second_set = 1; - serial_second_data = v; - serial_second_clock = clock; - serial_second_transfer_start = transfer_start; - return; - } - - /* received side OK */ - serial.data_recv = 1; - serial.data_recv_clock = clock; - serial.data_to_recv = v; - serial.data_recv_transfer_start = transfer_start; - - /* notify main thread in case it's waiting */ - //if (serial_waiting_data) - //pthread_cond_signal(&serial_cond); -} - -void serial_send_byte() -{ - serial.data_sent = 1; - serial.data_to_send = serial.data; - serial.data_sent_clock = serial.clock; - serial.data_sent_transfer_start = serial.transfer_start; - - if (serial_data_send_cb) - (*serial_data_send_cb) (serial.data, serial.clock, - serial.transfer_start); -} - -void serial_set_send_cb(serial_data_send_cb_t cb) -{ - serial_data_send_cb = cb; -} - -void serial_wait_data() -{ - if (serial.data_sent && serial.data_recv == 0) - { - /* wait max 3 seconds */ - //struct timespec wait; - - //wait.tv_sec = time(NULL) + 3; - - /* this is very important to avoid EINVAL return! */ - //wait.tv_nsec = 0; - - /* declare i'm waiting for data */ - //serial_waiting_data = 1; - - /* notify something has arrived */ - // pthread_cond_timedwait(&serial_cond, &serial_mutex, &wait); - - /* not waiting anymore */ - //serial_waiting_data = 0; - } -} diff --git a/waterbox/pizza/lib/serial.h b/waterbox/pizza/lib/serial.h deleted file mode 100644 index d4cfb918eb..0000000000 --- a/waterbox/pizza/lib/serial.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __SERIAL_HDR__ -#define __SERIAL_HDR__ - -#include -#include - -typedef struct serial_ctrl_s -{ - uint8_t clock; - uint8_t speed; - uint8_t spare; - uint8_t transfer_start; -} serial_ctrl_t; - -typedef struct serial_s { - - /* pointer to serial controller register */ - // serial_ctrl_t ctrl; - - uint8_t clock; - uint8_t speed; - uint8_t spare; - uint8_t transfer_start; - - /* pointer to FF01 data */ - uint8_t data; - - /* sent bits */ - uint8_t bits_sent; - - /* data to send */ - uint8_t data_to_send; - - /* peer clock */ - uint8_t data_to_recv; - - /* counter */ - uint64_t next; - - /* peer connected? */ - uint8_t peer_connected:1; - uint8_t data_sent:1; - uint8_t data_sent_clock:1; - uint8_t data_sent_transfer_start:1; - uint8_t data_recv:1; - uint8_t data_recv_clock:1; - uint8_t data_recv_transfer_start:1; - uint8_t spare10:1; - - uint_fast32_t last_send_cnt; - -} serial_t; - -extern serial_t serial; - -/* callback when receive something on serial */ -typedef void (*serial_data_send_cb_t) (uint8_t v, uint8_t clock, - uint8_t transfer_start); - -/* prototypes */ -void serial_init(); -void serial_lock(); -void serial_write_reg(uint16_t a, uint8_t v); -void serial_verify_intr(); -uint8_t serial_read_reg(uint16_t a); -void serial_recv_byte(uint8_t v, uint8_t clock, uint8_t transfer_start); -void serial_recv_clock(); -void serial_send_byte(); -void serial_set_send_cb(serial_data_send_cb_t cb); -void serial_unlock(); -void serial_wait_data(); - -#endif diff --git a/waterbox/pizza/lib/sgb.c b/waterbox/pizza/lib/sgb.c deleted file mode 100644 index 68b516babc..0000000000 --- a/waterbox/pizza/lib/sgb.c +++ /dev/null @@ -1,999 +0,0 @@ -#include "sgb.h" -#include "utils.h" -#include -#include -#include "snes_spc/spc.h" - -const uint8_t iplrom[64] = { - /*ffc0*/ 0xcd, 0xef, //mov x,#$ef - /*ffc2*/ 0xbd, //mov sp,x - /*ffc3*/ 0xe8, 0x00, //mov a,#$00 - /*ffc5*/ 0xc6, //mov (x),a - /*ffc6*/ 0x1d, //dec x - /*ffc7*/ 0xd0, 0xfc, //bne $ffc5 - /*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa - /*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb - /*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc - /*ffd2*/ 0xd0, 0xfb, //bne $ffcf - /*ffd4*/ 0x2f, 0x19, //bra $ffef - /*ffd6*/ 0xeb, 0xf4, //mov y,$f4 - /*ffd8*/ 0xd0, 0xfc, //bne $ffd6 - /*ffda*/ 0x7e, 0xf4, //cmp y,$f4 - /*ffdc*/ 0xd0, 0x0b, //bne $ffe9 - /*ffde*/ 0xe4, 0xf5, //mov a,$f5 - /*ffe0*/ 0xcb, 0xf4, //mov $f4,y - /*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a - /*ffe4*/ 0xfc, //inc y - /*ffe5*/ 0xd0, 0xf3, //bne $ffda - /*ffe7*/ 0xab, 0x01, //inc $01 - /*ffe9*/ 0x10, 0xef, //bpl $ffda - /*ffeb*/ 0x7e, 0xf4, //cmp y,$f4 - /*ffed*/ 0x10, 0xeb, //bpl $ffda - /*ffef*/ 0xba, 0xf6, //movw ya,$f6 - /*fff1*/ 0xda, 0x00, //movw $00,ya - /*fff3*/ 0xba, 0xf4, //movw ya,$f4 - /*fff5*/ 0xc4, 0xf4, //mov $f4,a - /*fff7*/ 0xdd, //mov a,y - /*fff8*/ 0x5d, //mov x,a - /*fff9*/ 0xd0, 0xdb, //bne $ffd6 - /*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x) - /*fffe*/ 0xc0, 0xff //reset vector location ($ffc0) -}; - -// the "reference clock" is tied to the GB cpu. 35112 of these should equal one GB LCD frame. -// it is always increasing and never resets/rebases - -const int refclocks_per_spc_sample = 67; // ~32055hz - -typedef struct -{ - // writes to FF00 - uint64_t last_write_time; // last write time relative to reference clock - uint8_t last_write_value; - - // recv packets - uint8_t read_index; // 0-127, index of the next bit read. if 255, not currently reading - uint8_t packet[16]; // a packet in the process of being formed - - uint8_t command[16 * 7]; // a command in the process of being formed - uint8_t expected_packets; // total number of packets expected for a command - uint8_t next_packet; // index of the next packet to be read - - // joypad reading - uint8_t joypad_index; // index of currently reading joypad - uint8_t num_joypads; // number of currently selected joypads (MLT_REQ) - uint8_t joypad_data[4]; // data for each joypad - uint8_t joypad_has_been_read; // state for advancing joypad_index. extermely weird; logic lifted from VBA and probably wrong - - // palettes - uint32_t palette[8][16]; - uint32_t auxpalette[512][4]; - - // border - uint8_t tiles[256][64]; // tiles stored in packed form - uint16_t tilemap[32 * 32]; - - // frame data - uint8_t frame[160 * 144]; // the most recent obtained full frame - uint32_t frozenframe[256 * 224]; // the most recent saved full frame (MASK_EN) - uint8_t attr[20 * 18]; // current attr map for the GB screen - uint8_t auxattr[45][20 * 18]; // 45 attr files - - // MASK_EN - uint8_t active_mask; // true if mask is currently being used - - // audio - SNES_SPC *spc; - uint64_t frame_start; // when the current audio frame started relative to reference clock - uint32_t clock_remainder; // number of reference clocks not sent to the SPC last frame - uint8_t sound_control[4]; // TODO... - - // transfers - uint32_t waiting_transfer; -#define TRN_NONE 0 -#define TRN_SOUND 1 -#define TRN_PAL 2 -#define TRN_CHR_LOW 3 -#define TRN_CHR_HI 4 -#define TRN_PCT 5 -#define TRN_ATTR 6 - int32_t transfer_countdown; // number of frames until transfer. not entirely accurate -} sgb_t; - -static sgb_t sgb; - -static uint32_t makecol(uint16_t c) -{ - return c >> 7 & 0xf8 | c >> 12 & 0x07 | c << 6 & 0xf800 | c << 1 & 0x0700 | c << 19 & 0xf80000 | c << 14 & 0x070000 | 0xff000000; -} - -static void cmd_trn(uint32_t which) -{ - if ((sgb.command[0] & 7) == 1) - { - if (sgb.waiting_transfer == TRN_NONE) - { - sgb.waiting_transfer = which; - sgb.transfer_countdown = 4; - } - else - { - utils_log("SGB: TRN already queued!\n"); - } - } - else - { - utils_log("SGB: cmd_trn bad length\n"); - } -} - -static void cmd_pal(int a, int b) -{ - if ((sgb.command[0] & 7) == 1) - { - uint32_t c[7]; - for (int i = 0; i < 7; i++) - c[i] = makecol(sgb.command[i * 2 + 1] | sgb.command[i * 2 + 2] << 8); - sgb.palette[0][0] = c[0]; - sgb.palette[1][0] = c[0]; - sgb.palette[2][0] = c[0]; - sgb.palette[3][0] = c[0]; - sgb.palette[a][1] = c[1]; - sgb.palette[a][2] = c[2]; - sgb.palette[a][3] = c[3]; - sgb.palette[b][1] = c[4]; - sgb.palette[b][2] = c[5]; - sgb.palette[b][3] = c[6]; - } - else - { - utils_log("SGB: cmd_pal bad length\n"); - } -} - -static void cmd_pal_set(void) -{ - if ((sgb.command[0] & 7) == 1) - { - int p0 = sgb.command[1] | sgb.command[2] << 8 & 0x100; - for (int i = 0; i < 4; i++) - { - int p = sgb.command[i * 2 + 1] | sgb.command[i * 2 + 2] << 8 & 0x100; - sgb.palette[i][0] = sgb.auxpalette[p0][0]; - sgb.palette[i][1] = sgb.auxpalette[p][1]; - sgb.palette[i][2] = sgb.auxpalette[p][2]; - sgb.palette[i][3] = sgb.auxpalette[p][3]; - } - if (sgb.command[9] & 0x80) // change attribute - { - int attr = sgb.command[9] & 0x3f; - if (attr >= 45) - attr = 44; - memcpy(sgb.attr, sgb.auxattr[attr], sizeof(sgb.attr)); - } - if (sgb.command[9] & 0x40) // cancel mask - { - sgb.active_mask = 0; - } - } - else - { - utils_log("SGB: cmd_pal bad length\n"); - } -} - -static void cmd_attr_blk() -{ - int nset = sgb.command[1]; - if (nset <= 0 || nset >= 19) - { - utils_log("SGB: cmd_attr_blk bad nset\n"); - return; - } - int npacket = (nset * 6 + 16) / 16; - if ((sgb.command[0] & 7) != npacket) - { - utils_log("SGB: cmd_attr_blk bad length\n"); - return; - } - for (int i = 0; i < nset; i++) - { - int ctrl = sgb.command[i * 6 + 2] & 7; - int pals = sgb.command[i * 6 + 3]; - int x1 = sgb.command[i * 6 + 4]; - int y1 = sgb.command[i * 6 + 5]; - int x2 = sgb.command[i * 6 + 6]; - int y2 = sgb.command[i * 6 + 7]; - int inside = ctrl & 1; - int line = ctrl & 2; - int outside = ctrl & 4; - int insidepal = pals & 3; - int linepal = pals >> 2 & 3; - int outsidepal = pals >> 4 & 3; - if (ctrl == 1) - { - ctrl = 3; - linepal = insidepal; - } - else if (ctrl == 4) - { - ctrl = 6; - linepal = outsidepal; - } - uint8_t *dst = sgb.attr; - for (int y = 0; y < 18; y++) - { - for (int x = 0; x < 20; x++) - { - if (outside && (x < x1 || x > x2 || y < y1 || y > y2)) - *dst = outsidepal; - else if (inside && x > x1 && x < x2 && y > y1 && y < y2) - *dst = insidepal; - else if (line) - *dst = linepal; - dst++; - } - } - } -} - -static void cmd_attr_lin() -{ - int nset = sgb.command[1]; - if (nset <= 0 || nset >= 111) - { - utils_log("SGB: cmd_attr_lin bad nset\n"); - return; - } - int npacket = (nset + 17) / 16; - if ((sgb.command[0] & 7) != npacket) - { - utils_log("SGB: cmd_attr_lin bad length\n"); - return; - } - for (int i = 0; i < nset; i++) - { - uint8_t v = sgb.command[i + 2]; - int line = v & 31; - int a = v >> 5 & 3; - if (v & 0x80) // horizontal - { - if (line > 17) - line = 17; - memset(sgb.attr + line * 20, a, 20); - } - else // vertical - { - if (line > 19) - line = 19; - uint8_t *dst = sgb.attr + line; - for (int i = 0; i < 18; i++, dst += 20) - dst[0] = a; - } - } -} - -static void cmd_attr_div() -{ - if ((sgb.command[0] & 7) == 1) - { - uint8_t v = sgb.command[1]; - - int c = v & 3; - int a = v >> 2 & 3; - int b = v >> 4 & 3; - - int pos = sgb.command[2]; - uint8_t *dst = sgb.attr; - if (v & 0x40) // horizontal - { - if (pos > 17) - pos = 17; - int i; - for (i = 0; i < pos; i++, dst += 20) - memset(dst, a, 20); - memset(dst, b, 20); - i++, dst += 20; - for (; i < 18; i++, dst += 20) - memset(dst, c, 20); - } - else // vertical - { - if (pos > 19) - pos = 19; - for (int j = 0; j < 18; j++) - { - int i; - for (i = 0; i < pos; i++) - *dst++ = a; - *dst++ = b; - i++; - for (; i < 20; i++) - *dst++ = c; - } - } - } - else - { - utils_log("SGB: cmd_attr_div bad length\n"); - } -} - -static void cmd_attr_chr() -{ - int x = sgb.command[1]; - int y = sgb.command[2]; - int n = sgb.command[3] | sgb.command[4] << 8; - if (n > 360) - { - utils_log("SGB: cmd_attr_chr bad n\n"); - return; - } - int npacket = (n + 87) / 64; - if ((sgb.command[0] & 7) != npacket) - { - utils_log("SGB: cmd_attr_chr bad length\n"); - return; - } - uint8_t *dst = sgb.attr; - if (x > 19) - x = 19; - if (y > 17) - y = 17; - int vertical = sgb.command[5]; - for (int i = 0; i < 360; i++) - { - uint8_t v = i / 4 + 6; - int a = v >> (2 * (3 - (i & 3))) & 3; - dst[y * 20 + x] = a; - if (vertical) - { - y++; - if (y == 18) - { - y = 0; - x++; - if (x == 20) - return; - } - } - else - { - x++; - if (x == 20) - { - x = 0; - y++; - if (y == 18) - return; - } - } - } -} - -static void cmd_attr_set() -{ - if ((sgb.command[0] & 7) == 1) - { - int attr = sgb.command[1] & 0x3f; - if (attr >= 45) - attr = 44; - memcpy(sgb.attr, sgb.auxattr[attr], sizeof(sgb.attr)); - if (sgb.command[1] & 0x40) - { - sgb.active_mask = 0; - } - } - else - { - utils_log("SGB: cmd_attr_set bad length\n"); - } -} - -static void cmd_mlt_req(void) -{ - if ((sgb.command[0] & 7) == 1) - { - switch (sgb.command[1] & 3) - { - case 0: - case 2: - sgb.num_joypads = 1; - sgb.joypad_index = 0; - break; - case 1: - sgb.num_joypads = 2; - sgb.joypad_index = 1; - break; - case 3: - sgb.num_joypads = 4; - sgb.joypad_index = 1; - break; - } - utils_log("SGB: %u joypads\n", sgb.num_joypads); - } - else - { - utils_log("SGB: cmd_mlt_req bad length\n"); - } -} - -static void cmd_mask(void) -{ - if ((sgb.command[0] & 7) == 1) - { - switch (sgb.command[1] & 3) - { - case 0: - sgb.active_mask = 0; - break; - case 1: - sgb.active_mask = 1; - break; - case 2: - case 3: - sgb.active_mask = 1; - for (int i = 0; i < 256 * 224; i++) - sgb.frozenframe[i] = sgb.palette[0][0]; - break; - } - } - else - { - utils_log("SGB: cmd_mask bad length\n"); - } -} - -static void cmd_sound(void) -{ - if ((sgb.command[0] & 7) == 1) - { - sgb.sound_control[1] = sgb.command[1]; - sgb.sound_control[2] = sgb.command[2]; - sgb.sound_control[3] = sgb.command[3]; - sgb.sound_control[0] = sgb.command[4]; - } - else - { - utils_log("SGB: cmd_sound bad length\n"); - } -} - -static void do_command(void) -{ - const int command = sgb.command[0] >> 3; - switch (command) - { - default: - utils_log("SGB: Unknown or unimplemented command %02xh\n", command); - break; - - case 0x00: // PAL01 - utils_log("SGB: PAL01\n"); - cmd_pal(0, 1); - break; - case 0x01: // PAL23 - utils_log("SGB: PAL23\n"); - cmd_pal(2, 3); - break; - case 0x02: // PAL03 - utils_log("SGB: PAL03\n"); - cmd_pal(0, 3); - break; - case 0x03: // PAL12 - utils_log("SGB: PAL12\n"); - cmd_pal(1, 2); - break; - case 0x0a: // PAL_SET - utils_log("SGB: PAL_SET\n"); - cmd_pal_set(); - break; - - case 0x04: // ATTR_BLK - utils_log("SGB: ATTR_BLK\n"); - cmd_attr_blk(); - break; - case 0x05: // ATTR_LIN - utils_log("SGB: ATTR_LIN\n"); - cmd_attr_lin(); - break; - case 0x06: // ATTR_DIV - utils_log("SGB: ATTR_DIV\n"); - cmd_attr_div(); - break; - case 0x07: // ATTR_CHR - utils_log("SGB: ATTR_CHR\n"); - cmd_attr_chr(); - break; - case 0x16: // ATTR_SET - utils_log("SGB: ATTR_SET\n"); - cmd_attr_set(); - break; - - case 0x17: // MASK_EN - utils_log("SGB: MASK_EN\n"); - cmd_mask(); - break; - - // unknown functions - case 0x0c: // ATRC_EN - utils_log("SGB: ATRC_EN??\n"); - break; - case 0x0d: // TEST_EN - utils_log("SGB: TEST_EN??\n"); - break; - case 0x0e: // ICON_EN - utils_log("SGB: ICON_EN??\n"); - break; - case 0x18: // OBJ_TRN - // no game used this - utils_log("SGB: OBJ_TRN??\n"); - break; - - // unimplementable functions - case 0x0f: // DATA_SND - // TODO: Is it possible for this (and DATA_TRN) to write data to - // memory areas used for the attribute file, etc? - // If so, do games do this? - utils_log("SGB: DATA_SND!! %02x:%02x%02x [%02x]\n", sgb.command[3], sgb.command[2], sgb.command[1], sgb.command[4]); - break; - case 0x10: // DATA_TRN - utils_log("SGB: DATA_TRN!!\n"); - break; - case 0x12: // JUMP - utils_log("SGB: JUMP!!\n"); - break; - - // joypad - case 0x11: // MLT_REQ - utils_log("SGB: MLT_REQ\n"); - cmd_mlt_req(); - break; - - // sound - case 0x08: // SOUND - utils_log("SGB: SOUND %02x %02x %02x %02x\n", sgb.command[1], sgb.command[2], sgb.command[3], sgb.command[4]); - cmd_sound(); - break; - - // all vram transfers - case 0x09: // SOU_TRN - utils_log("SGB: SOU_TRN\n"); - cmd_trn(TRN_SOUND); - break; - case 0x0b: // PAL_TRN - utils_log("SGB: PAL_TRN\n"); - cmd_trn(TRN_PAL); - break; - case 0x13: // CHR_TRN - utils_log("SGB: CHR_TRN\n"); - cmd_trn(sgb.command[1] & 1 ? TRN_CHR_HI : TRN_CHR_LOW); - break; - case 0x14: // PCT_TRN - utils_log("SGB: PCT_TRN\n"); - cmd_trn(TRN_PCT); - break; - case 0x15: // ATTR_TRN - utils_log("SGB: ATTR_TRN\n"); - cmd_trn(TRN_ATTR); - break; - } -} - -static void do_packet(void) -{ - memcpy(sgb.command + sgb.next_packet * 16, sgb.packet, sizeof(sgb.packet)); - sgb.next_packet++; - - if (sgb.expected_packets == 0) // not in the middle of a command - sgb.expected_packets = sgb.command[0] & 7; - - if (sgb.expected_packets == 0) // huh? - { - utils_log("SGB: zero packet command\n"); - sgb.expected_packets = 0; - sgb.next_packet = 0; - } - else if (sgb.next_packet == sgb.expected_packets) - { - do_command(); - sgb.expected_packets = 0; - sgb.next_packet = 0; - } -} - -int sgb_init(const uint8_t *spc, int length) -{ - memset(&sgb, 0, sizeof(sgb)); - sgb.read_index = 255; - sgb.num_joypads = 1; - sgb.palette[0][0] = 0xffffffff; - sgb.palette[0][1] = 0xffaaaaaa; - sgb.palette[0][2] = 0xff555555; - sgb.palette[0][3] = 0xff000000; - - sgb.spc = spc_new(); - spc_init_rom(sgb.spc, iplrom); - spc_reset(sgb.spc); - if (spc_load_spc(sgb.spc, spc, length) != NULL) - { - utils_log("SGB: Failed to load SPC\n"); - return 0; - } - - return 1; -} - -void sgb_write_ff00(uint8_t val, uint64_t time) -{ - val &= 0x30; - - //utils_log("ZZ: %02x, %llu", val, time); - const int p14_fell = (val & 0x10) < (sgb.last_write_value & 0x10); - const int p15_fell = (val & 0x20) < (sgb.last_write_value & 0x20); - const int p14_rose = (val & 0x10) > (sgb.last_write_value & 0x10); - const int p15_rose = (val & 0x20) > (sgb.last_write_value & 0x20); - - if (val == 0) // reset command processing - { - sgb.read_index = 0; - memset(sgb.packet, 0, sizeof(sgb.packet)); - } - else if (sgb.read_index != 255) // currently reading a packet - { - if (p14_fell || p15_fell) - { - if (sgb.read_index == 128) // end of packet - { - if (p14_fell) - do_packet(); - else - utils_log("SGB: Stop bit not present\n"); - sgb.read_index = 255; - } - else - { - if (p15_fell) - { - int byte = sgb.read_index >> 3; - int bit = sgb.read_index & 7; - sgb.packet[byte] |= 1 << bit; - } - sgb.read_index++; - } - } - } - else // joypad processing - { - if (val == 0x10) - sgb.joypad_has_been_read |= 2; // reading P15 - if (val == 0x20) - sgb.joypad_has_been_read |= 1; // reading P14 - if (val == 0x30 && (p14_rose || p15_rose)) - { - if (sgb.joypad_has_been_read == 7) - { - sgb.joypad_has_been_read = 0; - sgb.joypad_index++; - sgb.joypad_index &= sgb.num_joypads - 1; - //utils_log("SGB: joypad index to %u", sgb.joypad_index); - } - else - { - sgb.joypad_has_been_read &= 3; // the other line must be asserted and a read must happen before joypad_index inc?? - } - } - } - - sgb.last_write_value = val; - sgb.last_write_time = time; -} - -uint8_t sgb_read_ff00(uint64_t time) -{ - uint8_t ret = sgb.last_write_value & 0xf0 | 0xc0; - const int p14 = !(ret & 0x10); - const int p15 = !(ret & 0x20); - const int ji = sgb.joypad_index; - - // TODO: is this "reset" correct? - sgb.joypad_has_been_read |= 4; // read occured - sgb.read_index = 255; - sgb.next_packet = 0; - sgb.expected_packets = 0; - - if (!p14 && !p15) - { - //utils_log("SGB: SCAN%u", ji); - // scan id - return ret | (15 - ji); - } - else - { - // get data - const uint8_t j = sgb.joypad_data[ji]; - if (p14) - ret |= j >> 4; - if (p15) - ret |= j & 0x0f; - //utils_log("SGB: READ%u %02x", ji, ret ^ 0x0f); - return ret ^ 0x0f; - } -} - -// for each of 4 joypads: -// 7......0 -// DULRSsBA -void sgb_set_controller_data(const uint8_t *buttons) -{ - memcpy(sgb.joypad_data, buttons, sizeof(sgb.joypad_data)); -} - -static void trn_sound(const uint8_t* data) -{ - int len = data[0] | data[1] << 8; - int addr = data[2] | data[3] << 8; - utils_log("TRN_SOUND %04x %04x\n", addr, len); - uint8_t* dst = spc_get_ram(sgb.spc); - - if (len > 0xffc) - { - utils_log("TRN_SOUND src overflow\n"); - return; - } - if (len + addr >= 0x10000) - { - utils_log("TRN_SOUND dst overflow\n"); - return; - } - memcpy(dst + addr, data + 4, len); -} - -static void trn_pal(const uint8_t *data) -{ - const uint16_t *src = (const uint16_t *)data; - uint32_t *dst = sgb.auxpalette[0]; - for (int i = 0; i < 2048; i++) - dst[i] = makecol(src[i]); -} - -static void trn_attr(const uint8_t *data) -{ - uint8_t *dst = sgb.auxattr[0]; - for (int n = 0; n < 45 * 90; n++) - { - uint8_t s = *data++; - *dst++ = s >> 6 & 3; - *dst++ = s >> 4 & 3; - *dst++ = s >> 2 & 3; - *dst++ = s >> 0 & 3; - } -} - -static void trn_pct(const uint8_t *data) -{ - memcpy(sgb.tilemap, data, sizeof(sgb.tilemap)); - const uint16_t *palettes = (const uint16_t *)(data + sizeof(sgb.tilemap)); - uint32_t *dst = sgb.palette[4]; - for (int i = 0; i < 64; i++) - dst[i] = makecol(palettes[i]); -} - -static void trn_chr(const uint8_t *data, int bank) -{ - uint8_t *dst = sgb.tiles[128 * bank]; - for (int n = 0; n < 128; n++) - { - for (int y = 0; y < 8; y++) - { - int a = data[0]; - int b = data[1] << 1; - int c = data[16] << 2; - int d = data[17] << 3; - for (int x = 7; x >= 0; x--) - { - dst[x] = a & 1 | b & 2 | c & 4 | d & 8; - a >>= 1; - b >>= 1; - c >>= 1; - d >>= 1; - } - dst += 8; - data += 2; - } - data += 16; - } -} - -static void do_vram_transfer(void) -{ - uint8_t vram[4096]; - for (int tilenum = 0; tilenum < 256; tilenum++) - { - const int ty = tilenum / 20; - const int tx = tilenum % 20; - const uint8_t *src = sgb.frame + ty * 8 * 160 + tx * 8; - uint8_t *dst = vram + 16 * tilenum; - for (int j = 0; j < 8; j++) - { - uint32_t a = 0, b = 0; - a |= (src[7] & 1) << 0; - a |= (src[6] & 1) << 1; - a |= (src[5] & 1) << 2; - a |= (src[4] & 1) << 3; - a |= (src[3] & 1) << 4; - a |= (src[2] & 1) << 5; - a |= (src[1] & 1) << 6; - a |= (src[0] & 1) << 7; - - b |= (src[7] & 2) >> 1; - b |= (src[6] & 2) << 0; - b |= (src[5] & 2) << 1; - b |= (src[4] & 2) << 2; - b |= (src[3] & 2) << 3; - b |= (src[2] & 2) << 4; - b |= (src[1] & 2) << 5; - b |= (src[0] & 2) << 6; - *dst++ = a; - *dst++ = b; - src += 160; - } - } - - switch (sgb.waiting_transfer) - { - case TRN_SOUND: - trn_sound(vram); - break; - case TRN_PAL: - trn_pal(vram); - break; - case TRN_CHR_LOW: - trn_chr(vram, 0); - break; - case TRN_CHR_HI: - trn_chr(vram, 1); - break; - case TRN_PCT: - trn_pct(vram); - break; - case TRN_ATTR: - trn_attr(vram); - break; - } -} - -static void sgb_render_frame_gb(uint32_t *vbuff) -{ - const uint8_t *attr = sgb.attr; - const uint8_t *src = sgb.frame; - uint32_t *dst = vbuff + ((224 - 144) / 2 * 256 + (256 - 160) / 2); - - for (int j = 0; j < 144; j++) - { - const uint8_t *attr_line = attr + j / 8 * 20; - for (int i = 0; i < 160; i++) - { - const int attr_index = i / 8; - *dst++ = sgb.palette[attr_line[attr_index]][*src++]; - } - dst += 256 - 160; - } -} - -static void draw_tile(uint16_t entry, uint32_t *dest) -{ - const uint8_t *tile = sgb.tiles[entry & 0xff]; - const uint32_t *palette = sgb.palette[entry >> 10 & 7]; - int hflip = entry & 0x4000; - int vflip = entry & 0x8000; - int hinc, vinc; - if (hflip) - { - hinc = -1; - dest += 7; - } - else - { - hinc = 1; - } - if (vflip) - { - vinc = -256; - dest += 7 * 256; - } - else - { - vinc = 256; - } - vinc -= 8 * hinc; - for (int y = 0; y < 8; y++, dest += vinc) - { - for (int x = 0; x < 8; x++, dest += hinc) - { - int c = *tile++; - if (c) - *dest = palette[c]; - } - } -} - -static void sgb_render_border(uint32_t *vbuff) -{ - const uint16_t *tilemap = sgb.tilemap; - for (int n = 0; n < 32 * 28; n++) - { - draw_tile(*tilemap++, vbuff); - vbuff += 8; - if ((n & 31) == 31) - vbuff += 256 * 7; - } -} - -// 160x144 32bpp pixel data -// assumed to contain exact pixel values 00, 55, aa, ff -void sgb_take_frame(uint32_t *vbuff) -{ - for (int i = 0; i < 160 * 144; i++) - { - sgb.frame[i] = 3 - (vbuff[i] >> 6 & 3); // 0, 1, 2, or 3 for each pixel - } - if (sgb.waiting_transfer != TRN_NONE) - { - if (!--sgb.transfer_countdown) - { - do_vram_transfer(); - sgb.waiting_transfer = TRN_NONE; - } - } - if (!sgb.active_mask) - { - // render the frame now - for (int i = 0; i < 256 * 224; i++) - sgb.frozenframe[i] = sgb.palette[0][0]; - sgb_render_frame_gb(sgb.frozenframe); - sgb_render_border(sgb.frozenframe); - } -} - -void sgb_render_frame(uint32_t *vbuff) -{ - memcpy(vbuff, sgb.frozenframe, sizeof(sgb.frozenframe)); -} - -void sgb_render_audio(uint64_t time, void (*callback)(int16_t l, int16_t r, uint64_t time)) -{ - int16_t sound_buffer[4096]; - uint32_t diff = time - sgb.frame_start + sgb.clock_remainder; - //utils_log("%ul", diff); - - uint32_t samples = diff / refclocks_per_spc_sample; - uint32_t new_remainder = diff % refclocks_per_spc_sample; - - spc_set_output(sgb.spc, sound_buffer, sizeof(sound_buffer) / sizeof(sound_buffer[0])); - int p; - for (p = 0; p < 4; p++) - { - if (spc_read_port(sgb.spc, 0, p) != sgb.sound_control[p]) - break; - } - if (p == 4) // recived - { - sgb.sound_control[0] = 0; - sgb.sound_control[1] = 0; - sgb.sound_control[2] = 0; - } - for (p = 0; p < 4; p++) - { - spc_write_port(sgb.spc, 0, p, sgb.sound_control[p]); - } - - spc_end_frame(sgb.spc, samples * 32); - - uint64_t t = sgb.frame_start + refclocks_per_spc_sample - sgb.clock_remainder; - for (int i = 0; i < samples; i++, t += refclocks_per_spc_sample) - callback(sound_buffer[i * 2], sound_buffer[i * 2] + 1, t); - - sgb.frame_start = time; - sgb.clock_remainder = new_remainder; -} diff --git a/waterbox/pizza/lib/sgb.h b/waterbox/pizza/lib/sgb.h deleted file mode 100644 index 35e76dcad9..0000000000 --- a/waterbox/pizza/lib/sgb.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include - -// whenever a time is asked for, it is relative to a clock that ticks 35112 times -// per nominal frame on the GB lcd, starts at 0 when emulation begins, and never resets/rebases - -// write to MMIO ff00. only bits 4 and 5 are used -void sgb_write_ff00(uint8_t val, uint64_t time); - -// read from MMIO ff00. supplies data for all 8 bits -uint8_t sgb_read_ff00(uint64_t time); - -// set controller data to be used by subsequent controller reads -// buttons[0] = controller 1, buttons[3] = controller 4 -// 7......0 -// DULRSsBA -void sgb_set_controller_data(const uint8_t* buttons); - -// initialize the SGB module. pass an SPC file that results from the real S-CPU initialization, -// and the length of that file -int sgb_init(const uint8_t* spc, int length); - -// call whenever the gameboy has finished producing a video frame -// data is 32bpp 160x144 screen data. for each pixel: -//31 7 0 -// xxxxxxxx xxxxxxxx xxxxxxxx DDxxxxxx -- DD = 0, 1, 2, or 3. x = don't care -void sgb_take_frame(uint32_t* vbuff); - -// copy the finished video frame to an output buffer. pixel format is 32bpp xrgb -// can be called at any time, including right after sgb_take_frame -void sgb_render_frame(uint32_t* vbuff); - -// call to finish a frame's worth of audio. should be called once every 35112 time units (some jitter is OK) -// callback will be called with L and R sample values for various time points -// between the last time sgb_render_audio was called and now -void sgb_render_audio(uint64_t time, void(*callback)(int16_t l, int16_t r, uint64_t time)); diff --git a/waterbox/pizza/lib/snes_spc/SNES_SPC.cpp b/waterbox/pizza/lib/snes_spc/SNES_SPC.cpp deleted file mode 100644 index fb3b147ae8..0000000000 --- a/waterbox/pizza/lib/snes_spc/SNES_SPC.cpp +++ /dev/null @@ -1,564 +0,0 @@ -// Core SPC emulation: CPU, timers, SMP registers, memory - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#include - -/* Copyright (C) 2004-2007 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 */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - -// Note: SPC_MORE_ACCURACY exists mainly so I can run my validation tests, which -// do crazy echo buffer accesses. -#ifndef SPC_MORE_ACCURACY - #define SPC_MORE_ACCURACY 0 -#endif - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - - -//// Timers - -#if SPC_DISABLE_TEMPO - #define TIMER_DIV( t, n ) ((n) >> t->prescaler) - #define TIMER_MUL( t, n ) ((n) << t->prescaler) -#else - #define TIMER_DIV( t, n ) ((n) / t->prescaler) - #define TIMER_MUL( t, n ) ((n) * t->prescaler) -#endif - -SNES_SPC::Timer* SNES_SPC::run_timer_( Timer* t, rel_time_t time ) -{ - int elapsed = TIMER_DIV( t, time - t->next_time ) + 1; - t->next_time += TIMER_MUL( t, elapsed ); - - if ( t->enabled ) - { - int remain = IF_0_THEN_256( t->period - t->divider ); - int divider = t->divider + elapsed; - int over = elapsed - remain; - if ( over >= 0 ) - { - int n = over / t->period; - t->counter = (t->counter + 1 + n) & 0x0F; - divider = over - n * t->period; - } - t->divider = (uint8_t) divider; - } - return t; -} - -inline SNES_SPC::Timer* SNES_SPC::run_timer( Timer* t, rel_time_t time ) -{ - if ( time >= t->next_time ) - t = run_timer_( t, time ); - return t; -} - - -//// ROM - -void SNES_SPC::enable_rom( int enable ) -{ - if ( m.rom_enabled != enable ) - { - m.rom_enabled = enable; - if ( enable ) - memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram ); - memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size ); - // TODO: ROM can still get overwritten when DSP writes to echo buffer - } -} - - -//// DSP - -#if SPC_LESS_ACCURATE - int const max_reg_time = 29; - - signed char const SNES_SPC::reg_times_ [256] = - { - -1, 0,-11,-10,-15,-11, -2, -2, 4, 3, 14, 14, 26, 26, 14, 22, - 2, 3, 0, 1,-12, 0, 1, 1, 7, 6, 14, 14, 27, 14, 14, 23, - 5, 6, 3, 4, -1, 3, 4, 4, 10, 9, 14, 14, 26, -5, 14, 23, - 8, 9, 6, 7, 2, 6, 7, 7, 13, 12, 14, 14, 27, -4, 14, 24, - 11, 12, 9, 10, 5, 9, 10, 10, 16, 15, 14, 14, -2, -4, 14, 24, - 14, 15, 12, 13, 8, 12, 13, 13, 19, 18, 14, 14, -2,-36, 14, 24, - 17, 18, 15, 16, 11, 15, 16, 16, 22, 21, 14, 14, 28, -3, 14, 25, - 20, 21, 18, 19, 14, 18, 19, 19, 25, 24, 14, 14, 14, 29, 14, 25, - - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - }; - - #define RUN_DSP( time, offset ) \ - int count = (time) - (offset) - m.dsp_time;\ - if ( count >= 0 )\ - {\ - int clock_count = (count & ~(clocks_per_sample - 1)) + clocks_per_sample;\ - m.dsp_time += clock_count;\ - dsp.run( clock_count );\ - } -#else - #define RUN_DSP( time, offset ) \ - {\ - int count = (time) - m.dsp_time;\ - if ( !SPC_MORE_ACCURACY || count )\ - {\ - assert( count > 0 );\ - m.dsp_time = (time);\ - dsp.run( count );\ - }\ - } -#endif - -int SNES_SPC::dsp_read( rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr] & 0x7F] ); - - int result = dsp.read( REGS [r_dspaddr] & 0x7F ); - - #ifdef SPC_DSP_READ_HOOK - SPC_DSP_READ_HOOK( spc_time + time, (REGS [r_dspaddr] & 0x7F), result ); - #endif - - return result; -} - -inline void SNES_SPC::dsp_write( int data, rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr]] ) - #if SPC_LESS_ACCURATE - else if ( m.dsp_time == skipping_time ) - { - int r = REGS [r_dspaddr]; - if ( r == SPC_DSP::r_kon ) - m.skipped_kon |= data & ~dsp.read( SPC_DSP::r_koff ); - - if ( r == SPC_DSP::r_koff ) - { - m.skipped_koff |= data; - m.skipped_kon &= ~data; - } - } - #endif - - #ifdef SPC_DSP_WRITE_HOOK - SPC_DSP_WRITE_HOOK( m.spc_time + time, REGS [r_dspaddr], (uint8_t) data ); - #endif - - if ( REGS [r_dspaddr] <= 0x7F ) - dsp.write( REGS [r_dspaddr], data ); - else if ( !SPC_MORE_ACCURACY ) - dprintf( "SPC wrote to DSP register > $7F\n" ); -} - - -//// Memory access extras - -#if SPC_MORE_ACCURACY - #define MEM_ACCESS( time, addr ) \ - {\ - if ( time >= m.dsp_time )\ - {\ - RUN_DSP( time, max_reg_time );\ - }\ - } -#elif !defined (NDEBUG) - // Debug-only check for read/write within echo buffer, since this might result in - // inaccurate emulation due to the DSP not being caught up to the present. - - bool SNES_SPC::check_echo_access( int addr ) - { - if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) - { - int start = 0x100 * dsp.read( SPC_DSP::r_esa ); - int size = 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); - int end = start + (size ? size : 4); - if ( start <= addr && addr < end ) - { - if ( !m.echo_accessed ) - { - m.echo_accessed = 1; - return true; - } - } - } - return false; - } - - #define MEM_ACCESS( time, addr ) check( !check_echo_access( (uint16_t) addr ) ); -#else - #define MEM_ACCESS( time, addr ) -#endif - - -//// CPU write - -#if SPC_MORE_ACCURACY -static unsigned char const glitch_probs [3] [256] = -{ - 0xC3,0x92,0x5B,0x1C,0xD1,0x92,0x5B,0x1C,0xDB,0x9C,0x72,0x18,0xCD,0x5C,0x38,0x0B, - 0xE1,0x9C,0x74,0x17,0xCF,0x75,0x45,0x0C,0xCF,0x6E,0x4A,0x0D,0xA3,0x3A,0x1D,0x08, - 0xDB,0xA0,0x82,0x19,0xD9,0x73,0x3C,0x0E,0xCB,0x76,0x52,0x0B,0xA5,0x46,0x1D,0x09, - 0xDA,0x74,0x55,0x0F,0xA2,0x3F,0x21,0x05,0x9A,0x40,0x20,0x07,0x63,0x1E,0x10,0x01, - 0xDF,0xA9,0x85,0x1D,0xD3,0x84,0x4B,0x0E,0xCF,0x6F,0x49,0x0F,0xB3,0x48,0x1E,0x05, - 0xD8,0x77,0x52,0x12,0xB7,0x49,0x23,0x06,0xAA,0x45,0x28,0x07,0x7D,0x28,0x0F,0x07, - 0xCC,0x7B,0x4A,0x0E,0xB2,0x4F,0x24,0x07,0xAD,0x43,0x2C,0x06,0x86,0x29,0x11,0x07, - 0xAE,0x48,0x1F,0x0A,0x76,0x21,0x19,0x05,0x76,0x21,0x14,0x05,0x44,0x11,0x0B,0x01, - 0xE7,0xAD,0x96,0x23,0xDC,0x86,0x59,0x0E,0xDC,0x7C,0x5F,0x15,0xBB,0x53,0x2E,0x09, - 0xD6,0x7C,0x4A,0x16,0xBB,0x4A,0x25,0x08,0xB3,0x4F,0x28,0x0B,0x8E,0x23,0x15,0x08, - 0xCF,0x7F,0x57,0x11,0xB5,0x4A,0x23,0x0A,0xAA,0x42,0x28,0x05,0x7D,0x22,0x12,0x03, - 0xA6,0x49,0x28,0x09,0x82,0x2B,0x0D,0x04,0x7A,0x20,0x0F,0x04,0x3D,0x0F,0x09,0x03, - 0xD1,0x7C,0x4C,0x0F,0xAF,0x4E,0x21,0x09,0xA8,0x46,0x2A,0x07,0x85,0x1F,0x0E,0x07, - 0xA6,0x3F,0x26,0x07,0x7C,0x24,0x14,0x07,0x78,0x22,0x16,0x04,0x46,0x12,0x0A,0x02, - 0xA6,0x41,0x2C,0x0A,0x7E,0x28,0x11,0x05,0x73,0x1B,0x14,0x05,0x3D,0x11,0x0A,0x02, - 0x70,0x22,0x17,0x05,0x48,0x13,0x08,0x03,0x3C,0x07,0x0D,0x07,0x26,0x07,0x06,0x01, - - 0xE0,0x9F,0xDA,0x7C,0x4F,0x18,0x28,0x0D,0xE9,0x9F,0xDA,0x7C,0x4F,0x18,0x1F,0x07, - 0xE6,0x97,0xD8,0x72,0x64,0x13,0x26,0x09,0xDC,0x67,0xA9,0x38,0x21,0x07,0x15,0x06, - 0xE9,0x91,0xD2,0x6B,0x63,0x14,0x2B,0x0E,0xD6,0x61,0xB7,0x41,0x2B,0x0E,0x10,0x09, - 0xCF,0x59,0xB0,0x2F,0x35,0x08,0x0F,0x07,0xB6,0x30,0x7A,0x21,0x17,0x07,0x09,0x03, - 0xE7,0xA3,0xE5,0x6B,0x65,0x1F,0x34,0x09,0xD8,0x6B,0xBE,0x45,0x27,0x07,0x10,0x07, - 0xDA,0x54,0xB1,0x39,0x2E,0x0E,0x17,0x08,0xA9,0x3C,0x86,0x22,0x16,0x06,0x07,0x03, - 0xD4,0x51,0xBC,0x3D,0x38,0x0A,0x13,0x06,0xB2,0x37,0x79,0x1C,0x17,0x05,0x0E,0x06, - 0xA7,0x31,0x74,0x1C,0x11,0x06,0x0C,0x02,0x6D,0x1A,0x38,0x10,0x0B,0x05,0x06,0x03, - 0xEB,0x9A,0xE1,0x7A,0x6F,0x13,0x34,0x0E,0xE6,0x75,0xC5,0x45,0x3E,0x0B,0x1A,0x05, - 0xD8,0x63,0xC1,0x40,0x3C,0x1B,0x19,0x06,0xB3,0x42,0x83,0x29,0x18,0x0A,0x08,0x04, - 0xD4,0x58,0xBA,0x43,0x3F,0x0A,0x1F,0x09,0xB1,0x33,0x8A,0x1F,0x1F,0x06,0x0D,0x05, - 0xAF,0x3C,0x7A,0x1F,0x16,0x08,0x0A,0x01,0x72,0x1B,0x52,0x0D,0x0B,0x09,0x06,0x01, - 0xCF,0x63,0xB7,0x47,0x40,0x10,0x14,0x06,0xC0,0x41,0x96,0x20,0x1C,0x09,0x10,0x05, - 0xA6,0x35,0x82,0x1A,0x20,0x0C,0x0E,0x04,0x80,0x1F,0x53,0x0F,0x0B,0x02,0x06,0x01, - 0xA6,0x31,0x81,0x1B,0x1D,0x01,0x08,0x08,0x7B,0x20,0x4D,0x19,0x0E,0x05,0x07,0x03, - 0x6B,0x17,0x49,0x07,0x0E,0x03,0x0A,0x05,0x37,0x0B,0x1F,0x06,0x04,0x02,0x07,0x01, - - 0xF0,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x47,0x1E,0x6E,0x1B,0x32,0x0A, - 0xF0,0xD6,0xEA,0xA4,0xED,0xC4,0xDE,0x82,0x98,0x1F,0x50,0x13,0x52,0x15,0x2A,0x0A, - 0xF1,0xD1,0xEB,0xA2,0xEB,0xB7,0xD8,0x69,0xA2,0x1F,0x5B,0x18,0x55,0x18,0x2C,0x0A, - 0xED,0xB5,0xDE,0x7E,0xE6,0x85,0xD3,0x59,0x59,0x0F,0x2C,0x09,0x24,0x07,0x15,0x09, - 0xF1,0xD6,0xEA,0xA0,0xEC,0xBB,0xDA,0x77,0xA9,0x23,0x58,0x14,0x5D,0x12,0x2F,0x09, - 0xF1,0xC1,0xE3,0x86,0xE4,0x87,0xD2,0x4E,0x68,0x15,0x26,0x0B,0x27,0x09,0x15,0x02, - 0xEE,0xA6,0xE0,0x5C,0xE0,0x77,0xC3,0x41,0x67,0x1B,0x3C,0x07,0x2A,0x06,0x19,0x07, - 0xE4,0x75,0xC6,0x43,0xCC,0x50,0x95,0x23,0x35,0x09,0x14,0x04,0x15,0x05,0x0B,0x04, - 0xEE,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x56,0x14,0x5A,0x12,0x26,0x0A, - 0xEE,0xBB,0xE7,0x7E,0xE9,0x8D,0xCB,0x49,0x67,0x11,0x34,0x07,0x2B,0x0B,0x14,0x07, - 0xED,0xA7,0xE5,0x76,0xE3,0x7E,0xC4,0x4B,0x77,0x14,0x34,0x08,0x27,0x07,0x14,0x04, - 0xE7,0x8B,0xD2,0x4C,0xCA,0x56,0x9E,0x31,0x36,0x0C,0x11,0x07,0x14,0x04,0x0A,0x02, - 0xF0,0x9B,0xEA,0x6F,0xE5,0x81,0xC4,0x43,0x74,0x10,0x30,0x0B,0x2D,0x08,0x1B,0x06, - 0xE6,0x83,0xCA,0x48,0xD9,0x56,0xA7,0x23,0x3B,0x09,0x12,0x09,0x15,0x07,0x0A,0x03, - 0xE5,0x5F,0xCB,0x3C,0xCF,0x48,0x91,0x22,0x31,0x0A,0x17,0x08,0x15,0x04,0x0D,0x02, - 0xD1,0x43,0x91,0x20,0xA9,0x2D,0x54,0x12,0x17,0x07,0x09,0x02,0x0C,0x04,0x05,0x03, -}; -#endif - -// divided into multiple functions to keep rarely-used functionality separate -// so often-used functionality can be optimized better by compiler - -// If write isn't preceded by read, data has this added to it -int const no_read_before_write = 0x2000; - -void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, int addr ) -{ - switch ( addr ) - { - case r_t0target: - case r_t1target: - case r_t2target: { - Timer* t = &m.timers [addr - r_t0target]; - int period = IF_0_THEN_256( data ); - if ( t->period != period ) - { - t = run_timer( t, time ); - #if SPC_MORE_ACCURACY - // Insane behavior when target is written just after counter is - // clocked and counter matches new period and new period isn't 1, 2, 4, or 8 - if ( t->divider == (period & 0xFF) && - t->next_time == time + TIMER_MUL( t, 1 ) && - ((period - 1) | ~0x0F) & period ) - { - //dprintf( "SPC pathological timer target write\n" ); - - // If the period is 3, 5, or 9, there's a probability this behavior won't occur, - // based on the previous period - int prob = 0xFF; - int old_period = t->period & 0xFF; - if ( period == 3 ) prob = glitch_probs [0] [old_period]; - if ( period == 5 ) prob = glitch_probs [1] [old_period]; - if ( period == 9 ) prob = glitch_probs [2] [old_period]; - - // The glitch suppresses incrementing of one of the counter bits, based on - // the lowest set bit in the new period - int b = 1; - while ( !(period & b) ) - b <<= 1; - - if ( (rand() >> 4 & 0xFF) <= prob ) - t->divider = (t->divider - b) & 0xFF; - } - #endif - t->period = period; - } - break; - } - - case r_t0out: - case r_t1out: - case r_t2out: - if ( !SPC_MORE_ACCURACY ) - dprintf( "SPC wrote to counter %d\n", (int) addr - r_t0out ); - - if ( data < no_read_before_write / 2 ) - run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0; - break; - - // Registers that act like RAM - case 0x8: - case 0x9: - REGS_IN [addr] = (uint8_t) data; - break; - - case r_test: - if ( (uint8_t) data != 0x0A ) - dprintf( "SPC wrote to test register\n" ); - break; - - case r_control: - // port clears - if ( data & 0x10 ) - { - REGS_IN [r_cpuio0] = 0; - REGS_IN [r_cpuio1] = 0; - } - if ( data & 0x20 ) - { - REGS_IN [r_cpuio2] = 0; - REGS_IN [r_cpuio3] = 0; - } - - // timers - { - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - int enabled = data >> i & 1; - if ( t->enabled != enabled ) - { - t = run_timer( t, time ); - t->enabled = enabled; - if ( enabled ) - { - t->divider = 0; - t->counter = 0; - } - } - } - } - enable_rom( data & 0x80 ); - break; - } -} - -void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr ) -{ - if ( addr == r_dspdata ) // 99% - dsp_write( data, time ); - else - cpu_write_smp_reg_( data, time, addr ); -} - -void SNES_SPC::cpu_write_high( int data, int i, rel_time_t time ) -{ - if ( i < rom_size ) - { - m.hi_ram [i] = (uint8_t) data; - if ( m.rom_enabled ) - RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM - } - else - { - assert( RAM [i + rom_addr] == (uint8_t) data ); - RAM [i + rom_addr] = cpu_pad_fill; // restore overwritten padding - cpu_write( data, i + rom_addr - 0x10000, time ); - } -} - -int const bits_in_int = CHAR_BIT * sizeof (int); - -void SNES_SPC::cpu_write( int data, int addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - RAM [addr] = (uint8_t) data; - int reg = addr - 0xF0; - if ( reg >= 0 ) // 64% - { - // $F0-$FF - if ( reg < reg_count ) // 87% - { - REGS [reg] = (uint8_t) data; - - // Ports - #ifdef SPC_PORT_WRITE_HOOK - if ( (unsigned) (reg - r_cpuio0) < port_count ) - SPC_PORT_WRITE_HOOK( m.spc_time + time, (reg - r_cpuio0), - (uint8_t) data, ®S [r_cpuio0] ); - #endif - - // Registers other than $F2 and $F4-$F7 - //if ( reg != 2 && reg != 4 && reg != 5 && reg != 6 && reg != 7 ) - // TODO: this is a bit on the fragile side - if ( ((~0x2F00 << (bits_in_int - 16)) << reg) < 0 ) // 36% - cpu_write_smp_reg( data, time, reg ); - } - // High mem/address wrap-around - else - { - reg -= rom_addr - 0xF0; - if ( reg >= 0 ) // 1% in IPL ROM area or address wrapped around - cpu_write_high( data, reg, time ); - } - } -} - - -//// CPU read - -inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time ) -{ - int result = REGS_IN [reg]; - reg -= r_dspaddr; - // DSP addr and data - if ( (unsigned) reg <= 1 ) // 4% 0xF2 and 0xF3 - { - result = REGS [r_dspaddr]; - if ( (unsigned) reg == 1 ) - result = dsp_read( time ); // 0xF3 - } - return result; -} - -int SNES_SPC::cpu_read( int addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - int result = RAM [addr]; - int reg = addr - 0xF0; - if ( reg >= 0 ) // 40% - { - reg -= 0x10; - if ( (unsigned) reg >= 0xFF00 ) // 21% - { - reg += 0x10 - r_t0out; - - // Timers - if ( (unsigned) reg < timer_count ) // 90% - { - Timer* t = &m.timers [reg]; - if ( time >= t->next_time ) - t = run_timer_( t, time ); - result = t->counter; - t->counter = 0; - } - // Other registers - else if ( reg < 0 ) // 10% - { - result = cpu_read_smp_reg( reg + r_t0out, time ); - } - else // 1% - { - assert( reg + (r_t0out + 0xF0 - 0x10000) < 0x100 ); - result = cpu_read( reg + (r_t0out + 0xF0 - 0x10000), time ); - } - } - } - - return result; -} - - -//// Run - -// Prefix and suffix for CPU emulator function -#define SPC_CPU_RUN_FUNC \ -BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\ -{\ - rel_time_t rel_time = m.spc_time - end_time;\ - assert( rel_time <= 0 );\ - m.spc_time = end_time;\ - m.dsp_time += rel_time;\ - m.timers [0].next_time += rel_time;\ - m.timers [1].next_time += rel_time;\ - m.timers [2].next_time += rel_time; - -#define SPC_CPU_RUN_FUNC_END \ - m.spc_time += rel_time;\ - m.dsp_time -= rel_time;\ - m.timers [0].next_time -= rel_time;\ - m.timers [1].next_time -= rel_time;\ - m.timers [2].next_time -= rel_time;\ - assert( m.spc_time <= end_time );\ - return ®S [r_cpuio0];\ -} - -int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks - -void SNES_SPC::end_frame( time_t end_time ) -{ - // Catch CPU up to as close to end as possible. If final instruction - // would exceed end, does NOT execute it and leaves m.spc_time < end. - if ( end_time > m.spc_time ) - run_until_( end_time ); - - m.spc_time -= end_time; - m.extra_clocks += end_time; - - // Greatest number of clocks early that emulation can stop early due to - // not being able to execute current instruction without going over - // allowed time. - assert( -cpu_lag_max <= m.spc_time && m.spc_time <= 0 ); - - // Catch timers up to CPU - for ( int i = 0; i < timer_count; i++ ) - run_timer( &m.timers [i], 0 ); - - // Catch DSP up to CPU - if ( m.dsp_time < 0 ) - { - RUN_DSP( 0, max_reg_time ); - } - - // Save any extra samples beyond what should be generated - if ( m.buf_begin ) - save_extra(); -} - -// Inclusion here allows static memory access functions and better optimization -#include "SPC_CPU.h" diff --git a/waterbox/pizza/lib/snes_spc/SNES_SPC.h b/waterbox/pizza/lib/snes_spc/SNES_SPC.h deleted file mode 100644 index fb1ad18a45..0000000000 --- a/waterbox/pizza/lib/snes_spc/SNES_SPC.h +++ /dev/null @@ -1,284 +0,0 @@ -// SNES SPC-700 APU emulator - -// snes_spc 0.9.0 -#ifndef SNES_SPC_H -#define SNES_SPC_H - -#include "SPC_DSP.h" -#include "blargg_endian.h" -#include - -struct SNES_SPC { -public: - typedef BOOST::uint8_t uint8_t; - - // Must be called once before using - blargg_err_t init(); - - // Sample pairs generated per second - enum { sample_rate = 32000 }; - -// Emulator use - - // Sets IPL ROM data. Library does not include ROM data. Most SPC music files - // don't need ROM, but a full emulator must provide this. - enum { rom_size = 0x40 }; - void init_rom( uint8_t const rom [rom_size] ); - - // Sets destination for output samples - typedef short sample_t; - void set_output( sample_t* out, int out_size ); - - // Number of samples written to output since last set - int sample_count() const; - - // Resets SPC to power-on state. This resets your output buffer, so you must - // call set_output() after this. - void reset(); - - // Emulates pressing reset switch on SNES. This resets your output buffer, so - // you must call set_output() after this. - void soft_reset(); - - // 1024000 SPC clocks per second, sample pair every 32 clocks - typedef int time_t; - enum { clock_rate = 1024000 }; - enum { clocks_per_sample = 32 }; - - // Emulated port read/write at specified time - enum { port_count = 4 }; - int read_port ( time_t, int port ); - void write_port( time_t, int port, int data ); - - // Runs SPC to end_time and starts a new time frame at 0 - void end_frame( time_t end_time ); - - uint8_t* get_ram(); - -// Sound control - - // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). - // Reduces emulation accuracy. - enum { voice_count = 8 }; - void mute_voices( int mask ); - - // If true, prevents channels and global volumes from being phase-negated. - // Only supported by fast DSP. - void disable_surround( bool disable = true ); - - // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. - enum { tempo_unit = 0x100 }; - void set_tempo( int ); - -// SPC music files - - // Loads SPC data into emulator - enum { spc_min_file_size = 0x10180 }; - enum { spc_file_size = 0x10200 }; - blargg_err_t load_spc( void const* in, long size ); - - // Clears echo region. Useful after loading an SPC as many have garbage in echo. - void clear_echo(); - - // Plays for count samples and write samples to out. Discards samples if out - // is NULL. Count must be a multiple of 2 since output is stereo. - blargg_err_t play( int count, sample_t* out ); - - // Skips count samples. Several times faster than play() when using fast DSP. - blargg_err_t skip( int count ); - -// State save/load (only available with accurate DSP) - -#if !SPC_NO_COPY_STATE_FUNCS - // Saves/loads state - enum { state_size = 67 * 1024L }; // maximum space needed when saving - typedef SPC_DSP::copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); - - // Writes minimal header to spc_out - static void init_header( void* spc_out ); - - // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. - // Does not set up SPC header; use init_header() for that. - void save_spc( void* spc_out ); - - // Returns true if new key-on events occurred since last check. Useful for - // trimming silence while saving an SPC. - bool check_kon(); -#endif - -public: - BLARGG_DISABLE_NOTHROW - - typedef BOOST::uint16_t uint16_t; - - // Time relative to m_spc_time. Speeds up code a bit by eliminating need to - // constantly add m_spc_time to time from CPU. CPU uses time that ends at - // 0 to eliminate reloading end time every instruction. It pays off. - typedef int rel_time_t; - - struct Timer - { - rel_time_t next_time; // time of next event - int prescaler; - int period; - int divider; - int enabled; - int counter; - }; - enum { reg_count = 0x10 }; - enum { timer_count = 3 }; - enum { extra_size = SPC_DSP::extra_size }; - - enum { signature_size = 35 }; - -private: - SPC_DSP dsp; - - #if SPC_LESS_ACCURATE - static signed char const reg_times_ [256]; - signed char reg_times [256]; - #endif - - struct state_t - { - Timer timers [timer_count]; - - uint8_t smp_regs [2] [reg_count]; - - struct - { - int pc; - int a; - int x; - int y; - int psw; - int sp; - } cpu_regs; - - rel_time_t dsp_time; - time_t spc_time; - bool echo_accessed; - - int tempo; - int skipped_kon; - int skipped_koff; - const char* cpu_error; - - int extra_clocks; - sample_t* buf_begin; - sample_t const* buf_end; - sample_t* extra_pos; - sample_t extra_buf [extra_size]; - - int rom_enabled; - uint8_t rom [rom_size]; - uint8_t hi_ram [rom_size]; - - unsigned char cycle_table [256]; - - struct - { - // padding to neutralize address overflow - union { - uint8_t padding1 [0x100]; - uint16_t align; // makes compiler align data for 16-bit access - } padding1 [1]; - uint8_t ram [0x10000]; - uint8_t padding2 [0x100]; - } ram; - }; - state_t m; - - enum { rom_addr = 0xFFC0 }; - - enum { skipping_time = 127 }; - - // Value that padding should be filled with - enum { cpu_pad_fill = 0xFF }; - - enum { - r_test = 0x0, r_control = 0x1, - r_dspaddr = 0x2, r_dspdata = 0x3, - r_cpuio0 = 0x4, r_cpuio1 = 0x5, - r_cpuio2 = 0x6, r_cpuio3 = 0x7, - r_f8 = 0x8, r_f9 = 0x9, - r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC, - r_t0out = 0xD, r_t1out = 0xE, r_t2out = 0xF - }; - - void timers_loaded(); - void enable_rom( int enable ); - void reset_buf(); - void save_extra(); - void load_regs( uint8_t const in [reg_count] ); - void ram_loaded(); - void regs_loaded(); - void reset_time_regs(); - void reset_common( int timer_counter_init ); - - Timer* run_timer_ ( Timer* t, rel_time_t ); - Timer* run_timer ( Timer* t, rel_time_t ); - int dsp_read ( rel_time_t ); - void dsp_write ( int data, rel_time_t ); - void cpu_write_smp_reg_( int data, rel_time_t, int addr ); - void cpu_write_smp_reg ( int data, rel_time_t, int addr ); - void cpu_write_high ( int data, int i, rel_time_t ); - void cpu_write ( int data, int addr, rel_time_t ); - int cpu_read_smp_reg ( int i, rel_time_t ); - int cpu_read ( int addr, rel_time_t ); - unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t ); - - bool check_echo_access ( int addr ); - uint8_t* run_until_( time_t end_time ); - - struct spc_file_t - { - char signature [signature_size]; - uint8_t has_id666; - uint8_t version; - uint8_t pcl, pch; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t psw; - uint8_t sp; - char text [212]; - uint8_t ram [0x10000]; - uint8_t dsp [128]; - uint8_t unused [0x40]; - uint8_t ipl_rom [0x40]; - }; - - static char const signature [signature_size + 1]; - - void save_regs( uint8_t out [reg_count] ); -}; - -#include - -inline uint8_t* SNES_SPC::get_ram() { return m.ram.ram; } - -inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; } - -inline int SNES_SPC::read_port( time_t t, int port ) -{ - assert( (unsigned) port < port_count ); - return run_until_( t ) [port]; -} - -inline void SNES_SPC::write_port( time_t t, int port, int data ) -{ - assert( (unsigned) port < port_count ); - run_until_( t ) [0x10 + port] = data; -} - -inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); } - -inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); } - -#if !SPC_NO_COPY_STATE_FUNCS -inline bool SNES_SPC::check_kon() { return dsp.check_kon(); } -#endif - -#endif diff --git a/waterbox/pizza/lib/snes_spc/SNES_SPC_misc.cpp b/waterbox/pizza/lib/snes_spc/SNES_SPC_misc.cpp deleted file mode 100644 index 87288ab8ee..0000000000 --- a/waterbox/pizza/lib/snes_spc/SNES_SPC_misc.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// SPC emulation support: init, sample buffering, reset, SPC loading - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#include - -/* Copyright (C) 2004-2007 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 */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - - -//// Init - -blargg_err_t SNES_SPC::init() -{ - memset( &m, 0, sizeof m ); - dsp.init( RAM ); - - m.tempo = tempo_unit; - - // Most SPC music doesn't need ROM, and almost all the rest only rely - // on these two bytes - m.rom [0x3E] = 0xFF; - m.rom [0x3F] = 0xC0; - - static unsigned char const cycle_table [128] = - {// 01 23 45 67 89 AB CD EF - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x68, // 0 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x46, // 1 - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x74, // 2 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x38, // 3 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x66, // 4 - 0x48,0x47,0x45,0x56,0x55,0x45,0x22,0x43, // 5 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x75, // 6 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x36, // 7 - 0x28,0x47,0x34,0x36,0x26,0x54,0x52,0x45, // 8 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0xC5, // 9 - 0x38,0x47,0x34,0x36,0x26,0x44,0x52,0x44, // A - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x34, // B - 0x38,0x47,0x45,0x47,0x25,0x64,0x52,0x49, // C - 0x48,0x47,0x56,0x67,0x45,0x55,0x22,0x83, // D - 0x28,0x47,0x34,0x36,0x24,0x53,0x43,0x40, // E - 0x48,0x47,0x45,0x56,0x34,0x54,0x22,0x60, // F - }; - - // unpack cycle table - for ( int i = 0; i < 128; i++ ) - { - int n = cycle_table [i]; - m.cycle_table [i * 2 + 0] = n >> 4; - m.cycle_table [i * 2 + 1] = n & 0x0F; - } - - #if SPC_LESS_ACCURATE - memcpy( reg_times, reg_times_, sizeof reg_times ); - #endif - - reset(); - return 0; -} - -void SNES_SPC::init_rom( uint8_t const in [rom_size] ) -{ - memcpy( m.rom, in, sizeof m.rom ); -} - -void SNES_SPC::set_tempo( int t ) -{ - m.tempo = t; - int const timer2_shift = 4; // 64 kHz - int const other_shift = 3; // 8 kHz - - #if SPC_DISABLE_TEMPO - m.timers [2].prescaler = timer2_shift; - m.timers [1].prescaler = timer2_shift + other_shift; - m.timers [0].prescaler = timer2_shift + other_shift; - #else - if ( !t ) - t = 1; - int const timer2_rate = 1 << timer2_shift; - int rate = (timer2_rate * tempo_unit + (t >> 1)) / t; - if ( rate < timer2_rate / 4 ) - rate = timer2_rate / 4; // max 4x tempo - m.timers [2].prescaler = rate; - m.timers [1].prescaler = rate << other_shift; - m.timers [0].prescaler = rate << other_shift; - #endif -} - -// Timer registers have been loaded. Applies these to the timers. Does not -// reset timer prescalers or dividers. -void SNES_SPC::timers_loaded() -{ - int i; - for ( i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->period = IF_0_THEN_256( REGS [r_t0target + i] ); - t->enabled = REGS [r_control] >> i & 1; - t->counter = REGS_IN [r_t0out + i] & 0x0F; - } - - set_tempo( m.tempo ); -} - -// Loads registers from unified 16-byte format -void SNES_SPC::load_regs( uint8_t const in [reg_count] ) -{ - memcpy( REGS, in, reg_count ); - memcpy( REGS_IN, REGS, reg_count ); - - // These always read back as 0 - REGS_IN [r_test ] = 0; - REGS_IN [r_control ] = 0; - REGS_IN [r_t0target] = 0; - REGS_IN [r_t1target] = 0; - REGS_IN [r_t2target] = 0; -} - -// RAM was just loaded from SPC, with $F0-$FF containing SMP registers -// and timer counts. Copies these to proper registers. -void SNES_SPC::ram_loaded() -{ - m.rom_enabled = 0; - load_regs( &RAM [0xF0] ); - - // Put STOP instruction around memory to catch PC underflow/overflow - memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 ); - memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 ); -} - -// Registers were just loaded. Applies these new values. -void SNES_SPC::regs_loaded() -{ - enable_rom( REGS [r_control] & 0x80 ); - timers_loaded(); -} - -void SNES_SPC::reset_time_regs() -{ - m.cpu_error = 0; - m.echo_accessed = 0; - m.spc_time = 0; - m.dsp_time = 0; - #if SPC_LESS_ACCURATE - m.dsp_time = clocks_per_sample + 1; - #endif - - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->next_time = 1; - t->divider = 0; - } - - regs_loaded(); - - m.extra_clocks = 0; - reset_buf(); -} - -void SNES_SPC::reset_common( int timer_counter_init ) -{ - int i; - for ( i = 0; i < timer_count; i++ ) - REGS_IN [r_t0out + i] = timer_counter_init; - - // Run IPL ROM - memset( &m.cpu_regs, 0, sizeof m.cpu_regs ); - m.cpu_regs.pc = rom_addr; - - REGS [r_test ] = 0x0A; - REGS [r_control] = 0xB0; // ROM enabled, clear ports - for ( i = 0; i < port_count; i++ ) - REGS_IN [r_cpuio0 + i] = 0; - - reset_time_regs(); -} - -void SNES_SPC::soft_reset() -{ - reset_common( 0 ); - dsp.soft_reset(); -} - -void SNES_SPC::reset() -{ - memset( RAM, 0xFF, 0x10000 ); - ram_loaded(); - reset_common( 0x0F ); - dsp.reset(); -} - -char const SNES_SPC::signature [signature_size + 1] = - "SNES-SPC700 Sound File Data v0.30\x1A\x1A"; - -blargg_err_t SNES_SPC::load_spc( void const* data, long size ) -{ - spc_file_t const* const spc = (spc_file_t const*) data; - - // be sure compiler didn't insert any padding into fle_t - assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 ); - - // Check signature and file size - if ( size < signature_size || memcmp( spc, signature, 27 ) ) - return "Not an SPC file"; - - if ( size < spc_min_file_size ) - return "Corrupt SPC file"; - - // CPU registers - m.cpu_regs.pc = spc->pch * 0x100 + spc->pcl; - m.cpu_regs.a = spc->a; - m.cpu_regs.x = spc->x; - m.cpu_regs.y = spc->y; - m.cpu_regs.psw = spc->psw; - m.cpu_regs.sp = spc->sp; - - // RAM and registers - memcpy( RAM, spc->ram, 0x10000 ); - ram_loaded(); - - // DSP registers - dsp.load( spc->dsp ); - - reset_time_regs(); - - return 0; -} - -void SNES_SPC::clear_echo() -{ - if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) - { - int addr = 0x100 * dsp.read( SPC_DSP::r_esa ); - int end = addr + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); - if ( end > 0x10000 ) - end = 0x10000; - memset( &RAM [addr], 0xFF, end - addr ); - } -} - - -//// Sample output - -void SNES_SPC::reset_buf() -{ - // Start with half extra buffer of silence - sample_t* out = m.extra_buf; - while ( out < &m.extra_buf [extra_size / 2] ) - *out++ = 0; - - m.extra_pos = out; - m.buf_begin = 0; - - dsp.set_output( 0, 0 ); -} - -void SNES_SPC::set_output( sample_t* out, int size ) -{ - require( (size & 1) == 0 ); // size must be even - - m.extra_clocks &= clocks_per_sample - 1; - if ( out ) - { - sample_t const* out_end = out + size; - m.buf_begin = out; - m.buf_end = out_end; - - // Copy extra to output - sample_t const* in = m.extra_buf; - while ( in < m.extra_pos && out < out_end ) - *out++ = *in++; - - // Handle output being full already - if ( out >= out_end ) - { - // Have DSP write to remaining extra space - out = dsp.extra(); - out_end = &dsp.extra() [extra_size]; - - // Copy any remaining extra samples as if DSP wrote them - while ( in < m.extra_pos ) - *out++ = *in++; - assert( out <= out_end ); - } - - dsp.set_output( out, out_end - out ); - } - else - { - reset_buf(); - } -} - -void SNES_SPC::save_extra() -{ - // Get end pointers - sample_t const* main_end = m.buf_end; // end of data written to buf - sample_t const* dsp_end = dsp.out_pos(); // end of data written to dsp.extra() - if ( m.buf_begin <= dsp_end && dsp_end <= main_end ) - { - main_end = dsp_end; - dsp_end = dsp.extra(); // nothing in DSP's extra - } - - // Copy any extra samples at these ends into extra_buf - sample_t* out = m.extra_buf; - sample_t const* in; - for ( in = m.buf_begin + sample_count(); in < main_end; in++ ) - *out++ = *in; - for ( in = dsp.extra(); in < dsp_end ; in++ ) - *out++ = *in; - - m.extra_pos = out; - assert( out <= &m.extra_buf [extra_size] ); -} - -blargg_err_t SNES_SPC::play( int count, sample_t* out ) -{ - require( (count & 1) == 0 ); // must be even - if ( count ) - { - set_output( out, count ); - end_frame( count * (clocks_per_sample / 2) ); - } - - const char* err = m.cpu_error; - m.cpu_error = 0; - return err; -} - -blargg_err_t SNES_SPC::skip( int count ) -{ - #if SPC_LESS_ACCURATE - if ( count > 2 * sample_rate * 2 ) - { - set_output( 0, 0 ); - - // Skip a multiple of 4 samples - time_t end = count; - count = (count & 3) + 1 * sample_rate * 2; - end = (end - count) * (clocks_per_sample / 2); - - m.skipped_kon = 0; - m.skipped_koff = 0; - - // Preserve DSP and timer synchronization - // TODO: verify that this really preserves it - int old_dsp_time = m.dsp_time + m.spc_time; - m.dsp_time = end - m.spc_time + skipping_time; - end_frame( end ); - m.dsp_time = m.dsp_time - skipping_time + old_dsp_time; - - dsp.write( SPC_DSP::r_koff, m.skipped_koff & ~m.skipped_kon ); - dsp.write( SPC_DSP::r_kon , m.skipped_kon ); - clear_echo(); - } - #endif - - return play( count, 0 ); -} diff --git a/waterbox/pizza/lib/snes_spc/SNES_SPC_state.cpp b/waterbox/pizza/lib/snes_spc/SNES_SPC_state.cpp deleted file mode 100644 index a8052b6587..0000000000 --- a/waterbox/pizza/lib/snes_spc/SNES_SPC_state.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// SPC emulation state save/load: copy_state(), save_spc() -// Separate file to avoid linking in unless needed - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#if !SPC_NO_COPY_STATE_FUNCS - -#include - -/* Copyright (C) 2004-2007 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 */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -void SNES_SPC::save_regs( uint8_t out [reg_count] ) -{ - // Use current timer counter values - for ( int i = 0; i < timer_count; i++ ) - out [r_t0out + i] = m.timers [i].counter; - - // Last written values - memcpy( out, REGS, r_t0out ); -} - -void SNES_SPC::init_header( void* spc_out ) -{ - spc_file_t* const spc = (spc_file_t*) spc_out; - - spc->has_id666 = 26; // has none - spc->version = 30; - memcpy( spc, signature, sizeof spc->signature ); - memset( spc->text, 0, sizeof spc->text ); -} - -void SNES_SPC::save_spc( void* spc_out ) -{ - spc_file_t* const spc = (spc_file_t*) spc_out; - - // CPU - spc->pcl = (uint8_t) (m.cpu_regs.pc >> 0); - spc->pch = (uint8_t) (m.cpu_regs.pc >> 8); - spc->a = m.cpu_regs.a; - spc->x = m.cpu_regs.x; - spc->y = m.cpu_regs.y; - spc->psw = m.cpu_regs.psw; - spc->sp = m.cpu_regs.sp; - - // RAM, ROM - memcpy( spc->ram, RAM, sizeof spc->ram ); - if ( m.rom_enabled ) - memcpy( spc->ram + rom_addr, m.hi_ram, sizeof m.hi_ram ); - memset( spc->unused, 0, sizeof spc->unused ); - memcpy( spc->ipl_rom, m.rom, sizeof spc->ipl_rom ); - - // SMP registers - save_regs( &spc->ram [0xF0] ); - int i; - for ( i = 0; i < port_count; i++ ) - spc->ram [0xF0 + r_cpuio0 + i] = REGS_IN [r_cpuio0 + i]; - - // DSP registers - for ( i = 0; i < SPC_DSP::register_count; i++ ) - spc->dsp [i] = dsp.read( i ); -} - -void SNES_SPC::copy_state( unsigned char** io, copy_func_t copy ) -{ - SPC_State_Copier copier( io, copy ); - - // Make state data more readable by putting 64K RAM, 16 SMP registers, - // then DSP (with its 128 registers) first - - // RAM - enable_rom( 0 ); // will get re-enabled if necessary in regs_loaded() below - copier.copy( RAM, 0x10000 ); - - { - // SMP registers - uint8_t out_ports [port_count]; - uint8_t regs [reg_count]; - memcpy( out_ports, ®S [r_cpuio0], sizeof out_ports ); - save_regs( regs ); - copier.copy( regs, sizeof regs ); - copier.copy( out_ports, sizeof out_ports ); - load_regs( regs ); - regs_loaded(); - memcpy( ®S [r_cpuio0], out_ports, sizeof out_ports ); - } - - // CPU registers - SPC_COPY( uint16_t, m.cpu_regs.pc ); - SPC_COPY( uint8_t, m.cpu_regs.a ); - SPC_COPY( uint8_t, m.cpu_regs.x ); - SPC_COPY( uint8_t, m.cpu_regs.y ); - SPC_COPY( uint8_t, m.cpu_regs.psw ); - SPC_COPY( uint8_t, m.cpu_regs.sp ); - copier.extra(); - - SPC_COPY( int16_t, m.spc_time ); - SPC_COPY( int16_t, m.dsp_time ); - - // DSP - dsp.copy_state( io, copy ); - - // Timers - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - SPC_COPY( int16_t, t->next_time ); - SPC_COPY( uint8_t, t->divider ); - copier.extra(); - } - copier.extra(); -} -#endif diff --git a/waterbox/pizza/lib/snes_spc/SPC_CPU.h b/waterbox/pizza/lib/snes_spc/SPC_CPU.h deleted file mode 100644 index 664fc4886e..0000000000 --- a/waterbox/pizza/lib/snes_spc/SPC_CPU.h +++ /dev/null @@ -1,1220 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -/* Copyright (C) 2004-2007 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 */ - -//// Memory access - -#if SPC_MORE_ACCURACY - #define SUSPICIOUS_OPCODE( name ) ((void) 0) -#else - #define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" ) -#endif - -#define CPU_READ( time, offset, addr )\ - cpu_read( addr, time + offset ) - -#define CPU_WRITE( time, offset, addr, data )\ - cpu_write( data, addr, time + offset ) - -#if SPC_MORE_ACCURACY - #define CPU_READ_TIMER( time, offset, addr, out )\ - { out = CPU_READ( time, offset, addr ); } - -#else - // timers are by far the most common thing read from dp - #define CPU_READ_TIMER( time, offset, addr_, out )\ - {\ - rel_time_t adj_time = time + offset;\ - int dp_addr = addr_;\ - int ti = dp_addr - (r_t0out + 0xF0);\ - if ( (unsigned) ti < timer_count )\ - {\ - Timer* t = &m.timers [ti];\ - if ( adj_time >= t->next_time )\ - t = run_timer_( t, adj_time );\ - out = t->counter;\ - t->counter = 0;\ - }\ - else\ - {\ - out = ram [dp_addr];\ - int i = dp_addr - 0xF0;\ - if ( (unsigned) i < 0x10 )\ - out = cpu_read_smp_reg( i, adj_time );\ - }\ - } -#endif - -#define TIME_ADJ( n ) (n) - -#define READ_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out ) -#define READ( time, addr ) CPU_READ ( rel_time, TIME_ADJ(time), (addr) ) -#define WRITE( time, addr, data ) CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) ) - -#define DP_ADDR( addr ) (dp + (addr)) - -#define READ_DP_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out ) -#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) ) -#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data ) - -#define READ_PROG16( addr ) GET_LE16( ram + (addr) ) - -#define SET_PC( n ) (pc = ram + (n)) -#define GET_PC() (pc - ram) -#define READ_PC( pc ) (*(pc)) -#define READ_PC16( pc ) GET_LE16( pc ) - -// TODO: remove non-wrapping versions? -#define SPC_NO_SP_WRAPAROUND 0 - -#define SET_SP( v ) (sp = ram + 0x101 + (v)) -#define GET_SP() (sp - 0x101 - ram) - -#if SPC_NO_SP_WRAPAROUND -#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) -#define PUSH( v ) (void) (*--sp = (uint8_t) (v)) -#define POP( out ) (void) ((out) = *sp++) - -#else -#define PUSH16( data )\ -{\ - int addr = (sp -= 2) - ram;\ - if ( addr > 0x100 )\ - {\ - SET_LE16( sp, data );\ - }\ - else\ - {\ - ram [(uint8_t) addr + 0x100] = (uint8_t) data;\ - sp [1] = (uint8_t) (data >> 8);\ - sp += 0x100;\ - }\ -} - -#define PUSH( data )\ -{\ - *--sp = (uint8_t) (data);\ - if ( sp - ram == 0x100 )\ - sp += 0x100;\ -} - -#define POP( out )\ -{\ - out = *sp++;\ - if ( sp - ram == 0x201 )\ - {\ - out = sp [-0x101];\ - sp -= 0x100;\ - }\ -} - -#endif - -#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel ) - -unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time ) -{ - unsigned addr = READ_PC16( pc ); - unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13); - return t << 8 & 0x100; -} - -//// Status flag handling - -// Hex value in name to clarify code and bit shifting. -// Flag stored in indicated variable during emulation -int const n80 = 0x80; // nz -int const v40 = 0x40; // psw -int const p20 = 0x20; // dp -int const b10 = 0x10; // psw -int const h08 = 0x08; // psw -int const i04 = 0x04; // psw -int const z02 = 0x02; // nz -int const c01 = 0x01; // c - -int const nz_neg_mask = 0x880; // either bit set indicates N flag set - -#define GET_PSW( out )\ -{\ - out = psw & ~(n80 | p20 | z02 | c01);\ - out |= c >> 8 & c01;\ - out |= dp >> 3 & p20;\ - out |= ((nz >> 4) | nz) & n80;\ - if ( !(uint8_t) nz ) out |= z02;\ -} - -#define SET_PSW( in )\ -{\ - psw = in;\ - c = in << 8;\ - dp = in << 3 & 0x100;\ - nz = (in << 4 & 0x800) | (~in & z02);\ -} - -SPC_CPU_RUN_FUNC -{ - uint8_t* const ram = RAM; - int a = m.cpu_regs.a; - int x = m.cpu_regs.x; - int y = m.cpu_regs.y; - uint8_t const* pc; - uint8_t* sp; - int psw; - int c; - int nz; - int dp; - - SET_PC( m.cpu_regs.pc ); - SET_SP( m.cpu_regs.sp ); - SET_PSW( m.cpu_regs.psw ); - - goto loop; - - - // Main loop - -cbranch_taken_loop: - pc += *(BOOST::int8_t const*) pc; -inc_pc_loop: - pc++; -loop: -{ - unsigned opcode; - unsigned data; - - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - opcode = *pc; - if ( (rel_time += m.cycle_table [opcode]) > 0 ) - goto out_of_time; - - #ifdef SPC_CPU_OPCODE_HOOK - SPC_CPU_OPCODE_HOOK( GET_PC(), opcode ); - #endif - /* - //SUB_CASE_COUNTER( 1 ); - #define PROFILE_TIMER_LOOP( op, addr, len )\ - if ( opcode == op )\ - {\ - int cond = (unsigned) ((addr) - 0xFD) < 3 &&\ - pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\ - SUB_CASE_COUNTER( op && cond );\ - } - - PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 ); - PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 ); - PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 ); - */ - - // TODO: if PC is at end of memory, this will get wrong operand (very obscure) - data = *++pc; - switch ( opcode ) - { - -// Common instructions - -#define BRANCH( cond )\ -{\ - pc++;\ - pc += (BOOST::int8_t) data;\ - if ( cond )\ - goto loop;\ - pc -= (BOOST::int8_t) data;\ - rel_time -= 2;\ - goto loop;\ -} - - case 0xF0: // BEQ - BRANCH( !(uint8_t) nz ) // 89% taken - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ) - - case 0x3F:{// CALL - int old_addr = GET_PC() + 2; - SET_PC( READ_PC16( pc ) ); - PUSH16( old_addr ); - goto loop; - } - - case 0x6F:// RET - #if SPC_NO_SP_WRAPAROUND - { - SET_PC( GET_LE16( sp ) ); - sp += 2; - } - #else - { - int addr = sp - ram; - SET_PC( GET_LE16( sp ) ); - sp += 2; - if ( addr < 0x1FF ) - goto loop; - - SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] ); - sp -= 0x100; - } - #endif - goto loop; - - case 0xE4: // MOV a,dp - ++pc; - // 80% from timer - READ_DP_TIMER( 0, data, a = nz ); - goto loop; - - case 0xFA:{// MOV dp,dp - int temp; - READ_DP_TIMER( -2, data, temp ); - data = temp + no_read_before_write ; - } - // fall through - case 0x8F:{// MOV dp,#imm - int temp = READ_PC( pc + 1 ); - pc += 2; - - #if !SPC_MORE_ACCURACY - { - int i = dp + temp; - ram [i] = (uint8_t) data; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 76% - { - REGS [i] = (uint8_t) data; - - // Registers other than $F2 and $F4-$F7 - //if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 ) - if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12% - cpu_write_smp_reg( data, rel_time, i ); - } - } - #else - WRITE_DP( 0, temp, data ); - #endif - goto loop; - } - - case 0xC4: // MOV dp,a - ++pc; - #if !SPC_MORE_ACCURACY - { - int i = dp + data; - ram [i] = (uint8_t) a; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 39% - { - unsigned sel = i - 2; - REGS [i] = (uint8_t) a; - - if ( sel == 1 ) // 51% $F3 - dsp_write( a, rel_time ); - else if ( sel > 1 ) // 1% not $F2 or $F3 - cpu_write_smp_reg_( a, rel_time, i ); - } - } - #else - WRITE_DP( 0, data, a ); - #endif - goto loop; - -#define CASE( n ) case n: - -// Define common address modes based on opcode for immediate mode. Execution -// ends with data set to the address of the operand. -#define ADDR_MODES_( op )\ - CASE( op - 0x02 ) /* (X) */\ - data = x + dp;\ - pc--;\ - goto end_##op;\ - CASE( op + 0x0F ) /* (dp)+Y */\ - data = READ_PROG16( data + dp ) + y;\ - goto end_##op;\ - CASE( op - 0x01 ) /* (dp+X) */\ - data = READ_PROG16( ((uint8_t) (data + x)) + dp );\ - goto end_##op;\ - CASE( op + 0x0E ) /* abs+Y */\ - data += y;\ - goto abs_##op;\ - CASE( op + 0x0D ) /* abs+X */\ - data += x;\ - CASE( op - 0x03 ) /* abs */\ - abs_##op:\ - data += 0x100 * READ_PC( ++pc );\ - goto end_##op;\ - CASE( op + 0x0C ) /* dp+X */\ - data = (uint8_t) (data + x); - -#define ADDR_MODES_NO_DP( op )\ - ADDR_MODES_( op )\ - data += dp;\ - end_##op: - -#define ADDR_MODES( op )\ - ADDR_MODES_( op )\ - CASE( op - 0x04 ) /* dp */\ - data += dp;\ - end_##op: - -// 1. 8-bit Data Transmission Commands. Group I - - ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr - a = nz = READ( 0, data ); - goto inc_pc_loop; - - case 0xBF:{// MOV A,(X)+ - int temp = x + dp; - x = (uint8_t) (x + 1); - a = nz = READ( -1, temp ); - goto loop; - } - - case 0xE8: // MOV A,imm - a = data; - nz = data; - goto inc_pc_loop; - - case 0xF9: // MOV X,dp+Y - data = (uint8_t) (data + y); - case 0xF8: // MOV X,dp - READ_DP_TIMER( 0, data, x = nz ); - goto inc_pc_loop; - - case 0xE9: // MOV X,abs - data = READ_PC16( pc ); - ++pc; - data = READ( 0, data ); - case 0xCD: // MOV X,imm - x = data; - nz = data; - goto inc_pc_loop; - - case 0xFB: // MOV Y,dp+X - data = (uint8_t) (data + x); - case 0xEB: // MOV Y,dp - // 70% from timer - pc++; - READ_DP_TIMER( 0, data, y = nz ); - goto loop; - - case 0xEC:{// MOV Y,abs - int temp = READ_PC16( pc ); - pc += 2; - READ_TIMER( 0, temp, y = nz ); - //y = nz = READ( 0, temp ); - goto loop; - } - - case 0x8D: // MOV Y,imm - y = data; - nz = data; - goto inc_pc_loop; - -// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 - - ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A - WRITE( 0, data, a ); - goto inc_pc_loop; - - { - int temp; - case 0xCC: // MOV abs,Y - temp = y; - goto mov_abs_temp; - case 0xC9: // MOV abs,X - temp = x; - mov_abs_temp: - WRITE( 0, READ_PC16( pc ), temp ); - pc += 2; - goto loop; - } - - case 0xD9: // MOV dp+Y,X - data = (uint8_t) (data + y); - case 0xD8: // MOV dp,X - WRITE( 0, data + dp, x ); - goto inc_pc_loop; - - case 0xDB: // MOV dp+X,Y - data = (uint8_t) (data + x); - case 0xCB: // MOV dp,Y - WRITE( 0, data + dp, y ); - goto inc_pc_loop; - -// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. - - case 0x7D: // MOV A,X - a = x; - nz = x; - goto loop; - - case 0xDD: // MOV A,Y - a = y; - nz = y; - goto loop; - - case 0x5D: // MOV X,A - x = a; - nz = a; - goto loop; - - case 0xFD: // MOV Y,A - y = a; - nz = a; - goto loop; - - case 0x9D: // MOV X,SP - x = nz = GET_SP(); - goto loop; - - case 0xBD: // MOV SP,X - SET_SP( x ); - goto loop; - - //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2) - - case 0xAF: // MOV (X)+,A - WRITE_DP( 0, x, a + no_read_before_write ); - x++; - goto loop; - -// 5. 8-BIT LOGIC OPERATION COMMANDS - -#define LOGICAL_OP( op, func )\ - ADDR_MODES( op ) /* addr */\ - data = READ( 0, data );\ - case op: /* imm */\ - nz = a func##= data;\ - goto inc_pc_loop;\ - { unsigned addr;\ - case op + 0x11: /* X,Y */\ - data = READ_DP( -2, y );\ - addr = x + dp;\ - goto addr_##op;\ - case op + 0x01: /* dp,dp */\ - data = READ_DP( -3, data );\ - case op + 0x10:{/*dp,imm*/\ - uint8_t const* addr2 = pc + 1;\ - pc += 2;\ - addr = READ_PC( addr2 ) + dp;\ - }\ - addr_##op:\ - nz = data func READ( -1, addr );\ - WRITE( 0, addr, nz );\ - goto loop;\ - } - - LOGICAL_OP( 0x28, & ); // AND - - LOGICAL_OP( 0x08, | ); // OR - - LOGICAL_OP( 0x48, ^ ); // EOR - -// 4. 8-BIT ARITHMETIC OPERATION COMMANDS - - ADDR_MODES( 0x68 ) // CMP addr - data = READ( 0, data ); - case 0x68: // CMP imm - nz = a - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x79: // CMP (X),(Y) - data = READ_DP( -2, y ); - nz = READ_DP( -1, x ) - data; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x69: // CMP dp,dp - data = READ_DP( -3, data ); - case 0x78: // CMP dp,imm - nz = READ_DP( -1, READ_PC( ++pc ) ) - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x3E: // CMP X,dp - data += dp; - goto cmp_x_addr; - case 0x1E: // CMP X,abs - data = READ_PC16( pc ); - pc++; - cmp_x_addr: - data = READ( 0, data ); - case 0xC8: // CMP X,imm - nz = x - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x7E: // CMP Y,dp - data += dp; - goto cmp_y_addr; - case 0x5E: // CMP Y,abs - data = READ_PC16( pc ); - pc++; - cmp_y_addr: - data = READ( 0, data ); - case 0xAD: // CMP Y,imm - nz = y - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - { - int addr; - case 0xB9: // SBC (x),(y) - case 0x99: // ADC (x),(y) - pc--; // compensate for inc later - data = READ_DP( -2, y ); - addr = x + dp; - goto adc_addr; - case 0xA9: // SBC dp,dp - case 0x89: // ADC dp,dp - data = READ_DP( -3, data ); - case 0xB8: // SBC dp,imm - case 0x98: // ADC dp,imm - addr = READ_PC( ++pc ) + dp; - adc_addr: - nz = READ( -1, addr ); - goto adc_data; - -// catch ADC and SBC together, then decode later based on operand -#undef CASE -#define CASE( n ) case n: case (n) + 0x20: - ADDR_MODES( 0x88 ) // ADC/SBC addr - data = READ( 0, data ); - case 0xA8: // SBC imm - case 0x88: // ADC imm - addr = -1; // A - nz = a; - adc_data: { - int flags; - if ( opcode >= 0xA0 ) // SBC - data ^= 0xFF; - - flags = data ^ nz; - nz += data + (c >> 8 & 1); - flags ^= nz; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = nz; - if ( addr < 0 ) - { - a = (uint8_t) nz; - goto inc_pc_loop; - } - WRITE( 0, addr, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - } - - } - -// 6. ADDITION & SUBTRACTION COMMANDS - -#define INC_DEC_REG( reg, op )\ - nz = reg op;\ - reg = (uint8_t) nz;\ - goto loop; - - case 0xBC: INC_DEC_REG( a, + 1 ) // INC A - case 0x3D: INC_DEC_REG( x, + 1 ) // INC X - case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y - - case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A - case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X - case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y - - case 0x9B: // DEC dp+X - case 0xBB: // INC dp+X - data = (uint8_t) (data + x); - case 0x8B: // DEC dp - case 0xAB: // INC dp - data += dp; - goto inc_abs; - case 0x8C: // DEC abs - case 0xAC: // INC abs - data = READ_PC16( pc ); - pc++; - inc_abs: - nz = (opcode >> 4 & 2) - 1; - nz += READ( -1, data ); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - -// 7. SHIFT, ROTATION COMMANDS - - case 0x5C: // LSR A - c = 0; - case 0x7C:{// ROR A - nz = (c >> 1 & 0x80) | (a >> 1); - c = a << 8; - a = nz; - goto loop; - } - - case 0x1C: // ASL A - c = 0; - case 0x3C:{// ROL A - int temp = c >> 8 & 1; - c = a << 1; - nz = c | temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x0B: // ASL dp - c = 0; - data += dp; - goto rol_mem; - case 0x1B: // ASL dp+X - c = 0; - case 0x3B: // ROL dp+X - data = (uint8_t) (data + x); - case 0x2B: // ROL dp - data += dp; - goto rol_mem; - case 0x0C: // ASL abs - c = 0; - case 0x2C: // ROL abs - data = READ_PC16( pc ); - pc++; - rol_mem: - nz = c >> 8 & 1; - nz |= (c = READ( -1, data ) << 1); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - - case 0x4B: // LSR dp - c = 0; - data += dp; - goto ror_mem; - case 0x5B: // LSR dp+X - c = 0; - case 0x7B: // ROR dp+X - data = (uint8_t) (data + x); - case 0x6B: // ROR dp - data += dp; - goto ror_mem; - case 0x4C: // LSR abs - c = 0; - case 0x6C: // ROR abs - data = READ_PC16( pc ); - pc++; - ror_mem: { - int temp = READ( -1, data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - WRITE( 0, data, nz ); - goto inc_pc_loop; - } - - case 0x9F: // XCN - nz = a = (a >> 4) | (uint8_t) (a << 4); - goto loop; - -// 8. 16-BIT TRANSMISION COMMANDS - - case 0xBA: // MOVW YA,dp - a = READ_DP( -2, data ); - nz = (a & 0x7F) | (a >> 1); - y = READ_DP( 0, (uint8_t) (data + 1) ); - nz |= y; - goto inc_pc_loop; - - case 0xDA: // MOVW dp,YA - WRITE_DP( -1, data, a ); - WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write ); - goto inc_pc_loop; - -// 9. 16-BIT OPERATION COMMANDS - - case 0x3A: // INCW dp - case 0x1A:{// DECW dp - int temp; - // low byte - data += dp; - temp = READ( -3, data ); - temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW - nz = ((temp >> 1) | temp) & 0x7F; - WRITE( -2, data, /*(uint8_t)*/ temp ); - - // high byte - data = (uint8_t) (data + 1) + dp; - temp = (uint8_t) ((temp >> 8) + READ( -1, data )); - nz |= temp; - WRITE( 0, data, temp ); - - goto inc_pc_loop; - } - - case 0x7A: // ADDW YA,dp - case 0x9A:{// SUBW YA,dp - int lo = READ_DP( -2, data ); - int hi = READ_DP( 0, (uint8_t) (data + 1) ); - int result; - int flags; - - if ( opcode == 0x9A ) // SUBW - { - lo = (lo ^ 0xFF) + 1; - hi ^= 0xFF; - } - - lo += a; - result = y + hi + (lo >> 8); - flags = hi ^ y ^ result; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = result; - a = (uint8_t) lo; - result = (uint8_t) result; - y = result; - nz = (((lo >> 1) | lo) & 0x7F) | result; - - goto inc_pc_loop; - } - - case 0x5A: { // CMPW YA,dp - int temp = a - READ_DP( -1, data ); - nz = ((temp >> 1) | temp) & 0x7F; - temp = y + (temp >> 8); - temp -= READ_DP( 0, (uint8_t) (data + 1) ); - nz |= temp; - c = ~temp; - nz &= 0xFF; - goto inc_pc_loop; - } - -// 10. MULTIPLICATION & DIVISON COMMANDS - - case 0xCF: { // MUL YA - unsigned temp = y * a; - a = (uint8_t) temp; - nz = ((temp >> 1) | temp) & 0x7F; - y = temp >> 8; - nz |= y; - goto loop; - } - - case 0x9E: // DIV YA,X - { - unsigned ya = y * 0x100 + a; - - psw &= ~(h08 | v40); - - if ( y >= x ) - psw |= v40; - - if ( (y & 15) >= (x & 15) ) - psw |= h08; - - if ( y < x * 2 ) - { - a = ya / x; - y = ya - a * x; - } - else - { - a = 255 - (ya - x * 0x200) / (256 - x); - y = x + (ya - x * 0x200) % (256 - x); - } - - nz = (uint8_t) a; - a = (uint8_t) a; - - goto loop; - } - -// 11. DECIMAL COMPENSATION COMMANDS - - case 0xDF: // DAA - SUSPICIOUS_OPCODE( "DAA" ); - if ( a > 0x99 || c & 0x100 ) - { - a += 0x60; - c = 0x100; - } - - if ( (a & 0x0F) > 9 || psw & h08 ) - a += 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - - case 0xBE: // DAS - SUSPICIOUS_OPCODE( "DAS" ); - if ( a > 0x99 || !(c & 0x100) ) - { - a -= 0x60; - c = 0; - } - - if ( (a & 0x0F) > 9 || !(psw & h08) ) - a -= 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - -// 12. BRANCHING COMMANDS - - case 0x2F: // BRA rel - pc += (BOOST::int8_t) data; - goto inc_pc_loop; - - case 0x30: // BMI - BRANCH( (nz & nz_neg_mask) ) - - case 0x10: // BPL - BRANCH( !(nz & nz_neg_mask) ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - - case 0x70: // BVS - BRANCH( psw & v40 ) - - case 0x50: // BVC - BRANCH( !(psw & v40) ) - - #define CBRANCH( cond )\ - {\ - pc++;\ - if ( cond )\ - goto cbranch_taken_loop;\ - rel_time -= 2;\ - goto inc_pc_loop;\ - } - - case 0x03: // BBS dp.bit,rel - case 0x23: - case 0x43: - case 0x63: - case 0x83: - case 0xA3: - case 0xC3: - case 0xE3: - CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 ) - - case 0x13: // BBC dp.bit,rel - case 0x33: - case 0x53: - case 0x73: - case 0x93: - case 0xB3: - case 0xD3: - case 0xF3: - CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) ) - - case 0xDE: // CBNE dp+X,rel - data = (uint8_t) (data + x); - // fall through - case 0x2E:{// CBNE dp,rel - int temp; - // 61% from timer - READ_DP_TIMER( -4, data, temp ); - CBRANCH( temp != a ) - } - - case 0x6E: { // DBNZ dp,rel - unsigned temp = READ_DP( -4, data ) - 1; - WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write ); - CBRANCH( temp ) - } - - case 0xFE: // DBNZ Y,rel - y = (uint8_t) (y - 1); - BRANCH( y ) - - case 0x1F: // JMP [abs+X] - SET_PC( READ_PC16( pc ) + x ); - // fall through - case 0x5F: // JMP abs - SET_PC( READ_PC16( pc ) ); - goto loop; - -// 13. SUB-ROUTINE CALL RETURN COMMANDS - - case 0x0F:{// BRK - int temp; - int ret_addr = GET_PC(); - SUSPICIOUS_OPCODE( "BRK" ); - SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified - PUSH16( ret_addr ); - GET_PSW( temp ); - psw = (psw | b10) & ~i04; - PUSH( temp ); - goto loop; - } - - case 0x4F:{// PCALL offset - int ret_addr = GET_PC() + 1; - SET_PC( 0xFF00 | data ); - PUSH16( ret_addr ); - goto loop; - } - - case 0x01: // TCALL n - case 0x11: - case 0x21: - case 0x31: - case 0x41: - case 0x51: - case 0x61: - case 0x71: - case 0x81: - case 0x91: - case 0xA1: - case 0xB1: - case 0xC1: - case 0xD1: - case 0xE1: - case 0xF1: { - int ret_addr = GET_PC(); - SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) ); - PUSH16( ret_addr ); - goto loop; - } - -// 14. STACK OPERATION COMMANDS - - { - int temp; - case 0x7F: // RET1 - temp = *sp; - SET_PC( GET_LE16( sp + 1 ) ); - sp += 3; - goto set_psw; - case 0x8E: // POP PSW - POP( temp ); - set_psw: - SET_PSW( temp ); - goto loop; - } - - case 0x0D: { // PUSH PSW - int temp; - GET_PSW( temp ); - PUSH( temp ); - goto loop; - } - - case 0x2D: // PUSH A - PUSH( a ); - goto loop; - - case 0x4D: // PUSH X - PUSH( x ); - goto loop; - - case 0x6D: // PUSH Y - PUSH( y ); - goto loop; - - case 0xAE: // POP A - POP( a ); - goto loop; - - case 0xCE: // POP X - POP( x ); - goto loop; - - case 0xEE: // POP Y - POP( y ); - goto loop; - -// 15. BIT OPERATION COMMANDS - - case 0x02: // SET1 - case 0x22: - case 0x42: - case 0x62: - case 0x82: - case 0xA2: - case 0xC2: - case 0xE2: - case 0x12: // CLR1 - case 0x32: - case 0x52: - case 0x72: - case 0x92: - case 0xB2: - case 0xD2: - case 0xF2: { - int bit = 1 << (opcode >> 5); - int mask = ~bit; - if ( opcode & 0x10 ) - bit = 0; - data += dp; - WRITE( 0, data, (READ( -1, data ) & mask) | bit ); - goto inc_pc_loop; - } - - case 0x0E: // TSET1 abs - case 0x4E: // TCLR1 abs - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data ); - nz = (uint8_t) (a - temp); - temp &= ~a; - if ( opcode == 0x0E ) - temp |= a; - WRITE( 0, data, temp ); - } - goto loop; - - case 0x4A: // AND1 C,mem.bit - c &= MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x6A: // AND1 C,/mem.bit - c &= ~MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x0A: // OR1 C,mem.bit - c |= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x2A: // OR1 C,/mem.bit - c |= ~MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x8A: // EOR1 C,mem.bit - c ^= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0xEA: // NOT1 mem.bit - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -1, data & 0x1FFF ); - temp ^= 1 << (data >> 13); - WRITE( 0, data & 0x1FFF, temp ); - } - goto loop; - - case 0xCA: // MOV1 mem.bit,C - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data & 0x1FFF ); - unsigned bit = data >> 13; - temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit); - WRITE( 0, data & 0x1FFF, temp + no_read_before_write ); - } - goto loop; - - case 0xAA: // MOV1 C,mem.bit - c = MEM_BIT( 0 ); - pc += 2; - goto loop; - -// 16. PROGRAM PSW FLAG OPERATION COMMANDS - - case 0x60: // CLRC - c = 0; - goto loop; - - case 0x80: // SETC - c = ~0; - goto loop; - - case 0xED: // NOTC - c ^= 0x100; - goto loop; - - case 0xE0: // CLRV - psw &= ~(v40 | h08); - goto loop; - - case 0x20: // CLRP - dp = 0; - goto loop; - - case 0x40: // SETP - dp = 0x100; - goto loop; - - case 0xA0: // EI - SUSPICIOUS_OPCODE( "EI" ); - psw |= i04; - goto loop; - - case 0xC0: // DI - SUSPICIOUS_OPCODE( "DI" ); - psw &= ~i04; - goto loop; - -// 17. OTHER COMMANDS - - case 0x00: // NOP - goto loop; - - case 0xFF:{// STOP - // handle PC wrap-around - unsigned addr = GET_PC() - 1; - if ( addr >= 0x10000 ) - { - addr &= 0xFFFF; - SET_PC( addr ); - dprintf( "SPC: PC wrapped around\n" ); - goto loop; - } - } - // fall through - case 0xEF: // SLEEP - SUSPICIOUS_OPCODE( "STOP/SLEEP" ); - --pc; - rel_time = 0; - m.cpu_error = "SPC emulation error"; - goto stop; - } // switch - - assert( 0 ); // catch any unhandled instructions -} -out_of_time: - rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode -stop: - - // Uncache registers - if ( GET_PC() >= 0x10000 ) - dprintf( "SPC: PC wrapped around\n" ); - m.cpu_regs.pc = (uint16_t) GET_PC(); - m.cpu_regs.sp = ( uint8_t) GET_SP(); - m.cpu_regs.a = ( uint8_t) a; - m.cpu_regs.x = ( uint8_t) x; - m.cpu_regs.y = ( uint8_t) y; - { - int temp; - GET_PSW( temp ); - m.cpu_regs.psw = (uint8_t) temp; - } -} -SPC_CPU_RUN_FUNC_END diff --git a/waterbox/pizza/lib/snes_spc/SPC_DSP.cpp b/waterbox/pizza/lib/snes_spc/SPC_DSP.cpp deleted file mode 100644 index dd180506fc..0000000000 --- a/waterbox/pizza/lib/snes_spc/SPC_DSP.cpp +++ /dev/null @@ -1,1018 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SPC_DSP.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2007 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 */ - -#include "blargg_source.h" - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -#if INT_MAX < 0x7FFFFFFF - #error "Requires that int type have at least 32 bits" -#endif - -// TODO: add to blargg_endian.h -#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr )) -#define GET_LE16A( addr ) GET_LE16( addr ) -#define SET_LE16A( addr, data ) SET_LE16( addr, data ) - -static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = -{ - 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, - 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, - 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, - 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, - 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, - 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF, - 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, - 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF -}; - -// if ( io < -32768 ) io = -32768; -// if ( io > 32767 ) io = 32767; -#define CLAMP16( io )\ -{\ - if ( (int16_t) io != io )\ - io = (io >> 31) ^ 0x7FFF;\ -} - -// Access global DSP register -#define REG(n) m.regs [r_##n] - -// Access voice DSP register -#define VREG(r,n) r [v_##n] - -#define WRITE_SAMPLES( l, r, out ) \ -{\ - out [0] = l;\ - out [1] = r;\ - out += 2;\ - if ( out >= m.out_end )\ - {\ - check( out == m.out_end );\ - check( m.out_end != &m.extra [extra_size] || \ - (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ - out = m.extra;\ - m.out_end = &m.extra [extra_size];\ - }\ -}\ - -void SPC_DSP::set_output( sample_t* out, int size ) -{ - require( (size & 1) == 0 ); // must be even - if ( !out ) - { - out = m.extra; - size = extra_size; - } - m.out_begin = out; - m.out = out; - m.out_end = out + size; -} - -// Volume registers and efb are signed! Easy to forget int8_t cast. -// Prefixes are to avoid accidental use of locals with same names. - -// Gaussian interpolation - -static short const gauss [512] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, - 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, - 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, - 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, - 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, - 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, - 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, - 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, - 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, - 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, - 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, - 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, - 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, - 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, - 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, - 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, - 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, - 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, - 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, -1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, -1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, -1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, -1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, -1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, -1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, -1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, -}; - -inline int SPC_DSP::interpolate( voice_t const* v ) -{ - // Make pointers into gaussian based on fractional position between samples - int offset = v->interp_pos >> 4 & 0xFF; - short const* fwd = gauss + 255 - offset; - short const* rev = gauss + offset; // mirror left half of gaussian - - int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; - int out; - out = (fwd [ 0] * in [0]) >> 11; - out += (fwd [256] * in [1]) >> 11; - out += (rev [256] * in [2]) >> 11; - out = (int16_t) out; - out += (rev [ 0] * in [3]) >> 11; - - CLAMP16( out ); - out &= ~1; - return out; -} - - -//// Counters - -int const simple_counter_range = 2048 * 5 * 3; // 30720 - -static unsigned const counter_rates [32] = -{ - simple_counter_range + 1, // never fires - 2048, 1536, - 1280, 1024, 768, - 640, 512, 384, - 320, 256, 192, - 160, 128, 96, - 80, 64, 48, - 40, 32, 24, - 20, 16, 12, - 10, 8, 6, - 5, 4, 3, - 2, - 1 -}; - -static unsigned const counter_offsets [32] = -{ - 1, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 536, 0, 1040, - 0, - 0 -}; - -inline void SPC_DSP::init_counter() -{ - m.counter = 0; -} - -inline void SPC_DSP::run_counters() -{ - if ( --m.counter < 0 ) - m.counter = simple_counter_range - 1; -} - -inline unsigned SPC_DSP::read_counter( int rate ) -{ - return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; -} - - -//// Envelope - -inline void SPC_DSP::run_envelope( voice_t* const v ) -{ - int env = v->env; - if ( v->env_mode == env_release ) // 60% - { - if ( (env -= 0x8) < 0 ) - env = 0; - v->env = env; - } - else - { - int rate; - int env_data = VREG(v->regs,adsr1); - if ( m.t_adsr0 & 0x80 ) // 99% ADSR - { - if ( v->env_mode >= env_decay ) // 99% - { - env--; - env -= env >> 8; - rate = env_data & 0x1F; - if ( v->env_mode == env_decay ) // 1% - rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; - } - else // env_attack - { - rate = (m.t_adsr0 & 0x0F) * 2 + 1; - env += rate < 31 ? 0x20 : 0x400; - } - } - else // GAIN - { - int mode; - env_data = VREG(v->regs,gain); - mode = env_data >> 5; - if ( mode < 4 ) // direct - { - env = env_data * 0x10; - rate = 31; - } - else - { - rate = env_data & 0x1F; - if ( mode == 4 ) // 4: linear decrease - { - env -= 0x20; - } - else if ( mode < 6 ) // 5: exponential decrease - { - env--; - env -= env >> 8; - } - else // 6,7: linear increase - { - env += 0x20; - if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) - env += 0x8 - 0x20; // 7: two-slope linear increase - } - } - } - - // Sustain level - if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) - v->env_mode = env_sustain; - - v->hidden_env = env; - - // unsigned cast because linear decrease going negative also triggers this - if ( (unsigned) env > 0x7FF ) - { - env = (env < 0 ? 0 : 0x7FF); - if ( v->env_mode == env_attack ) - v->env_mode = env_decay; - } - - if ( !read_counter( rate ) ) - v->env = env; // nothing else is controlled by the counter - } -} - - -//// BRR Decoding - -inline void SPC_DSP::decode_brr( voice_t* v ) -{ - // Arrange the four input nybbles in 0xABCD order for easy decoding - int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; - - int const header = m.t_brr_header; - - // Write to next four samples in circular buffer - int* pos = &v->buf [v->buf_pos]; - int* end; - if ( (v->buf_pos += 4) >= brr_buf_size ) - v->buf_pos = 0; - - // Decode four samples - for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) - { - // Extract nybble and sign-extend - int s = (int16_t) nybbles >> 12; - - // Shift sample based on header - int const shift = header >> 4; - s = (s << shift) >> 1; - if ( shift >= 0xD ) // handle invalid range - s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) - - // Apply IIR filter (8 is the most commonly used) - int const filter = header & 0x0C; - int const p1 = pos [brr_buf_size - 1]; - int const p2 = pos [brr_buf_size - 2] >> 1; - if ( filter >= 8 ) - { - s += p1; - s -= p2; - if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 - { - s += p2 >> 4; - s += (p1 * -3) >> 6; - } - else // s += p1 * 0.8984375 - p2 * 0.40625 - { - s += (p1 * -13) >> 7; - s += (p2 * 3) >> 4; - } - } - else if ( filter ) // s += p1 * 0.46875 - { - s += p1 >> 1; - s += (-p1) >> 5; - } - - // Adjust and write sample - CLAMP16( s ); - s = (int16_t) (s * 2); - pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around - } -} - - -//// Misc - -#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() - -MISC_CLOCK( 27 ) -{ - m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON -} -MISC_CLOCK( 28 ) -{ - m.t_non = REG(non); - m.t_eon = REG(eon); - m.t_dir = REG(dir); -} -MISC_CLOCK( 29 ) -{ - if ( (m.every_other_sample ^= 1) != 0 ) - m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read -} -MISC_CLOCK( 30 ) -{ - if ( m.every_other_sample ) - { - m.kon = m.new_kon; - m.t_koff = REG(koff) | m.mute_mask; - } - - run_counters(); - - // Noise - if ( !read_counter( REG(flg) & 0x1F ) ) - { - int feedback = (m.noise << 13) ^ (m.noise << 14); - m.noise = (feedback & 0x4000) ^ (m.noise >> 1); - } -} - - -//// Voices - -#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) - -inline VOICE_CLOCK( V1 ) -{ - m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; - m.t_srcn = VREG(v->regs,srcn); -} -inline VOICE_CLOCK( V2 ) -{ - // Read sample pointer (ignored if not needed) - uint8_t const* entry = &m.ram [m.t_dir_addr]; - if ( !v->kon_delay ) - entry += 2; - m.t_brr_next_addr = GET_LE16A( entry ); - - m.t_adsr0 = VREG(v->regs,adsr0); - - // Read pitch, spread over two clocks - m.t_pitch = VREG(v->regs,pitchl); -} -inline VOICE_CLOCK( V3a ) -{ - m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; -} -inline VOICE_CLOCK( V3b ) -{ - // Read BRR header and byte - m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; - m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking -} -VOICE_CLOCK( V3c ) -{ - // Pitch modulation using previous voice's output - if ( m.t_pmon & v->vbit ) - m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; - - if ( v->kon_delay ) - { - // Get ready to start BRR decoding on next sample - if ( v->kon_delay == 5 ) - { - v->brr_addr = m.t_brr_next_addr; - v->brr_offset = 1; - v->buf_pos = 0; - m.t_brr_header = 0; // header is ignored on this sample - m.kon_check = true; - } - - // Envelope is never run during KON - v->env = 0; - v->hidden_env = 0; - - // Disable BRR decoding until last three samples - v->interp_pos = 0; - if ( --v->kon_delay & 3 ) - v->interp_pos = 0x4000; - - // Pitch is never added during KON - m.t_pitch = 0; - } - - // Gaussian interpolation - { - int output = interpolate( v ); - - // Noise - if ( m.t_non & v->vbit ) - output = (int16_t) (m.noise * 2); - - // Apply envelope - m.t_output = (output * v->env) >> 11 & ~1; - v->t_envx_out = (uint8_t) (v->env >> 4); - } - - // Immediate silence due to end of sample or soft reset - if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) - { - v->env_mode = env_release; - v->env = 0; - } - - if ( m.every_other_sample ) - { - // KOFF - if ( m.t_koff & v->vbit ) - v->env_mode = env_release; - - // KON - if ( m.kon & v->vbit ) - { - v->kon_delay = 5; - v->env_mode = env_attack; - } - } - - // Run envelope for next sample - if ( !v->kon_delay ) - run_envelope( v ); -} -inline void SPC_DSP::voice_output( voice_t const* v, int ch ) -{ - // Apply left/right volume - int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; - - // Add to output total - m.t_main_out [ch] += amp; - CLAMP16( m.t_main_out [ch] ); - - // Optionally add to echo total - if ( m.t_eon & v->vbit ) - { - m.t_echo_out [ch] += amp; - CLAMP16( m.t_echo_out [ch] ); - } -} -VOICE_CLOCK( V4 ) -{ - // Decode BRR - m.t_looped = 0; - if ( v->interp_pos >= 0x4000 ) - { - decode_brr( v ); - - if ( (v->brr_offset += 2) >= brr_block_size ) - { - // Start decoding next BRR block - assert( v->brr_offset == brr_block_size ); - v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; - if ( m.t_brr_header & 1 ) - { - v->brr_addr = m.t_brr_next_addr; - m.t_looped = v->vbit; - } - v->brr_offset = 1; - } - } - - // Apply pitch - v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; - - // Keep from getting too far ahead (when using pitch modulation) - if ( v->interp_pos > 0x7FFF ) - v->interp_pos = 0x7FFF; - - // Output left - voice_output( v, 0 ); -} -inline VOICE_CLOCK( V5 ) -{ - // Output right - voice_output( v, 1 ); - - // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier - int endx_buf = REG(endx) | m.t_looped; - - // Clear bit in ENDX if KON just began - if ( v->kon_delay == 5 ) - endx_buf &= ~v->vbit; - m.endx_buf = (uint8_t) endx_buf; -} -inline VOICE_CLOCK( V6 ) -{ - (void) v; // avoid compiler warning about unused v - m.outx_buf = (uint8_t) (m.t_output >> 8); -} -inline VOICE_CLOCK( V7 ) -{ - // Update ENDX - REG(endx) = m.endx_buf; - - m.envx_buf = v->t_envx_out; -} -inline VOICE_CLOCK( V8 ) -{ - // Update OUTX - VREG(v->regs,outx) = m.outx_buf; -} -inline VOICE_CLOCK( V9 ) -{ - // Update ENVX - VREG(v->regs,envx) = m.envx_buf; -} - -// Most voices do all these in one clock, so make a handy composite -inline VOICE_CLOCK( V3 ) -{ - voice_V3a( v ); - voice_V3b( v ); - voice_V3c( v ); -} - -// Common combinations of voice steps on different voices. This greatly reduces -// code size and allows everything to be inlined in these functions. -VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } -VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } -VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } - - -//// Echo - -// Current echo buffer pointer for left/right channel -#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) - -// Sample in echo history buffer, where 0 is the oldest -#define ECHO_FIR( i ) (m.echo_hist_pos [i]) - -// Calculate FIR point for left/right channel -#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) - -#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() - -inline void SPC_DSP::echo_read( int ch ) -{ - int s = GET_LE16SA( ECHO_PTR( ch ) ); - // second copy simplifies wrap-around handling - ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; -} - -ECHO_CLOCK( 22 ) -{ - // History - if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) - m.echo_hist_pos = m.echo_hist; - - m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; - echo_read( 0 ); - - // FIR (using l and r temporaries below helps compiler optimize) - int l = CALC_FIR( 0, 0 ); - int r = CALC_FIR( 0, 1 ); - - m.t_echo_in [0] = l; - m.t_echo_in [1] = r; -} -ECHO_CLOCK( 23 ) -{ - int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); - int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); - - m.t_echo_in [0] += l; - m.t_echo_in [1] += r; - - echo_read( 1 ); -} -ECHO_CLOCK( 24 ) -{ - int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); - int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); - - m.t_echo_in [0] += l; - m.t_echo_in [1] += r; -} -ECHO_CLOCK( 25 ) -{ - int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); - int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); - - l = (int16_t) l; - r = (int16_t) r; - - l += (int16_t) CALC_FIR( 7, 0 ); - r += (int16_t) CALC_FIR( 7, 1 ); - - CLAMP16( l ); - CLAMP16( r ); - - m.t_echo_in [0] = l & ~1; - m.t_echo_in [1] = r & ~1; -} -inline int SPC_DSP::echo_output( int ch ) -{ - int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + - (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); - CLAMP16( out ); - return out; -} -ECHO_CLOCK( 26 ) -{ - // Left output volumes - // (save sample for next clock so we can output both together) - m.t_main_out [0] = echo_output( 0 ); - - // Echo feedback - int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); - int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); - - CLAMP16( l ); - CLAMP16( r ); - - m.t_echo_out [0] = l & ~1; - m.t_echo_out [1] = r & ~1; -} -ECHO_CLOCK( 27 ) -{ - // Output - int l = m.t_main_out [0]; - int r = echo_output( 1 ); - m.t_main_out [0] = 0; - m.t_main_out [1] = 0; - - // TODO: global muting isn't this simple (turns DAC on and off - // or something, causing small ~37-sample pulse when first muted) - if ( REG(flg) & 0x40 ) - { - l = 0; - r = 0; - } - - // Output sample to DAC - #ifdef SPC_DSP_OUT_HOOK - SPC_DSP_OUT_HOOK( l, r ); - #else - sample_t* out = m.out; - WRITE_SAMPLES( l, r, out ); - m.out = out; - #endif -} -ECHO_CLOCK( 28 ) -{ - m.t_echo_enabled = REG(flg); -} -inline void SPC_DSP::echo_write( int ch ) -{ - if ( !(m.t_echo_enabled & 0x20) ) - SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); - m.t_echo_out [ch] = 0; -} -ECHO_CLOCK( 29 ) -{ - m.t_esa = REG(esa); - - if ( !m.echo_offset ) - m.echo_length = (REG(edl) & 0x0F) * 0x800; - - m.echo_offset += 4; - if ( m.echo_offset >= m.echo_length ) - m.echo_offset = 0; - - // Write left echo - echo_write( 0 ); - - m.t_echo_enabled = REG(flg); -} -ECHO_CLOCK( 30 ) -{ - // Write right echo - echo_write( 1 ); -} - - -//// Timing - -// Execute clock for a particular voice -#define V( clock, voice ) voice_##clock( &m.voices [voice] ); - -/* The most common sequence of clocks uses composite operations -for efficiency. For example, the following are equivalent to the -individual steps on the right: - -V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) -V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) -V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ - -// Voice 0 1 2 3 4 5 6 7 -#define GEN_DSP_TIMING \ -PHASE( 0) V(V5,0)V(V2,1)\ -PHASE( 1) V(V6,0)V(V3,1)\ -PHASE( 2) V(V7_V4_V1,0)\ -PHASE( 3) V(V8_V5_V2,0)\ -PHASE( 4) V(V9_V6_V3,0)\ -PHASE( 5) V(V7_V4_V1,1)\ -PHASE( 6) V(V8_V5_V2,1)\ -PHASE( 7) V(V9_V6_V3,1)\ -PHASE( 8) V(V7_V4_V1,2)\ -PHASE( 9) V(V8_V5_V2,2)\ -PHASE(10) V(V9_V6_V3,2)\ -PHASE(11) V(V7_V4_V1,3)\ -PHASE(12) V(V8_V5_V2,3)\ -PHASE(13) V(V9_V6_V3,3)\ -PHASE(14) V(V7_V4_V1,4)\ -PHASE(15) V(V8_V5_V2,4)\ -PHASE(16) V(V9_V6_V3,4)\ -PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ -PHASE(18) V(V8_V5_V2,5)\ -PHASE(19) V(V9_V6_V3,5)\ -PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ -PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ -PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ -PHASE(23) V(V7,7) echo_23();\ -PHASE(24) V(V8,7) echo_24();\ -PHASE(25) V(V3b,0) V(V9,7) echo_25();\ -PHASE(26) echo_26();\ -PHASE(27) misc_27(); echo_27();\ -PHASE(28) misc_28(); echo_28();\ -PHASE(29) misc_29(); echo_29();\ -PHASE(30) misc_30();V(V3c,0) echo_30();\ -PHASE(31) V(V4,0) V(V1,2)\ - -#if !SPC_DSP_CUSTOM_RUN - -void SPC_DSP::run( int clocks_remain ) -{ - require( clocks_remain > 0 ); - - int const phase = m.phase; - m.phase = (phase + clocks_remain) & 31; - switch ( phase ) - { - loop: - - #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: - GEN_DSP_TIMING - #undef PHASE - - if ( --clocks_remain ) - goto loop; - } -} - -#endif - - -//// Setup - -void SPC_DSP::init( void* ram_64k ) -{ - m.ram = (uint8_t*) ram_64k; - mute_voices( 0 ); - disable_surround( false ); - set_output( 0, 0 ); - reset(); - - #ifndef NDEBUG - // be sure this sign-extends - assert( (int16_t) 0x8000 == -0x8000 ); - - // be sure right shift preserves sign - assert( (-1 >> 1) == -1 ); - - // check clamp macro - int i; - i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); - i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); - - blargg_verify_byte_order(); - #endif -} - -void SPC_DSP::soft_reset_common() -{ - require( m.ram ); // init() must have been called already - - m.noise = 0x4000; - m.echo_hist_pos = m.echo_hist; - m.every_other_sample = 1; - m.echo_offset = 0; - m.phase = 0; - - init_counter(); -} - -void SPC_DSP::soft_reset() -{ - REG(flg) = 0xE0; - soft_reset_common(); -} - -void SPC_DSP::load( uint8_t const regs [register_count] ) -{ - memcpy( m.regs, regs, sizeof m.regs ); - memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); - - // Internal state - for ( int i = voice_count; --i >= 0; ) - { - voice_t* v = &m.voices [i]; - v->brr_offset = 1; - v->vbit = 1 << i; - v->regs = &m.regs [i * 0x10]; - } - m.new_kon = REG(kon); - m.t_dir = REG(dir); - m.t_esa = REG(esa); - - soft_reset_common(); -} - -void SPC_DSP::reset() { load( initial_regs ); } - - -//// State save/load - -#if !SPC_NO_COPY_STATE_FUNCS - -void SPC_State_Copier::copy( void* state, size_t size ) -{ - func( buf, state, size ); -} - -int SPC_State_Copier::copy_int( int state, int size ) -{ - BOOST::uint8_t s [2]; - SET_LE16( s, state ); - func( buf, &s, size ); - return GET_LE16( s ); -} - -void SPC_State_Copier::skip( int count ) -{ - if ( count > 0 ) - { - char temp [64]; - memset( temp, 0, sizeof temp ); - do - { - int n = sizeof temp; - if ( n > count ) - n = count; - count -= n; - func( buf, temp, n ); - } - while ( count ); - } -} - -void SPC_State_Copier::extra() -{ - int n = 0; - SPC_State_Copier& copier = *this; - SPC_COPY( uint8_t, n ); - skip( n ); -} - -void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) -{ - SPC_State_Copier copier( io, copy ); - - // DSP registers - copier.copy( m.regs, register_count ); - - // Internal state - - // Voices - int i; - for ( i = 0; i < voice_count; i++ ) - { - voice_t* v = &m.voices [i]; - - // BRR buffer - int i; - for ( i = 0; i < brr_buf_size; i++ ) - { - int s = v->buf [i]; - SPC_COPY( int16_t, s ); - v->buf [i] = v->buf [i + brr_buf_size] = s; - } - - SPC_COPY( uint16_t, v->interp_pos ); - SPC_COPY( uint16_t, v->brr_addr ); - SPC_COPY( uint16_t, v->env ); - SPC_COPY( int16_t, v->hidden_env ); - SPC_COPY( uint8_t, v->buf_pos ); - SPC_COPY( uint8_t, v->brr_offset ); - SPC_COPY( uint8_t, v->kon_delay ); - { - int m = v->env_mode; - SPC_COPY( uint8_t, m ); - v->env_mode = (enum env_mode_t) m; - } - SPC_COPY( uint8_t, v->t_envx_out ); - - copier.extra(); - } - - // Echo history - for ( i = 0; i < echo_hist_size; i++ ) - { - int j; - for ( j = 0; j < 2; j++ ) - { - int s = m.echo_hist_pos [i] [j]; - SPC_COPY( int16_t, s ); - m.echo_hist [i] [j] = s; // write back at offset 0 - } - } - m.echo_hist_pos = m.echo_hist; - memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); - - // Misc - SPC_COPY( uint8_t, m.every_other_sample ); - SPC_COPY( uint8_t, m.kon ); - - SPC_COPY( uint16_t, m.noise ); - SPC_COPY( uint16_t, m.counter ); - SPC_COPY( uint16_t, m.echo_offset ); - SPC_COPY( uint16_t, m.echo_length ); - SPC_COPY( uint8_t, m.phase ); - - SPC_COPY( uint8_t, m.new_kon ); - SPC_COPY( uint8_t, m.endx_buf ); - SPC_COPY( uint8_t, m.envx_buf ); - SPC_COPY( uint8_t, m.outx_buf ); - - SPC_COPY( uint8_t, m.t_pmon ); - SPC_COPY( uint8_t, m.t_non ); - SPC_COPY( uint8_t, m.t_eon ); - SPC_COPY( uint8_t, m.t_dir ); - SPC_COPY( uint8_t, m.t_koff ); - - SPC_COPY( uint16_t, m.t_brr_next_addr ); - SPC_COPY( uint8_t, m.t_adsr0 ); - SPC_COPY( uint8_t, m.t_brr_header ); - SPC_COPY( uint8_t, m.t_brr_byte ); - SPC_COPY( uint8_t, m.t_srcn ); - SPC_COPY( uint8_t, m.t_esa ); - SPC_COPY( uint8_t, m.t_echo_enabled ); - - SPC_COPY( int16_t, m.t_main_out [0] ); - SPC_COPY( int16_t, m.t_main_out [1] ); - SPC_COPY( int16_t, m.t_echo_out [0] ); - SPC_COPY( int16_t, m.t_echo_out [1] ); - SPC_COPY( int16_t, m.t_echo_in [0] ); - SPC_COPY( int16_t, m.t_echo_in [1] ); - - SPC_COPY( uint16_t, m.t_dir_addr ); - SPC_COPY( uint16_t, m.t_pitch ); - SPC_COPY( int16_t, m.t_output ); - SPC_COPY( uint16_t, m.t_echo_ptr ); - SPC_COPY( uint8_t, m.t_looped ); - - copier.extra(); -} -#endif diff --git a/waterbox/pizza/lib/snes_spc/SPC_DSP.h b/waterbox/pizza/lib/snes_spc/SPC_DSP.h deleted file mode 100644 index 4522ace915..0000000000 --- a/waterbox/pizza/lib/snes_spc/SPC_DSP.h +++ /dev/null @@ -1,304 +0,0 @@ -// Highly accurate SNES SPC-700 DSP emulator - -// snes_spc 0.9.0 -#ifndef SPC_DSP_H -#define SPC_DSP_H - -#include "blargg_common.h" - -extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } - -class SPC_DSP { -public: - typedef BOOST::uint8_t uint8_t; - -// Setup - - // Initializes DSP and has it use the 64K RAM provided - void init( void* ram_64k ); - - // Sets destination for output samples. If out is NULL or out_size is 0, - // doesn't generate any. - typedef short sample_t; - void set_output( sample_t* out, int out_size ); - - // Number of samples written to output since it was last set, always - // a multiple of 2. Undefined if more samples were generated than - // output buffer could hold. - int sample_count() const; - -// Emulation - - // Resets DSP to power-on state - void reset(); - - // Emulates pressing reset switch on SNES - void soft_reset(); - - // Reads/writes DSP registers. For accuracy, you must first call run() - // to catch the DSP up to present. - int read ( int addr ) const; - void write( int addr, int data ); - - // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks - // a pair of samples is be generated. - void run( int clock_count ); - -// Sound control - - // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). - // Reduces emulation accuracy. - enum { voice_count = 8 }; - void mute_voices( int mask ); - -// State - - // Resets DSP and uses supplied values to initialize registers - enum { register_count = 128 }; - void load( uint8_t const regs [register_count] ); - - // Saves/loads exact emulator state - enum { state_size = 640 }; // maximum space needed when saving - typedef dsp_copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); - - // Returns non-zero if new key-on events occurred since last call - bool check_kon(); - -// DSP register addresses - - // Global registers - enum { - r_mvoll = 0x0C, r_mvolr = 0x1C, - r_evoll = 0x2C, r_evolr = 0x3C, - r_kon = 0x4C, r_koff = 0x5C, - r_flg = 0x6C, r_endx = 0x7C, - r_efb = 0x0D, r_pmon = 0x2D, - r_non = 0x3D, r_eon = 0x4D, - r_dir = 0x5D, r_esa = 0x6D, - r_edl = 0x7D, - r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F - }; - - // Voice registers - enum { - v_voll = 0x00, v_volr = 0x01, - v_pitchl = 0x02, v_pitchh = 0x03, - v_srcn = 0x04, v_adsr0 = 0x05, - v_adsr1 = 0x06, v_gain = 0x07, - v_envx = 0x08, v_outx = 0x09 - }; - -public: - enum { extra_size = 16 }; - sample_t* extra() { return m.extra; } - sample_t const* out_pos() const { return m.out; } - void disable_surround( bool ) { } // not supported -public: - BLARGG_DISABLE_NOTHROW - - typedef BOOST::int8_t int8_t; - typedef BOOST::int16_t int16_t; - - enum { echo_hist_size = 8 }; - - enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; - enum { brr_buf_size = 12 }; - struct voice_t - { - int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) - int buf_pos; // place in buffer where next samples will be decoded - int interp_pos; // relative fractional position in sample (0x1000 = 1.0) - int brr_addr; // address of current BRR block - int brr_offset; // current decoding offset in BRR block - uint8_t* regs; // pointer to voice's DSP registers - int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. - int kon_delay; // KON delay/current setup phase - env_mode_t env_mode; - int env; // current envelope level - int hidden_env; // used by GAIN mode 7, very obscure quirk - uint8_t t_envx_out; - }; -private: - enum { brr_block_size = 9 }; - - struct state_t - { - uint8_t regs [register_count]; - - // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) - int echo_hist [echo_hist_size * 2] [2]; - int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] - - int every_other_sample; // toggles every sample - int kon; // KON value when last checked - int noise; - int counter; - int echo_offset; // offset from ESA in echo buffer - int echo_length; // number of bytes that echo_offset will stop at - int phase; // next clock cycle to run (0-31) - bool kon_check; // set when a new KON occurs - - // Hidden registers also written to when main register is written to - int new_kon; - uint8_t endx_buf; - uint8_t envx_buf; - uint8_t outx_buf; - - // Temporary state between clocks - - // read once per sample - int t_pmon; - int t_non; - int t_eon; - int t_dir; - int t_koff; - - // read a few clocks ahead then used - int t_brr_next_addr; - int t_adsr0; - int t_brr_header; - int t_brr_byte; - int t_srcn; - int t_esa; - int t_echo_enabled; - - // internal state that is recalculated every sample - int t_dir_addr; - int t_pitch; - int t_output; - int t_looped; - int t_echo_ptr; - - // left/right sums - int t_main_out [2]; - int t_echo_out [2]; - int t_echo_in [2]; - - voice_t voices [voice_count]; - - // non-emulation state - uint8_t* ram; // 64K shared RAM between DSP and SMP - int mute_mask; - sample_t* out; - sample_t* out_end; - sample_t* out_begin; - sample_t extra [extra_size]; - }; - state_t m; - - void init_counter(); - void run_counters(); - unsigned read_counter( int rate ); - - int interpolate( voice_t const* v ); - void run_envelope( voice_t* const v ); - void decode_brr( voice_t* v ); - - void misc_27(); - void misc_28(); - void misc_29(); - void misc_30(); - - void voice_output( voice_t const* v, int ch ); - void voice_V1( voice_t* const ); - void voice_V2( voice_t* const ); - void voice_V3( voice_t* const ); - void voice_V3a( voice_t* const ); - void voice_V3b( voice_t* const ); - void voice_V3c( voice_t* const ); - void voice_V4( voice_t* const ); - void voice_V5( voice_t* const ); - void voice_V6( voice_t* const ); - void voice_V7( voice_t* const ); - void voice_V8( voice_t* const ); - void voice_V9( voice_t* const ); - void voice_V7_V4_V1( voice_t* const ); - void voice_V8_V5_V2( voice_t* const ); - void voice_V9_V6_V3( voice_t* const ); - - void echo_read( int ch ); - int echo_output( int ch ); - void echo_write( int ch ); - void echo_22(); - void echo_23(); - void echo_24(); - void echo_25(); - void echo_26(); - void echo_27(); - void echo_28(); - void echo_29(); - void echo_30(); - - void soft_reset_common(); -}; - -#include - -inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } - -inline int SPC_DSP::read( int addr ) const -{ - assert( (unsigned) addr < register_count ); - return m.regs [addr]; -} - -inline void SPC_DSP::write( int addr, int data ) -{ - assert( (unsigned) addr < register_count ); - - m.regs [addr] = (uint8_t) data; - switch ( addr & 0x0F ) - { - case v_envx: - m.envx_buf = (uint8_t) data; - break; - - case v_outx: - m.outx_buf = (uint8_t) data; - break; - - case 0x0C: - if ( addr == r_kon ) - m.new_kon = (uint8_t) data; - - if ( addr == r_endx ) // always cleared, regardless of data written - { - m.endx_buf = 0; - m.regs [r_endx] = 0; - } - break; - } -} - -inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } - -inline bool SPC_DSP::check_kon() -{ - bool old = m.kon_check; - m.kon_check = 0; - return old; -} - -#if !SPC_NO_COPY_STATE_FUNCS - -class SPC_State_Copier { - SPC_DSP::copy_func_t func; - unsigned char** buf; -public: - SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } - void copy( void* state, size_t size ); - int copy_int( int state, int size ); - void skip( int count ); - void extra(); -}; - -#define SPC_COPY( type, state )\ -{\ - state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\ - assert( (BOOST::type) state == state );\ -} - -#endif - -#endif diff --git a/waterbox/pizza/lib/snes_spc/SPC_Filter.cpp b/waterbox/pizza/lib/snes_spc/SPC_Filter.cpp deleted file mode 100644 index b3d5770822..0000000000 --- a/waterbox/pizza/lib/snes_spc/SPC_Filter.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SPC_Filter.h" - -#include - -/* Copyright (C) 2007 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 */ - -#include "blargg_source.h" - -void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); } - -SPC_Filter::SPC_Filter() -{ - gain = gain_unit; - bass = bass_norm; - clear(); -} - -void SPC_Filter::run( short* io, int count ) -{ - require( (count & 1) == 0 ); // must be even - - int const gain = this->gain; - int const bass = this->bass; - chan_t* c = &ch [2]; - do - { - // cache in registers - int sum = (--c)->sum; - int pp1 = c->pp1; - int p1 = c->p1; - - for ( int i = 0; i < count; i += 2 ) - { - // Low-pass filter (two point FIR with coeffs 0.25, 0.75) - int f = io [i] + p1; - p1 = io [i] * 3; - - // High-pass filter ("leaky integrator") - int delta = f - pp1; - pp1 = f; - int s = sum >> (gain_bits + 2); - sum += (delta * gain) - (sum >> bass); - - // Clamp to 16 bits - if ( (short) s != s ) - s = (s >> 31) ^ 0x7FFF; - - io [i] = (short) s; - } - - c->p1 = p1; - c->pp1 = pp1; - c->sum = sum; - ++io; - } - while ( c != ch ); -} diff --git a/waterbox/pizza/lib/snes_spc/SPC_Filter.h b/waterbox/pizza/lib/snes_spc/SPC_Filter.h deleted file mode 100644 index d5c83cb8f1..0000000000 --- a/waterbox/pizza/lib/snes_spc/SPC_Filter.h +++ /dev/null @@ -1,47 +0,0 @@ -// Simple low-pass and high-pass filter to better match sound output of a SNES - -// snes_spc 0.9.0 -#ifndef SPC_FILTER_H -#define SPC_FILTER_H - -#include "blargg_common.h" - -struct SPC_Filter { -public: - - // Filters count samples of stereo sound in place. Count must be a multiple of 2. - typedef short sample_t; - void run( sample_t* io, int count ); - -// Optional features - - // Clears filter to silence - void clear(); - - // Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit - // are fine, since output is clamped to 16-bit sample range. - enum { gain_unit = 0x100 }; - void set_gain( int gain ); - - // Sets amount of bass (logarithmic scale) - enum { bass_none = 0 }; - enum { bass_norm = 8 }; // normal amount - enum { bass_max = 31 }; - void set_bass( int bass ); - -public: - SPC_Filter(); - BLARGG_DISABLE_NOTHROW -private: - enum { gain_bits = 8 }; - int gain; - int bass; - struct chan_t { int p1, pp1, sum; }; - chan_t ch [2]; -}; - -inline void SPC_Filter::set_gain( int g ) { gain = g; } - -inline void SPC_Filter::set_bass( int b ) { bass = b; } - -#endif diff --git a/waterbox/pizza/lib/snes_spc/blargg_common.h b/waterbox/pizza/lib/snes_spc/blargg_common.h deleted file mode 100644 index 75edff3914..0000000000 --- a/waterbox/pizza/lib/snes_spc/blargg_common.h +++ /dev/null @@ -1,186 +0,0 @@ -// Sets up common environment for Shay Green's libraries. -// To change configuration options, modify blargg_config.h, not this file. - -// snes_spc 0.9.0 -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -#include -#include -#include -#include - -#undef BLARGG_COMMON_H -// allow blargg_config.h to #include blargg_common.h -#include "blargg_config.h" -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -// BLARGG_RESTRICT: equivalent to restrict, where supported -#if defined (__GNUC__) || _MSC_VER >= 1100 - #define BLARGG_RESTRICT __restrict -#else - #define BLARGG_RESTRICT -#endif - -// STATIC_CAST(T,expr): Used in place of static_cast (expr) -#ifndef STATIC_CAST - #define STATIC_CAST(T,expr) ((T) (expr)) -#endif - -// blargg_err_t (0 on success, otherwise error string) -#ifndef blargg_err_t - typedef const char* blargg_err_t; -#endif - -// blargg_vector - very lightweight vector of POD types (no constructor/destructor) -template -class blargg_vector { - T* begin_; - size_t size_; -public: - blargg_vector() : begin_( 0 ), size_( 0 ) { } - ~blargg_vector() { free( begin_ ); } - size_t size() const { return size_; } - T* begin() const { return begin_; } - T* end() const { return begin_ + size_; } - blargg_err_t resize( size_t n ) - { - // TODO: blargg_common.cpp to hold this as an outline function, ugh - void* p = realloc( begin_, n * sizeof (T) ); - if ( p ) - begin_ = (T*) p; - else if ( n > size_ ) // realloc failure only a problem if expanding - return "Out of memory"; - size_ = n; - return 0; - } - void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } - T& operator [] ( size_t n ) const - { - assert( n <= size_ ); // <= to allow past-the-end value - return begin_ [n]; - } -}; - -#ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if operator new can return NULL - #if __cplusplus >= 199711 || defined (__GNUC__) - #define BLARGG_THROWS( spec ) throw spec - #else - #define BLARGG_THROWS( spec ) - #endif - #define BLARGG_DISABLE_NOTHROW \ - void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ - void operator delete ( void* p ) { free( p ); } - #define BLARGG_NEW new -#else - #include - #define BLARGG_NEW new (std::nothrow) -#endif - -// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) -#define BLARGG_4CHAR( a, b, c, d ) \ - ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) - -// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. -#ifndef BOOST_STATIC_ASSERT - #ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) - #else - // Some other compilers fail when declaring same function multiple times in class, - // so differentiate them by line - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) - #endif -#endif - -// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, -// compiler is assumed to support bool. If undefined, availability is determined. -#ifndef BLARGG_COMPILER_HAS_BOOL - #if defined (__MWERKS__) - #if !__option(bool) - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (_MSC_VER) - #if _MSC_VER < 1100 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (__GNUC__) - // supports bool - #elif __cplusplus < 199711 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif -#endif -#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL - // If you get errors here, modify your blargg_config.h file - typedef int bool; - const bool true = 1; - const bool false = 0; -#endif - -// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough - -#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF - typedef long blargg_long; -#else - typedef int blargg_long; -#endif - -#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF - typedef unsigned long blargg_ulong; -#else - typedef unsigned blargg_ulong; -#endif - -// BOOST::int8_t etc. - -// HAVE_STDINT_H: If defined, use for int8_t etc. -#if defined (HAVE_STDINT_H) - #include - #define BOOST - -// HAVE_INTTYPES_H: If defined, use for int8_t etc. -#elif defined (HAVE_INTTYPES_H) - #include - #define BOOST - -#else - struct BOOST - { - #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F - typedef signed char int8_t; - typedef unsigned char uint8_t; - #else - // No suitable 8-bit type available - typedef struct see_blargg_common_h int8_t; - typedef struct see_blargg_common_h uint8_t; - #endif - - #if USHRT_MAX == 0xFFFF - typedef short int16_t; - typedef unsigned short uint16_t; - #else - // No suitable 16-bit type available - typedef struct see_blargg_common_h int16_t; - typedef struct see_blargg_common_h uint16_t; - #endif - - #if ULONG_MAX == 0xFFFFFFFF - typedef long int32_t; - typedef unsigned long uint32_t; - #elif UINT_MAX == 0xFFFFFFFF - typedef int int32_t; - typedef unsigned int uint32_t; - #else - // No suitable 32-bit type available - typedef struct see_blargg_common_h int32_t; - typedef struct see_blargg_common_h uint32_t; - #endif - }; -#endif - -#endif -#endif diff --git a/waterbox/pizza/lib/snes_spc/blargg_config.h b/waterbox/pizza/lib/snes_spc/blargg_config.h deleted file mode 100644 index 9dc69db836..0000000000 --- a/waterbox/pizza/lib/snes_spc/blargg_config.h +++ /dev/null @@ -1,24 +0,0 @@ -// snes_spc 0.9.0 user configuration file. Don't replace when updating library. - -// snes_spc 0.9.0 -#ifndef BLARGG_CONFIG_H -#define BLARGG_CONFIG_H - -// Uncomment to disable debugging checks -//#define NDEBUG 1 - -// Uncomment to enable platform-specific (and possibly non-portable) optimizations -//#define BLARGG_NONPORTABLE 1 - -// Uncomment if automatic byte-order determination doesn't work -//#define BLARGG_BIG_ENDIAN 1 - -// Uncomment if you get errors in the bool section of blargg_common.h -//#define BLARGG_COMPILER_HAS_BOOL 1 - -// Use standard config.h if present -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#endif diff --git a/waterbox/pizza/lib/snes_spc/blargg_endian.h b/waterbox/pizza/lib/snes_spc/blargg_endian.h deleted file mode 100644 index f2daca6416..0000000000 --- a/waterbox/pizza/lib/snes_spc/blargg_endian.h +++ /dev/null @@ -1,185 +0,0 @@ -// CPU Byte Order Utilities - -// snes_spc 0.9.0 -#ifndef BLARGG_ENDIAN -#define BLARGG_ENDIAN - -#include "blargg_common.h" - -// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) -#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ - defined (__x86_64__) || defined (__ia64__) || defined (__i386__) - #define BLARGG_CPU_X86 1 - #define BLARGG_CPU_CISC 1 -#endif - -#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) - #define BLARGG_CPU_POWERPC 1 - #define BLARGG_CPU_RISC 1 -#endif - -// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only -// one may be #defined to 1. Only needed if something actually depends on byte order. -#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) -#ifdef __GLIBC__ - // GCC handles this for us - #include - #if __BYTE_ORDER == __LITTLE_ENDIAN - #define BLARGG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER == __BIG_ENDIAN - #define BLARGG_BIG_ENDIAN 1 - #endif -#else - -#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ - (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) - #define BLARGG_LITTLE_ENDIAN 1 -#endif - -#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ - defined (__sparc__) || BLARGG_CPU_POWERPC || \ - (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) - #define BLARGG_BIG_ENDIAN 1 -#elif !defined (__mips__) - // No endian specified; assume little-endian, since it's most common - #define BLARGG_LITTLE_ENDIAN 1 -#endif -#endif -#endif - -#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN - #undef BLARGG_LITTLE_ENDIAN - #undef BLARGG_BIG_ENDIAN -#endif - -inline void blargg_verify_byte_order() -{ - #ifndef NDEBUG - #if BLARGG_BIG_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i == 0 ); - #elif BLARGG_LITTLE_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i != 0 ); - #endif - #endif -} - -inline unsigned get_le16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 8 | - (unsigned) ((unsigned char const*) p) [1]; -} - -inline blargg_ulong get_le32( void const* p ) -{ - return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | - (blargg_ulong) ((unsigned char const*) p) [2] << 16 | - (blargg_ulong) ((unsigned char const*) p) [1] << 8 | - (blargg_ulong) ((unsigned char const*) p) [0]; -} - -inline blargg_ulong get_be32( void const* p ) -{ - return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | - (blargg_ulong) ((unsigned char const*) p) [1] << 16 | - (blargg_ulong) ((unsigned char const*) p) [2] << 8 | - (blargg_ulong) ((unsigned char const*) p) [3]; -} - -inline void set_le16( void* p, unsigned n ) -{ - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [0] = (unsigned char) n; -} - -inline void set_be16( void* p, unsigned n ) -{ - ((unsigned char*) p) [0] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) n; -} - -inline void set_le32( void* p, blargg_ulong n ) -{ - ((unsigned char*) p) [0] = (unsigned char) n; - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [2] = (unsigned char) (n >> 16); - ((unsigned char*) p) [3] = (unsigned char) (n >> 24); -} - -inline void set_be32( void* p, blargg_ulong n ) -{ - ((unsigned char*) p) [3] = (unsigned char) n; - ((unsigned char*) p) [2] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) (n >> 16); - ((unsigned char*) p) [0] = (unsigned char) (n >> 24); -} - -#if BLARGG_NONPORTABLE - // Optimized implementation if byte order is known - #if BLARGG_LITTLE_ENDIAN - #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) - #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) - #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - #elif BLARGG_BIG_ENDIAN - #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) - #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) - #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) - #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) - - #if BLARGG_CPU_POWERPC - // PowerPC has special byte-reversed instructions - #if defined (__MWERKS__) - #define GET_LE16( addr ) (__lhbrx( addr, 0 )) - #define GET_LE32( addr ) (__lwbrx( addr, 0 )) - #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) - #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) - #elif defined (__GNUC__) - #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) - #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) - #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) - #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) - #endif - #endif - #endif -#endif - -#ifndef GET_LE16 - #define GET_LE16( addr ) get_le16( addr ) - #define SET_LE16( addr, data ) set_le16( addr, data ) -#endif - -#ifndef GET_LE32 - #define GET_LE32( addr ) get_le32( addr ) - #define SET_LE32( addr, data ) set_le32( addr, data ) -#endif - -#ifndef GET_BE16 - #define GET_BE16( addr ) get_be16( addr ) - #define SET_BE16( addr, data ) set_be16( addr, data ) -#endif - -#ifndef GET_BE32 - #define GET_BE32( addr ) get_be32( addr ) - #define SET_BE32( addr, data ) set_be32( addr, data ) -#endif - -// auto-selecting versions - -inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } -inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } -inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } -inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } -inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } -inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } -inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } -inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } - -#endif diff --git a/waterbox/pizza/lib/snes_spc/blargg_source.h b/waterbox/pizza/lib/snes_spc/blargg_source.h deleted file mode 100644 index 5e45c4fb42..0000000000 --- a/waterbox/pizza/lib/snes_spc/blargg_source.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Included at the beginning of library source files, after all other #include lines. -Sets up helpful macros and services used in my source code. They don't need -module an annoying module prefix on their names since they are defined after -all other #include lines. */ - -// snes_spc 0.9.0 -#ifndef BLARGG_SOURCE_H -#define BLARGG_SOURCE_H - -// If debugging is enabled, abort program if expr is false. Meant for checking -// internal state and consistency. A failed assertion indicates a bug in the module. -// void assert( bool expr ); -#include - -// If debugging is enabled and expr is false, abort program. Meant for checking -// caller-supplied parameters and operations that are outside the control of the -// module. A failed requirement indicates a bug outside the module. -// void require( bool expr ); -#undef require -#define require( expr ) assert( expr ) - -// Like printf() except output goes to debug log file. Might be defined to do -// nothing (not even evaluate its arguments). -// void dprintf( const char* format, ... ); -static inline void blargg_dprintf_( const char*, ... ) { } -#undef dprintf -#define dprintf (1) ? (void) 0 : blargg_dprintf_ - -// If enabled, evaluate expr and if false, make debug log entry with source file -// and line. Meant for finding situations that should be examined further, but that -// don't indicate a problem. In all cases, execution continues normally. -#undef check -#define check( expr ) ((void) 0) - -// If expr yields error string, return it from current function, otherwise continue. -#undef RETURN_ERR -#define RETURN_ERR( expr ) do { \ - blargg_err_t blargg_return_err_ = (expr); \ - if ( blargg_return_err_ ) return blargg_return_err_; \ - } while ( 0 ) - -// If ptr is 0, return out of memory error string. -#undef CHECK_ALLOC -#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) - -// Avoid any macros which evaluate their arguments multiple times -#undef min -#undef max - -#define DEF_MIN_MAX( type ) \ - static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ - static inline type max( type x, type y ) { if ( y < x ) return x; return y; } - -DEF_MIN_MAX( int ) -DEF_MIN_MAX( unsigned ) -DEF_MIN_MAX( long ) -DEF_MIN_MAX( unsigned long ) -DEF_MIN_MAX( float ) -DEF_MIN_MAX( double ) - -#undef DEF_MIN_MAX - -/* -// using const references generates crappy code, and I am currenly only using these -// for built-in types, so they take arguments by value - -// TODO: remove -inline int min( int x, int y ) -template -inline T min( T x, T y ) -{ - if ( x < y ) - return x; - return y; -} - -template -inline T max( T x, T y ) -{ - if ( x < y ) - return y; - return x; -} -*/ - -// TODO: good idea? bad idea? -#undef byte -#define byte byte_ -typedef unsigned char byte; - -// deprecated -#define BLARGG_CHECK_ALLOC CHECK_ALLOC -#define BLARGG_RETURN_ERR RETURN_ERR - -// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check -#ifdef BLARGG_SOURCE_BEGIN - #include BLARGG_SOURCE_BEGIN -#endif - -#endif diff --git a/waterbox/pizza/lib/snes_spc/changes.txt b/waterbox/pizza/lib/snes_spc/changes.txt deleted file mode 100644 index 33661832b4..0000000000 --- a/waterbox/pizza/lib/snes_spc/changes.txt +++ /dev/null @@ -1,107 +0,0 @@ -snes_spc Change Log -------------------- - -snes_spc 0.9.0 --------------- -- Improved documentation - -- SPC: Added spc_skip() function for quickly seeking in an SPC music -file. Runs 3-4x faster than normal playback using the fast DSP (or about -43-60X real-time on my 400 MHz Mac). - -- SPC: Added spc_set_tempo() to change tempo of SPC music playback. - -- SPC: Sample generation is now corrected to generate exactly one pair -of samples every 32 clocks without exception. Before it could generate a -few samples more or less depending on how far ahead or behind DSP was at -the moment. - -- SPC: Changed spc_reset() and spc_soft_reset() to also reset output -buffer (see spc.h). - -- SPC: Fixed minor timer counting bug. - -- SPC: Stack pointer wrap-around is now emulated (and without any -noticeable performance hit). - -- SPC: Runs about 5% faster due to various optimizations. - -- SPC: Found way to make fast DSP register accesses cycle-accurate in -most cases, without reducing performance. Allows fast DSP to pass most -of my validation tests. - -- DSP: Added surround disable support to fast DSP again. - -- DSP: Improved voice un-muting to take effect immediately on fast DSP. - -- DSP: Noise shift register now starts at 0x4000 instead of 0x4001 as it -incorrectly did before. - -- Converted library to C++ code internally. A C interface is still -included in spc.h and dsp.h. Note that these are different than the -previous interface, so your code will require minor changes: - - Old SPC code New SPC code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #include "spc/spc.h" #include "snes_spc/spc.h" - - snes_spc_t* spc; SNES_SPC* spc; - spc = malloc( sizeof (snes_spc_t) ); spc = spc_new(); - spc_init( spc ); - - spc_end_frame( time ); spc_end_frame( spc, time ); - /* etc. */ - - /* done using SPC */ spc_delete( spc ); - - - Old DSP code New DSP code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #include "spc/spc_dsp.h" #include "snes_spc/dsp.h" - - spc_dsp_init( ram ); SPC_DSP* dsp; - dsp = spc_dsp_new(); - spc_dsp_init( dsp, ram ); - - spc_dsp_run( count ); spc_dsp_run( dsp, count ); - /* etc. */ - - /* done using DSP */ spc_dsp_delete( dsp ); - - -snes_spc 0.8.0 --------------- -- Added several demos - -- Added high-pass/low-pass filter to better match SNES sound - -- Added save state functionality for SPC and accurate DSP (but not fast -DSP) - -- Added emulation of reset switch on NES (soft reset) - -- Made source more compatible with pre-C99 compilers by eliminating -mid-block declarations - -- SPC: Many S-SMP accuracy improvements, mostly in memory access times - -- SPC: S-SMP speed improvements - -- SPC: Added SPC load/save functions and KON checking to help trim -silence from beginning - -- SPC: Changed spc_init() to have you allocate most of the memory used -by the library so you have more control over it - -- DSP: New highly accurate DSP and faster version derived from same code - -- DSP: Changed prefix from dsp_ to spc_dsp_. Your DSP code will require -changes. - -- DSP: Removed surround disable and gain. Gain can now be done with the -dsp_filter module, and surround disable will probably only be -implemented in the fast DSP at some point. - -- DSP: Changed interface to work in clocks rather than samples, -necessary for the new accurate DSP. Sample output is now done with -separate functions. Your DSP code will require changes. diff --git a/waterbox/pizza/lib/snes_spc/dsp.cpp b/waterbox/pizza/lib/snes_spc/dsp.cpp deleted file mode 100644 index 99d0cf5c5e..0000000000 --- a/waterbox/pizza/lib/snes_spc/dsp.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "dsp.h" - -#include "SPC_DSP.h" - -/* Copyright (C) 2007 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 */ - -#include "blargg_source.h" - -SPC_DSP* spc_dsp_new( void ) -{ - // be sure constants match - assert( spc_dsp_voice_count == (int) SPC_DSP::voice_count ); - assert( spc_dsp_register_count == (int) SPC_DSP::register_count ); - #if !SPC_NO_COPY_STATE_FUNCS - assert( spc_dsp_state_size == (int) SPC_DSP::state_size ); - #endif - - return new SPC_DSP; -} - -void spc_dsp_delete ( SPC_DSP* s ) { delete s; } -void spc_dsp_init ( SPC_DSP* s, void* ram_64k ) { s->init( ram_64k ); } -void spc_dsp_set_output ( SPC_DSP* s, spc_dsp_sample_t* p, int n ) { s->set_output( p, n ); } -int spc_dsp_sample_count( SPC_DSP const* s ) { return s->sample_count(); } -void spc_dsp_reset ( SPC_DSP* s ) { s->reset(); } -void spc_dsp_soft_reset ( SPC_DSP* s ) { s->soft_reset(); } -int spc_dsp_read ( SPC_DSP const* s, int addr ) { return s->read( addr ); } -void spc_dsp_write ( SPC_DSP* s, int addr, int data ) { s->write( addr, data ); } -void spc_dsp_run ( SPC_DSP* s, int clock_count ) { s->run( clock_count ); } -void spc_dsp_mute_voices ( SPC_DSP* s, int mask ) { s->mute_voices( mask ); } -void spc_dsp_disable_surround( SPC_DSP* s, int disable ) { s->disable_surround( disable ); } -void spc_dsp_load ( SPC_DSP* s, unsigned char const regs [spc_dsp_register_count] ) { s->load( regs ); } - -#if !SPC_NO_COPY_STATE_FUNCS -void spc_dsp_copy_state ( SPC_DSP* s, unsigned char** p, spc_dsp_copy_func_t f ) { s->copy_state( p, f ); } -int spc_dsp_check_kon ( SPC_DSP* s ) { return s->check_kon(); } -#endif diff --git a/waterbox/pizza/lib/snes_spc/dsp.h b/waterbox/pizza/lib/snes_spc/dsp.h deleted file mode 100644 index 59867d92f9..0000000000 --- a/waterbox/pizza/lib/snes_spc/dsp.h +++ /dev/null @@ -1,83 +0,0 @@ -/* SNES SPC-700 DSP emulator C interface (also usable from C++) */ - -/* snes_spc 0.9.0 */ -#ifndef DSP_H -#define DSP_H - -#include - -#ifdef __cplusplus - extern "C" { -#endif - -typedef struct SPC_DSP SPC_DSP; - -/* Creates new DSP emulator. NULL if out of memory. */ -SPC_DSP* spc_dsp_new( void ); - -/* Frees DSP emulator */ -void spc_dsp_delete( SPC_DSP* ); - -/* Initializes DSP and has it use the 64K RAM provided */ -void spc_dsp_init( SPC_DSP*, void* ram_64k ); - -/* Sets destination for output samples. If out is NULL or out_size is 0, -doesn't generate any. */ -typedef short spc_dsp_sample_t; -void spc_dsp_set_output( SPC_DSP*, spc_dsp_sample_t* out, int out_size ); - -/* Number of samples written to output since it was last set, always -a multiple of 2. Undefined if more samples were generated than -output buffer could hold. */ -int spc_dsp_sample_count( SPC_DSP const* ); - - -/**** Emulation *****/ - -/* Resets DSP to power-on state */ -void spc_dsp_reset( SPC_DSP* ); - -/* Emulates pressing reset switch on SNES */ -void spc_dsp_soft_reset( SPC_DSP* ); - -/* Reads/writes DSP registers. For accuracy, you must first call spc_dsp_run() */ -/* to catch the DSP up to present. */ -int spc_dsp_read ( SPC_DSP const*, int addr ); -void spc_dsp_write( SPC_DSP*, int addr, int data ); - -/* Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks */ -/* a pair of samples is be generated. */ -void spc_dsp_run( SPC_DSP*, int clock_count ); - - -/**** Sound control *****/ - -/* Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */ -enum { spc_dsp_voice_count = 8 }; -void spc_dsp_mute_voices( SPC_DSP*, int mask ); - -/* If true, prevents channels and global volumes from being phase-negated. -Only supported by fast DSP; has no effect on accurate DSP. */ -void spc_dsp_disable_surround( SPC_DSP*, int disable ); - - -/**** State save/load *****/ - -/* Resets DSP and uses supplied values to initialize registers */ -enum { spc_dsp_register_count = 128 }; -void spc_dsp_load( SPC_DSP*, unsigned char const regs [spc_dsp_register_count] ); - -/* Saves/loads exact emulator state (accurate DSP only) */ -enum { spc_dsp_state_size = 640 }; /* maximum space needed when saving */ -typedef void (*spc_dsp_copy_func_t)( unsigned char** io, void* state, size_t ); -void spc_dsp_copy_state( SPC_DSP*, unsigned char** io, spc_dsp_copy_func_t ); - -/* Returns non-zero if new key-on events occurred since last call (accurate DSP only) */ -int spc_dsp_check_kon( SPC_DSP* ); - - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/waterbox/pizza/lib/snes_spc/license.txt b/waterbox/pizza/lib/snes_spc/license.txt deleted file mode 100644 index 5faba9d48c..0000000000 --- a/waterbox/pizza/lib/snes_spc/license.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library 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 library 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 library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/waterbox/pizza/lib/snes_spc/readme.txt b/waterbox/pizza/lib/snes_spc/readme.txt deleted file mode 100644 index 979913f0ac..0000000000 --- a/waterbox/pizza/lib/snes_spc/readme.txt +++ /dev/null @@ -1,86 +0,0 @@ -snes_spc 0.9.0: SNES SPC-700 APU Emulator ------------------------------------------ -This library includes a full SPC emulator and an S-DSP emulator that can -be used on its own. Two S-DSP emulators are available: a highly accurate -one for use in a SNES emulator, and a 3x faster one for use in an SPC -music player or a resource-limited SNES emulator. - -* Can be used from C and C++ code -* Full SPC-700 APU emulator with cycle accuracy in most cases -* Loads, plays, and saves SPC music files -* Can save and load exact full emulator state -* DSP voice muting, surround sound disable, and song tempo adjustment -* Uses 7% CPU average on 400 MHz Mac to play an SPC using fast DSP - -The accurate DSP emulator is based on past research by others and -hundreds of hours of recent research by me. It passes over a hundred -strenuous timing and behavior validation tests that were also run on the -SNES. As far as I know, it's the first DSP emulator with cycle accuracy, -properly emulating every DSP register and memory access at the exact SPC -cycle it occurs at, whereas previous DSP emulators emulated these only -to the nearest sample (which occurs every 32 clocks). - -Author : Shay Green -Website: http://www.slack.net/~ant/ -Forum : http://groups.google.com/group/blargg-sound-libs -License: GNU Lesser General Public License (LGPL) - - -Getting Started ---------------- -Build a program consisting of demo/play_spc.c, demo/demo_util.c, -demo/wave_writer.c, and all source files in snes_spc/. Put an SPC music -file in the same directory and name it "test.spc". Running the program -should generate the recording "out.wav". - -Read snes_spc.txt for more information. Post to the discussion forum for -assistance. - - -Files ------ -snes_spc.txt Documentation -changes.txt Change log -license.txt GNU LGPL license - -demo/ - play_spc.c Records SPC file to wave sound file - benchmark.c Finds how fast emulator runs on your computer - trim_spc.c Trims silence off beginning of an SPC file - save_state.c Saves/loads exact emulator state to/from file - comm.c Communicates with SPC how SNES would - demo_util.h General utility functions used by demos - demo_util.c - wave_writer.h WAVE sound file writer used for demo output - wave_writer.c - -fast_dsp/ Optional standalone fast DSP emulator - SPC_DSP.h To use with full SPC emulator, move into - SPC_DSP.cpp snes_spc/ and replace original files - -snes_spc/ Library sources - blargg_config.h Configuration (modify as necessary) - - spc.h C interface to SPC emulator and sound filter - spc.cpp - - SPC_Filter.h Optional filter to make sound more authentic - SPC_Filter.cpp - - SNES_SPC.h Full SPC emulator - SNES_SPC.cpp - SNES_SPC_misc.cpp - SNES_SPC_state.cpp - SPC_CPU.h - - dsp.h C interface to DSP emulator - dsp.cpp - - SPC_DSP.h Standalone accurate DSP emulator - SPC_DSP.cpp - blargg_common.h - blargg_endian.h - blargg_source.h - --- -Shay Green diff --git a/waterbox/pizza/lib/snes_spc/snes_spc.txt b/waterbox/pizza/lib/snes_spc/snes_spc.txt deleted file mode 100644 index d37b34347f..0000000000 --- a/waterbox/pizza/lib/snes_spc/snes_spc.txt +++ /dev/null @@ -1,318 +0,0 @@ -snes_spc 0.9.0: SNES SPC-700 APU Emulator ------------------------------------------ -Author : Shay Green -Website: http://www.slack.net/~ant/ -Forum : http://groups.google.com/group/blargg-sound-libs -License: GNU Lesser General Public License (LGPL) - - -Contents --------- -* C and C++ Interfaces -* Overview -* Full SPC Emulation -* DSP Emulation -* SPC Music Playback -* State Copying -* Library Compilation -* Error handling -* Solving Problems -* Accurate S-DSP Limitations -* Fast S-DSP Limitations -* S-SMP Limitations -* To Do -* Thanks - - -C and C++ Interfaces --------------------- -The library includes a C interface in spc.h and dsp.h, which can be used -from C and C++. This C interface is referred to in the following -documentation. If you're building this as a shared library (rather than -linking statically), you should use the C interface since it will change -less in future versions. - -The native C++ interface is in the header files SNES_SPC.h, SPC_DSP.h, -and SPC_Filter.h, and the two interfaces can be freely mixed in C++ -code. Conversion between the two interfaces generally follows a pattern: - - C interface C++ interface - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SNES_SPC* spc; SNES_SPC* spc; - - spc = spc_new(); spc = new SNES_SPC; - - spc_play( spc, count, buf ); spc->play( count, buf ); - - spc_sample_rate SNES_SPC::sample_rate - - spc_delete( spc ); delete spc; - - -Overview --------- -There are three main roles for this library: -* Full SPC emulation in a SNES emulator -* DSP emulation in a SNES emulator (where you emulate the SMP CPU) -* SPC playback in an SPC music file player - -Each of these uses are described separately below. - - -Full SPC Emulation ------------------- -See spc.h for full function reference (SNES_SPC.h if using C++). - -* Create SPC emulator with spc_new() and check for NULL. - -* Call spc_init_rom() with a pointer to the 64-byte IPL ROM dump (not -included with library). - -* When your emulated SNES is powered on, call spc_reset(). When the -reset switch is pressed, call spc_soft_reset(). - -* Call spc_set_output() with your output buffer, then do emulation. - -* When the SNES CPU accesses APU ports, call spc_read_port() and -spc_write_port(). - -* When your emulator's timebase is going back to 0, call -spc_end_frame(), usually at the end of a video frame or scanline. - -* Periodically play samples from your buffer. Use spc_sample_count() to -find out how many samples have been written, then spc_set_output() after -you've made more space in your buffer. - -* Save/load full emulator state with spc_copy_state(). - -* You can save as an SPC music file with spc_save_spc(). - -* When done, use spc_delete() to free memory. - - -DSP Emulation -------------- -See dsp.h for full function reference (SPC_DSP.h if using C++). - -* Create DSP emulator with spc_dsp_new() and check for NULL. - -* Let the DSP know where your 64K RAM is with spc_dsp_init(). - -* When your emulated SNES is powered on, call spc_dsp_reset(). When the -reset switch is pressed, call spc_dsp_soft_reset(). - -* Call spc_dsp_set_output() with your output buffer, then do emulation. - -* Use spc_dsp_run() to run DSP for specified number of clocks (1024000 -per second). Every 32 clocks a pair of samples is added to your output -buffer. - -* Use spc_dsp_read() and spc_dsp_write() to handle DSP reads/writes from -the S-SMP. Before calling these always catch the DSP up to present time -with spc_dsp_run(). - -* Periodically play samples from your buffer. Use spc_dsp_sample_count() -to find out how many samples have been written, then -spc_dsp_set_output() after you've made more space in your buffer. - -* Use spc_dsp_copy_state() to save/load full DSP state. - -* When done, use spc_delete() to free memory. - - -SPC Music Playback ------------------- -See spc.h for full function reference (SNES_SPC.h if using C++). - -* Create SPC emulator with spc_new() and check for NULL. - -* Load SPC with spc_load_spc() and check for error. - -* Optionally cear echo buffer with spc_clear_echo(). Many SPCs have -garbage in echo buffer, which causes noise at the beginning. - -* Generate samples as needed with spc_play(). - -* When done, use spc_delete() to free memory. - -* For a more complete game music playback library, use Game_Music_Emu - - -State Copying -------------- -The SPC and DSP modules include state save/load functions. They take a -pointer to a pointer to a buffer to store state, and a copy function. -This copy function can either copy data to the buffer or from it, -allowing state save and restore with the same library function. The -internal save state format allows for future expansion without making -previous save states unusable. - -The SPC save state format puts the most important parts first to make it -easier to manually examine. It's organized as follows: - -Offset Size Data -- - - - - - - - - - - - - - - - - - - 0 $10000 SPC RAM -$10000 $10 SMP $F0-$FF registers -$10010 4 SMP $F4-$F8 output registers -$10014 2 PC -$10016 1 A -$10017 1 X -$10018 1 Y -$10019 1 PSW -$1001A 1 SP -$1001B 5 internal -$10020 $80 DSP registers -$100A0 ... internal - - -Library Compilation -------------------- -While this library is in C++, it has been written to easily link in a C -program *without* needing the standard C++ library. It doesn't use -exception handling or run-time type information (RTTI), so you can -disable these in your C++ compiler to increase efficiency. - -If you're building a shared library (DLL), I recommend only exporting -the C interfaces in spc.h and dsp.h, as the C++ interfaces expose -implementation details that will break link compatibility across -versions. - -If you're using C and compiling with GCC, I recommend the following -command-line options when compiling the library source, otherwise GCC -will insert calls to the standard C++ library and require that it be -linked in: - - -fno-rtti -fno-exceptions - -For maximum optimization, see the NDEBUG and BLARGG_NONPORTABLE options -in blargg_config. If using GCC, you can enable these by adding the -following command-line options when you invoke gcc. If you encounter -problems, try without -DBLARGG_NONPORTABLE; if that works, contact me so -I can figure out why BLARGG_NONPORTABLE was causing it to fail. - - -O3 -DNDEBUG -DBLARGG_NONPORTABLE -fno-rtti -fno-exceptions - - - -Error handling --------------- -Functions which can fail have a return type of spc_err_t (blargg_err_t -in the C++ interfaces), which is a pointer to an error string (const -char*). If a function is successful it returns NULL. Errors that you can -easily avoid are checked with debug assertions; spc_err_t return values -are only used for genuine run-time errors that can't be easily predicted -in advance (out of memory, I/O errors, incompatible file data). Your -code should check all error values. - -To improve usability for C programmers, C++ programmers unfamiliar with -exceptions, and compatibility with older C++ compilers, the library does -*not* throw any C++ exceptions and uses malloc() instead of the standard -operator new. This means that you *must* check for NULL when creating a -library object with the new operator. - - -Solving Problems ----------------- -If you're having problems, try the following: - -* If you're getting garbled sound, try this simple siren generator in -place of your call to play(). This will quickly tell whether the problem -is in the library or in your code. - - static void play_siren( long count, short* out ) - { - static double a, a2; - while ( count-- ) - *out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) ); - } - -* Enable debugging support in your environment. This enables assertions -and other run-time checks. - -* Turn the compiler's optimizer is off. Sometimes an optimizer generates -bad code. - -* If multiple threads are being used, ensure that only one at a time is -accessing a given set of objects from the library. This library is not -in general thread-safe, though independent objects can be used in -separate threads. - -* If all else fails, see if the demos work. - - -Accurate S-DSP Limitations --------------------------- -* Power-up and soft reset behavior might have slight inaccuracies. - -* Muting (FLG bit 6) behavior when toggling bit very rapidly is not -emulated properly. - -* No other known inaccuracies. Has passed 100+ strenuous tests. - - -Fast S-DSP Limitations ----------------------- -* Uses faster sample calculations except in cases where exact value is -actually important (BRR decoding, and gaussian interpolation combined -with pitch modulation). - -* Stops decoding BRR data when a voice's envelope has released to -silence. - -* Emulates 32 clocks at a time, so DSP register and memory accesses are -all done in a bunch rather than spread out. Even though, some clever -code makes register accesses separated by 40 or so clocks occur with -cycle-accurate timing. - - -S-SMP Limitations ------------------ -* Opcode fetches and indirect pointers are always read directly from -memory, even for the $F0-$FF region, and the DSP is not caught up for -these fetches. - -* Attempts to perversely execute data in registers or an area being -modified by echo will not be emulated properly. - -* Has not been thoroughly tested. - -* Test register ($F0) is not implemented. - -* Echo buffer can overwrite IPL ROM area, and does not correctly update -extra RAM there. - - -To Do ------ -* I'd like feedback on the interface and any ways to improve it. In -particular, the differing features between the accurate and fast DSP -emulators might make it harder to cleanly switch between them without -modifying source code. - -* Finish thorough tests on SMP memory access times. - -* Finish thorough tests on SMP instruction behavior (flags, registers). - -* Finish thorough tests on SMP timers. - -* Finish power-up and reset behavior testing. - -* Come up with best starting conditions to play an SPC and implement in -hardware SNES SPC player for verification. - - -Thanks ------- -Thanks to Anti-Resonance's SPC2ROM and help getting SPCs playing on my -SNES in the first place, then Brad Martin's openspc and Chris Moeller's -openspc++ C++ adaptation, giving me a good SPC emulator to start with -several years ago. Thanks to Richard Bannister, Mahendra Tallur, Shazz, -nenolod, theHobbit, Johan Samuelsson, nes6502, and Micket for helping -test my Game_Music_Emu library. Thanks to hcs for help in converting to -C for the Rockbox port. Thanks to byuu (bsnes author) and pagefault and -Nach (zsnes team) for testing and using my new rewritten DSP in their -emulators. Thanks to anomie for his good SNES documentation and -discussions with me to keep it up to date with my latest findings. --- -Shay Green diff --git a/waterbox/pizza/lib/snes_spc/spc.cpp b/waterbox/pizza/lib/snes_spc/spc.cpp deleted file mode 100644 index 4e5a77ef15..0000000000 --- a/waterbox/pizza/lib/snes_spc/spc.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "spc.h" - -#include "SNES_SPC.h" -#include "SPC_Filter.h" - -/* Copyright (C) 2004-2007 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 */ - -#include "blargg_source.h" - -SNES_SPC* spc_new( void ) -{ - // be sure constants match - assert( spc_sample_rate == (int) SNES_SPC::sample_rate ); - assert( spc_rom_size == (int) SNES_SPC::rom_size ); - assert( spc_clock_rate == (int) SNES_SPC::clock_rate ); - assert( spc_clocks_per_sample == (int) SNES_SPC::clocks_per_sample ); - assert( spc_port_count == (int) SNES_SPC::port_count ); - assert( spc_voice_count == (int) SNES_SPC::voice_count ); - assert( spc_tempo_unit == (int) SNES_SPC::tempo_unit ); - assert( spc_file_size == (int) SNES_SPC::spc_file_size ); - #if !SPC_NO_COPY_STATE_FUNCS - assert( spc_state_size == (int) SNES_SPC::state_size ); - #endif - - SNES_SPC* s = new SNES_SPC; - if ( s && s->init() ) - { - delete s; - s = 0; - } - return s; -} - -void spc_delete ( SNES_SPC* s ) { delete s; } -void spc_init_rom ( SNES_SPC* s, unsigned char const r [64] ) { s->init_rom( r ); } -void spc_set_output ( SNES_SPC* s, spc_sample_t* p, int n ) { s->set_output( p, n ); } -int spc_sample_count ( SNES_SPC const* s ) { return s->sample_count(); } -void spc_reset ( SNES_SPC* s ) { s->reset(); } -void spc_soft_reset ( SNES_SPC* s ) { s->soft_reset(); } -int spc_read_port ( SNES_SPC* s, spc_time_t t, int p ) { return s->read_port( t, p ); } -void spc_write_port ( SNES_SPC* s, spc_time_t t, int p, int d ) { s->write_port( t, p, d ); } -void spc_end_frame ( SNES_SPC* s, spc_time_t t ) { s->end_frame( t ); } -void spc_mute_voices ( SNES_SPC* s, int mask ) { s->mute_voices( mask ); } -void spc_disable_surround( SNES_SPC* s, int disable ) { s->disable_surround( disable ); } -void spc_set_tempo ( SNES_SPC* s, int tempo ) { s->set_tempo( tempo ); } -uint8_t* spc_get_ram(SNES_SPC* s) { return s->get_ram(); } -spc_err_t spc_load_spc ( SNES_SPC* s, void const* p, long n ) { return s->load_spc( p, n ); } -void spc_clear_echo ( SNES_SPC* s ) { s->clear_echo(); } -spc_err_t spc_play ( SNES_SPC* s, int count, short* out ) { return s->play( count, out ); } -spc_err_t spc_skip ( SNES_SPC* s, int count ) { return s->skip( count ); } -#if !SPC_NO_COPY_STATE_FUNCS -void spc_copy_state ( SNES_SPC* s, unsigned char** p, spc_copy_func_t f ) { s->copy_state( p, f ); } -void spc_init_header ( void* spc_out ) { SNES_SPC::init_header( spc_out ); } -void spc_save_spc ( SNES_SPC* s, void* spc_out ) { s->save_spc( spc_out ); } -int spc_check_kon ( SNES_SPC* s ) { return s->check_kon(); } -#endif - -SPC_Filter* spc_filter_new( void ) { return new SPC_Filter; } -void spc_filter_delete( SPC_Filter* f ) { delete f; } -void spc_filter_run( SPC_Filter* f, spc_sample_t* p, int s ) { f->run( p, s ); } -void spc_filter_clear( SPC_Filter* f ) { f->clear(); } -void spc_filter_set_gain( SPC_Filter* f, int gain ) { f->set_gain( gain ); } -void spc_filter_set_bass( SPC_Filter* f, int bass ) { f->set_bass( bass ); } diff --git a/waterbox/pizza/lib/snes_spc/spc.h b/waterbox/pizza/lib/snes_spc/spc.h deleted file mode 100644 index cf23f3c945..0000000000 --- a/waterbox/pizza/lib/snes_spc/spc.h +++ /dev/null @@ -1,149 +0,0 @@ -/* SNES SPC-700 APU emulator C interface (also usable from C++) */ - -/* snes_spc 0.9.0 */ -#ifndef SPC_H -#define SPC_H - -#include -#include - -#ifdef __cplusplus - extern "C" { -#endif - -/* Error string return. NULL if success, otherwise error message. */ -typedef const char* spc_err_t; - -typedef struct SNES_SPC SNES_SPC; - -/* Creates new SPC emulator. NULL if out of memory. */ -SNES_SPC* spc_new( void ); - -/* Frees SPC emulator */ -void spc_delete( SNES_SPC* ); - -/* Sample pairs generated per second */ -enum { spc_sample_rate = 32000 }; - - -/**** Emulator use ****/ - -/* Sets IPL ROM data. Library does not include ROM data. Most SPC music files -don't need ROM, but a full emulator must provide this. */ -enum { spc_rom_size = 0x40 }; -void spc_init_rom( SNES_SPC*, unsigned char const rom [spc_rom_size] ); - -/* Sets destination for output samples */ -typedef short spc_sample_t; -void spc_set_output( SNES_SPC*, spc_sample_t* out, int out_size ); - -/* Number of samples written to output since last set */ -int spc_sample_count( SNES_SPC const* ); - -/* Resets SPC to power-on state. This resets your output buffer, so you must -call spc_set_output() after this. */ -void spc_reset( SNES_SPC* ); - -/* Emulates pressing reset switch on SNES. This resets your output buffer, so -you must call spc_set_output() after this. */ -void spc_soft_reset( SNES_SPC* ); - -/* 1024000 SPC clocks per second, sample pair every 32 clocks */ -typedef int spc_time_t; -enum { spc_clock_rate = 1024000 }; -enum { spc_clocks_per_sample = 32 }; - -/* Reads/writes port at specified time */ -enum { spc_port_count = 4 }; -int spc_read_port ( SNES_SPC*, spc_time_t, int port ); -void spc_write_port( SNES_SPC*, spc_time_t, int port, int data ); - -/* Runs SPC to end_time and starts a new time frame at 0 */ -void spc_end_frame( SNES_SPC*, spc_time_t end_time ); - -uint8_t* spc_get_ram(SNES_SPC*); - -/**** Sound control ****/ - -/*Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */ -enum { spc_voice_count = 8 }; -void spc_mute_voices( SNES_SPC*, int mask ); - -/* If true, prevents channels and global volumes from being phase-negated. -Only supported by fast DSP; has no effect on accurate DSP. */ -void spc_disable_surround( SNES_SPC*, int disable ); - -/* Sets tempo, where spc_tempo_unit = normal, spc_tempo_unit / 2 = half speed, etc. */ -enum { spc_tempo_unit = 0x100 }; -void spc_set_tempo( SNES_SPC*, int ); - - -/**** SPC music playback *****/ - -/* Loads SPC data into emulator. Returns NULL on success, otherwise error string. */ -spc_err_t spc_load_spc( SNES_SPC*, void const* spc_in, long size ); - -/* Clears echo region. Useful after loading an SPC as many have garbage in echo. */ -void spc_clear_echo( SNES_SPC* ); - -/* Plays for count samples and write samples to out. Discards samples if out -is NULL. Count must be a multiple of 2 since output is stereo. */ -spc_err_t spc_play( SNES_SPC*, int count, short* out ); - -/* Skips count samples. Several times faster than spc_play(). */ -spc_err_t spc_skip( SNES_SPC*, int count ); - - -/**** State save/load (only available with accurate DSP) ****/ - -/* Saves/loads exact emulator state */ -enum { spc_state_size = 67 * 1024L }; /* maximum space needed when saving */ -typedef void (*spc_copy_func_t)( unsigned char** io, void* state, size_t ); -void spc_copy_state( SNES_SPC*, unsigned char** io, spc_copy_func_t ); - -/* Writes minimal SPC file header to spc_out */ -void spc_init_header( void* spc_out ); - -/* Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. -Does not set up SPC header; use spc_init_header() for that. */ -enum { spc_file_size = 0x10200 }; /* spc_out must have this many bytes allocated */ -void spc_save_spc( SNES_SPC*, void* spc_out ); - -/* Returns non-zero if new key-on events occurred since last check. Useful for -trimming silence while saving an SPC. */ -int spc_check_kon( SNES_SPC* ); - - -/**** SPC_Filter ****/ - -typedef struct SPC_Filter SPC_Filter; - -/* Creates new filter. NULL if out of memory. */ -SPC_Filter* spc_filter_new( void ); - -/* Frees filter */ -void spc_filter_delete( SPC_Filter* ); - -/* Filters count samples of stereo sound in place. Count must be a multiple of 2. */ -void spc_filter_run( SPC_Filter*, spc_sample_t* io, int count ); - -/* Clears filter to silence */ -void spc_filter_clear( SPC_Filter* ); - -/* Sets gain (volume), where spc_filter_gain_unit is normal. Gains greater than -spc_filter_gain_unit are fine, since output is clamped to 16-bit sample range. */ -enum { spc_filter_gain_unit = 0x100 }; -void spc_filter_set_gain( SPC_Filter*, int gain ); - -/* Sets amount of bass (logarithmic scale) */ -enum { spc_filter_bass_none = 0 }; -enum { spc_filter_bass_norm = 8 }; /* normal amount */ -enum { spc_filter_bass_max = 31 }; -void spc_filter_set_bass( SPC_Filter*, int bass ); - - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/waterbox/pizza/lib/sound.c b/waterbox/pizza/lib/sound.c deleted file mode 100644 index 183e07a6b7..0000000000 --- a/waterbox/pizza/lib/sound.c +++ /dev/null @@ -1,1159 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include "cycles.h" -#include "global.h" -#include "gpu.h" -#include "mmu.h" -#include "sound.h" -#include "utils.h" -#include "sound_output.h" - -#include -#include -#include - -/* super variable for audio controller */ -sound_t sound; - -// functions to connect to blip buf -static int16_t last_sample[8]; - -#define BLIP_LEFT(v,i) if(1){int32_t d = (v)-last_sample[(i)*2];blip_left(d);last_sample[(i)*2] = (v);} -#define BLIP_RIGHT(v,i) if(1){int32_t d = (v)-last_sample[(i)*2+1];blip_right(d);last_sample[(i)*2+1] = (v);} - -static void blip_ch1() -{ - if (sound.channel_one.active) - { - if (sound.nr51->ch1_to_so1) - BLIP_RIGHT(sound.channel_one.sample, 0); - if (sound.nr51->ch1_to_so2) - BLIP_LEFT(sound.channel_one.sample, 0); - } -} -static void blip_ch2() -{ - if (sound.channel_two.active) - { - if (sound.nr51->ch2_to_so1) - BLIP_RIGHT(sound.channel_two.sample, 1); - if (sound.nr51->ch2_to_so2) - BLIP_LEFT(sound.channel_two.sample, 1); - } -} -static void blip_ch3() -{ - if (sound.channel_three.active) - { - uint16_t sample; - uint8_t shift = sound.nr32->volume_code == 0 ? 4 : sound.nr32->volume_code - 1; - - /* volume is zero in any case */ - if (shift == 4) - sample = 0; - else - { - /* apply volume change */ - uint8_t idx = sound.channel_three.index; - uint16_t s; - - /* extract current sample */ - if ((idx & 0x01) == 0) - s = (sound.wave_table[idx >> 1] & 0xf0) >> 4; - else - s = sound.wave_table[idx >> 1] & 0x0f; - - /* transform it into signed 16 bit sample */ - sample = ((s * 0x222) >> shift); - } - - if (sound.nr51->ch3_to_so1) - BLIP_RIGHT(sample, 2); - if (sound.nr51->ch3_to_so2) - BLIP_LEFT(sample, 2); - } -} -static void blip_ch4() -{ - if (sound.channel_four.active) - { - if (sound.nr51->ch4_to_so1) - BLIP_RIGHT(sound.channel_four.sample, 3); - if (sound.nr51->ch4_to_so2) - BLIP_LEFT(sound.channel_four.sample, 3); - } -} - -/* internal prototypes */ -void sound_envelope_step(); -void sound_length_ctrl_step(); -void sound_sweep_step(); -void sound_write_wave(uint16_t a, uint8_t v); - -void sound_init_pointers() -{ - /* point sound structures to their memory areas */ - sound.nr10 = (nr10_t *) mmu_addr(0xFF10); - sound.nr11 = (nr11_t *) mmu_addr(0xFF11); - sound.nr12 = (nr12_t *) mmu_addr(0xFF12); - sound.nr13 = (nr13_t *) mmu_addr(0xFF13); - sound.nr14 = (nr14_t *) mmu_addr(0xFF14); - - sound.nr21 = (nr21_t *) mmu_addr(0xFF16); - sound.nr22 = (nr22_t *) mmu_addr(0xFF17); - sound.nr23 = (nr23_t *) mmu_addr(0xFF18); - sound.nr24 = (nr24_t *) mmu_addr(0xFF19); - - sound.nr30 = (nr30_t *) mmu_addr(0xFF1A); - sound.nr31 = (nr31_t *) mmu_addr(0xFF1B); - sound.nr32 = (nr32_t *) mmu_addr(0xFF1C); - sound.nr33 = (nr33_t *) mmu_addr(0xFF1D); - sound.nr34 = (nr34_t *) mmu_addr(0xFF1E); - - sound.nr41 = (nr41_t *) mmu_addr(0xFF20); - sound.nr42 = (nr42_t *) mmu_addr(0xFF21); - sound.nr43 = (nr43_t *) mmu_addr(0xFF22); - sound.nr44 = (nr44_t *) mmu_addr(0xFF23); - - sound.nr50 = mmu_addr(0xFF24); - sound.nr51 = mmu_addr(0xFF25); - sound.nr52 = mmu_addr(0xFF26); - - sound.wave_table = mmu_addr(0xFF30); -} - -/* init sound states */ -void sound_init() -{ - /* reset structure */ - bzero(&sound, sizeof(sound_t)); - - /* point sound structures to their memory areas */ - sound_init_pointers(); - - /* how many cpu cycles we need to emit a 512hz clock (frame sequencer) */ - sound.fs_cycles = 4194304 / 512; - - /* how many cpu cycles to generate a single frame seq clock? */ - sound.fs_cycles_next = sound.fs_cycles; -} - -void sound_set_speed(char dbl) -{ -} - -/* update sound internal state given CPU T-states */ -void sound_step_fs() -{ - /* rotate from 0 to 7 */ - sound.fs_cycles_idx = (sound.fs_cycles_idx + 1) & 0x07; - - /* reset fs cycles counter */ - sound.fs_cycles_next = cycles.cnt + - (sound.fs_cycles << global_cpu_double_speed); - - /* length controller works at 256hz */ - if ((sound.fs_cycles_idx & 0x01) == 0) - sound_length_ctrl_step(); - - /* sweep works at 128hz */ - if (sound.fs_cycles_idx == 2 || sound.fs_cycles_idx == 6) - sound_sweep_step(); - - /* envelope works at 64hz */ - if (sound.fs_cycles_idx == 7) - sound_envelope_step(); - blip_ch1(); - blip_ch2(); - blip_ch3(); - blip_ch4(); -} - -/* update all channels */ -void sound_step_ch1() -{ - /* recalc current samples */ - if ((sound.channel_one.duty >> sound.channel_one.duty_idx) & 0x01) - sound.channel_one.sample = sound.channel_one.volume; - else - sound.channel_one.sample = -sound.channel_one.volume; - - /* step to the next duty value */ - sound.channel_one.duty_idx = - (sound.channel_one.duty_idx + 1) & 0x07; - - /* go back */ - sound.channel_one.duty_cycles_next += sound.channel_one.duty_cycles; - blip_ch1(); -} - -void sound_step_ch2() -{ - /* recalc current samples */ - if ((sound.channel_two.duty >> sound.channel_two.duty_idx) & 0x01) - sound.channel_two.sample = sound.channel_two.volume; - else - sound.channel_two.sample = -sound.channel_two.volume; - - /* step to the next duty value */ - sound.channel_two.duty_idx = - (sound.channel_two.duty_idx + 1) & 0x07; - - /* go back */ - sound.channel_two.duty_cycles_next += sound.channel_two.duty_cycles; - blip_ch2(); -} - -void sound_step_ch3() -{ - /* switch to the next wave sample */ - sound.channel_three.index = (sound.channel_three.index + 1) & 0x1F; - - /* set the new current sample */ - sound.channel_three.sample = - sound.channel_three.wave[sound.channel_three.index]; - - /* reload new period */ - uint_fast16_t freq = sound.nr33->frequency_lsb | - (sound.nr34->frequency_msb << 8); - - /* qty of cpu ticks needed for a wave sample change */ - sound.channel_three.cycles = ((2048 - freq) * 2) << global_cpu_double_speed; - sound.channel_three.cycles_next += sound.channel_three.cycles; - blip_ch3(); -} - -void sound_step_ch4() -{ - /* update LSFR */ - if (sound.nr43->shift < 14) - { - /* shift register one bit right */ - uint16_t s = sound.channel_four.reg >> 1; - - /* xor current register and the shifted version */ - /* and extract bit zero */ - uint16_t x = (sound.channel_four.reg ^ s) & 1; - - /* update register */ - sound.channel_four.reg = s | x << 14; - - /* if width is set... */ - if (sound.nr43->width) - sound.channel_four.reg = - (sound.channel_four.reg & 0xBF) | x << 6; - } - - /* update sample */ - if (sound.channel_four.reg & 0x01) - sound.channel_four.sample = -sound.channel_four.volume; - else - sound.channel_four.sample = sound.channel_four.volume; - - /* qty of cpu ticks needed for a wave sample change */ - sound.channel_four.cycles_next += sound.channel_four.period_lfsr; - blip_ch4(); -} - -/* update length of channel1 */ -void static inline sound_length_ctrl_step_ch(char length_enable, - uint_fast32_t *length, - uint8_t *active) -{ - if (length_enable && *length != 0) - { - (*length)--; - - /* if ZERO is reached, turn off the channel */ - if (*length == 0) - *active = 0; - } -} - -/* length controller step */ -void sound_length_ctrl_step() -{ - /* step every channel */ - sound_length_ctrl_step_ch(sound.nr14->length_enable, - &sound.channel_one.length, - &sound.channel_one.active); - - sound_length_ctrl_step_ch(sound.nr24->length_enable, - &sound.channel_two.length, - &sound.channel_two.active); - - sound_length_ctrl_step_ch(sound.nr34->length_enable, - &sound.channel_three.length, - &sound.channel_three.active); - - sound_length_ctrl_step_ch(sound.nr44->length_enable, - &sound.channel_four.length, - &sound.channel_four.active); -} - -/* calc the new frequency by sweep module */ -uint_fast32_t sound_sweep_calc() -{ - uint_fast32_t new_freq; - - /* time to update frequency */ - uint_fast32_t diff = - sound.channel_one.sweep_shadow_frequency >> - sound.nr10->shift; - - /* the calculated diff must be summed or subtracted to frequency */ - if (sound.nr10->negate) - { - new_freq = sound.channel_one.sweep_shadow_frequency - diff; - sound.channel_one.sweep_neg = 1; - } - else - new_freq = sound.channel_one.sweep_shadow_frequency + diff; - - /* if freq > 2047, turn off the channel */ - if (new_freq > 2047) - sound.channel_one.active = 0; - - return new_freq; -} - -/* set channel one new frequency */ -void sound_set_frequency(uint_fast32_t new_freq) -{ - /* too high? */ - if (new_freq > 2047) - { - sound.channel_one.active = 0; - return; - } - - /* update with the new frequency */ - sound.channel_one.frequency = new_freq; - - /* update them also into memory */ - sound.nr13->frequency_lsb = (uint8_t) (new_freq & 0x000000ff); - sound.nr14->frequency_msb = (uint8_t) ((new_freq >> 8) & 0x00000007); - - /* update the duty cycles */ - sound.channel_one.duty_cycles = - ((2048 - new_freq) * 4) << global_cpu_double_speed; - - /* and reset them */ - sound.channel_one.duty_cycles_next = - cycles.cnt + sound.channel_one.duty_cycles; -} - -/* step of frequency sweep at 128hz */ -void sound_sweep_step() -{ - uint_fast32_t new_freq; - - if (sound.channel_one.active && - sound.channel_one.sweep_active) - { - /* make it rotate from 0 to 8 */ - sound.channel_one.sweep_cnt++; - - /* enough cycles? */ - if (sound.channel_one.sweep_cnt == sound.channel_one.sweep_next) - { - /* reload the next step - 0 is treated as 8 */ - sound.channel_one.sweep_next = - sound.nr10->sweep_period ? - sound.nr10->sweep_period : 8; - - /* reset sweep counter */ - sound.channel_one.sweep_cnt = 0; - - /* period must be > 0 if new freq gotta be updated */ - if (sound.nr10->sweep_period == 0) - return; - - /* calc new frequency */ - new_freq = sound_sweep_calc(); - - /* set it only if < 2048 and shift != 0 */ - if (sound.nr10->shift && - new_freq < 2048) - { - /* copy new_freq into shadow register */ - sound.channel_one.sweep_shadow_frequency = new_freq; - - /* update all the stuff related to new frequency */ - sound_set_frequency(new_freq); - - /* update freq again (but only in shadow register) */ - sound_sweep_calc(); - } - } - } -} - -/* step of envelope at 64hz */ -void sound_envelope_step() -{ - if (sound.channel_one.active && sound.nr12->period) - { - /* update counter */ - sound.channel_one.envelope_cnt++; - - /* if counter reaches period, update volume */ - if (sound.channel_one.envelope_cnt == sound.nr12->period) - { - if (sound.nr12->add) - { - if (sound.channel_one.volume < (14 * 0x111)) - sound.channel_one.volume += 0x111; - } - else - { - if (sound.channel_one.volume >= 0x111) - sound.channel_one.volume -= 0x111; - } - - /* reset counter */ - sound.channel_one.envelope_cnt = 0; - } - } - - if (sound.channel_two.active && sound.nr22->period) - { - /* update counter */ - sound.channel_two.envelope_cnt++; - - /* if counter reaches period, update volume */ - if (sound.channel_two.envelope_cnt == sound.nr22->period) - { - if (sound.nr22->add) - { - if (sound.channel_two.volume < (14 * 0x111)) - sound.channel_two.volume += 0x111; - } - else - { - if (sound.channel_two.volume >= 0x111) - sound.channel_two.volume -= 0x111; - } - - /* reset counter */ - sound.channel_two.envelope_cnt = 0; - } - } - - if (sound.channel_four.active && sound.nr42->period) - { - /* update counter */ - sound.channel_four.envelope_cnt++; - - /* if counter reaches period, update volume */ - if (sound.channel_four.envelope_cnt == sound.nr42->period) - { - if (sound.nr42->add) - { - if (sound.channel_four.volume < (14 * 0x111)) - sound.channel_four.volume += 0x111; - } - else - { - if (sound.channel_four.volume > 0x111) - sound.channel_four.volume -= 0x111; - } - - /* reset counter */ - sound.channel_four.envelope_cnt = 0; - } - } -} - -uint8_t sound_read_reg(uint16_t a, uint8_t v) -{ - switch (a) - { - /* NR1X */ - case 0xFF10: return v | 0x80; - case 0xFF11: return v | 0x3F; - case 0xFF12: return v; - case 0xFF13: return v | 0xFF; - case 0xFF14: return v | 0xBF; - /* NR2X */ - case 0xFF15: return v | 0xFF; - case 0xFF16: return v | 0x3F; - case 0xFF17: return v; - case 0xFF18: return v | 0xFF; - case 0xFF19: return v | 0xBF; - /* NR3X */ - case 0xFF1A: return v | 0x7F; - case 0xFF1B: return v | 0xFF; - case 0xFF1C: return v | 0x9F; - case 0xFF1D: return v | 0xFF; - case 0xFF1E: return v | 0xBF; - /* NR4X */ - case 0xFF1F: return v | 0xFF; - case 0xFF20: return v | 0xFF; - case 0xFF21: return v; - case 0xFF22: return v; - case 0xFF23: return v | 0xBF; - /* NR5X */ - case 0xFF24: return v; - case 0xFF25: return v; - case 0xFF26: - if (sound.nr52->power) - return 0xf0 | - sound.channel_one.active | - (sound.channel_two.active << 1) | - (sound.channel_three.active << 2) | - (sound.channel_four.active << 3); - else - return 0x70; - case 0xFF27: - case 0xFF28: - case 0xFF29: - case 0xFF2A: - case 0xFF2B: - case 0xFF2C: - case 0xFF2D: - case 0xFF2E: - case 0xFF2F: return 0xFF; - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - if (sound.channel_three.active) - { -/* if (!global_cgb && sound.channel_three.ram_access != 0) - { - printf("RAM ACCESSO NON ZERO %u - CNT %d NEXT %d\n", - sound.channel_three.ram_access, cycles.cnt, sound.channel_three.ram_access_next); - return 0xFF; - }*/ - if (!global_cgb && - cycles.cnt < sound.channel_three.ram_access_next) - return 0xFF; - - return sound.wave_table[sound.channel_three.index >> 1]; - } - - default: return v; - } -} - -void sound_write_reg(uint16_t a, uint8_t v) -{ - /* when turned off, only write to NR52 (0xFF26) is legit */ - if (!sound.nr52->power && a != 0xFF26) - { - /* CGB mode doesnt allow any write on register during power off */ - if (global_cgb) - return; - - /* in DMG mode, update length is legit while no power */ - switch (a) - { - case 0xFF11: sound.channel_one.length = 64 - (v & 0x3f); return; - case 0xFF16: sound.channel_two.length = 64 - (v & 0x3f); return; - case 0xFF1B: sound.channel_three.length = 256 - v; return; - case 0xFF20: sound.channel_four.length = 64 - (v & 0x3f); return; - default: return; - } - } - - /* wave write */ - if (a >= 0xFF30 && a <= 0xFF3F) - return sound_write_wave(a, v); - - /* save old value */ - uint8_t old = *((uint8_t *) mmu_addr(a)); - - /* confirm write on memory */ - *((uint8_t *) mmu_addr(a)) = v; - - switch (a) - { - case 0xFF10: - - if (!sound.nr10->negate && sound.channel_one.sweep_neg) - sound.channel_one.active = 0; - - break; - - case 0xFF11: - - /* set length as 64 - length_load */ - sound.channel_one.length = 64 - sound.nr11->length_load; - - /* update duty type */ - switch (sound.nr11->duty) - { - /* 12.5 % */ - case 0x00: sound.channel_one.duty = 0x80; - break; - - /* 25% */ - case 0x01: sound.channel_one.duty = 0x81; - break; - - /* 50% */ - case 0x02: sound.channel_one.duty = 0xE1; - break; - - /* 75% */ - case 0x03: sound.channel_one.duty = 0x7E; - break; - } - - break; - - case 0xFF12: - - /* volume 0 = turn off the DAC = turn off channeru */ - if (sound.nr12->volume == 0 && - sound.nr12->add == 0) - sound.channel_one.active = 0; - - break; - - case 0xFF13: - - /* update frequncy */ - sound.channel_one.frequency = sound.nr13->frequency_lsb | - (sound.nr14->frequency_msb << 8); - - /* update duty cycles */ - sound.channel_one.duty_cycles = - ((2048 - sound.channel_one.frequency) * 4) - << global_cpu_double_speed; - - break; - - case 0xFF14: - - /* length counter turned on */ - if (sound.nr14->length_enable) - { - nr14_t *old_nr14 = (nr14_t *) &old; - - /* give an extra length clock if */ - /* 1) we switched from off to on the len counter */ - /* 2) we are in the first half of len clock */ - /* 3) actual length is not zero */ - if ((old_nr14->length_enable == 0) && - ((sound.fs_cycles_idx & 0x01) == 0x00) && - (sound.channel_one.length != 0)) - sound_length_ctrl_step_ch(sound.nr14->length_enable, - &sound.channel_one.length, - &sound.channel_one.active); - } - - /* always update frequency, even if it's not a trigger */ - sound.channel_one.frequency = sound.nr13->frequency_lsb | - (sound.nr14->frequency_msb << 8); - - /* qty of cpu ticks needed for a duty change */ - /* (1/8 of wave cycle) */ - sound.channel_one.duty_cycles = - ((2048 - sound.channel_one.frequency) * 4) - << global_cpu_double_speed; - - if (v & 0x80) - { - /* if we switch from OFF to ON, reset duty idx */ - if (sound.channel_two.active == 0) - sound.channel_two.duty_idx = 0; - - /* setting internal modules data with stuff taken from memory */ - sound.channel_one.active = 1; - sound.channel_one.duty_cycles_next = - cycles.cnt + sound.channel_one.duty_cycles; - - /* set the 8 phase of a duty cycle by setting 8 bits */ - switch (sound.nr11->duty) - { - /* 12.5 % */ - case 0x00: sound.channel_one.duty = 0x80; - break; - - /* 25% */ - case 0x01: sound.channel_one.duty = 0x81; - break; - - /* 50% */ - case 0x02: sound.channel_one.duty = 0xE1; - break; - - /* 75% */ - case 0x03: sound.channel_one.duty = 0x7E; - break; - } - - /* calc length */ - if (sound.channel_one.length == 0) - sound.channel_one.length = 64; - - /* base volume */ - sound.channel_one.volume = - sound.nr12->volume * 0x111; - - /* reset envelope counter */ - sound.channel_one.envelope_cnt = 0; - - /* save current freq into sweep shadow register */ - sound.channel_one.sweep_shadow_frequency = - sound.channel_one.frequency; - - /* reset sweep timer */ - sound.channel_one.sweep_cnt = 0; - - /* reset sweep neg bool */ - sound.channel_one.sweep_neg = 0; - - /* reload the next step */ - sound.channel_one.sweep_next = sound.nr10->sweep_period ? - sound.nr10->sweep_period : 8; - - /* set sweep as active if period != 0 or shift != 0 */ - if (sound.nr10->sweep_period != 0 || - sound.nr10->shift != 0) - sound.channel_one.sweep_active = 1; - else - sound.channel_one.sweep_active = 0; - - /* if shift is != 0, calc the new frequency */ - if (sound.nr10->shift != 0) - { - uint32_t new_freq = sound_sweep_calc(); - - /* update all the stuff related to new frequency */ - sound_set_frequency(new_freq); - } - - /* if DAC is off, turn off the channel */ - if (sound.nr12->add == 0 && - sound.nr12->volume == 0) - sound.channel_one.active = 0; - - /* extra length clock if length == 64 */ - /* and FS is in the fist half */ - if ((sound.fs_cycles_idx & 0x01) == 0x00 && - sound.channel_one.length == 64) - sound_length_ctrl_step_ch(sound.nr14->length_enable, - &sound.channel_one.length, - &sound.channel_one.active); - } - - - break; - - case 0xFF16: - - sound.channel_two.length = 64 - sound.nr21->length_load; - - /* update duty type */ - switch (sound.nr21->duty) - { - /* 12.5 % */ - case 0x00: sound.channel_two.duty = 0x80; - break; - - /* 25% */ - case 0x01: sound.channel_two.duty = 0x81; - break; - - /* 50% */ - case 0x02: sound.channel_two.duty = 0xE1; - break; - - /* 75% */ - case 0x03: sound.channel_two.duty = 0x7E; - break; - } - - break; - - case 0xFF17: - - /* volume 0 = turn off the DAC = turn off channeru */ - if (sound.nr22->volume == 0 && - sound.nr22->add == 0) - sound.channel_two.active = 0; - - break; - - case 0xFF18: - - /* update frequncy */ - sound.channel_two.frequency = (sound.nr23->frequency_lsb | - (sound.nr24->frequency_msb << 8)); - - /* update duty cycles */ - sound.channel_two.duty_cycles = - ((2048 - sound.channel_two.frequency) * 4) - << global_cpu_double_speed; - - break; - - case 0xFF19: - - /* length counter turned on */ - if (sound.nr24->length_enable) - { - nr24_t *old_nr24 = (nr24_t *) &old; - - /* give an extra length clock if */ - /* 1) we switched from off to on the len counter */ - /* 2) we are in the first half of len clock */ - /* 3) actual length is not zero */ - if ((old_nr24->length_enable == 0) && - ((sound.fs_cycles_idx & 0x01) == 0x00) && - (sound.channel_two.length != 0)) - sound_length_ctrl_step_ch(sound.nr24->length_enable, - &sound.channel_two.length, - &sound.channel_two.active); - } - - /* always update frequency, even if it's not a trigger */ - sound.channel_two.frequency = sound.nr23->frequency_lsb | - (sound.nr24->frequency_msb << 8); - - /* qty of cpu ticks needed for a duty change */ - /* (1/8 of wave cycle) */ - sound.channel_two.duty_cycles = - ((2048 - sound.channel_two.frequency) * 4) - << global_cpu_double_speed; - - if (v & 0x80) - { - /* if we switch from OFF to ON, reset duty idx */ - if (sound.channel_two.active == 0) - sound.channel_two.duty_idx = 0; - - /* setting internal modules data with stuff taken from memory */ - sound.channel_two.active = 1; - sound.channel_two.duty_cycles_next = - cycles.cnt + sound.channel_two.duty_cycles; - - /* set the 8 phase of a duty cycle by setting 8 bits */ - switch (sound.nr21->duty) - { - /* 12.5 % */ - case 0x00: sound.channel_two.duty = 0x80; - break; - - /* 25% */ - case 0x01: sound.channel_two.duty = 0x81; - break; - - /* 50% */ - case 0x02: sound.channel_two.duty = 0xE1; - break; - - /* 75% */ - case 0x03: sound.channel_two.duty = 0x7E; - break; - } - - /* calc length */ - if (sound.channel_two.length == 0) - sound.channel_two.length = 64; - - /* base volume */ - sound.channel_two.volume = - sound.nr22->volume * 0x111; - - /* reset envelope counter */ - sound.channel_two.envelope_cnt = 0; - - /* if DAC is off, turn off the channel */ - if (sound.nr22->add == 0 && - sound.nr22->volume == 0) - sound.channel_two.active = 0; - - /* extra length clock if length == 64 */ - /* and FS is in the fist half */ - if ((sound.fs_cycles_idx & 0x01) == 0x00 && - sound.channel_two.length == 64) - sound_length_ctrl_step_ch(sound.nr24->length_enable, - &sound.channel_two.length, - &sound.channel_two.active); - } - - break; - - case 0xFF1A: - - /* if DAC is off, disable the channel */ - if (sound.nr30->dac == 0) - sound.channel_three.active = 0; - - break; - - case 0xFF1B: - - sound.channel_three.length = - 256 - sound.nr31->length_load; - - break; - - case 0xFF1C: - - break; - - case 0xFF1E: - - /* length counter turned on */ - if (sound.nr34->length_enable) - { - nr34_t *old_nr34 = (nr34_t *) &old; - - /* give an extra length clock if */ - /* 1) we switched from off to on the len counter */ - /* 2) we are in the first half of len clock */ - /* 3) actual length is not zero */ - if ((old_nr34->length_enable == 0) && - ((sound.fs_cycles_idx & 0x01) == 0x00) && - (sound.channel_three.length != 0)) - sound_length_ctrl_step_ch(sound.nr34->length_enable, - &sound.channel_three.length, - &sound.channel_three.active); - } - - if (v & 0x80) - { - uint16_t freq = sound.nr33->frequency_lsb | - (sound.nr34->frequency_msb << 8); - - /* setting internal modules data with stuff taken from memory */ - sound.channel_three.active = 1; - - uint_fast32_t old_cycles = sound.channel_three.cycles; - - /* qty of cpu ticks needed for a wave sample change */ - sound.channel_three.cycles = - (((2048 - freq) * 2) + 6) << global_cpu_double_speed; - - - /* treat obscure behaviours.... */ - if (!global_cgb && - cycles.cnt + 8 == sound.channel_three.cycles_next + - sound.channel_three.cycles - - old_cycles) - { - uint8_t next = - ((sound.channel_three.index + 1) & 0x1F) >> 1; - - if (next < 4) - sound.wave_table[0] = sound.wave_table[next]; - else - memcpy(sound.wave_table, - &sound.wave_table[next & 0xfc], 4); - } - - /* init wave table index */ - sound.channel_three.index = 0; - sound.channel_three.cycles_next = - cycles.cnt + sound.channel_three.cycles; - - /* calc length */ - if (sound.channel_three.length == 0) - sound.channel_three.length = 256; - - /* if DAC is off, disable the channel */ - if (sound.nr30->dac == 0) - sound.channel_three.active = 0; - - /* extra length clock if length == 256 */ - /* and FS is in the fist half */ - if ((sound.fs_cycles_idx & 0x01) == 0x00 && - sound.channel_three.length == 256) - sound_length_ctrl_step_ch(sound.nr34->length_enable, - &sound.channel_three.length, - &sound.channel_three.active); - - /* i accessed to the wave RAM... */ - sound.channel_three.ram_access = sound.channel_three.cycles; - - if (sound.channel_three.cycles % 4 == 0) - sound.channel_three.ram_access_next = - cycles.cnt + sound.channel_three.cycles; - else - sound.channel_three.ram_access_next = -1; - -/* printf("RAM ACCESS RICARICATO %u - CNT %d CYCLES %d \n", - sound.channel_three.ram_access, - cycles.cnt, sound.channel_three.cycles);*/ - } - break; - - case 0xFF20: - - sound.channel_four.length = 64 - sound.nr41->length_load; - - break; - - case 0xFF21: - - /* highest 5 bits cleared = turn off the DAC = turn off channeru */ - if (sound.nr42->volume == 0 && - sound.nr42->add == 0) - sound.channel_four.active = 0; - - break; - - case 0xFF23: - - /* length counter turned on */ - if (sound.nr44->length_enable) - { - nr44_t *old_nr44 = (nr44_t *) &old; - - /* give an extra length clock if */ - /* 1) we switched from off to on the len counter */ - /* 2) we are in the first half of len clock */ - /* 3) actual length is not zero */ - if ((old_nr44->length_enable == 0) && - ((sound.fs_cycles_idx & 0x01) == 0x00) && - (sound.channel_four.length != 0)) - sound_length_ctrl_step_ch(sound.nr44->length_enable, - &sound.channel_four.length, - &sound.channel_four.active); - } - - if (v & 0x80) - { - /* setting internal modules data with stuff taken from memory */ - sound.channel_four.active = 1; - - /* calc length */ - if (sound.channel_four.length == 0) - sound.channel_four.length = 64; - - uint16_t divisor; - - /* calc LFSR period */ - switch (sound.nr43->divisor) - { - case 0: divisor = 8; break; - case 1: divisor = 16; break; - case 2: divisor = 32; break; - case 3: divisor = 48; break; - case 4: divisor = 64; break; - case 5: divisor = 80; break; - case 6: divisor = 96; break; - case 7: divisor = 112; break; - } - - /* calc LFSR period */ - sound.channel_four.period_lfsr = divisor << sound.nr43->shift; - sound.channel_four.cycles_next = - cycles.cnt + sound.channel_four.period_lfsr; - - /* init reg to all bits to 1 */ - sound.channel_four.reg = 0x7FFF; - - /* base volume */ - sound.channel_four.volume = - sound.nr42->volume * 0x111; - - /* reset envelope counter */ - sound.channel_four.envelope_cnt = 0; - - /* if DAC is off, turn off the channel */ - if (sound.nr42->add == 0 && - sound.nr42->volume == 0) - sound.channel_four.active = 0; - - /* extra length clock if length == 64 */ - /* and FS is in the fist half */ - if ((sound.fs_cycles_idx & 0x01) == 0x00 && - sound.channel_four.length == 64) - sound_length_ctrl_step_ch(sound.nr44->length_enable, - &sound.channel_four.length, - &sound.channel_four.active); - } - - break; - - case 0xFF26: - - if (v & 0x80) - { - /* power from off to on! */ - if (!(old & 0x80)) - { - /* reset frame sequencer so the next step will be zero */ - sound.fs_cycles_idx = 7; - - /* reset wave index */ - sound.channel_three.index = 0; - - /* wave samples are resetted */ - bzero(sound.wave_table, 16); - } - } - else - { - /* power off */ - - /* clear all the sound memory */ - bzero(mmu_addr(0xFF10), 22); - - if (global_cgb) - { - sound.nr41->length_load = 0; - sound.channel_four.length = 0; - } - - /* turn off every channeru */ - sound.channel_one.active = 0; - sound.channel_two.active = 0; - sound.channel_three.active = 0; - sound.channel_four.active = 0; - } - - } -} - -void sound_write_wave(uint16_t a, uint8_t v) -{ - if (sound.channel_three.active) - { -// if (!global_cgb && sound.channel_three.ram_access != 0) -// return; - if (!global_cgb && cycles.cnt < sound.channel_three.ram_access_next) - return; - - sound.wave_table[sound.channel_three.index >> 1] = v; - - return; - } - - sound.wave_table[a - 0xFF30] = v; -} diff --git a/waterbox/pizza/lib/sound.h b/waterbox/pizza/lib/sound.h deleted file mode 100644 index 226b8650bd..0000000000 --- a/waterbox/pizza/lib/sound.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __SOUND_HDR__ -#define __SOUND_HDR__ - -#define SOUND_SAMPLES 4096 - -typedef struct nr10_s -{ - uint8_t shift:3; - uint8_t negate:1; - uint8_t sweep_period:3; - uint8_t spare:1; - -} nr10_t; - -typedef struct nr11_s -{ - uint8_t length_load:6; - uint8_t duty:2; - -} nr11_t; - -typedef struct nr12_s -{ - uint8_t period:3; - uint8_t add:1; - uint8_t volume:4; - -} nr12_t; - -typedef struct nr13_s -{ - uint8_t frequency_lsb; - -} nr13_t; - -typedef struct nr14_s -{ - uint8_t frequency_msb:3; - uint8_t spare:3; - uint8_t length_enable:1; - uint8_t trigger:1; - -} nr14_t; - -typedef struct nr21_s -{ - uint8_t length_load:6; - uint8_t duty:2; - -} nr21_t; - -typedef struct nr22_s -{ - uint8_t period:3; - uint8_t add:1; - uint8_t volume:4; - -} nr22_t; - -typedef struct nr23_s -{ - uint8_t frequency_lsb; - -} nr23_t; - -typedef struct nr24_s -{ - uint8_t frequency_msb:3; - uint8_t spare:3; - uint8_t length_enable:1; - uint8_t trigger:1; - -} nr24_t; - - -typedef struct nr30_s -{ - uint8_t spare:7; - uint8_t dac:1; - -} nr30_t; - -typedef struct nr31_s -{ - uint8_t length_load; - -} nr31_t; - -typedef struct nr32_s -{ - uint8_t spare:5; - uint8_t volume_code:2; - uint8_t spare2:1; - -} nr32_t; - -typedef struct nr33_s -{ - uint8_t frequency_lsb; - -} nr33_t; - -typedef struct nr34_s -{ - uint8_t frequency_msb:3; - uint8_t spare:3; - uint8_t length_enable:1; - uint8_t trigger:1; - -} nr34_t; - -typedef struct nr41_s -{ - uint8_t length_load:6; - uint8_t spare:2; - -} nr41_t; - -typedef struct nr42_s -{ - uint8_t period:3; - uint8_t add:1; - uint8_t volume:4; - -} nr42_t; - -typedef struct nr43_s -{ - uint8_t divisor:3; - uint8_t width:1; - uint8_t shift:4; - -} nr43_t; - -typedef struct nr44_s -{ - uint8_t spare:6; - uint8_t length_enable:1; - uint8_t trigger:1; - -} nr44_t; - -typedef struct nr50_s -{ - uint8_t so1_volume:3; - uint8_t vin_to_so1:1; - uint8_t so2_volume:3; - uint8_t vin_to_so2:1; -} nr50_t; - -typedef struct nr51_s -{ - uint8_t ch1_to_so1:1; - uint8_t ch2_to_so1:1; - uint8_t ch3_to_so1:1; - uint8_t ch4_to_so1:1; - uint8_t ch1_to_so2:1; - uint8_t ch2_to_so2:1; - uint8_t ch3_to_so2:1; - uint8_t ch4_to_so2:1; -} nr51_t; - -typedef struct nr52_s -{ - uint8_t spare:7; - uint8_t power:1; -} nr52_t; - -typedef struct channel_square_s -{ - uint8_t active; - uint8_t duty; - uint8_t duty_idx; - uint8_t envelope_cnt; - uint_fast16_t duty_cycles; - uint64_t duty_cycles_next; - uint_fast32_t length; - uint_fast32_t frequency; - int16_t sample; - int16_t spare; - uint_fast16_t sweep_active; - uint_fast16_t sweep_cnt; - uint_fast16_t sweep_neg; - uint_fast16_t sweep_next; - int16_t volume; - int16_t spare2; - uint32_t sweep_shadow_frequency; - -} channel_square_t; - -typedef struct channel_wave_s -{ - uint8_t active; - uint8_t index; - uint16_t ram_access; - int16_t sample; - int16_t spare; - int16_t wave[32]; - uint_fast32_t cycles; - uint64_t cycles_next; - uint_fast32_t ram_access_next; - uint_fast32_t length; - -} channel_wave_t; - -typedef struct channel_noise_s -{ - uint8_t active; - uint8_t envelope_cnt; - uint16_t spare; - uint_fast32_t length; - uint_fast16_t period_lfsr; - uint64_t cycles_next; - int16_t volume; - int16_t sample; - uint16_t reg; - uint16_t spare2; - -} channel_noise_t; - -typedef struct sound_s -{ - nr10_t *nr10; - nr11_t *nr11; - nr12_t *nr12; - nr13_t *nr13; - nr14_t *nr14; - - nr21_t *nr21; - nr22_t *nr22; - nr23_t *nr23; - nr24_t *nr24; - - nr30_t *nr30; - nr31_t *nr31; - nr32_t *nr32; - nr33_t *nr33; - nr34_t *nr34; - - nr41_t *nr41; - nr42_t *nr42; - nr43_t *nr43; - nr44_t *nr44; - - nr50_t *nr50; - nr51_t *nr51; - nr52_t *nr52; - - uint8_t *wave_table; - - channel_square_t channel_one; - channel_square_t channel_two; - channel_wave_t channel_three; - channel_noise_t channel_four; - - /* emulation speed stuff */ - uint_fast16_t frame_counter; - - /* output rate */ - uint_fast32_t output_rate; - - /* CPU cycles to internal cycles counters */ - uint_fast32_t fs_cycles; - uint_fast32_t fs_cycles_idx; - uint64_t fs_cycles_next; -} sound_t; - -extern sound_t sound; - -/* prototypes */ -void sound_init(); -uint8_t sound_read_reg(uint16_t a, uint8_t v); -void sound_set_speed(char dbl); -void sound_step_fs(); -void sound_step_ch1(); -void sound_step_ch2(); -void sound_step_ch3(); -void sound_step_ch4(); -void sound_write_reg(uint16_t a, uint8_t v); - -#endif diff --git a/waterbox/pizza/lib/sound_output.c b/waterbox/pizza/lib/sound_output.c deleted file mode 100644 index cf9d32c949..0000000000 --- a/waterbox/pizza/lib/sound_output.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "../blip_buf/blip_buf.h" -#include "sound_output.h" -#include "cycles.h" -#include "sgb.h" -#include "global.h" - -static blip_t* lb; -static blip_t* rb; -static uint64_t startclock; - -#define RELATIVECLOCK (cycles.sampleclock - startclock) - -void blip_left(int delta) -{ - if (delta) - blip_add_delta(lb, RELATIVECLOCK, delta); -} -void blip_right(int delta) -{ - if (delta) - blip_add_delta(rb, RELATIVECLOCK, delta); -} - -void sound_output_init(double clock_rate, double sample_rate) -{ - lb = blip_new(1024); - rb = blip_new(1024); - blip_set_rates(lb, clock_rate, sample_rate); - blip_set_rates(rb, clock_rate, sample_rate); -} - -static int32_t sgb_last_l; -static int32_t sgb_last_r; - -static void sgb_audio_callback(int16_t l, int16_t r, uint64_t time) -{ - uint64_t t = time - startclock; - int32_t ld = l - sgb_last_l; - int32_t rd = r - sgb_last_r; - blip_add_delta(lb, t, ld); - blip_add_delta(rb, t, rd); - sgb_last_l = l; - sgb_last_r = r; -} - -int sound_output_read(int16_t* output) -{ - if (global_sgb) - sgb_render_audio(cycles.sampleclock, sgb_audio_callback); - - blip_end_frame(lb, RELATIVECLOCK); - blip_end_frame(rb, RELATIVECLOCK); - startclock = cycles.sampleclock; - int ret = blip_read_samples(lb, output, 2048, 1); - blip_read_samples(rb, output + 1, 2048, 1); - return ret; -} diff --git a/waterbox/pizza/lib/sound_output.h b/waterbox/pizza/lib/sound_output.h deleted file mode 100644 index 91561da49a..0000000000 --- a/waterbox/pizza/lib/sound_output.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -void blip_left(int delta); -void blip_right(int delta); - -void sound_output_init(double clock_rate, double sample_rate); -int sound_output_read(int16_t* output); diff --git a/waterbox/pizza/lib/timer.c b/waterbox/pizza/lib/timer.c deleted file mode 100644 index a46c224bda..0000000000 --- a/waterbox/pizza/lib/timer.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include "cycles.h" -#include "interrupt.h" -#include "mmu.h" -#include "timer.h" - -/* pointer to interrupt flags (handy) */ -interrupts_flags_t *timer_if; - - -void timer_init() -{ - /* reset values */ - timer.next = 256; - timer.sub = 0; - - /* pointer to interrupt flags */ - timer_if = mmu_addr(0xFF0F); -} - -void timer_write_reg(uint16_t a, uint8_t v) -{ - switch (a) - { - case 0xFF04: timer.div = 0; return; - case 0xFF05: timer.cnt = v; return; - case 0xFF06: timer.mod = v; return; - case 0xFF07: timer.ctrl = v; - } - - if (timer.ctrl & 0x04) - timer.active = 1; - else - timer.active = 0; - - switch (timer.ctrl & 0x03) - { - case 0x00: timer.threshold = 1024; break; - case 0x01: timer.threshold = 16; break; - case 0x02: timer.threshold = 64; break; - case 0x03: timer.threshold = 256; break; - } - - if (timer.active) - timer.sub_next = cycles.cnt + timer.threshold; -} - -uint8_t timer_read_reg(uint16_t a) -{ - switch (a) - { - case 0xFF04: return timer.div; - case 0xFF05: return timer.cnt; - case 0xFF06: return timer.mod; - case 0xFF07: return timer.ctrl; - } - - return 0xFF; -} - - diff --git a/waterbox/pizza/lib/timer.h b/waterbox/pizza/lib/timer.h deleted file mode 100644 index 531116121b..0000000000 --- a/waterbox/pizza/lib/timer.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __TIMER_HDR__ -#define __TIMER_HDR__ - -#include - -/* timer status */ -typedef struct timer_gb_s -{ - /* is it active? */ - uint8_t active; - - /* divider - 0xFF04 */ - uint8_t div; - - /* modulo - 0xFF06 */ - uint8_t mod; - - /* control - 0xFF07 */ - uint8_t ctrl; - - /* counter - 0xFF05 */ - uint_fast32_t cnt; - - /* threshold */ - uint32_t threshold; - - /* current value */ - uint_fast32_t sub; - uint64_t next; - - /* spare */ - uint_fast32_t sub_next; -} timer_gb_t; - -/* global status of timer */ -timer_gb_t timer; - -/* prototypes */ -void timer_init(); -void timer_step(); -void timer_write_reg(uint16_t a, uint8_t v); -uint8_t timer_read_reg(uint16_t a); - -#endif diff --git a/waterbox/pizza/lib/utils.c b/waterbox/pizza/lib/utils.c deleted file mode 100644 index e413d644cc..0000000000 --- a/waterbox/pizza/lib/utils.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include - -#include -#include - -#include "cycles.h" -#include "gpu.h" -#include "utils.h" - -uint64_t prev_cycles = 0; - -void utils_log(const char *format, ...) -{ - char buf[256]; - - va_list args; - va_start(args, format); - vsnprintf(buf, 256, format, args); - fputs(buf, stdout); - va_end(args); -} - - -void utils_log_urgent(const char *format, ...) -{ - char buf[256]; - - va_list args; - va_start(args, format); - vsnprintf(buf, 256, format, args); - fputs(buf, stdout); - va_end(args); -} - -void utils_ts_log(const char *format, ...) -{ - va_list args; - va_start(args, format); - - char buf[256]; - char buf2[512]; - struct timeval tv; - - - vsprintf(buf, format, args); - //gettimeofday(&tv, NULL); -// printf("%ld - %s\n", tv.tv_sec, buf); - sprintf(buf2, "LINE %u - CYCLES %lu - DIFF %lu - %ld:%06ld - %s", - *(gpu.ly), cycles.cnt, cycles.cnt - prev_cycles, - tv.tv_sec, tv.tv_usec, buf); - _debug_puts(buf2); - prev_cycles = cycles.cnt; - - va_end(args); -} diff --git a/waterbox/pizza/lib/utils.h b/waterbox/pizza/lib/utils.h deleted file mode 100644 index 17e632de51..0000000000 --- a/waterbox/pizza/lib/utils.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#ifndef __UTILS_HDR__ -#define __UTILS_HDR__ - -void utils_log(const char *format, ...); -void utils_log_urgent(const char *format, ...); -void utils_ts_log(const char *format, ...); - -#endif diff --git a/waterbox/pizza/lib/z80_gameboy.h b/waterbox/pizza/lib/z80_gameboy.h deleted file mode 100644 index db8c78c66d..0000000000 --- a/waterbox/pizza/lib/z80_gameboy.h +++ /dev/null @@ -1,2480 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include -#include -#include -#include -#include "mmu.h" -#include "z80_gameboy_regs.h" - -/* main struct describing CPU state */ - -typedef struct z80_state_s -{ - uint8_t spare; - uint8_t a; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - uint8_t c; - uint8_t b; -#else - uint8_t b; - uint8_t c; -#endif -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - uint8_t e; - uint8_t d; -#else - uint8_t d; - uint8_t e; -#endif -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - uint8_t l; - uint8_t h; -#else - uint8_t h; - uint8_t l; -#endif - - uint16_t sp; - uint16_t pc; - - /* shortcuts */ - uint16_t *bc; - uint16_t *de; - uint16_t *hl; - uint8_t *f; - - uint32_t spare4; - uint32_t skip_cycle; - - z80_flags_t flags; - uint8_t int_enable; - - /* latest T-state */ - uint16_t spare3; - - /* total cycles */ - uint64_t cycles; - -} z80_state_t; - -#define Z80_MAX_MEMORY 65536 - - -/* state of the Z80 CPU */ -z80_state_t state; - -/* precomputed flags masks */ -uint8_t zc[1 << 9]; -uint8_t z[1 << 9]; - -/* macro to access addresses passed as parameters */ -#define ADDR mmu_read_16(state.pc + 1) -#define NN mmu_read_16(state.pc + 2) - -/* dummy value for 0x06 regs resulution table */ -uint8_t dummy; - -/* Registers table */ -uint8_t **regs_dst; -uint8_t **regs_src; - -#define FLAG_MASK_Z (1 << FLAG_OFFSET_Z) -#define FLAG_MASK_AC (1 << FLAG_OFFSET_AC) -#define FLAG_MASK_N (1 << FLAG_OFFSET_N) -#define FLAG_MASK_CY (1 << FLAG_OFFSET_CY) - - -/********************************/ -/* */ -/* FLAGS OPS */ -/* */ -/********************************/ - -/* calc flags SZ with 16 bit param */ -void static inline z80_set_flags_z(unsigned int v) -{ - state.flags.z = (v & 0xff) == 0; -} - -/* calc flags SZC with 16 bit param */ -void static inline z80_set_flags_zc(unsigned int v) -{ - state.flags.z = (v & 0xff) == 0; - state.flags.cy = (v > 0xff); -} - -/* calc flags SZC with 32 bit result */ -void static inline z80_set_flags_zc_16(unsigned int v) -{ - state.flags.z = (v & 0xffff) == 0; - state.flags.cy = (v > 0xffff); -} - -/* calc AC for given operands */ -void static inline z80_set_flags_ac(uint8_t a, uint8_t b, - unsigned int r) -{ - /* calc xor for AC and overflow */ - unsigned int c = (a ^ b ^ r); - - /* set AC */ - state.flags.ac = ((c & 0x10) != 0); - - return; -} - -/* calc AC and overflow flag given operands (16 bit flavour) */ -void static inline z80_set_flags_ac_16(unsigned int a, - unsigned int b, - unsigned int r) -{ - /* calc xor for AC and overflow */ - unsigned int c = (a ^ b ^ r); - - /* set AC */ - state.flags.ac = ((c & 0x01000) != 0); - - return; -} - -/* calc AC flag given operands and result */ -char static inline z80_calc_ac(uint8_t a, uint8_t b, unsigned int r) -{ - /* calc xor for AC and overflow */ - unsigned int c = a ^ b ^ r; - - /* AC */ - if (c & 0x10) - return 1; - - return 0; -} - -/* calculate flags mask array */ -void static z80_calc_flags_mask_array() -{ - z80_flags_t f; - unsigned int i; - - // bzero(sz53pc, sizeof(sz53pc)); - - /* create a mask for bit 5 and 3 and its reverse */ -/* f.spare = 0= 1; f.z = 1; f.u5 = 0; f.ac = 1; f.u3 = 0; f.p = 1; f.n = 1; f.cy = 1; - u53_mask = *((uint8_t *) &f); - r53_mask = ~(u53_mask); */ - - bzero(&f, 1); - - for (i=0; i<512; i++) - { - f.z = ((i & 0xff) == 0); - f.cy = (i > 0xff); - - zc[i] = *((uint8_t *) &f); - - f.cy = 0; - - z[i] = *((uint8_t *) &f); - - /* no CY and parity */ -/* f.cy = 0; - f.p = parity[i & 0xff]; - sz53p[i] = *((uint8_t *) &f); -*/ - /* similar but with no u3 and u5 */ -/* f.u3 = 0; - f.u5 = 0; - szp[i] = *((uint8_t *) &f); -*/ - /* similar but with carry and no p */ -/* f.cy = (i > 0xff); - f.p = 0; - szc[i] = *((uint8_t *) &f); */ - } -} - - -/********************************/ -/* */ -/* INSTRUCTIONS SEGMENT */ -/* ordered by name */ -/* */ -/********************************/ - - -/* add A register, b parameter and Carry flag, then calculate flags */ -void static inline z80_adc(uint8_t b) -{ - /* calc result */ - unsigned int result = state.a + b + state.flags.cy; - - /* set flags - SZ5H3V0C */ - *state.f = zc[result & 0x1ff]; - - /* set AC and overflow flags */ - z80_set_flags_ac(state.a, b, result); - - /* save result into A register */ - state.a = (uint8_t) result; - - return; -} - -/* add a and b parameters (both 16 bits) and the carry, thencalculate flags */ -unsigned int static inline z80_adc_16(unsigned int a, unsigned int b) -{ - /* calc result */ - unsigned int result = a + b + state.flags.cy; - - /* set them - SZ5H3V0C */ - z80_set_flags_zc_16(result); - state.flags.n = 0; - - /* get only high byte */ - // unsigned int r16 = (result >> 8); - - /* set AC and overflow flags */ - z80_set_flags_ac_16(a, b, result); - - return result; -} - -/* add A register and b parameter and calculate flags */ -void static inline z80_add(uint8_t b) -{ - /* calc result */ - unsigned int result = state.a + b; - - /* set them - SZ5H3P0C */ - *state.f = zc[result & 0x1ff]; - - /* set AC and overflow flags - given AC and V set to 0 */ - z80_set_flags_ac(state.a, b, result); - - /* save result into A register */ - state.a = result; - - return; -} - -/* add a and b parameters (both 16 bits), then calculate flags */ -unsigned int static inline z80_add_16(unsigned int a, unsigned int b) -{ - /* calc result */ - unsigned int result = a + b; - - /* get only high byte */ - // uint8_t r16 = (result >> 8); - - /* not a subtraction */ - state.flags.n = 0; - - /* calc xor for AC */ - z80_set_flags_ac(a, b, result); - - /* set CY */ - state.flags.cy = (result > 0xffff); - - return result; -} - -/* b AND A register and calculate flags */ -void static inline z80_ana(uint8_t b) -{ - /* calc result */ - uint8_t result = state.a & b; - - /* set them */ - *state.f = zc[result] | FLAG_MASK_AC; - - /* save result into A register */ - state.a = result; - - return; -} - -/* BIT instruction, test pos-th bit and set flags */ -void static inline z80_bit(uint8_t *v, uint8_t pos, uint8_t muffa) -{ - uint8_t r = *v & (0x01 << pos); - - /* set flags AC,Z, N = 0 */ - state.flags.n = 0; - state.flags.ac = 1; - state.flags.z = (r == 0) ; - - return; -} - -/* push the current PC on the stack and move PC to the function addr */ -int static inline z80_call(unsigned int addr) -{ - /* move to the next instruction */ - state.pc += 3; - - /* add 4 more cycles */ - cycles_step(); - - /* save it into stack */ - mmu_write_16(state.sp - 2, state.pc); - - /* update stack pointer */ - state.sp -= 2; - - /* move PC to the called function address */ - state.pc = addr; - - return 0; -} - -/* compare b parameter against A register and calculate flags */ -void static inline z80_cmp(uint8_t b) -{ - /* calc result */ - unsigned int result = state.a - b; - - /* set flags - SZ5H3PN* */ - *state.f = zc[result & 0x1ff] | - FLAG_MASK_N; - - /* set AC and overflow flags */ - z80_set_flags_ac(state.a, b, result); - - return; -} - -/* compare b parameter against A register and calculate flags */ -void static inline z80_cpid(uint8_t b, int8_t add) -{ - /* calc result */ - unsigned int result = state.a - b; - - /* calc AC */ - state.flags.ac = z80_calc_ac(state.a, b, result); - - /* increase (add = +1) or decrease (add = -1) HL */ - *state.hl += add; - - /* decrease BC */ - *state.bc = *state.bc - 1; - - /* calc n as result - half carry flag */ - // unsigned int n = result - state.flags.ac; - - /* set flags - SZ5H3P1* */ - state.flags.z = (result & 0xff) == 0; - -// z80_set_flags_z(result); - - /* cmp = subtraction */ - state.flags.n = 1; - - /* set P if BC != 0 */ - // state.flags.p = (*state.bc != 0); - - /* flag 3 and 5 are taken from (result - ac) and not the result */ - /* and u5 is taken exceptionally from the bit 1 */ -// state.flags.u5 = (n & 0x0002) != 0; -// state.flags.u3 = (n & 0x0008) != 0; - - return; -} - -/* DAA instruction... what else? */ -void static inline z80_daa() -{ - unsigned int a = state.a; - uint8_t al = state.a & 0x0f; - - if (state.flags.n) - { - if (state.flags.ac) - a = (a - 6) & 0xFF; - - if (state.flags.cy) - a -= 0x60; - } - else - { - if (al > 9 || state.flags.ac) - { - state.flags.ac = (al > 9); - a += 6; - } - - if (state.flags.cy || ((a & 0x1f0) > 0x90)) - a += 0x60; - } - - if (a & 0x0100) state.flags.cy = 1; - - /* set computer A value */ - state.a = a & 0xff; - - state.flags.ac = 0; - state.flags.z = (state.a == 0); - - return; -} - -/* DAA instruction... what else? */ -void static inline z80_daa_ignore_n() -{ - unsigned int a = state.a; - uint8_t al = state.a & 0x0f; - - if (al > 9 || state.flags.ac) - { - state.flags.ac = (al > 9); - a += 6; - } - - if (state.flags.cy || ((a & 0x1f0) > 0x90)) - a += 0x60; - - if (a & 0x0100) state.flags.cy = 1; - - /* set computer A value */ - state.a = a & 0xff; - - /* reset H flag */ - state.flags.z = (state.a == 0x00); - state.flags.ac = 0; - - /* and its flags */ - // z80_set_flags_sz53p(state.a); - - return; -} - -/* add a and b parameters (both 16 bits) and the carry, thencalculate flags */ -unsigned int static inline dad_16(unsigned int a, unsigned int b) -{ - /* calc result */ - unsigned int result = a + b; - - /* reset n */ - state.flags.n = 0; - - /* calc xor for AC and overflow */ - unsigned int c = a ^ b ^ result; - - /* set AC */ - state.flags.ac = ((c & 0x1000) != 0); - - /* set CY */ - state.flags.cy = (result > 0xffff); - - return result; -} - -/* dec the operand and return result increased by one */ -uint8_t static inline z80_dcr(uint8_t b) -{ - unsigned int result = b - 1; - - /* set flags - SZ5H3V1* */ - z80_set_flags_z(result); - - /* it's a subtraction */ - state.flags.n = 1; - - /* set overflow and AC */ - z80_set_flags_ac(b, 1, result); - -// state.flags.ac = 0; - - return result; -} - -/* inc the operand and return result increased by one */ -uint8_t static inline z80_inr(uint8_t b) -{ - unsigned int result = b + 1; - - /* set flags - SZ5H3V1* */ - z80_set_flags_z(result); - - /* it's not a subtraction */ - state.flags.n = 0; - - /* set overflow and AC */ - z80_set_flags_ac(1, b, result); - - return result; -} - -/* same as call, but save on the stack the current PC instead of next instr */ -int static inline z80_intr(unsigned int addr) -{ - /* push the current PC into stack */ - mmu_write_16(state.sp - 2, state.pc); - - cycles_step(); - - /* update stack pointer */ - state.sp -= 2; - - /* move PC to the called function address */ - state.pc = addr; - - return 0; -} - -/* copy (HL) in (DE) and decrease HL, DE and BC */ -void static inline z80_ldd() -{ - uint8_t byte; - - /* copy! */ - mmu_move(*state.de, *state.hl); - - /* get last moved byte and sum A */ - byte = mmu_read(*state.de); - byte += state.a; - - /* decrease HL, DE and BC */ - *state.hl = *state.hl - 1; - *state.de = *state.de - 1; - *state.bc = *state.bc - 1; - - /* reset flags - preserve ZC */ - *state.f &= FLAG_MASK_Z | - FLAG_MASK_CY; - - return; -} - -/* copy (HL) in (DE) and increase HL and DE. BC is decreased */ -void static inline z80_ldi() -{ - uint8_t byte; - - /* copy! */ - mmu_move(*state.de, *state.hl); - - /* get last moved byte and sum A */ - byte = mmu_read(*state.de); - byte += state.a; - - /* u5 flag is bit 1 of last moved byte + A (WTF?) */ - // state.flags.u5 = (byte & 0x02) >> 1; - - /* u3 flag is bit 3 of last moved byte + A (WTF?) */ - // state.flags.u3 = (byte & 0x08) >> 3; - - /* decrease HL, DE and BC */ - *state.hl = *state.hl + 1; - *state.de = *state.de + 1; - *state.bc = *state.bc - 1; - - /* reset negative, half carry and parity flags */ - state.flags.n = 0; - state.flags.ac = 0; - // state.flags.p = (*state.bc != 0); - - return; -} - -/* negate register A */ -void static inline z80_neg() -{ - /* calc result */ - unsigned int result = 0 - state.a; - - /* set flags - SZ5H3V1C */ - *state.f = zc[result & 0x1ff] | FLAG_MASK_N; - - /* set AC and overflow */ - z80_set_flags_ac(0, state.a, result); - - /* save result into A register */ - state.a = (uint8_t) result; - - return; -} - -/* OR b parameter and A register and calculate flags */ -void static inline z80_ora(uint8_t b) -{ - state.a |= b; - - /* set them SZ503P0C */ - *state.f = zc[state.a]; - - return; -} - -/* RES instruction, put a 0 on pos-th bit and set flags */ -uint8_t static inline z80_res(uint8_t *v, uint8_t pos) -{ - *v &= ~(0x01 << pos); - - return *v; -} - -/* pop the return address from the stack and move PC to that address */ -int static inline z80_ret() -{ - state.pc = mmu_read_16(state.sp); - state.sp += 2; - - /* add 4 cycles */ - cycles_step(); - - return 0; -} - -/* RL (Rotate Left) instruction */ -uint8_t static inline z80_rl(uint8_t *v, char with_carry) -{ - uint8_t carry; - - /* apply RLC to the memory pointed byte */ - carry = (*v & 0x80) >> 7; - *v = *v << 1; - - if (with_carry) - *v |= carry; - else - *v |= state.flags.cy; - - /* set flags - SZ503P0C */ - *state.f = 0; // sz53p[*v]; - - state.flags.z = (*v == 0); - state.flags.cy = carry; - - return *v; -} - -/* RLA instruction */ -uint8_t static inline z80_rla(uint8_t *v, char with_carry) -{ - uint8_t carry; - - /* apply RLA to the memory pointed byte */ - carry = (*v & 0x80) >> 7; - *v = *v << 1; - - if (with_carry) - *v |= carry; - else - *v |= state.flags.cy; - - /* reset flags */ - *state.f = 0; - - /* just set carry */ - state.flags.cy = carry; - - return *v; -} - -/* RLD instruction */ -void static inline z80_rld() -{ - uint8_t hl = mmu_read(*state.hl); - - /* save lowest A 4 bits */ - uint8_t al = state.a & 0x0f; - - /* A lowest bits are overwritten by (HL) highest ones */ - state.a &= 0xf0; - state.a |= (hl >> 4); - - /* (HL) highest bits are overwritten by (HL) lowest ones */ - hl <<= 4; - - /* finally, (HL) lowest bits are overwritten by A lowest */ - hl &= 0xf0; - hl |= al; - - /* set (HL) with his new value ((HL) low | A low) */ - mmu_write(*state.hl, hl); - - /* reset flags - preserve CY */ - *state.f &= FLAG_MASK_CY; - - /* set flags - SZ503P0* */ - *state.f |= z[state.a]; - - return; -} - -/* RR instruction */ -uint8_t static inline z80_rr(uint8_t *v, char with_carry) -{ - uint8_t carry; - - /* apply RRC to the memory pointed byte */ - carry = *v & 0x01; - *v = (*v >> 1); - - /* 7th bit taken from old bit 0 or from CY */ - if (with_carry) - *v |= (carry << 7); - else - *v |= (state.flags.cy << 7); - - /* set flags - SZ503P0C */ - *state.f = z[*v]; - - state.flags.cy = carry; - - return *v; -} - -/* RRA instruction */ -uint8_t static inline z80_rra(uint8_t *v, char with_carry) -{ - uint8_t carry; - - /* apply RRC to the memory pointed byte */ - carry = *v & 0x01; - *v = (*v >> 1); - - /* 7th bit taken from old bit 0 or from CY */ - if (with_carry) - *v |= (carry << 7); - else - *v |= (state.flags.cy << 7); - - /* reset flags */ - *state.f = 0; - - state.flags.cy = carry; - -// state.flags.n = 0; -// state.flags.ac = 0; - - /* copy bit 3 and 5 of the result */ - // state.flags.u3 = ((*v & 0x08) != 0); - // state.flags.u5 = ((*v & 0x20) != 0); - - return *v; -} - -/* RRD instruction */ -void static inline z80_rrd() -{ - uint8_t hl = mmu_read(*state.hl); - - /* save lowest (HL) 4 bits */ - uint8_t hll = hl & 0x0f; - - /* (HL) lowest bits are overwritten by (HL) highest ones */ - hl >>= 4; - - /* (HL) highest bits are overwritten by A lowest ones */ - hl |= ((state.a & 0x0f) << 4); - - /* set (HL) with his new value (A low | (HL) high) */ - mmu_write(*state.hl, hl); - - /* finally, A lowest bits are overwritten by (HL) lowest */ - state.a &= 0xf0; - state.a |= hll; - - /* reset flags - preserve CY */ - *state.f &= FLAG_MASK_CY; - - /* set flags - SZ503P0* */ - *state.f |= z[state.a]; - - return; -} - -/* subtract b parameter and Carry from A register and calculate flags */ -void static inline z80_sbc(uint8_t b) -{ - /* calc result */ - unsigned int result = state.a - b - state.flags.cy; - - /* set flags - ZC and N = 1 */ - *state.f = zc[result & 0x1ff] | FLAG_MASK_N; - - /* set AC */ - z80_set_flags_ac(state.a, b, result); - - /* save result into A register */ - state.a = (uint8_t) result; - - return; -} - -/* subtract a and b parameters (both 16 bits) and the carry, then calculate flags */ -unsigned int static inline z80_sbc_16(unsigned int a, unsigned int b) -{ - /* calc result */ - unsigned int result = a - b - state.flags.cy; - - /* set flags - SZ5H3V1C */ - z80_set_flags_zc_16(result); - state.flags.n = 1; - - /* get only high byte */ - // unsigned int r16 = (result >> 8); - - /* set AC and overflow flags */ - z80_set_flags_ac_16(a, b, result); - - return result; -} - -/* SET instruction, put a 1 on pos-th bit and set flags */ -uint8_t static inline z80_set(uint8_t *v, uint8_t pos) -{ - *v |= (0x01 << pos); - - return *v; -} - -/* SL instruction (SLA = v * 2, SLL = v * 2 + 1) */ -uint8_t static inline z80_sl(uint8_t *v, char one_insertion) -{ - /* move pointed value to local (gives an huge boost in perf!) */ - uint8_t l = *v; - - /* apply SL to the memory pointed byte */ - uint8_t cy = (l & 0x80) != 0; - l = (l << 1) | one_insertion; - - /* set flags - SZ503P0C */ - *state.f = z[l]; - - state.flags.cy = cy; - - /* re-assign local value */ - *v = l; - - return l; -} - -/* SR instruction (SRA = preserve 8th bit, SRL = discard 8th bit) */ -uint8_t static inline z80_sr(uint8_t *v, char preserve) -{ - uint8_t bit = 0; - - /* save the bit 0 */ - uint8_t cy = (*v & 0x01); - - /* apply SL to the memory pointed byte */ - if (preserve) - bit = *v & 0x80; - - /* move 1 pos right and restore highest bit (in case of SRA) */ - *v = (*v >> 1) | bit; - - /* set flags - SZ503P0C */ - *state.f = z[*v]; - - state.flags.cy = cy; - - return *v; -} - -/* subtract b parameter from A register and calculate flags */ -void static inline z80_sub(uint8_t b) -{ - /* calc result */ - unsigned int result = state.a - b; - - /* set them - SZ5H3V1C */ - *state.f = zc[result & 0x1ff] | FLAG_MASK_N; - - /* set AC and overflow flags */ - z80_set_flags_ac(state.a, b, result); - - /* save result into A register */ - state.a = (uint8_t) result; - - return; -} - -/* xor b parameter and A register and calculate flags */ -void static inline z80_xra(uint8_t b) -{ - /* calc result */ - state.a ^= b; - - /* set them SZ503P00 */ - *state.f = z[state.a]; - - return; -} - - - -/********************************/ -/* */ -/* INSTRUCTIONS BRANCHES */ -/* */ -/********************************/ - - -/* Z80 extended OPs */ -int static inline z80_ext_cb_execute() -{ - uint8_t byte = 1; - int b = 2; - - /* CB family (ROT, BIT, RES, SET) */ - uint8_t cbfam; - - /* CB operation */ - uint8_t cbop; - - /* choosen register */ - uint8_t reg; - - /* get CB code */ - uint8_t code = mmu_read(state.pc + 1); - - /* extract family */ - cbfam = code >> 6; - - /* extract involved register */ - reg = code & 0x07; - - /* if reg == 0x06, refresh the pointer */ - // if (reg == 0x06 && code != 0x36) - // { - /* add 4 more cycles for reading data from memory */ - // cycles_step(); - - // regs_src[0x06] = mmu_addr(*state.hl); - // } - - switch (cbfam) - { - /* Rotate Family */ - case 0x00: cbop = code & 0xf8; - - switch(cbop) - { - /* RLC REG */ - case 0x00: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_rl(&byte, 1)); - } - else - z80_rl(regs_src[reg], 1); - break; - - /* RRC REG */ - case 0x08: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_rr(&byte, 1)); - } - else - z80_rr(regs_src[reg], 1); - - break; - - /* RL REG */ - case 0x10: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_rl(&byte, 0)); - } - else - z80_rl(regs_src[reg], 0); - - break; - - /* RR REG */ - case 0x18: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_rr(&byte, 0)); - } - else - z80_rr(regs_src[reg], 0); - - break; - - /* SLA REG */ - case 0x20: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_sl(&byte, 0)); - } - else - z80_sl(regs_src[reg], 0); - - break; - - /* SRA REG */ - case 0x28: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_sr(&byte, 1)); - } - else - z80_sr(regs_src[reg], 1); - - break; - - /* SWAP */ - case 0x30: - switch (code & 0x37) - { - /* SWAP B */ - case 0x30: byte = state.b; - state.b = ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4); - break; - - /* SWAP C */ - case 0x31: byte = state.c; - state.c = ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4); - break; - - /* SWAP D */ - case 0x32: byte = state.d; - state.d = ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4); - break; - - /* SWAP E */ - case 0x33: byte = state.e; - state.e = ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4); - break; - - /* SWAP H */ - case 0x34: byte = state.h; - state.h = ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4); - break; - - /* SWAP L */ - case 0x35: byte = state.l; - state.l = ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4); - break; - - /* SWAP *HL */ - case 0x36: byte = mmu_read(*state.hl); - mmu_write(*state.hl, - ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4)); - - break; - - /* SWAP A */ - case 0x37: - byte = state.a; - state.a = ((byte & 0xf0) >> 4) | - ((byte & 0x0f) << 4); - break; - - } - - /* swap functions set Z flags */ - state.flags.z = (byte == 0x00); - - /* reset all the others */ - state.flags.ac = 0; - state.flags.cy = 0; - state.flags.n = 0; - - break; - - /* SRL REG */ - case 0x38: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_sr(&byte, 0)); - } - else - z80_sr(regs_src[reg], 0); - - break; - } - - /* accessing HL needs more T-cycles */ - //if (reg == 0x06 && code != 0x36) - // cycles_step(); - - /* accessing HL needs more T-cycles */ -// if (reg == 0x06) -// cycles_step(); - - break; - - /* BIT Family */ - case 0x01: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - z80_bit(&byte, (code >> 3) & 0x07, - (uint8_t) *state.hl); - } - else - z80_bit(regs_src[reg], (code >> 3) & 0x07, - *regs_src[reg]); - break; - - /* RES Family */ - case 0x02: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_res(&byte, (code >> 3) & 0x07)); - } - else - z80_res(regs_src[reg], (code >> 3) & 0x07); - - break; - - /* SET Family */ - case 0x03: if (reg == 0x06) - { - byte = mmu_read(*state.hl); - mmu_write(*state.hl, z80_set(&byte, (code >> 3) & 0x07)); - } - else - z80_set(regs_src[reg], (code >> 3) & 0x07); - - break; - -// default: printf("Unimplemented CB family: %02x\n", -// cbfam); - - } - - return b; -} - - -/* really execute the OP. Could be ran by normal execution or * - * because an interrupt occours */ -int static inline z80_execute(unsigned char code) -{ - int b = 1; - uint8_t *p; - uint8_t byte = 1; - uint8_t byte2 = 1; - unsigned int result; - uint_fast16_t addr; - - switch (code) - { - /* NOP */ - case 0x00: break; - - /* LXI B */ - case 0x01: *state.bc = ADDR; - b = 3; - break; - - /* STAX B */ - case 0x02: mmu_write(*state.bc, state.a); - break; - - /* INX B */ - case 0x03: (*state.bc)++; - cycles_step(); - break; - - /* INR B */ - case 0x04: state.b = z80_inr(state.b); - break; - - /* DCR B */ - case 0x05: state.b = z80_dcr(state.b); - break; - - /* MVI B */ - case 0x06: state.b = mmu_read(state.pc + 1); - b = 2; - break; - - /* RLCA */ - case 0x07: z80_rla(&state.a, 1); - break; - - /* LD (NN),SP */ - case 0x08: mmu_write_16(ADDR, state.sp); - b = 3; - break; - - /* DAD B */ - case 0x09: *state.hl = dad_16(*state.hl, *state.bc); - - /* needs 4 more cycles */ - cycles_step(); - - break; - - /* LDAX B */ - case 0x0A: state.a = mmu_read(*state.bc); - break; - - /* DCX B */ - case 0x0B: (*state.bc)--; - cycles_step(); - break; - - /* INR C */ - case 0x0C: state.c = z80_inr(state.c); - break; - - /* DCR C */ - case 0x0D: state.c = z80_dcr(state.c); - break; - - /* MVI C */ - case 0x0E: state.c = mmu_read(state.pc + 1); - b = 2; - break; - - /* RRC */ - case 0x0F: z80_rra(&state.a, 1); - break; - - /* STOP */ - case 0x10: b = 2; - break; - - /* LXI D */ - case 0x11: *state.de = ADDR; - b = 3; - break; - - /* STAX D */ - case 0x12: mmu_write(*state.de, state.a); - break; - - /* INX D */ - case 0x13: (*state.de)++; - cycles_step(); - break; - - /* INR D */ - case 0x14: state.d = z80_inr(state.d); - break; - - /* DCR D */ - case 0x15: state.d = z80_dcr(state.d); - break; - - /* MVI D */ - case 0x16: state.d = mmu_read(state.pc + 1); - b = 2; - break; - - /* RLA */ - case 0x17: z80_rla(&state.a, 0); - break; - - /* JR */ - case 0x18: cycles_step(); - state.pc += (int8_t) mmu_read(state.pc + 1); - b = 2; - break; - - /* DAD D */ - case 0x19: *state.hl = dad_16(*state.hl, *state.de); - - /* needs 4 more cycles */ - cycles_step(); - - break; - - /* LDAX D */ - case 0x1A: state.a = mmu_read(*state.de); - break; - - /* DCX D */ - case 0x1B: (*state.de)--; - cycles_step(); - break; - - /* INR E */ - case 0x1C: state.e = z80_inr(state.e); - break; - - /* DCR E */ - case 0x1D: state.e = z80_dcr(state.e); - break; - - /* MVI E */ - case 0x1E: state.e = mmu_read(state.pc + 1); - b = 2; - break; - - /* RRA */ - case 0x1F: z80_rra(&state.a, 0); - break; - - /* JRNZ */ - case 0x20: cycles_step(); - - if (!state.flags.z) - state.pc += (int8_t) mmu_read(state.pc + 1); - - b = 2; - break; - - /* LXI H */ - case 0x21: *state.hl = ADDR; - b = 3; - break; - - /* LDI (HL), A */ - case 0x22: mmu_write(*state.hl, state.a); - (*state.hl)++; - break; - - /* INX H */ - case 0x23: (*state.hl)++; - cycles_step(); - break; - - /* INR H */ - case 0x24: state.h = z80_inr(state.h); - break; - - /* DCR H */ - case 0x25: state.h = z80_dcr(state.h); - break; - - /* MVI H */ - case 0x26: state.h = mmu_read(state.pc + 1); - b = 2; - break; - - /* DAA */ - case 0x27: z80_daa(); - break; - - /* JRZ */ - case 0x28: cycles_step(); - if (state.flags.z) - state.pc += (int8_t) mmu_read(state.pc + 1); - - b = 2; - break; - - /* DAD H */ - case 0x29: *state.hl = dad_16(*state.hl, *state.hl); - - /* needs 4 more cycles */ - cycles_step(); - - break; - - /* LDI A,(HL) */ - case 0x2A: state.a = mmu_read(*state.hl); - (*state.hl)++; - break; - - /* DCX H */ - case 0x2B: (*state.hl)--; - cycles_step(); - break; - - /* INR L */ - case 0x2C: state.l = z80_inr(state.l); - break; - - /* DCR L */ - case 0x2D: state.l = z80_dcr(state.l); - break; - - /* MVI L */ - case 0x2E: state.l = mmu_read(state.pc + 1); - b = 2; - break; - - /* CMA A */ - case 0x2F: state.a = ~state.a; - state.flags.ac = 1; - state.flags.n = 1; - break; - - /* JRNC */ - case 0x30: cycles_step(); - - if (!state.flags.cy) - state.pc += (int8_t) mmu_read(state.pc + 1); - - b = 2; - break; - - /* LXI SP */ - case 0x31: state.sp = ADDR; - b = 3; - break; - - /* LDD (HL), A */ - case 0x32: mmu_write(*state.hl, state.a); - (*state.hl)--; - break; - - /* INX SP */ - case 0x33: state.sp++; - cycles_step(); - break; - - /* INR M */ - case 0x34: mmu_write(*state.hl, z80_inr(mmu_read(*state.hl))); - break; - - /* DCR M */ - case 0x35: mmu_write(*state.hl, z80_dcr(mmu_read(*state.hl))); - break; - - /* MVI M */ - case 0x36: mmu_move(*state.hl, state.pc + 1); - b = 2; - break; - - /* STC */ - case 0x37: state.flags.cy = 1; - state.flags.ac = 0; - state.flags.n = 0; - break; - - /* JRC */ - case 0x38: cycles_step(); - if (state.flags.cy) - state.pc += (int8_t) mmu_read(state.pc + 1); - - b = 2; - break; - - /* DAD SP */ - case 0x39: *state.hl = dad_16(*state.hl, state.sp); - - /* needs 4 more cycles */ - cycles_step(); - - break; - - /* LDD A,(HL) */ - case 0x3A: state.a = mmu_read(*state.hl); - (*state.hl)--; - break; - - /* DCX SP */ - case 0x3B: state.sp--; - cycles_step(); - break; - - /* INR A */ - case 0x3C: state.a = z80_inr(state.a); - break; - - /* DCR A */ - case 0x3D: state.a = z80_dcr(state.a); - break; - - /* MVI A */ - case 0x3E: state.a = mmu_read(state.pc + 1); - b = 2; - break; - - /* CCF */ - case 0x3F: state.flags.ac = 0; - state.flags.cy = !state.flags.cy; - state.flags.n = 0; - - break; - - /* MOV B,B */ - case 0x40: state.b = state.b; - break; - - /* MOV B,C */ - case 0x41: state.b = state.c; - break; - - /* MOV B,D */ - case 0x42: state.b = state.d; - break; - - /* MOV B,E */ - case 0x43: state.b = state.e; - break; - - /* MOV B,H */ - case 0x44: state.b = state.h; - break; - - /* MOV B,L */ - case 0x45: state.b = state.l; - break; - - /* MOV B,M */ - case 0x46: state.b = mmu_read(*state.hl); - break; - - /* MOV B,A */ - case 0x47: state.b = state.a; - break; - - /* MOV C,B */ - case 0x48: state.c = state.b; - break; - - /* MOV C,C */ - case 0x49: state.c = state.c; - break; - - /* MOV C,D */ - case 0x4A: state.c = state.d; - break; - - /* MOV C,E */ - case 0x4B: state.c = state.e; - break; - - /* MOV C,H */ - case 0x4C: state.c = state.h; - break; - - /* MOV C,L */ - case 0x4D: state.c = state.l; - break; - - /* MOV C,M */ - case 0x4E: state.c = mmu_read(*state.hl); - break; - - /* MOV C,A */ - case 0x4F: state.c = state.a; - break; - - /* MOV D,B */ - case 0x50: state.d = state.b; - break; - - /* MOV D,C */ - case 0x51: state.d = state.c; - break; - - /* MOV D,D */ - case 0x52: state.d = state.d; - break; - - /* MOV D,E */ - case 0x53: state.d = state.e; - break; - - /* MOV D,H */ - case 0x54: state.d = state.h; - break; - - /* MOV D,L */ - case 0x55: state.d = state.l; - break; - - /* MOV D,M */ - case 0x56: state.d = mmu_read(*state.hl); - break; - - /* MOV D,A */ - case 0x57: state.d = state.a; - break; - - /* MOV E,B */ - case 0x58: state.e = state.b; - break; - - /* MOV E,C */ - case 0x59: state.e = state.c; - break; - - /* MOV E,D */ - case 0x5A: state.e = state.d; - break; - - /* MOV E,E */ - case 0x5B: state.e = state.e; - break; - - /* MOV E,H */ - case 0x5C: state.e = state.h; - break; - - /* MOV E,L */ - case 0x5D: state.e = state.l; - break; - - /* MOV E,M */ - case 0x5E: state.e = mmu_read(*state.hl); - break; - - /* MOV E,A */ - case 0x5F: state.e = state.a; - break; - - /* MOV H,B */ - case 0x60: state.h = state.b; - break; - - /* MOV H,C */ - case 0x61: state.h = state.c; - break; - - /* MOV H,D */ - case 0x62: state.h = state.d; - break; - - /* MOV H,E */ - case 0x63: state.h = state.e; - break; - - /* MOV H,H */ - case 0x64: state.h = state.h; - break; - - /* MOV H,L */ - case 0x65: state.h = state.l; - break; - - /* MOV H,M */ - case 0x66: state.h = mmu_read(*state.hl); - break; - - /* MOV H,A */ - case 0x67: state.h = state.a; - break; - - /* MOV L,B */ - case 0x68: state.l = state.b; - break; - - /* MOV L,C */ - case 0x69: state.l = state.c; - break; - - /* MOV L,D */ - case 0x6A: state.l = state.d; - break; - - /* MOV L,E */ - case 0x6B: state.l = state.e; - break; - - /* MOV L,H */ - case 0x6C: state.l = state.h; - break; - - /* MOV L,L */ - case 0x6D: state.l = state.l; - break; - - /* MOV L,M */ - case 0x6E: state.l = mmu_read(*state.hl); - break; - - /* MOV L,A */ - case 0x6F: state.l = state.a; - break; - - /* MOV M,B */ - case 0x70: mmu_write(*state.hl, state.b); - break; - - /* MOV M,C */ - case 0x71: mmu_write(*state.hl, state.c); - break; - - /* MOV M,D */ - case 0x72: mmu_write(*state.hl, state.d); - break; - - /* MOV M,E */ - case 0x73: mmu_write(*state.hl, state.e); - break; - - /* MOV M,H */ - case 0x74: mmu_write(*state.hl, state.h); - break; - - /* MOV M,L */ - case 0x75: mmu_write(*state.hl, state.l); - break; - - /* HLT */ - case 0x76: return 1; - - /* MOV M,A */ - case 0x77: mmu_write(*state.hl, state.a); - break; - - /* MOV A,B */ - case 0x78: state.a = state.b; - break; - - /* MOV A,C */ - case 0x79: state.a = state.c; - break; - - /* MOV A,D */ - case 0x7A: state.a = state.d; - break; - - /* MOV A,E */ - case 0x7B: state.a = state.e; - break; - - /* MOV A,H */ - case 0x7C: state.a = state.h; - break; - - /* MOV A,L */ - case 0x7D: state.a = state.l; - break; - - /* MOV A,M */ - case 0x7E: state.a = mmu_read(*state.hl); - break; - - /* MOV A,A */ - case 0x7F: state.a = state.a; - break; - - /* ADD B */ - case 0x80: z80_add(state.b); - break; - - /* ADD C */ - case 0x81: z80_add(state.c); - break; - - /* ADD D */ - case 0x82: z80_add(state.d); - break; - - /* ADD E */ - case 0x83: z80_add(state.e); - break; - - /* ADD H */ - case 0x84: z80_add(state.h); - break; - - /* ADD L */ - case 0x85: z80_add(state.l); - break; - - /* ADD M */ - case 0x86: z80_add(mmu_read(*state.hl)); - break; - - /* ADD A */ - case 0x87: z80_add(state.a); - break; - - /* ADC B */ - case 0x88: z80_adc(state.b); - break; - - /* ADC C */ - case 0x89: z80_adc(state.c); - break; - - /* ADC D */ - case 0x8A: z80_adc(state.d); - break; - - /* ADC E */ - case 0x8B: z80_adc(state.e); - break; - - /* ADC H */ - case 0x8C: z80_adc(state.h); - break; - - /* ADC L */ - case 0x8D: z80_adc(state.l); - break; - - /* ADC M */ - case 0x8E: z80_adc(mmu_read(*state.hl)); - break; - - /* ADC A */ - case 0x8F: z80_adc(state.a); - break; - - /* SUB B */ - case 0x90: z80_sub(state.b); - break; - - /* SUB C */ - case 0x91: z80_sub(state.c); - break; - - /* SUB D */ - case 0x92: z80_sub(state.d); - break; - - /* SUB E */ - case 0x93: z80_sub(state.e); - break; - - /* SUB H */ - case 0x94: z80_sub(state.h); - break; - - /* SUB L */ - case 0x95: z80_sub(state.l); - break; - - /* SUB M */ - case 0x96: z80_sub(mmu_read(*state.hl)); - break; - - /* SUB A */ - case 0x97: z80_sub(state.a); - break; - - /* SBC B */ - case 0x98: z80_sbc(state.b); - break; - - /* SBC C */ - case 0x99: z80_sbc(state.c); - break; - - /* SBC D */ - case 0x9a: z80_sbc(state.d); - break; - - /* SBC E */ - case 0x9b: z80_sbc(state.e); - break; - - /* SBC H */ - case 0x9c: z80_sbc(state.h); - break; - - /* SBC L */ - case 0x9d: z80_sbc(state.l); - break; - - /* SBC M */ - case 0x9E: z80_sbc(mmu_read(*state.hl)); - break; - - /* SBC A */ - case 0x9f: z80_sbc(state.a); - break; - - /* ANA B */ - case 0xA0: z80_ana(state.b); - break; - - /* ANA C */ - case 0xA1: z80_ana(state.c); - break; - - /* ANA D */ - case 0xA2: z80_ana(state.d); - break; - - /* ANA E */ - case 0xA3: z80_ana(state.e); - break; - - /* ANA H */ - case 0xA4: z80_ana(state.h); - break; - - /* ANA L */ - case 0xA5: z80_ana(state.l); - break; - - /* ANA M */ - case 0xA6: z80_ana(mmu_read(*state.hl)); - break; - - /* ANA A */ - case 0xA7: z80_ana(state.a); - break; - - /* XRA B */ - case 0xA8: z80_xra(state.b); - break; - - /* XRA C */ - case 0xA9: z80_xra(state.c); - break; - - /* XRA D */ - case 0xAA: z80_xra(state.d); - break; - - /* XRA E */ - case 0xAB: z80_xra(state.e); - break; - - /* XRA H */ - case 0xAC: z80_xra(state.h); - break; - - /* XRA L */ - case 0xAD: z80_xra(state.l); - break; - - /* XRA M */ - case 0xAE: z80_xra(mmu_read(*state.hl)); - break; - - /* XRA A */ - case 0xAF: z80_xra(state.a); - break; - - /* ORA B */ - case 0xB0: z80_ora(state.b); - break; - - /* ORA C */ - case 0xB1: z80_ora(state.c); - break; - - /* ORA D */ - case 0xB2: z80_ora(state.d); - break; - - /* ORA E */ - case 0xB3: z80_ora(state.e); - break; - - /* ORA H */ - case 0xB4: z80_ora(state.h); - break; - - /* ORA L */ - case 0xB5: z80_ora(state.l); - break; - - /* ORA M */ - case 0xB6: z80_ora(mmu_read(*state.hl)); - break; - - /* ORA A */ - case 0xB7: z80_ora(state.a); - break; - - /* CMP B */ - case 0xB8: z80_cmp(state.b); - break; - - /* CMP C */ - case 0xB9: z80_cmp(state.c); - break; - - /* CMP D */ - case 0xBA: z80_cmp(state.d); - break; - - /* CMP E */ - case 0xBB: z80_cmp(state.e); - break; - - /* CMP H */ - case 0xBC: z80_cmp(state.h); - break; - - /* CMP L */ - case 0xBD: z80_cmp(state.l); - break; - - /* CMP M */ - case 0xBE: z80_cmp(mmu_read(*state.hl)); - break; - - /* CMP A */ - case 0xBF: z80_cmp(state.a); - break; - - /* RNZ */ - case 0xC0: cycles_step(); - - if (state.flags.z == 0) - return z80_ret(); - - break; - - /* POP B */ - case 0xC1: *state.bc = mmu_read_16(state.sp); - state.sp += 2; - break; - - /* JNZ addr */ - case 0xC2: /* this will add 8 cycles */ - addr = ADDR; - - if (state.flags.z == 0) - { - /* add 4 more cycles */ - cycles_step(); - - state.pc = addr; - return 0; - } - - b = 3; - break; - - /* JMP addr */ - case 0xC3: state.pc = ADDR; - - /* add 4 cycles */ - cycles_step(); - - return 0; - - /* CNZ */ - case 0xC4: addr = ADDR; - - if (state.flags.z == 0) - return z80_call(addr); - - b = 3; - break; - - /* PUSH B */ - case 0xC5: cycles_step(); - mmu_write_16(state.sp - 2, *state.bc); - state.sp -= 2; - break; - - /* ADI */ - case 0xC6: z80_add(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 0 */ - case 0xC7: state.pc++; - return z80_intr(0x0008 * 0); - - /* RZ */ - case 0xC8: cycles_step(); - - if (state.flags.z) - return z80_ret(); - - break; - - /* RET */ - case 0xC9: return z80_ret(); - - /* JZ */ - case 0xCA: /* add 8 cycles */ - addr = ADDR; - - if (state.flags.z) - { - /* add 4 more cycles */ - cycles_step(); - - state.pc = addr; - return 0; - } - - b = 3; - break; - - /* CB */ - case 0xCB: b = z80_ext_cb_execute(); - break; - - /* CZ */ - case 0xCC: addr = ADDR; - - if (state.flags.z) - return z80_call(addr); - - b = 3; - break; - - /* CALL addr */ - case 0xCD: return z80_call(ADDR); - - /* ACI */ - case 0xCE: z80_adc(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 1 */ - case 0xCF: state.pc++; - return z80_intr(0x0008 * 1); - - /* RNC */ - case 0xD0: cycles_step(); - - if (state.flags.cy == 0) - return z80_ret(); - - break; - - /* POP D */ - case 0xD1: *state.de = mmu_read_16(state.sp); - state.sp += 2; - break; - - /* JNC */ - case 0xD2: /* add 8 cycles */ - addr = ADDR; - - if (state.flags.cy == 0) - { - /* add 4 more cycles */ - cycles_step(); - - state.pc = addr; - return 0; - } - - b = 3; - break; - - /* not present */ - case 0xD3: // b = 2; - break; - - /* CNC */ - case 0xD4: addr = ADDR; - - if (state.flags.cy == 0) - return z80_call(addr); - - b = 3; - break; - - /* PUSH D */ - case 0xD5: cycles_step(); - mmu_write_16(state.sp - 2, *state.de); - state.sp -= 2; - break; - - /* SUI */ - case 0xD6: z80_sub(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 2 */ - case 0xD7: state.pc++; - return z80_intr(0x0008 * 2); - - /* RC */ - case 0xD8: cycles_step(); - - if (state.flags.cy) - return z80_ret(); - - break; - - /* RETI */ - case 0xD9: state.int_enable = 1; - return z80_ret(); - break; - - /* JC */ - case 0xDA: /* add 8 cycles */ - addr = ADDR; - - if (state.flags.cy) - { - /* add 4 more cycles */ - cycles_step(); - - state.pc = addr; - return 0; - } - - b = 3; - break; - - /* not present */ - case 0xDB: break; - - /* CC */ - case 0xDC: addr = ADDR; - - if (state.flags.cy) - return z80_call(addr); - - b = 3; - break; - - /* SBI */ - case 0xDE: z80_sbc(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 3 */ - case 0xDF: state.pc++; - return z80_intr(0x0008 * 3); - - /* LD (FF00+N),A */ - case 0xE0: mmu_write(0xFF00 + mmu_read(state.pc + 1), state.a); - b = 2; - break; - - /* POP H */ - case 0xE1: *state.hl = mmu_read_16(state.sp); - state.sp += 2; - break; - - /* LD (FF00+C),A */ - case 0xE2: mmu_write(0xFF00 + state.c, state.a); - break; - - /* not present on Gameboy Z80 */ - case 0xE3: - case 0xE4: break; - - /* PUSH H */ - case 0xE5: cycles_step(); - mmu_write_16(state.sp - 2, *state.hl); - state.sp -= 2; - break; - - /* ANI */ - case 0xE6: z80_ana(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 4 */ - case 0xE7: state.pc++; - return z80_intr(0x0008 * 4); - - /* ADD SP,dd */ - case 0xE8: byte = mmu_read(state.pc + 1); - byte2 = (uint8_t) (state.sp & 0x00ff); - result = byte2 + byte; - - state.flags.z = 0; - state.flags.n = 0; - - state.flags.cy = (result > 0xff); - - /* add 8 cycles */ - cycles_step(); - cycles_step(); - - /* calc xor for AC */ - z80_set_flags_ac(byte2, byte, result); - - /* set sp */ - state.sp += (int8_t) byte; // result & 0xffff; - - b = 2; - break; - - /* PCHL */ - case 0xE9: state.pc = *state.hl; - return 0; - - /* LD (NN),A */ - case 0xEA: mmu_write(ADDR, state.a); - b = 3; - break; - - /* not present on Gameboy Z80 */ - case 0xEB: - case 0xEC: - case 0xED: break; - - /* XRI */ - case 0xEE: z80_xra(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 5 */ - case 0xEF: state.pc++; - return z80_intr(0x0008 * 5); - - /* LD A,(FF00+N) */ - case 0xF0: state.a = mmu_read(0xFF00 + mmu_read(state.pc + 1)); - b = 2; - break; - - /* POP PSW */ - case 0xF1: p = (uint8_t *) &state.flags; - *p = (mmu_read(state.sp) & 0xf0); - state.a = mmu_read(state.sp + 1); - - state.sp += 2; - break; - - /* LD A,(FF00+C) */ - case 0xF2: state.a = mmu_read(0xFF00 + state.c); - break; - - /* DI */ - case 0xF3: state.int_enable = 0; - break; - - /* not present on Gameboy Z80 */ - case 0xF4: break; - - /* PUSH PSW */ - case 0xF5: p = (uint8_t *) &state.flags; - - cycles_step(); - - mmu_write(state.sp - 1, state.a); - mmu_write(state.sp - 2, *p); - state.sp -= 2; - break; - - /* ORI */ - case 0xF6: z80_ora(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 6 */ - case 0xF7: state.pc++; - return z80_intr(0x0008 * 6); - - /* LD HL,SP+dd */ - case 0xF8: byte = mmu_read(state.pc + 1); - byte2 = (uint8_t) (state.sp & 0x00ff); - result = byte2 + byte; - - state.flags.z = 0; - state.flags.n = 0; - - state.flags.cy = (result > 0xff); - - /* add 4 cycles */ - cycles_step(); - - /* calc xor for AC */ - z80_set_flags_ac(byte2, byte, result); - - /* set sp */ - *state.hl = state.sp + (int8_t) byte; // result & 0xffff; - - b = 2; - break; - - /* SPHL */ - case 0xF9: cycles_step(); - state.sp = *state.hl; - break; - - /* LD A, (NN) */ - case 0xFA: state.a = mmu_read(ADDR); - b = 3; - break; - - /* EI */ - case 0xFB: state.int_enable = 1; - break; - - /* not present on Gameboy Z80 */ - case 0xFC: - case 0xFD: break; - - /* CPI */ - case 0xFE: z80_cmp(mmu_read(state.pc + 1)); - b = 2; - break; - - /* RST 7 */ - case 0xFF: state.pc++; - return z80_intr(0x0008 * 7); - - default: return 1; - } - - /* make the PC points to the next instruction */ - state.pc += b; - - return 0; -} - -/* init registers, flags and state.memory of Gameboy Z80 CPU */ -z80_state_t static *z80_init() -{ - /* wipe all the structs */ - bzero(&state, sizeof(z80_state_t)); - -/* 16 bit values just point to the first reg of the pairs */ -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - state.hl = (uint16_t *) &state.l; - state.bc = (uint16_t *) &state.c; - state.de = (uint16_t *) &state.e; -#else - state.hl = (uint16_t *) &state.h; - state.bc = (uint16_t *) &state.b; - state.de = (uint16_t *) &state.d; -#endif - - state.sp = 0xffff; - state.a = 0xff; - - state.b = 0x7f; - state.c = 0xbc; - state.d = 0x00; - state.e = 0x00; - state.h = 0x34; - state.l = 0xc0; - - regs_dst = malloc(8 * sizeof(uint8_t *)); - - regs_dst[0x00] = &state.b; - regs_dst[0x01] = &state.c; - regs_dst[0x02] = &state.d; - regs_dst[0x03] = &state.e; - regs_dst[0x04] = &state.h; - regs_dst[0x05] = &state.l; - regs_dst[0x06] = &dummy; - regs_dst[0x07] = &state.a; - - regs_src = malloc(8 * sizeof(uint8_t *)); - - regs_src[0x00] = &state.b; - regs_src[0x01] = &state.c; - regs_src[0x02] = &state.d; - regs_src[0x03] = &state.e; - regs_src[0x04] = &state.h; - regs_src[0x05] = &state.l; - regs_src[0x06] = mmu_addr(*state.hl); - regs_src[0x07] = &state.a; - - state.flags.cy = 1; - state.flags.n = 1; - state.flags.ac = 1; - state.flags.z = 1; - - /* flags shortcut */ - state.f = (uint8_t *) &state.flags; - - /* flags mask array */ - z80_calc_flags_mask_array(); - - return &state; -} diff --git a/waterbox/pizza/lib/z80_gameboy_regs.h b/waterbox/pizza/lib/z80_gameboy_regs.h deleted file mode 100644 index 6b403005f1..0000000000 --- a/waterbox/pizza/lib/z80_gameboy_regs.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - - -#ifndef Z80_REGS_H -#define Z80_REGS_H - -#include - -/* structs emulating z80 registers and flags */ -typedef struct z80_flags_s -{ - uint8_t spare:4; - uint8_t cy:1; - uint8_t ac:1; - uint8_t n:1; - uint8_t z:1; -} z80_flags_t; - - -/* flags offsets */ -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - - #define FLAG_OFFSET_CY 4 - #define FLAG_OFFSET_AC 5 - #define FLAG_OFFSET_N 6 - #define FLAG_OFFSET_Z 7 - -#endif - - -#endif diff --git a/waterbox/pizza/pizza.c b/waterbox/pizza/pizza.c deleted file mode 100644 index e88a33d59a..0000000000 --- a/waterbox/pizza/pizza.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - - This file is part of Emu-Pizza - - Emu-Pizza is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Emu-Pizza 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 Emu-Pizza. If not, see . - -*/ - -#include -#include -#include -#include "../emulibc/emulibc.h" -#include "../emulibc/waterboxcore.h" -#include - -#define EXPORT ECL_EXPORT - -#include "cartridge.h" -#include "cycles.h" -#include "gameboy.h" -#include "global.h" -#include "gpu.h" -#include "input.h" -#include "sound.h" -#include "serial.h" -#include "utils.h" -#include "mmu.h" -#include "sound_output.h" -#include "sgb.h" - -/* proto */ -void frame_cb(); -void connected_cb(); -void disconnected_cb(); -void rumble_cb(uint8_t rumble); -void network_send_data(uint8_t v); -void *start_thread(void *args); -void *start_thread_network(void *args); - -/* cartridge name */ -char cart_name[64]; - -int main(void) -{ -} - -EXPORT int Init(const void *rom, int romlen, int sgb, const void *spc, int spclen) -{ - /* init global variables */ - global_init(); - - /* first, load cartridge */ - char ret = cartridge_load(rom, romlen); - - if (ret != 0) - return 0; // failure - global_sgb = !!sgb; - if (global_sgb && global_cgb) - utils_log("Warn: CGB game in SGB mode\n"); - if (sgb && !sgb_init((const uint8_t*)spc, spclen)) - return 0; - - gameboy_init(); - - /* init GPU */ - gpu_init(frame_cb); - - /* set rumble cb */ - mmu_set_rumble_cb(&rumble_cb); - - sound_output_init(global_sgb ? 2147727 : 2097152, 44100); - - return 1; -} - -typedef struct -{ - uint32_t *VideoBuffer; - int16_t *SoundBuffer; - int64_t Cycles; - int32_t Width; - int32_t Height; - int32_t Samples; - int32_t Lagged; - int64_t Time; - uint32_t Keys; -} MyFrameInfo; - -static uint32_t *current_vbuff; -static uint64_t overflow; - -EXPORT void FrameAdvance(MyFrameInfo *frame) -{ - if (global_sgb) - sgb_set_controller_data((uint8_t *)&frame->Keys); - else - input_set_keys(frame->Keys); - current_vbuff = frame->VideoBuffer; - global_lagged = 1; - global_currenttime = frame->Time; - - uint64_t current = cycles.sampleclock; - uint64_t target = current + 35112 - overflow; - gameboy_run(target); - uint64_t elapsed = cycles.sampleclock - current; - frame->Cycles = elapsed; - overflow = cycles.sampleclock - target; - - frame->Samples = sound_output_read(frame->SoundBuffer); - if (global_sgb) - { - frame->Width = 256; - frame->Height = 224; - } - else - { - frame->Width = 160; - frame->Height = 144; - } - frame->Lagged = global_lagged; - current_vbuff = NULL; -} - -EXPORT int IsCGB(void) -{ - return global_cgb; -} - -EXPORT void SetInputCallback(void (*callback)(void)) -{ - global_input_callback = callback; -} - -EXPORT void GetMemoryAreas(MemoryArea *m) -{ - m[0].Data = mmu.memory; - m[0].Name = "Fake System Bus"; - m[0].Size = 0x10000; - m[0].Flags = MEMORYAREA_FLAGS_PRIMARY | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1; -} - -EXPORT int GetSaveramSize(void) -{ - return mmu_saveram_size(); -} - -EXPORT void PutSaveram(const uint8_t* data, int size) -{ - mmu_restore_saveram(data, size); -} - -EXPORT void GetSaveram(uint8_t* data, int size) -{ - mmu_save_saveram(data, size); -} - -void frame_cb() -{ - if (global_sgb) - { - sgb_render_frame(current_vbuff); - } - else - { - memcpy(current_vbuff, gpu.frame_buffer, sizeof(gpu.frame_buffer)); - } -} - -void connected_cb() -{ - utils_log("Connected\n"); -} - -void disconnected_cb() -{ - utils_log("Disconnected\n"); -} - -void rumble_cb(uint8_t rumble) -{ - if (rumble) - printf("RUMBLE\n"); -}