diff --git a/apu/apu.cpp b/apu/apu.cpp index f6e24456..47f03b6b 100644 --- a/apu/apu.cpp +++ b/apu/apu.cpp @@ -183,6 +183,7 @@ #include "display.h" #include "linear_resampler.h" #include "hermite_resampler.h" +#include "snes/snes.hpp" #define APU_DEFAULT_INPUT_RATE 32000 #define APU_MINIMUM_SAMPLE_COUNT 512 @@ -195,6 +196,11 @@ SNES_SPC *spc_core = NULL; +namespace SNES +{ + CPU cpu; +} + static uint8 APUROM[64] = { 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, diff --git a/apu/bapu/dsp/SPC_DSP.cpp b/apu/bapu/dsp/SPC_DSP.cpp new file mode 100755 index 00000000..e6ba49ed --- /dev/null +++ b/apu/bapu/dsp/SPC_DSP.cpp @@ -0,0 +1,1072 @@ +// 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,0x00,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; + + if (take_spc_snapshot) + { + take_spc_snapshot = 0; + if (spc_snapshot_callback) + spc_snapshot_callback(); + } + } + + // 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; + amp *= ((stereo_switch & (1 << (v->voice_number + ch * voice_count))) ? 1 : 0); + + // 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; + if ( m.t_echo_ptr >= 0xffc0 && rom_enabled ) + s = GET_LE16SA( &hi_ram [m.t_echo_ptr + ch * 2 - 0xffc0] ); + else + 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) ) + { + if ( m.t_echo_ptr >= 0xffc0 && rom_enabled ) + SET_LE16A( &hi_ram [m.t_echo_ptr + ch * 2 - 0xffc0], m.t_echo_out [ch] ); + else + 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(); + + stereo_switch = 0xffff; + take_spc_snapshot = 0; + spc_snapshot_callback = 0; + + #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(); + + for (int i = 0; i < voice_count; i++) + m.voices[i].voice_number = i; +} + +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 + + +//// Snes9x Accessor + +void SPC_DSP::set_spc_snapshot_callback( void (*callback) (void) ) +{ + spc_snapshot_callback = callback; +} + +void SPC_DSP::dump_spc_snapshot( void ) +{ + take_spc_snapshot = 1; +} + +void SPC_DSP::set_stereo_switch( int value ) +{ + stereo_switch = value; +} + +SPC_DSP::uint8_t SPC_DSP::reg_value( int ch, int addr ) +{ + return m.voices[ch].regs[addr]; +} + +int SPC_DSP::envx_value( int ch ) +{ + return m.voices[ch].env; +} diff --git a/apu/bapu/dsp/SPC_DSP.h b/apu/bapu/dsp/SPC_DSP.h new file mode 100755 index 00000000..61d05ab5 --- /dev/null +++ b/apu/bapu/dsp/SPC_DSP.h @@ -0,0 +1,319 @@ +// 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(); + +// Snes9x Accessor + + int stereo_switch; + int take_spc_snapshot; + int rom_enabled; // mirror + uint8_t *rom, *hi_ram; // mirror + void (*spc_snapshot_callback) (void); + + void set_spc_snapshot_callback( void (*callback) (void) ); + void dump_spc_snapshot( void ); + void set_stereo_switch( int ); + uint8_t reg_value( int, int ); + int envx_value( int ); + +// 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; + int voice_number; + }; +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/apu/bapu/dsp/blargg_common.h b/apu/bapu/dsp/blargg_common.h new file mode 100755 index 00000000..75edff39 --- /dev/null +++ b/apu/bapu/dsp/blargg_common.h @@ -0,0 +1,186 @@ +// 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/apu/bapu/dsp/blargg_config.h b/apu/bapu/dsp/blargg_config.h new file mode 100755 index 00000000..d85d2663 --- /dev/null +++ b/apu/bapu/dsp/blargg_config.h @@ -0,0 +1,24 @@ +// 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/apu/bapu/dsp/blargg_endian.h b/apu/bapu/dsp/blargg_endian.h new file mode 100755 index 00000000..f2daca64 --- /dev/null +++ b/apu/bapu/dsp/blargg_endian.h @@ -0,0 +1,185 @@ +// 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/apu/bapu/dsp/blargg_source.h b/apu/bapu/dsp/blargg_source.h new file mode 100755 index 00000000..5e45c4fb --- /dev/null +++ b/apu/bapu/dsp/blargg_source.h @@ -0,0 +1,100 @@ +/* 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/apu/bapu/dsp/dsp.cpp b/apu/bapu/dsp/dsp.cpp new file mode 100755 index 00000000..f82bd824 --- /dev/null +++ b/apu/bapu/dsp/dsp.cpp @@ -0,0 +1,61 @@ +#include + +#define DSP_CPP +namespace SNES { + +DSP dsp; + +#include "SPC_DSP.cpp" + +void DSP::step(unsigned clocks) { + clock += clocks; +} + +void DSP::synchronize_smp() { + while(clock >= 0) smp.enter(); +} + +void DSP::enter() { + spc_dsp.run(1); + step(24); + +/* signed count = spc_dsp.sample_count(); + if(count > 0) { + for(unsigned n = 0; n < count; n += 2) audio.sample(samplebuffer[n + 0], samplebuffer[n + 1]); + spc_dsp.set_output(samplebuffer, 8192); + } */ +} + +uint8 DSP::read(uint8 addr) { + return spc_dsp.read(addr); +} + +void DSP::write(uint8 addr, uint8 data) { + spc_dsp.write(addr, data); +} + +void DSP::power() { + spc_dsp.init(smp.apuram); + spc_dsp.reset(); + spc_dsp.set_output(samplebuffer, 8192); +} + +void DSP::reset() { + spc_dsp.soft_reset(); + spc_dsp.set_output(samplebuffer, 8192); +} + +void DSP::channel_enable(unsigned channel, bool enable) { + channel_enabled[channel & 7] = enable; + unsigned mask = 0; + for(unsigned i = 0; i < 8; i++) { + if(channel_enabled[i] == false) mask |= 1 << i; + } + spc_dsp.mute_voices(mask); +} + +DSP::DSP() { + for(unsigned i = 0; i < 8; i++) channel_enabled[i] = true; +} + +} diff --git a/apu/bapu/dsp/dsp.hpp b/apu/bapu/dsp/dsp.hpp new file mode 100755 index 00000000..634c6da4 --- /dev/null +++ b/apu/bapu/dsp/dsp.hpp @@ -0,0 +1,26 @@ +#include "SPC_DSP.h" + +class DSP : public Processor { +public: + enum { Threaded = false }; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_smp(); + + uint8 read(uint8 addr); + void write(uint8 addr, uint8 data); + + void enter(); + void power(); + void reset(); + + void channel_enable(unsigned channel, bool enable); + + DSP(); + +private: + SPC_DSP spc_dsp; + int16 samplebuffer[8192]; + bool channel_enabled[8]; +}; + +extern DSP dsp; diff --git a/apu/bapu/dsp/serialization.cpp b/apu/bapu/dsp/serialization.cpp new file mode 100755 index 00000000..0565a1b5 --- /dev/null +++ b/apu/bapu/dsp/serialization.cpp @@ -0,0 +1,31 @@ +#ifdef DSP_CPP + +static void dsp_state_save(unsigned char **out, void *in, size_t size) { + memcpy(*out, in, size); + *out += size; +} + +static void dsp_state_load(unsigned char **in, void *out, size_t size) { + memcpy(out, *in, size); + *in += size; +} + +void DSP::serialize(serializer &s) { + Processor::serialize(s); + s.array(samplebuffer); + + unsigned char state[SPC_DSP::state_size]; + unsigned char *p = state; + memset(&state, 0, SPC_DSP::state_size); + if(s.mode() == serializer::Save) { + spc_dsp.copy_state(&p, dsp_state_save); + s.array(state); + } else if(s.mode() == serializer::Load) { + s.array(state); + spc_dsp.copy_state(&p, dsp_state_load); + } else { + s.array(state); + } +} + +#endif diff --git a/apu/bapu/smp/algorithms.cpp b/apu/bapu/smp/algorithms.cpp new file mode 100755 index 00000000..a55369fb --- /dev/null +++ b/apu/bapu/smp/algorithms.cpp @@ -0,0 +1,122 @@ +uint8 SMP::op_adc(uint8 x, uint8 y) { + int r = x + y + regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = ~(x ^ y) & (x ^ r) & 0x80; + regs.p.h = (x ^ y ^ r) & 0x10; + regs.p.z = (uint8)r == 0; + regs.p.c = r > 0xff; + return r; +} + +uint16 SMP::op_addw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 0; + r = op_adc(x, y); + r |= op_adc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::op_and(uint8 x, uint8 y) { + x &= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_cmp(uint8 x, uint8 y) { + int r = x - y; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint16 SMP::op_cmpw(uint16 x, uint16 y) { + int r = x - y; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint8 SMP::op_eor(uint8 x, uint8 y) { + x ^= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_or(uint8 x, uint8 y) { + x |= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_sbc(uint8 x, uint8 y) { + int r = x - y - !regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = (x ^ y) & (x ^ r) & 0x80; + regs.p.h = !((x ^ y ^ r) & 0x10); + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return r; +} + +uint16 SMP::op_subw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 1; + r = op_sbc(x, y); + r |= op_sbc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::op_inc(uint8 x) { + x++; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_dec(uint8 x) { + x--; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_asl(uint8 x) { + regs.p.c = x & 0x80; + x <<= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_lsr(uint8 x) { + regs.p.c = x & 0x01; + x >>= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_rol(uint8 x) { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = x & 0x80; + x = (x << 1) | carry; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_ror(uint8 x) { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = x & 0x01; + x = carry | (x >> 1); + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} diff --git a/apu/bapu/smp/core.cpp b/apu/bapu/smp/core.cpp new file mode 100755 index 00000000..6e0a29b2 --- /dev/null +++ b/apu/bapu/smp/core.cpp @@ -0,0 +1,105 @@ +void SMP::tick() { + timer0.tick(); + timer1.tick(); + timer2.tick(); + + clock += cycle_step_cpu; + dsp.clock -= 24; + synchronize_dsp(); +} + +void SMP::op_io() { + #if defined(CYCLE_ACCURATE) + tick(); + #endif +} + +uint8 SMP::op_read(uint16 addr) { + #if defined(CYCLE_ACCURATE) + tick(); + #endif + if((addr & 0xfff0) == 0x00f0) return mmio_read(addr); + if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; + return apuram[addr]; +} + +void SMP::op_write(uint16 addr, uint8 data) { + #if defined(CYCLE_ACCURATE) + tick(); + #endif + if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data); + apuram[addr] = data; //all writes go to RAM, even MMIO writes +} + +void SMP::op_step() { + #define op_readpc() op_read(regs.pc++) + #define op_readdp(addr) op_read((regs.p.p << 8) + addr) + #define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data) + #define op_readaddr(addr) op_read(addr) + #define op_writeaddr(addr, data) op_write(addr, data) + #define op_readstack() op_read(0x0100 | ++regs.sp) + #define op_writestack(data) op_write(0x0100 | regs.sp--, data) + static unsigned rd, wr, dp, sp, ya, bit; + + #if defined(CYCLE_ACCURATE) + + if(opcode_cycle == 0) { + opcode_number = op_readpc(); + opcode_cycle++; + } else switch(opcode_number) { + #include "core/opcycle_misc.cpp" + #include "core/opcycle_mov.cpp" + #include "core/opcycle_pc.cpp" + #include "core/opcycle_read.cpp" + #include "core/opcycle_rmw.cpp" + } + + #else + + unsigned opcode = op_readpc(); + switch(opcode) { + #include "core/op_misc.cpp" + #include "core/op_mov.cpp" + #include "core/op_pc.cpp" + #include "core/op_read.cpp" + #include "core/op_rmw.cpp" + } + + //TODO: untaken branches should consume less cycles + + timer0.tick(cycle_count_table[opcode]); + timer1.tick(cycle_count_table[opcode]); + timer2.tick(cycle_count_table[opcode]); + + clock += cycle_table_cpu[opcode]; + dsp.clock -= cycle_table_dsp[opcode]; + synchronize_dsp(); + + #endif +} + +const unsigned SMP::cycle_count_table[256] = { + #define c 12 +//0 1 2 3 4 5 6 7 8 9 A B C D E F + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1 + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3 + + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4 + 4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5 + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7 + + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9 + 3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B + + 3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C + 4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D + 2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E + 4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F + + #undef c +}; diff --git a/apu/bapu/smp/core/cc.sh b/apu/bapu/smp/core/cc.sh new file mode 100755 index 00000000..937b7139 --- /dev/null +++ b/apu/bapu/smp/core/cc.sh @@ -0,0 +1 @@ +g++-4.5 -std=gnu++0x -I../../../.. -o generate generate.cpp diff --git a/apu/bapu/smp/core/generate.cpp b/apu/bapu/smp/core/generate.cpp new file mode 100755 index 00000000..77ab3ed2 --- /dev/null +++ b/apu/bapu/smp/core/generate.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +using namespace nall; + +static bool cycle_accurate; + +struct opcode_t { + string name; + lstring args; + unsigned opcode; +}; + +void generate(const char *sourceFilename, const char *targetFilename) { + file fp; + fp.open(targetFilename, file::mode::write); + + string filedata; + filedata.readfile(sourceFilename); + filedata.replace("\r", ""); + + lstring block; + block.split("\n\n", filedata); + + foreach(data, block) { + lstring lines; + lines.split("\n", data); + + linear_vector array; + + unsigned sourceStart = 0; + foreach(line, lines, currentLine) { + line.transform("()", "``"); + lstring part; + part.split("`", line); + lstring arguments; + arguments.split(", ", part[1]); + + opcode_t opcode; + opcode.name = part[0]; + opcode.args = arguments; + opcode.opcode = hex(arguments[0]); + array.append(opcode); + + line.rtrim<1>(","); + if(line.endswith(" {")) { + line.rtrim<1>("{ "); + sourceStart = currentLine + 1; + break; + } + } + + if(cycle_accurate == false) { + foreach(opcode, array) { + fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); + + for(unsigned n = sourceStart; n < lines.size(); n++) { + if(lines[n] == "}") break; + + string output; + + if(lines[n].beginswith(" ")) { + output = lines[n]; + } else { + lstring part; + part.split<1>(":", lines[n]); + output = { " ", part[1] }; + } + + output.replace("$1", opcode.args[1]); + output.replace("$2", opcode.args[2]); + output.replace("$3", opcode.args[3]); + output.replace("$4", opcode.args[4]); + output.replace("$5", opcode.args[5]); + output.replace("$6", opcode.args[6]); + output.replace("$7", opcode.args[7]); + output.replace("$8", opcode.args[8]); + output.replace("end;", "break;"); + + fp.print(output, "\n"); + } + + fp.print(" break;\n"); + fp.print("}\n\n"); + } + } else { + foreach(opcode, array) { + fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); + fp.print(" switch(opcode_cycle++) {\n"); + + for(unsigned n = sourceStart; n < lines.size(); n++) { + if(lines[n] == "}") break; + + bool nextLineEndsCycle = false; + if(lines[n + 1] == "}") nextLineEndsCycle = true; + if(lines[n + 1].beginswith(" ") == false) nextLineEndsCycle = true; + + string output; + + if(lines[n].beginswith(" ")) { + output = { " ", lines[n] }; + } else { + lstring part; + part.split<1>(":", lines[n]); + fp.print(" case ", (unsigned)decimal(part[0]), ":\n"); + output = { " ", part[1] }; + } + + output.replace("$1", opcode.args[1]); + output.replace("$2", opcode.args[2]); + output.replace("$3", opcode.args[3]); + output.replace("$4", opcode.args[4]); + output.replace("$5", opcode.args[5]); + output.replace("$6", opcode.args[6]); + output.replace("$7", opcode.args[7]); + output.replace("$8", opcode.args[8]); + output.replace("end;", "{ opcode_cycle = 0; break; }"); + + fp.print(output, "\n"); + if(nextLineEndsCycle) { + if(lines[n + 1].beginswith("}")) { + fp.print(" opcode_cycle = 0;\n"); + } + fp.print(" break;\n"); + } + } + + fp.print(" }\n"); + fp.print(" break;\n"); + fp.print("}\n\n"); + } + } + } + + fp.close(); +} + +int main() { + cycle_accurate = false; + generate("op_misc.b", "op_misc.cpp"); + generate("op_mov.b", "op_mov.cpp" ); + generate("op_pc.b", "op_pc.cpp" ); + generate("op_read.b", "op_read.cpp"); + generate("op_rmw.b", "op_rmw.cpp" ); + + cycle_accurate = true; + generate("op_misc.b", "opcycle_misc.cpp"); + generate("op_mov.b", "opcycle_mov.cpp" ); + generate("op_pc.b", "opcycle_pc.cpp" ); + generate("op_read.b", "opcycle_read.cpp"); + generate("op_rmw.b", "opcycle_rmw.cpp" ); + + return 0; +} diff --git a/apu/bapu/smp/core/op_misc.b b/apu/bapu/smp/core/op_misc.b new file mode 100755 index 00000000..fb258650 --- /dev/null +++ b/apu/bapu/smp/core/op_misc.b @@ -0,0 +1,163 @@ +nop(0x00) { +1:op_io(); +} + +sleep(0xef), +stop(0xff) { +1:op_io(); +2:op_io(); + regs.pc--; +} + +xcn(0x9f) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +daa(0xdf) { +1:op_io(); +2:op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +das(0xbe) { +1:op_io(); +2:op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +clrc(0x60, regs.p.c = 0), +clrp(0x20, regs.p.p = 0), +setc(0x80, regs.p.c = 1), +setp(0x40, regs.p.p = 1) { +1:op_io(); + $1; +} + +clrv(0xe0) { +1:op_io(); + regs.p.v = 0; + regs.p.h = 0; +} + +notc(0xed) { +1:op_io(); +2:op_io(); + regs.p.c = !regs.p.c; +} + +ei(0xa0, 1), +di(0xc0, 0) { +1:op_io(); +2:op_io(); + regs.p.i = $1; +} + +set0_dp(0x02, rd |= 0x01), +clr0_dp(0x12, rd &= ~0x01), +set1_dp(0x22, rd |= 0x02), +clr1_dp(0x32, rd &= ~0x02), +set2_dp(0x42, rd |= 0x04), +clr2_dp(0x52, rd &= ~0x04), +set3_dp(0x62, rd |= 0x08), +clr3_dp(0x72, rd &= ~0x08), +set4_dp(0x82, rd |= 0x10), +clr4_dp(0x92, rd &= ~0x10), +set5_dp(0xa2, rd |= 0x20), +clr5_dp(0xb2, rd &= ~0x20), +set6_dp(0xc2, rd |= 0x40), +clr6_dp(0xd2, rd &= ~0x40), +set7_dp(0xe2, rd |= 0x80), +clr7_dp(0xf2, rd &= ~0x80) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:$1; + op_writedp(dp, rd); +} + +push_a(0x2d, a), +push_x(0x4d, x), +push_y(0x6d, y), +push_p(0x0d, p) { +1:op_io(); +2:op_io(); +3:op_writestack(regs.$1); +} + +pop_a(0xae, a), +pop_x(0xce, x), +pop_y(0xee, y), +pop_p(0x8e, p) { +1:op_io(); +2:op_io(); +3:regs.$1 = op_readstack(); +} + +mul_ya(0xcf) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} + +div_ya_x(0x9e) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); +9:op_io(); +10:op_io(); +11:op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} diff --git a/apu/bapu/smp/core/op_misc.cpp b/apu/bapu/smp/core/op_misc.cpp new file mode 100755 index 00000000..9a6a062d --- /dev/null +++ b/apu/bapu/smp/core/op_misc.cpp @@ -0,0 +1,346 @@ +case 0x00: { + op_io(); + break; +} + +case 0xef: { + op_io(); + op_io(); + regs.pc--; + break; +} + +case 0xff: { + op_io(); + op_io(); + regs.pc--; + break; +} + +case 0x9f: { + op_io(); + op_io(); + op_io(); + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdf: { + op_io(); + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xbe: { + op_io(); + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x60: { + op_io(); + regs.p.c = 0; + break; +} + +case 0x20: { + op_io(); + regs.p.p = 0; + break; +} + +case 0x80: { + op_io(); + regs.p.c = 1; + break; +} + +case 0x40: { + op_io(); + regs.p.p = 1; + break; +} + +case 0xe0: { + op_io(); + regs.p.v = 0; + regs.p.h = 0; + break; +} + +case 0xed: { + op_io(); + op_io(); + regs.p.c = !regs.p.c; + break; +} + +case 0xa0: { + op_io(); + op_io(); + regs.p.i = 1; + break; +} + +case 0xc0: { + op_io(); + op_io(); + regs.p.i = 0; + break; +} + +case 0x02: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x01; + op_writedp(dp, rd); + break; +} + +case 0x12: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x01; + op_writedp(dp, rd); + break; +} + +case 0x22: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x02; + op_writedp(dp, rd); + break; +} + +case 0x32: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x02; + op_writedp(dp, rd); + break; +} + +case 0x42: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x04; + op_writedp(dp, rd); + break; +} + +case 0x52: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x04; + op_writedp(dp, rd); + break; +} + +case 0x62: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x08; + op_writedp(dp, rd); + break; +} + +case 0x72: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x08; + op_writedp(dp, rd); + break; +} + +case 0x82: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x10; + op_writedp(dp, rd); + break; +} + +case 0x92: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x10; + op_writedp(dp, rd); + break; +} + +case 0xa2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x20; + op_writedp(dp, rd); + break; +} + +case 0xb2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x20; + op_writedp(dp, rd); + break; +} + +case 0xc2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x40; + op_writedp(dp, rd); + break; +} + +case 0xd2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x40; + op_writedp(dp, rd); + break; +} + +case 0xe2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x80; + op_writedp(dp, rd); + break; +} + +case 0xf2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x80; + op_writedp(dp, rd); + break; +} + +case 0x2d: { + op_io(); + op_io(); + op_writestack(regs.a); + break; +} + +case 0x4d: { + op_io(); + op_io(); + op_writestack(regs.x); + break; +} + +case 0x6d: { + op_io(); + op_io(); + op_writestack(regs.y); + break; +} + +case 0x0d: { + op_io(); + op_io(); + op_writestack(regs.p); + break; +} + +case 0xae: { + op_io(); + op_io(); + regs.a = op_readstack(); + break; +} + +case 0xce: { + op_io(); + op_io(); + regs.x = op_readstack(); + break; +} + +case 0xee: { + op_io(); + op_io(); + regs.y = op_readstack(); + break; +} + +case 0x8e: { + op_io(); + op_io(); + regs.p = op_readstack(); + break; +} + +case 0xcf: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9e: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + diff --git a/apu/bapu/smp/core/op_mov.b b/apu/bapu/smp/core/op_mov.b new file mode 100755 index 00000000..dee821af --- /dev/null +++ b/apu/bapu/smp/core/op_mov.b @@ -0,0 +1,217 @@ +mov_a_x(0x7d, a, x), +mov_a_y(0xdd, a, y), +mov_x_a(0x5d, x, a), +mov_y_a(0xfd, y, a), +mov_x_sp(0x9d, x, sp) { +1:op_io(); + regs.$1 = regs.$2; + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_sp_x(0xbd, sp, x) { +1:op_io(); + regs.$1 = regs.$2; +} + +mov_a_const(0xe8, a), +mov_x_const(0xcd, x), +mov_y_const(0x8d, y) { +1:regs.$1 = op_readpc(); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_ix(0xe6) { +1:op_io(); +2:regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_ixinc(0xbf) { +1:op_io(); +2:regs.a = op_readdp(regs.x++); +3:op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_dp(0xe4, a), +mov_x_dp(0xf8, x), +mov_y_dp(0xeb, y) { +1:sp = op_readpc(); +2:regs.$1 = op_readdp(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_dpx(0xf4, a, x), +mov_x_dpy(0xf9, x, y), +mov_y_dpx(0xfb, y, x) { +1:sp = op_readpc(); +2:op_io(); +3:regs.$1 = op_readdp(sp + regs.$2); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addr(0xe5, a), +mov_x_addr(0xe9, x), +mov_y_addr(0xec, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:regs.$1 = op_readaddr(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addrx(0xf5, x), +mov_a_addry(0xf6, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:op_io(); +4:regs.a = op_readaddr(sp + regs.$1); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpx(0xe7) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpy(0xf7) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_dp_dp(0xfa) { +1:sp = op_readpc(); +2:rd = op_readdp(sp); +3:dp = op_readpc(); +4:op_writedp(dp, rd); +} + +mov_dp_const(0x8f) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:op_readdp(dp); +4:op_writedp(dp, rd); +} + +mov_ix_a(0xc6) { +1:op_io(); +2:op_readdp(regs.x); +3:op_writedp(regs.x, regs.a); +} + +mov_ixinc_a(0xaf) { +1:op_io(); +2:op_io(); +3:op_writedp(regs.x++, regs.a); +} + +mov_dp_a(0xc4, a), +mov_dp_x(0xd8, x), +mov_dp_y(0xcb, y) { +1:dp = op_readpc(); +2:op_readdp(dp); +3:op_writedp(dp, regs.$1); +} + +mov_dpx_a(0xd4, x, a), +mov_dpy_x(0xd9, y, x), +mov_dpx_y(0xdb, x, y) { +1:dp = op_readpc(); +2:op_io(); + dp += regs.$1; +3:op_readdp(dp); +4:op_writedp(dp, regs.$2); +} + +mov_addr_a(0xc5, a), +mov_addr_x(0xc9, x), +mov_addr_y(0xcc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_readaddr(dp); +4:op_writeaddr(dp, regs.$1); +} + +mov_addrx_a(0xd5, x), +mov_addry_a(0xd6, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); + dp += regs.$1; +4:op_readaddr(dp); +5:op_writeaddr(dp, regs.a); +} + +mov_idpx_a(0xc7) { +1:sp = op_readpc(); +2:op_io(); + sp += regs.x; +3:dp = op_readdp(sp); +4:dp |= op_readdp(sp + 1) << 8; +5:op_readaddr(dp); +6:op_writeaddr(dp, regs.a); +} + +mov_idpy_a(0xd7) { +1:sp = op_readpc(); +2:dp = op_readdp(sp); +3:dp |= op_readdp(sp + 1) << 8; +4:op_io(); + dp += regs.y; +5:op_readaddr(dp); +6:op_writeaddr(dp, regs.a); +} + +movw_ya_dp(0xba) { +1:sp = op_readpc(); +2:regs.a = op_readdp(sp); +3:op_io(); +4:regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); +} + +movw_dp_ya(0xda) { +1:dp = op_readpc(); +2:op_readdp(dp); +3:op_writedp(dp, regs.a); +4:op_writedp(dp + 1, regs.y); +} + +mov1_c_bit(0xaa) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); +} + +mov1_bit_c(0xca) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); +4:op_io(); +5:op_writeaddr(dp, rd); +} diff --git a/apu/bapu/smp/core/op_mov.cpp b/apu/bapu/smp/core/op_mov.cpp new file mode 100755 index 00000000..f3079423 --- /dev/null +++ b/apu/bapu/smp/core/op_mov.cpp @@ -0,0 +1,389 @@ +case 0x7d: { + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdd: { + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x5d: { + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xfd: { + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9d: { + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xbd: { + op_io(); + regs.sp = regs.x; + break; +} + +case 0xe8: { + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xcd: { + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0x8d: { + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xe6: { + op_io(); + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xbf: { + op_io(); + regs.a = op_readdp(regs.x++); + op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe4: { + sp = op_readpc(); + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf8: { + sp = op_readpc(); + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xeb: { + sp = op_readpc(); + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xf4: { + sp = op_readpc(); + op_io(); + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf9: { + sp = op_readpc(); + op_io(); + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xfb: { + sp = op_readpc(); + op_io(); + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xe5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe9: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xec: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xf5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf6: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xfa: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + op_writedp(dp, rd); + break; +} + +case 0x8f: { + rd = op_readpc(); + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, rd); + break; +} + +case 0xc6: { + op_io(); + op_readdp(regs.x); + op_writedp(regs.x, regs.a); + break; +} + +case 0xaf: { + op_io(); + op_io(); + op_writedp(regs.x++, regs.a); + break; +} + +case 0xc4: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.a); + break; +} + +case 0xd8: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.x); + break; +} + +case 0xcb: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.y); + break; +} + +case 0xd4: { + dp = op_readpc(); + op_io(); + dp += regs.x; + op_readdp(dp); + op_writedp(dp, regs.a); + break; +} + +case 0xd9: { + dp = op_readpc(); + op_io(); + dp += regs.y; + op_readdp(dp); + op_writedp(dp, regs.x); + break; +} + +case 0xdb: { + dp = op_readpc(); + op_io(); + dp += regs.x; + op_readdp(dp); + op_writedp(dp, regs.y); + break; +} + +case 0xc5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xc9: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.x); + break; +} + +case 0xcc: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.y); + break; +} + +case 0xd5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xd6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.y; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xc7: { + sp = op_readpc(); + op_io(); + sp += regs.x; + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xd7: { + sp = op_readpc(); + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_io(); + dp += regs.y; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xba: { + sp = op_readpc(); + regs.a = op_readdp(sp); + op_io(); + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + break; +} + +case 0xda: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.a); + op_writedp(dp + 1, regs.y); + break; +} + +case 0xaa: { + sp = op_readpc(); + sp |= op_readpc() << 8; + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); + break; +} + +case 0xca: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + op_io(); + op_writeaddr(dp, rd); + break; +} + diff --git a/apu/bapu/smp/core/op_pc.b b/apu/bapu/smp/core/op_pc.b new file mode 100755 index 00000000..affaf844 --- /dev/null +++ b/apu/bapu/smp/core/op_pc.b @@ -0,0 +1,179 @@ +bra(0x2f, 0), +beq(0xf0, !regs.p.z), +bne(0xd0, regs.p.z), +bcs(0xb0, !regs.p.c), +bcc(0x90, regs.p.c), +bvs(0x70, !regs.p.v), +bvc(0x50, regs.p.v), +bmi(0x30, !regs.p.n), +bpl(0x10, regs.p.n) { +1:rd = op_readpc(); + if($1)end; +2:op_io(); +3:op_io(); + regs.pc += (int8)rd; +} + +bbs0(0x03, 0x01, !=), +bbc0(0x13, 0x01, ==), +bbs1(0x23, 0x02, !=), +bbc1(0x33, 0x02, ==), +bbs2(0x43, 0x04, !=), +bbc2(0x53, 0x04, ==), +bbs3(0x63, 0x08, !=), +bbc3(0x73, 0x08, ==), +bbs4(0x83, 0x10, !=), +bbc4(0x93, 0x10, ==), +bbs5(0xa3, 0x20, !=), +bbc5(0xb3, 0x20, ==), +bbs6(0xc3, 0x40, !=), +bbc6(0xd3, 0x40, ==), +bbs7(0xe3, 0x80, !=), +bbc7(0xf3, 0x80, ==) { +1:dp = op_readpc(); +2:sp = op_readdp(dp); +3:rd = op_readpc(); +4:op_io(); + if((sp & $1) $2 $1)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dp(0x2e) { +1:dp = op_readpc(); +2:sp = op_readdp(dp); +3:rd = op_readpc(); +4:op_io(); + if(regs.a == sp)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dpx(0xde) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp + regs.x); +4:rd = op_readpc(); +5:op_io(); + if(regs.a == sp)end; +6:op_io(); +7:op_io(); + regs.pc += (int8)rd; +} + +dbnz_dp(0x6e) { +1:dp = op_readpc(); +2:wr = op_readdp(dp); +3:op_writedp(dp, --wr); +4:rd = op_readpc(); + if(wr == 0x00)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +dbnz_y(0xfe) { +1:rd = op_readpc(); +2:op_io(); + regs.y--; +3:op_io(); + if(regs.y == 0x00)end; +4:op_io(); +5:op_io(); + regs.pc += (int8)rd; +} + +jmp_addr(0x5f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; + regs.pc = rd; +} + +jmp_iaddrx(0x1f) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); + dp += regs.x; +4:rd = op_readaddr(dp); +5:rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; +} + +call(0x3f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +pcall(0x4f) { +1:rd = op_readpc(); +2:op_io(); +3:op_io(); +4:op_writestack(regs.pc >> 8); +5:op_writestack(regs.pc); + regs.pc = 0xff00 | rd; +} + +tcall_0(0x01, 0), +tcall_1(0x11, 1), +tcall_2(0x21, 2), +tcall_3(0x31, 3), +tcall_4(0x41, 4), +tcall_5(0x51, 5), +tcall_6(0x61, 6), +tcall_7(0x71, 7), +tcall_8(0x81, 8), +tcall_9(0x91, 9), +tcall_10(0xa1, 10), +tcall_11(0xb1, 11), +tcall_12(0xc1, 12), +tcall_13(0xd1, 13), +tcall_14(0xe1, 14), +tcall_15(0xf1, 15) { +1:dp = 0xffde - ($1 << 1); + rd = op_readaddr(dp); +2:rd |= op_readaddr(dp + 1) << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +brk(0x0f) { +1:rd = op_readaddr(0xffde); +2:rd |= op_readaddr(0xffdf) << 8; +3:op_io(); +4:op_io(); +5:op_writestack(regs.pc >> 8); +6:op_writestack(regs.pc); +7:op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; +} + +ret(0x6f) { +1:rd = op_readstack(); +2:rd |= op_readstack() << 8; +3:op_io(); +4:op_io(); + regs.pc = rd; +} + +reti(0x7f) { +1:regs.p = op_readstack(); +2:rd = op_readstack(); +3:rd |= op_readstack() << 8; +4:op_io(); +5:op_io(); + regs.pc = rd; +} diff --git a/apu/bapu/smp/core/op_pc.cpp b/apu/bapu/smp/core/op_pc.cpp new file mode 100755 index 00000000..763a033e --- /dev/null +++ b/apu/bapu/smp/core/op_pc.cpp @@ -0,0 +1,603 @@ +case 0x2f: { + rd = op_readpc(); + if(0)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xf0: { + rd = op_readpc(); + if(!regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xd0: { + rd = op_readpc(); + if(regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xb0: { + rd = op_readpc(); + if(!regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x90: { + rd = op_readpc(); + if(regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x70: { + rd = op_readpc(); + if(!regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x50: { + rd = op_readpc(); + if(regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x30: { + rd = op_readpc(); + if(!regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x10: { + rd = op_readpc(); + if(regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x03: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) != 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x13: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) == 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x23: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) != 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x33: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) == 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x43: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) != 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x53: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) == 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x63: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) != 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x73: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) == 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x83: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) != 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x93: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) == 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xa3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) != 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xb3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) == 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xc3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) != 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xd3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) == 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xe3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) != 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xf3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) == 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x2e: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xde: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + regs.x); + rd = op_readpc(); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x6e: { + dp = op_readpc(); + wr = op_readdp(dp); + op_writedp(dp, --wr); + rd = op_readpc(); + if(wr == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xfe: { + rd = op_readpc(); + op_io(); + regs.y--; + op_io(); + if(regs.y == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x5f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + regs.pc = rd; + break; +} + +case 0x1f: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; + break; +} + +case 0x3f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x4f: { + rd = op_readpc(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; + break; +} + +case 0x01: { + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x11: { + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x21: { + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x31: { + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x41: { + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x51: { + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x61: { + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x71: { + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x81: { + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x91: { + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xa1: { + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xb1: { + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xc1: { + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xd1: { + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xe1: { + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xf1: { + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x0f: { + rd = op_readaddr(0xffde); + rd |= op_readaddr(0xffdf) << 8; + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; + break; +} + +case 0x6f: { + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; +} + +case 0x7f: { + regs.p = op_readstack(); + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; +} + diff --git a/apu/bapu/smp/core/op_read.b b/apu/bapu/smp/core/op_read.b new file mode 100755 index 00000000..fd2f9d82 --- /dev/null +++ b/apu/bapu/smp/core/op_read.b @@ -0,0 +1,205 @@ +adc_a_const(0x88, adc, a), +and_a_const(0x28, and, a), +cmp_a_const(0x68, cmp, a), +cmp_x_const(0xc8, cmp, x), +cmp_y_const(0xad, cmp, y), +eor_a_const(0x48, eor, a), +or_a_const(0x08, or, a), +sbc_a_const(0xa8, sbc, a) { +1:rd = op_readpc(); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_ix(0x86, adc), +and_a_ix(0x26, and), +cmp_a_ix(0x66, cmp), +eor_a_ix(0x46, eor), +or_a_ix(0x06, or), +sbc_a_ix(0xa6, sbc) { +1:op_io(); +2:rd = op_readdp(regs.x); + regs.a = op_$1(regs.a, rd); +} + +adc_a_dp(0x84, adc, a), +and_a_dp(0x24, and, a), +cmp_a_dp(0x64, cmp, a), +cmp_x_dp(0x3e, cmp, x), +cmp_y_dp(0x7e, cmp, y), +eor_a_dp(0x44, eor, a), +or_a_dp(0x04, or, a), +sbc_a_dp(0xa4, sbc, a) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_dpx(0x94, adc), +and_a_dpx(0x34, and), +cmp_a_dpx(0x74, cmp), +eor_a_dpx(0x54, eor), +or_a_dpx(0x14, or), +sbc_a_dpx(0xb4, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); + regs.a = op_$1(regs.a, rd); +} + +adc_a_addr(0x85, adc, a), +and_a_addr(0x25, and, a), +cmp_a_addr(0x65, cmp, a), +cmp_x_addr(0x1e, cmp, x), +cmp_y_addr(0x5e, cmp, y), +eor_a_addr(0x45, eor, a), +or_a_addr(0x05, or, a), +sbc_a_addr(0xa5, sbc, a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_addrx(0x95, adc, x), +adc_a_addry(0x96, adc, y), +and_a_addrx(0x35, and, x), +and_a_addry(0x36, and, y), +cmp_a_addrx(0x75, cmp, x), +cmp_a_addry(0x76, cmp, y), +eor_a_addrx(0x55, eor, x), +eor_a_addry(0x56, eor, y), +or_a_addrx(0x15, or, x), +or_a_addry(0x16, or, y), +sbc_a_addrx(0xb5, sbc, x), +sbc_a_addry(0xb6, sbc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); +4:rd = op_readaddr(dp + regs.$2); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpx(0x87, adc), +and_a_idpx(0x27, and), +cmp_a_idpx(0x67, cmp), +eor_a_idpx(0x47, eor), +or_a_idpx(0x07, or), +sbc_a_idpx(0xa7, sbc) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpy(0x97, adc), +and_a_idpy(0x37, and), +cmp_a_idpy(0x77, cmp), +eor_a_idpy(0x57, eor), +or_a_idpy(0x17, or), +sbc_a_idpy(0xb7, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp + regs.y); + regs.a = op_$1(regs.a, rd); +} + +adc_ix_iy(0x99, adc, 1), +and_ix_iy(0x39, and, 1), +cmp_ix_iy(0x79, cmp, 0), +eor_ix_iy(0x59, eor, 1), +or_ix_iy(0x19, or, 1), +sbc_ix_iy(0xb9, sbc, 1) { +1:op_io(); +2:rd = op_readdp(regs.y); +3:wr = op_readdp(regs.x); + wr = op_$1(wr, rd); +4:($2) ? op_writedp(regs.x, wr) : op_io(); +} + +adc_dp_dp(0x89, adc, 1), +and_dp_dp(0x29, and, 1), +cmp_dp_dp(0x69, cmp, 0), +eor_dp_dp(0x49, eor, 1), +or_dp_dp(0x09, or, 1), +sbc_dp_dp(0xa9, sbc, 1) { +1:sp = op_readpc(); +2:rd = op_readdp(sp); +3:dp = op_readpc(); +4:wr = op_readdp(dp); +5:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +adc_dp_const(0x98, adc, 1), +and_dp_const(0x38, and, 1), +cmp_dp_const(0x78, cmp, 0), +eor_dp_const(0x58, eor, 1), +or_dp_const(0x18, or, 1), +sbc_dp_const(0xb8, sbc, 1) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:wr = op_readdp(dp); +4:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +addw_ya_dp(0x7a, addw), +subw_ya_dp(0x9a, subw) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:op_io(); +4:rd |= op_readdp(dp + 1) << 8; + regs.ya = op_$1(regs.ya, rd); +} + +cmpw_ya_dp(0x5a) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); +} + +and1_bit(0x4a, !!), +and1_notbit(0x6a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & $1(rd & (1 << bit)); +} + +eor1_bit(0x8a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); +} + +not1_bit(0xea) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); +4:op_writeaddr(dp, rd); +} + +or1_bit(0x0a, !!), +or1_notbit(0x2a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c | $1(rd & (1 << bit)); +} diff --git a/apu/bapu/smp/core/op_read.cpp b/apu/bapu/smp/core/op_read.cpp new file mode 100755 index 00000000..2a16a3c8 --- /dev/null +++ b/apu/bapu/smp/core/op_read.cpp @@ -0,0 +1,744 @@ +case 0x88: { + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x28: { + rd = op_readpc(); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x68: { + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0xc8: { + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0xad: { + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x48: { + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x08: { + rd = op_readpc(); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa8: { + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x86: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x26: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x66: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x46: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x06: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa6: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x84: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x24: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x64: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x3e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x7e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x44: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x04: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa4: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x94: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x34: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x74: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x54: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x14: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb4: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x85: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x25: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x65: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x1e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x5e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x45: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x05: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x95: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x96: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x35: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x36: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x75: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x76: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x55: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x56: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x15: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0x16: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0xb6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x87: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x27: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x67: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x47: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x07: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x97: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x37: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x77: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x57: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x17: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x99: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_adc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x39: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_and(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x79: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_cmp(wr, rd); + (0) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x59: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_eor(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x19: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_or(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0xb9: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_sbc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x89: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x29: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x69: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x49: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x09: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xa9: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x98: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x38: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x78: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x58: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x18: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xb8: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x7a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_addw(regs.ya, rd); + break; +} + +case 0x9a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_subw(regs.ya, rd); + break; +} + +case 0x5a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); + break; +} + +case 0x4a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); + break; +} + +case 0x6a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); + break; +} + +case 0x8a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); + break; +} + +case 0xea: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + op_writeaddr(dp, rd); + break; +} + +case 0x0a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); + break; +} + +case 0x2a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); + break; +} + diff --git a/apu/bapu/smp/core/op_rmw.b b/apu/bapu/smp/core/op_rmw.b new file mode 100755 index 00000000..425574e8 --- /dev/null +++ b/apu/bapu/smp/core/op_rmw.b @@ -0,0 +1,74 @@ +inc_a(0xbc, inc, a), +inc_x(0x3d, inc, x), +inc_y(0xfc, inc, y), +dec_a(0x9c, dec, a), +dec_x(0x1d, dec, x), +dec_y(0xdc, dec, y), +asl_a(0x1c, asl, a), +lsr_a(0x5c, lsr, a), +rol_a(0x3c, rol, a), +ror_a(0x7c, ror, a) { +1:op_io(); + regs.$2 = op_$1(regs.$2); +} + +inc_dp(0xab, inc), +dec_dp(0x8b, dec), +asl_dp(0x0b, asl), +lsr_dp(0x4b, lsr), +rol_dp(0x2b, rol), +ror_dp(0x6b, ror) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd = op_$1(rd); + op_writedp(dp, rd); +} + +inc_dpx(0xbb, inc), +dec_dpx(0x9b, dec), +asl_dpx(0x1b, asl), +lsr_dpx(0x5b, lsr), +rol_dpx(0x3b, rol), +ror_dpx(0x7b, ror) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); +4:rd = op_$1(rd); + op_writedp(dp + regs.x, rd); +} + +inc_addr(0xac, inc), +dec_addr(0x8c, dec), +asl_addr(0x0c, asl), +lsr_addr(0x4c, lsr), +rol_addr(0x2c, rol), +ror_addr(0x6c, ror) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); +4:rd = op_$1(rd); + op_writeaddr(dp, rd); +} + +tset_addr_a(0x0e, |), +tclr_addr_a(0x4e, &~) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); +4:op_readaddr(dp); +5:op_writeaddr(dp, rd $1 regs.a); +} + +incw_dp(0x3a, ++), +decw_dp(0x1a, --) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); + rd$1; +3:op_writedp(dp++, rd); +4:rd += op_readdp(dp) << 8; +5:op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); +} diff --git a/apu/bapu/smp/core/op_rmw.cpp b/apu/bapu/smp/core/op_rmw.cpp new file mode 100755 index 00000000..f89ecacf --- /dev/null +++ b/apu/bapu/smp/core/op_rmw.cpp @@ -0,0 +1,262 @@ +case 0xbc: { + op_io(); + regs.a = op_inc(regs.a); + break; +} + +case 0x3d: { + op_io(); + regs.x = op_inc(regs.x); + break; +} + +case 0xfc: { + op_io(); + regs.y = op_inc(regs.y); + break; +} + +case 0x9c: { + op_io(); + regs.a = op_dec(regs.a); + break; +} + +case 0x1d: { + op_io(); + regs.x = op_dec(regs.x); + break; +} + +case 0xdc: { + op_io(); + regs.y = op_dec(regs.y); + break; +} + +case 0x1c: { + op_io(); + regs.a = op_asl(regs.a); + break; +} + +case 0x5c: { + op_io(); + regs.a = op_lsr(regs.a); + break; +} + +case 0x3c: { + op_io(); + regs.a = op_rol(regs.a); + break; +} + +case 0x7c: { + op_io(); + regs.a = op_ror(regs.a); + break; +} + +case 0xab: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_inc(rd); + op_writedp(dp, rd); + break; +} + +case 0x8b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_dec(rd); + op_writedp(dp, rd); + break; +} + +case 0x0b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_asl(rd); + op_writedp(dp, rd); + break; +} + +case 0x4b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_lsr(rd); + op_writedp(dp, rd); + break; +} + +case 0x2b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_rol(rd); + op_writedp(dp, rd); + break; +} + +case 0x6b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_ror(rd); + op_writedp(dp, rd); + break; +} + +case 0xbb: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x9b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x1b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x5b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x3b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x7b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0xac: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_inc(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x8c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_dec(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_asl(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x4c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_lsr(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x2c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_rol(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x6c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_ror(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd | regs.a); + break; +} + +case 0x4e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd &~ regs.a); + break; +} + +case 0x3a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd++; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + +case 0x1a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd--; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + diff --git a/apu/bapu/smp/core/opcycle_misc.cpp b/apu/bapu/smp/core/opcycle_misc.cpp new file mode 100755 index 00000000..963f9fc2 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_misc.cpp @@ -0,0 +1,696 @@ +case 0x00: { + switch(opcode_cycle++) { + case 1: + op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xef: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.pc--; + opcode_cycle = 0; + break; + } + break; +} + +case 0xff: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.pc--; + opcode_cycle = 0; + break; + } + break; +} + +case 0x9f: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbe: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x60: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.c = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x20: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.p = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x80: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.c = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0x40: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.p = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe0: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.v = 0; + regs.p.h = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0xed: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.c = !regs.p.c; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa0: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.i = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc0: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.i = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x02: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x01; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x12: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x01; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x22: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x02; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x32: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x02; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x42: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x04; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x52: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x04; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x62: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x08; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x72: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x08; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x82: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x10; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x92: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x10; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x20; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x20; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x40; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x40; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x80; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x80; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.p); + opcode_cycle = 0; + break; + } + break; +} + +case 0xae: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.a = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xce: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.x = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xee: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.y = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8e: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.p = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_io(); + break; + case 7: + op_io(); + break; + case 8: + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9e: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_io(); + break; + case 7: + op_io(); + break; + case 8: + op_io(); + break; + case 9: + op_io(); + break; + case 10: + op_io(); + break; + case 11: + op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_mov.cpp b/apu/bapu/smp/core/opcycle_mov.cpp new file mode 100755 index 00000000..635c7ca5 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_mov.cpp @@ -0,0 +1,806 @@ +case 0x7d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.sp = regs.x; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe8: { + switch(opcode_cycle++) { + case 1: + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcd: { + switch(opcode_cycle++) { + case 1: + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8d: { + switch(opcode_cycle++) { + case 1: + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x++); + break; + case 3: + op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe4: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf8: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xeb: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf4: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfb: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe5: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xec: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf5: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf6: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfa: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_readdp(regs.x); + break; + case 3: + op_writedp(regs.x, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writedp(regs.x++, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd8: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.x; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd9: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.y; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.x; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc9: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcc: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.x; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd6: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.y; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc7: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + sp += regs.x; + break; + case 3: + dp = op_readdp(sp); + break; + case 4: + dp |= op_readdp(sp + 1) << 8; + break; + case 5: + op_readaddr(dp); + break; + case 6: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd7: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + dp = op_readdp(sp); + break; + case 3: + dp |= op_readdp(sp + 1) << 8; + break; + case 4: + op_io(); + dp += regs.y; + break; + case 5: + op_readaddr(dp); + break; + case 6: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xba: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + break; + case 3: + op_io(); + break; + case 4: + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xda: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + break; + case 4: + op_writedp(dp + 1, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaa: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0xca: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + break; + case 4: + op_io(); + break; + case 5: + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_pc.cpp b/apu/bapu/smp/core/opcycle_pc.cpp new file mode 100755 index 00000000..1cdda647 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_pc.cpp @@ -0,0 +1,1347 @@ +case 0x2f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(0){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.z){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.z){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.c){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x90: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.c){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x70: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.v){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x50: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.v){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x30: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.n){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x10: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.n){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x03: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x01) != 0x01){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x13: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x01) == 0x01){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x23: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x02) != 0x02){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x33: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x02) == 0x02){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x43: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x04) != 0x04){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x53: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x04) == 0x04){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x63: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x08) != 0x08){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x73: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x08) == 0x08){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x83: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x10) != 0x10){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x93: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x10) == 0x10){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x20) != 0x20){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x20) == 0x20){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x40) != 0x40){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x40) == 0x40){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x80) != 0x80){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x80) == 0x80){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x2e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if(regs.a == sp){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xde: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp + regs.x); + break; + case 4: + rd = op_readpc(); + break; + case 5: + op_io(); + if(regs.a == sp){ opcode_cycle = 0; break; } + break; + case 6: + op_io(); + break; + case 7: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x6e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + wr = op_readdp(dp); + break; + case 3: + op_writedp(dp, --wr); + break; + case 4: + rd = op_readpc(); + if(wr == 0x00){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xfe: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + op_io(); + regs.y--; + break; + case 3: + op_io(); + if(regs.y == 0x00){ opcode_cycle = 0; break; } + break; + case 4: + op_io(); + break; + case 5: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x5f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + rd |= op_readpc() << 8; + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x1f: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.x; + break; + case 4: + rd = op_readaddr(dp); + break; + case 5: + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x3f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + rd |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x4f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_writestack(regs.pc >> 8); + break; + case 5: + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x01: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x11: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x21: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x31: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x41: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x51: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x61: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x71: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x81: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x91: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x0f: { + switch(opcode_cycle++) { + case 1: + rd = op_readaddr(0xffde); + break; + case 2: + rd |= op_readaddr(0xffdf) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_writestack(regs.pc >> 8); + break; + case 6: + op_writestack(regs.pc); + break; + case 7: + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x6f: { + switch(opcode_cycle++) { + case 1: + rd = op_readstack(); + break; + case 2: + rd |= op_readstack() << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x7f: { + switch(opcode_cycle++) { + case 1: + regs.p = op_readstack(); + break; + case 2: + rd = op_readstack(); + break; + case 3: + rd |= op_readstack() << 8; + break; + case 4: + op_io(); + break; + case 5: + op_io(); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_read.cpp b/apu/bapu/smp/core/opcycle_read.cpp new file mode 100755 index 00000000..6c19f3a9 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_read.cpp @@ -0,0 +1,1599 @@ +case 0x88: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x28: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x68: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xad: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x48: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x08: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x86: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x26: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x66: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x46: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x06: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x84: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x24: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x64: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x44: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x04: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x94: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x34: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x74: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x54: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x14: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x85: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x25: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x65: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x45: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x05: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x95: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x96: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x35: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x36: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x75: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x76: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x55: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x56: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x15: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x16: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb6: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x87: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x27: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x67: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x47: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x07: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x97: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x37: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x77: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x57: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x17: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x99: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_adc(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x39: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_and(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x79: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_cmp(wr, rd); + break; + case 4: + (0) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x59: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_eor(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x19: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_or(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb9: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_sbc(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x89: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x29: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x69: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x49: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x09: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x98: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x38: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x78: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x58: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x18: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + op_io(); + break; + case 4: + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_addw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + op_io(); + break; + case 4: + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_subw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0xea: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + break; + case 4: + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_rmw.cpp b/apu/bapu/smp/core/opcycle_rmw.cpp new file mode 100755 index 00000000..eca62f02 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_rmw.cpp @@ -0,0 +1,550 @@ +case 0xbc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_inc(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = op_inc(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = op_inc(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_dec(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = op_dec(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = op_dec(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_asl(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_lsr(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_rol(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_ror(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xab: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_inc(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_dec(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_asl(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_lsr(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_rol(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_ror(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xac: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_inc(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_dec(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_asl(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_lsr(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_rol(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_ror(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, rd | regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, rd &~ regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + rd++; + break; + case 3: + op_writedp(dp++, rd); + break; + case 4: + rd += op_readdp(dp) << 8; + break; + case 5: + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + rd--; + break; + case 3: + op_writedp(dp++, rd); + break; + case 4: + rd += op_readdp(dp) << 8; + break; + case 5: + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/debugger/debugger.cpp b/apu/bapu/smp/debugger/debugger.cpp new file mode 100755 index 00000000..9546c118 --- /dev/null +++ b/apu/bapu/smp/debugger/debugger.cpp @@ -0,0 +1,75 @@ +#ifdef SMP_CPP + +void SMPDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] |= UsageExec; + opcode_pc = regs.pc; + + opcode_edge = true; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + if(step_event && step_event() == true) { + debugger.break_event = Debugger::BreakEvent::SMPStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } + opcode_edge = false; + + SMP::op_step(); + synchronize_cpu(); +} + +uint8 SMPDebugger::op_read(uint16 addr) { + uint8 data = SMP::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void SMPDebugger::op_write(uint16 addr, uint8 data) { + SMP::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +SMPDebugger::SMPDebugger() { + usage = new uint8[1 << 16](); + opcode_pc = 0xffc0; + opcode_edge = false; +} + +SMPDebugger::~SMPDebugger() { + delete[] usage; +} + +bool SMPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //$00f0 + item("$00f0", ""); + item("Clock Speed", (unsigned)status.clock_speed); + item("Timers Enable", status.timers_enable); + item("RAM Disable", status.ram_disable); + item("RAM Writable", status.ram_writable); + item("Timers Disable", status.timers_disable); + + //$00f1 + item("$00f1", ""); + item("IPLROM Enable", status.iplrom_enable); + + //$00f2 + item("$00f2", ""); + item("DSP Address", string("0x", hex<2>(status.dsp_addr))); + + #undef item + return false; +} + +#endif diff --git a/apu/bapu/smp/debugger/debugger.hpp b/apu/bapu/smp/debugger/debugger.hpp new file mode 100755 index 00000000..811aa4c6 --- /dev/null +++ b/apu/bapu/smp/debugger/debugger.hpp @@ -0,0 +1,27 @@ +class SMPDebugger : public SMP, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + }; + uint8 *usage; + uint16 opcode_pc; + bool opcode_edge; + + void op_step(); + uint8 op_read(uint16 addr); + void op_write(uint16 addr, uint8 data); + + SMPDebugger(); + ~SMPDebugger(); + + //disassembler + void disassemble_opcode(char *output, uint16 addr); + inline uint8 disassemble_read(uint16 addr); + inline uint16 relb(int8 offset, int op_len); +}; diff --git a/apu/bapu/smp/debugger/disassembler.cpp b/apu/bapu/smp/debugger/disassembler.cpp new file mode 100755 index 00000000..fb76ae92 --- /dev/null +++ b/apu/bapu/smp/debugger/disassembler.cpp @@ -0,0 +1,304 @@ +uint8 SMP::disassemble_read(uint16 addr) { + if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f]; + return smp.apuram[addr]; +} + +uint16 SMP::relb(int8 offset, int op_len) { + uint16 pc = regs.pc + op_len; + return pc + offset; +} + +void SMP::disassemble_opcode(char *output, uint16 addr) { + char *s, t[512]; + uint8 op, op0, op1; + uint16 opw, opdp0, opdp1; + s = output; + + sprintf(s, "..%.4x ", addr); + + op = disassemble_read(addr + 0); + op0 = disassemble_read(addr + 1); + op1 = disassemble_read(addr + 2); + opw = (op0) | (op1 << 8); + opdp0 = ((unsigned)regs.p.p << 8) + op0; + opdp1 = ((unsigned)regs.p.p << 8) + op1; + + strcpy(t, " "); + + switch(op) { + case 0x00: sprintf(t, "nop"); break; + case 0x01: sprintf(t, "tcall 0"); break; + case 0x02: sprintf(t, "set0 $%.3x", opdp0); break; + case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x04: sprintf(t, "or a,$%.3x", opdp0); break; + case 0x05: sprintf(t, "or a,$%.4x", opw); break; + case 0x06: sprintf(t, "or a,(x)"); break; + case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break; + case 0x08: sprintf(t, "or a,#$%.2x", op0); break; + case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break; + case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x0b: sprintf(t, "asl $%.3x", opdp0); break; + case 0x0c: sprintf(t, "asl $%.4x", opw); break; + case 0x0d: sprintf(t, "push p"); break; + case 0x0e: sprintf(t, "tset $%.4x,a", opw); break; + case 0x0f: sprintf(t, "brk"); break; + case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break; + case 0x11: sprintf(t, "tcall 1"); break; + case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break; + case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break; + case 0x15: sprintf(t, "or a,$%.4x+x", opw); break; + case 0x16: sprintf(t, "or a,$%.4x+y", opw); break; + case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break; + case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break; + case 0x19: sprintf(t, "or (x),(y)"); break; + case 0x1a: sprintf(t, "decw $%.3x", opdp0); break; + case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break; + case 0x1c: sprintf(t, "asl a"); break; + case 0x1d: sprintf(t, "dec x"); break; + case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break; + case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break; + case 0x20: sprintf(t, "clrp"); break; + case 0x21: sprintf(t, "tcall 2"); break; + case 0x22: sprintf(t, "set1 $%.3x", opdp0); break; + case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x24: sprintf(t, "and a,$%.3x", opdp0); break; + case 0x25: sprintf(t, "and a,$%.4x", opw); break; + case 0x26: sprintf(t, "and a,(x)"); break; + case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break; + case 0x28: sprintf(t, "and a,#$%.2x", op0); break; + case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break; + case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x2b: sprintf(t, "rol $%.3x", opdp0); break; + case 0x2c: sprintf(t, "rol $%.4x", opw); break; + case 0x2d: sprintf(t, "push a"); break; + case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break; + case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break; + case 0x31: sprintf(t, "tcall 3"); break; + case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break; + case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break; + case 0x35: sprintf(t, "and a,$%.4x+x", opw); break; + case 0x36: sprintf(t, "and a,$%.4x+y", opw); break; + case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break; + case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break; + case 0x39: sprintf(t, "and (x),(y)"); break; + case 0x3a: sprintf(t, "incw $%.3x", opdp0); break; + case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break; + case 0x3c: sprintf(t, "rol a"); break; + case 0x3d: sprintf(t, "inc x"); break; + case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break; + case 0x3f: sprintf(t, "call $%.4x", opw); break; + case 0x40: sprintf(t, "setp"); break; + case 0x41: sprintf(t, "tcall 4"); break; + case 0x42: sprintf(t, "set2 $%.3x", opdp0); break; + case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break; + case 0x45: sprintf(t, "eor a,$%.4x", opw); break; + case 0x46: sprintf(t, "eor a,(x)"); break; + case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break; + case 0x48: sprintf(t, "eor a,#$%.2x", op0); break; + case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break; + case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break; + case 0x4c: sprintf(t, "lsr $%.4x", opw); break; + case 0x4d: sprintf(t, "push x"); break; + case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break; + case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break; + case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break; + case 0x51: sprintf(t, "tcall 5"); break; + case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break; + case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break; + case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break; + case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break; + case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break; + case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break; + case 0x59: sprintf(t, "eor (x),(y)"); break; + case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break; + case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break; + case 0x5c: sprintf(t, "lsr a"); break; + case 0x5d: sprintf(t, "mov x,a"); break; + case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break; + case 0x5f: sprintf(t, "jmp $%.4x", opw); break; + case 0x60: sprintf(t, "clrc"); break; + case 0x61: sprintf(t, "tcall 6"); break; + case 0x62: sprintf(t, "set3 $%.3x", opdp0); break; + case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break; + case 0x65: sprintf(t, "cmp a,$%.4x", opw); break; + case 0x66: sprintf(t, "cmp a,(x)"); break; + case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break; + case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break; + case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break; + case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x6b: sprintf(t, "ror $%.3x", opdp0); break; + case 0x6c: sprintf(t, "ror $%.4x", opw); break; + case 0x6d: sprintf(t, "push y"); break; + case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x6f: sprintf(t, "ret"); break; + case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break; + case 0x71: sprintf(t, "tcall 7"); break; + case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break; + case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break; + case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break; + case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break; + case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break; + case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break; + case 0x79: sprintf(t, "cmp (x),(y)"); break; + case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break; + case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break; + case 0x7c: sprintf(t, "ror a"); break; + case 0x7d: sprintf(t, "mov a,x"); break; + case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break; + case 0x7f: sprintf(t, "reti"); break; + case 0x80: sprintf(t, "setc"); break; + case 0x81: sprintf(t, "tcall 8"); break; + case 0x82: sprintf(t, "set4 $%.3x", opdp0); break; + case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break; + case 0x85: sprintf(t, "adc a,$%.4x", opw); break; + case 0x86: sprintf(t, "adc a,(x)"); break; + case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break; + case 0x88: sprintf(t, "adc a,#$%.2x", op0); break; + case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break; + case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x8b: sprintf(t, "dec $%.3x", opdp0); break; + case 0x8c: sprintf(t, "dec $%.4x", opw); break; + case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break; + case 0x8e: sprintf(t, "pop p"); break; + case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break; + case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break; + case 0x91: sprintf(t, "tcall 9"); break; + case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break; + case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break; + case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break; + case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break; + case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break; + case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break; + case 0x99: sprintf(t, "adc (x),(y)"); break; + case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break; + case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break; + case 0x9c: sprintf(t, "dec a"); break; + case 0x9d: sprintf(t, "mov x,sp"); break; + case 0x9e: sprintf(t, "div ya,x"); break; + case 0x9f: sprintf(t, "xcn a"); break; + case 0xa0: sprintf(t, "ei"); break; + case 0xa1: sprintf(t, "tcall 10"); break; + case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break; + case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break; + case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break; + case 0xa6: sprintf(t, "sbc a,(x)"); break; + case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break; + case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break; + case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break; + case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xab: sprintf(t, "inc $%.3x", opdp0); break; + case 0xac: sprintf(t, "inc $%.4x", opw); break; + case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break; + case 0xae: sprintf(t, "pop a"); break; + case 0xaf: sprintf(t, "mov (x)+,a"); break; + case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break; + case 0xb1: sprintf(t, "tcall 11"); break; + case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break; + case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break; + case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break; + case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break; + case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break; + case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break; + case 0xb9: sprintf(t, "sbc (x),(y)"); break; + case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break; + case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break; + case 0xbc: sprintf(t, "inc a"); break; + case 0xbd: sprintf(t, "mov sp,x"); break; + case 0xbe: sprintf(t, "das a"); break; + case 0xbf: sprintf(t, "mov a,(x)+"); break; + case 0xc0: sprintf(t, "di"); break; + case 0xc1: sprintf(t, "tcall 12"); break; + case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break; + case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break; + case 0xc5: sprintf(t, "mov $%.4x,a", opw); break; + case 0xc6: sprintf(t, "mov (x),a"); break; + case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break; + case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break; + case 0xc9: sprintf(t, "mov $%.4x,x", opw); break; + case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break; + case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break; + case 0xcc: sprintf(t, "mov $%.4x,y", opw); break; + case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break; + case 0xce: sprintf(t, "pop x"); break; + case 0xcf: sprintf(t, "mul ya"); break; + case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break; + case 0xd1: sprintf(t, "tcall 13"); break; + case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break; + case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break; + case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break; + case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break; + case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break; + case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break; + case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break; + case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break; + case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break; + case 0xdc: sprintf(t, "dec y"); break; + case 0xdd: sprintf(t, "mov a,y"); break; + case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xdf: sprintf(t, "daa a"); break; + case 0xe0: sprintf(t, "clrv"); break; + case 0xe1: sprintf(t, "tcall 14"); break; + case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break; + case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break; + case 0xe5: sprintf(t, "mov a,$%.4x", opw); break; + case 0xe6: sprintf(t, "mov a,(x)"); break; + case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break; + case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break; + case 0xe9: sprintf(t, "mov x,$%.4x", opw); break; + case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break; + case 0xec: sprintf(t, "mov y,$%.4x", opw); break; + case 0xed: sprintf(t, "notc"); break; + case 0xee: sprintf(t, "pop y"); break; + case 0xef: sprintf(t, "sleep"); break; + case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break; + case 0xf1: sprintf(t, "tcall 15"); break; + case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break; + case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break; + case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break; + case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break; + case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break; + case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break; + case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break; + case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break; + case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break; + case 0xfc: sprintf(t, "inc y"); break; + case 0xfd: sprintf(t, "mov y,a"); break; + case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break; + case 0xff: sprintf(t, "stop"); break; + } + + t[strlen(t)] = ' '; + strcat(s, t); + + sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ", + regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya); + strcat(s, t); + + sprintf(t, "%c%c%c%c%c%c%c%c", + regs.p.n ? 'N' : 'n', + regs.p.v ? 'V' : 'v', + regs.p.p ? 'P' : 'p', + regs.p.b ? 'B' : 'b', + regs.p.h ? 'H' : 'h', + regs.p.i ? 'I' : 'i', + regs.p.z ? 'Z' : 'z', + regs.p.c ? 'C' : 'c'); + strcat(s, t); +} diff --git a/apu/bapu/smp/iplrom.cpp b/apu/bapu/smp/iplrom.cpp new file mode 100755 index 00000000..a2ade89d --- /dev/null +++ b/apu/bapu/smp/iplrom.cpp @@ -0,0 +1,44 @@ +#ifdef SMP_CPP + +//this is the IPLROM for the S-SMP coprocessor. +//the S-SMP does not allow writing to the IPLROM. +//all writes are instead mapped to the extended +//RAM region, accessible when $f1.d7 is clear. + +const uint8 SMP::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) +}; + +#endif diff --git a/apu/bapu/smp/memory.cpp b/apu/bapu/smp/memory.cpp new file mode 100755 index 00000000..aecba720 --- /dev/null +++ b/apu/bapu/smp/memory.cpp @@ -0,0 +1,130 @@ +unsigned SMP::port_read(unsigned addr) { + return apuram[0xf4 + (addr & 3)]; +} + +void SMP::port_write(unsigned addr, unsigned data) { + apuram[0xf4 + (addr & 3)] = data; +} + +unsigned SMP::mmio_read(unsigned addr) { + switch(addr) { + + case 0xf2: + return status.dsp_addr; + + case 0xf3: + return dsp.read(status.dsp_addr & 0x7f); + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + return cpu.port_read(addr); + + case 0xf8: + return status.ram00f8; + + case 0xf9: + return status.ram00f9; + + case 0xfd: { + unsigned result = timer0.stage3_ticks & 15; + timer0.stage3_ticks = 0; + return result; + } + + case 0xfe: { + unsigned result = timer1.stage3_ticks & 15; + timer1.stage3_ticks = 0; + return result; + } + + case 0xff: { + unsigned result = timer2.stage3_ticks & 15; + timer2.stage3_ticks = 0; + return result; + } + + } + + return 0x00; +} + +void SMP::mmio_write(unsigned addr, unsigned data) { + switch(addr) { + + case 0xf1: + status.iplrom_enable = data & 0x80; + + if(data & 0x30) { + synchronize_cpu(); + if(data & 0x20) { + cpu.port_write(3, 0x00); + cpu.port_write(2, 0x00); + } + if(data & 0x10) { + cpu.port_write(1, 0x00); + cpu.port_write(0, 0x00); + } + } + + if(timer2.enable == false && (data & 0x04)) { + timer2.stage2_ticks = 0; + timer2.stage3_ticks = 0; + } + timer2.enable = data & 0x04; + + if(timer1.enable == false && (data & 0x02)) { + timer1.stage2_ticks = 0; + timer1.stage3_ticks = 0; + } + timer1.enable = data & 0x02; + + if(timer0.enable == false && (data & 0x01)) { + timer0.stage2_ticks = 0; + timer0.stage3_ticks = 0; + } + timer0.enable = data & 0x01; + + break; + + case 0xf2: + status.dsp_addr = data; + break; + + case 0xf3: + if(status.dsp_addr & 0x80) break; + dsp.write(status.dsp_addr, data); + break; + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + port_write(addr, data); + break; + + case 0xf8: + status.ram00f8 = data; + break; + + case 0xf9: + status.ram00f9 = data; + break; + + case 0xfa: + timer0.target = data; + break; + + case 0xfb: + timer1.target = data; + break; + + case 0xfc: + timer2.target = data; + break; + + } +} diff --git a/apu/bapu/smp/smp.cpp b/apu/bapu/smp/smp.cpp new file mode 100755 index 00000000..ba26d0b4 --- /dev/null +++ b/apu/bapu/smp/smp.cpp @@ -0,0 +1,154 @@ +#define CYCLE_ACCURATE + +#include + +#define SMP_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + #include "debugger/disassembler.cpp" + SMPDebugger smp; +#else + SMP smp; +#endif + +#include "algorithms.cpp" +#include "core.cpp" +#include "iplrom.cpp" +#include "memory.cpp" +#include "timing.cpp" + +void SMP::synchronize_cpu() { + if(CPU::Threaded == true) { + //if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +void SMP::synchronize_dsp() { + if(DSP::Threaded == true) { + //if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread); + } else { + while(dsp.clock < 0) dsp.enter(); + } +} + +void SMP::enter() { + while(clock < 0) op_step(); +} + +void SMP::power() { +#ifdef BSNES + Processor::frequency = system.apu_frequency(); +#else + Processor::frequency = 1025600; +#endif + + Processor::clock = 0; + + timer0.target = 0; + timer1.target = 0; + timer2.target = 0; + + for(unsigned n = 0; n < 256; n++) { + cycle_table_dsp[n] = (cycle_count_table[n] * 24); + cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency; + } + + cycle_step_cpu = 24 * cpu.frequency; + + reset(); +} + +void SMP::reset() { + for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00; + + opcode_number = 0; + opcode_cycle = 0; + + regs.pc = 0xffc0; + regs.sp = 0xef; + regs.a = 0x00; + regs.x = 0x00; + regs.y = 0x00; + regs.p = 0x02; + + //$00f1 + status.iplrom_enable = true; + + //$00f2 + status.dsp_addr = 0x00; + + //$00f8,$00f9 + status.ram00f8 = 0x00; + status.ram00f9 = 0x00; + + //timers + timer0.enable = timer1.enable = timer2.enable = false; + timer0.stage1_ticks = timer1.stage1_ticks = timer2.stage1_ticks = 0; + timer0.stage2_ticks = timer1.stage2_ticks = timer2.stage2_ticks = 0; + timer0.stage3_ticks = timer1.stage3_ticks = timer2.stage3_ticks = 0; +} + +#ifdef BSNES +void SMP::serialize(serializer &s) { + Processor::serialize(s); + + s.array(apuram, 64 * 1024); + + s.integer(opcode_number); + s.integer(opcode_cycle); + + s.integer(regs.pc); + s.integer(regs.sp); + s.integer(regs.a); + s.integer(regs.x); + s.integer(regs.y); + + s.integer(regs.p.n); + s.integer(regs.p.v); + s.integer(regs.p.p); + s.integer(regs.p.b); + s.integer(regs.p.h); + s.integer(regs.p.i); + s.integer(regs.p.z); + s.integer(regs.p.c); + + s.integer(status.iplrom_enable); + + s.integer(status.dsp_addr); + + s.integer(status.ram00f8); + s.integer(status.ram00f9); + + s.integer(timer0.enable); + s.integer(timer0.target); + s.integer(timer0.stage1_ticks); + s.integer(timer0.stage2_ticks); + s.integer(timer0.stage3_ticks); + + s.integer(timer1.enable); + s.integer(timer1.target); + s.integer(timer1.stage1_ticks); + s.integer(timer1.stage2_ticks); + s.integer(timer1.stage3_ticks); + + s.integer(timer2.enable); + s.integer(timer2.target); + + s.integer(timer2.stage1_ticks); + s.integer(timer2.stage2_ticks); + s.integer(timer2.stage3_ticks); +} +#endif + +SMP::SMP() { + apuram = new uint8[64 * 1024]; +} + +SMP::~SMP() { +} + +} diff --git a/apu/bapu/smp/smp.hpp b/apu/bapu/smp/smp.hpp new file mode 100755 index 00000000..be52f77a --- /dev/null +++ b/apu/bapu/smp/smp.hpp @@ -0,0 +1,124 @@ +class SMP : public Processor { +public: + static const uint8 iplrom[64]; + uint8 *apuram; + + enum { Threaded = false }; + alwaysinline void synchronize_cpu(); + alwaysinline void synchronize_dsp(); + + unsigned port_read(unsigned port); + void port_write(unsigned port, unsigned data); + + unsigned mmio_read(unsigned addr); + void mmio_write(unsigned addr, unsigned data); + + void enter(); + void power(); + void reset(); + +#ifdef BSNES + void serialize(serializer&); +#endif + SMP(); + ~SMP(); + +//private: + struct Flags { + bool n, v, p, b, h, i, z, c; + + alwaysinline operator unsigned() const { + return (n << 7) | (v << 6) | (p << 5) | (b << 4) + | (h << 3) | (i << 2) | (z << 1) | (c << 0); + }; + + alwaysinline unsigned operator=(unsigned data) { + n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10; + h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; + return *this; + } + + alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); } + alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); } + alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); } + }; + + unsigned opcode_number; + unsigned opcode_cycle; + + struct Regs { + uint16 pc; + uint8 sp; + union { + uint16 ya; +#ifndef __BIG_ENDIAN__ + struct { uint8 a, y; }; +#else + struct { uint8 y, a; }; +#endif + }; + uint8 x; + Flags p; + } regs; + + struct Status { + //$00f1 + bool iplrom_enable; + + //$00f2 + unsigned dsp_addr; + + //$00f8,$00f9 + unsigned ram00f8; + unsigned ram00f9; + } status; + + template + struct Timer { + bool enable; + uint8 target; + uint8 stage1_ticks; + uint8 stage2_ticks; + uint8 stage3_ticks; + + void tick(); + void tick(unsigned clocks); + }; + + Timer<128> timer0; + Timer<128> timer1; + Timer< 16> timer2; + + void tick(); + alwaysinline void op_io(); + debugvirtual alwaysinline uint8 op_read(uint16 addr); + debugvirtual alwaysinline void op_write(uint16 addr, uint8 data); + debugvirtual alwaysinline void op_step(); + static const unsigned cycle_count_table[256]; + uint64 cycle_table_cpu[256]; + unsigned cycle_table_dsp[256]; + uint64 cycle_step_cpu; + + uint8 op_adc (uint8 x, uint8 y); + uint16 op_addw(uint16 x, uint16 y); + uint8 op_and (uint8 x, uint8 y); + uint8 op_cmp (uint8 x, uint8 y); + uint16 op_cmpw(uint16 x, uint16 y); + uint8 op_eor (uint8 x, uint8 y); + uint8 op_inc (uint8 x); + uint8 op_dec (uint8 x); + uint8 op_or (uint8 x, uint8 y); + uint8 op_sbc (uint8 x, uint8 y); + uint16 op_subw(uint16 x, uint16 y); + uint8 op_asl (uint8 x); + uint8 op_lsr (uint8 x); + uint8 op_rol (uint8 x); + uint8 op_ror (uint8 x); +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern SMPDebugger smp; +#else + extern SMP smp; +#endif diff --git a/apu/bapu/smp/timing.cpp b/apu/bapu/smp/timing.cpp new file mode 100755 index 00000000..d278f6f4 --- /dev/null +++ b/apu/bapu/smp/timing.cpp @@ -0,0 +1,26 @@ +template +void SMP::Timer::tick() { + if(++stage1_ticks < cycle_frequency) return; + + stage1_ticks = 0; + if(enable == false) return; + + if(++stage2_ticks != target) return; + + stage2_ticks = 0; + stage3_ticks = (stage3_ticks + 1) & 15; +} + +template +void SMP::Timer::tick(unsigned clocks) { + stage1_ticks += clocks; + if(stage1_ticks < cycle_frequency) return; + + stage1_ticks -= cycle_frequency; + if(enable == false) return; + + if(++stage2_ticks != target) return; + + stage2_ticks = 0; + stage3_ticks = (stage3_ticks + 1) & 15; +} diff --git a/apu/bapu/snes/snes.hpp b/apu/bapu/snes/snes.hpp new file mode 100755 index 00000000..47b687ff --- /dev/null +++ b/apu/bapu/snes/snes.hpp @@ -0,0 +1,45 @@ +#ifndef __SNES_HPP +#define __SNES_HPP + +#include "snes9x.h" + +#define alwaysinline inline +#define debugvirtual + +namespace SNES +{ + +struct Processor +{ + unsigned frequency; + int64 clock; +}; + +class CPU +{ +public: + enum { Threaded = false }; + int frequency; + + void enter () + { + } + + void port_write (uint8 port, uint8 data) + { + } + + uint8 port_read (uint8 port) + { + return 0; + } +}; + +extern CPU cpu; + +#include "smp/smp.hpp" +#include "dsp/dsp.hpp" + +} /* namespace SNES */ + +#endif diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 14d99899..4ec45d06 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -8,7 +8,7 @@ snes9x_gtk_CXXFLAGS = -fno-exceptions -fno-rtti endif noinst_LIBRARIES = -INCLUDES = -I$(top_srcdir) -I.. -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\" +INCLUDES = -I../apu/bapu -I$(top_srcdir) -I.. -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\" CLEANFILES = \ src/gtk_snes9x_ui.cpp \ @@ -123,8 +123,14 @@ snes9x_gtk_SOURCES += \ ../apu/SNES_SPC.cpp \ ../apu/SNES_SPC_misc.cpp \ ../apu/SNES_SPC_state.cpp \ - ../apu/SPC_DSP.cpp \ ../apu/SPC_Filter.cpp + +# Byuu's APU +snes9x_gtk_SOURCES += \ + ../apu/bapu/dsp/dsp.cpp \ + ../apu/bapu/dsp/serialization.cpp \ + ../apu/bapu/dsp/SPC_DSP.cpp \ + ../apu/bapu/smp/smp.cpp # DSP snes9x_gtk_SOURCES += \ diff --git a/gtk/src/gtk_s9xwindow.cpp b/gtk/src/gtk_s9xwindow.cpp index f7713978..f58d934f 100644 --- a/gtk/src/gtk_s9xwindow.cpp +++ b/gtk/src/gtk_s9xwindow.cpp @@ -221,7 +221,6 @@ event_motion_notify (GtkWidget *widget, gpointer user_data) { Snes9xWindow *window = (Snes9xWindow *) user_data; - int c_width, c_height; if (!window->config->rom_loaded || window->last_width <= 0 || @@ -230,9 +229,6 @@ event_motion_notify (GtkWidget *widget, return FALSE; } - c_width = window->get_width (); - c_height = window->get_height (); - window->mouse_loc_x = (uint16) ((int) (event->x) - window->mouse_region_x) * 256 / (window->mouse_region_width <= 0 ? 1 : window->mouse_region_width);