GME update with bug-fixes

- True fix for infinite loops [please verify!]
- True fix for KSS silence
- Fix for HES distorted and unstable/random tempo
This commit is contained in:
Vitaly Novichkov 2019-08-18 03:19:28 +03:00 committed by alexey.lysiuk
parent 7d73616fda
commit 1a070d12a1
7 changed files with 318 additions and 287 deletions

View file

@ -94,14 +94,14 @@ bool Hes_Cpu::run( hes_time_t end_time )
state_t s = this->state_; state_t s = this->state_;
this->state = &s; this->state = &s;
// even on x86, using s.time in place of s_time was slower // even on x86, using s.time in place of s_time was slower
int16_t s_time = s.time; blargg_long s_time = s.time;
// registers // registers
uint16_t pc = r.pc; uint_fast16_t pc = r.pc;
uint8_t a = r.a; uint_fast8_t a = r.a;
uint8_t x = r.x; uint_fast8_t x = r.x;
uint8_t y = r.y; uint_fast8_t y = r.y;
uint16_t sp; uint_fast16_t sp;
SET_SP( r.sp ); SET_SP( r.sp );
#define IS_NEG (nz & 0x8080) #define IS_NEG (nz & 0x8080)
@ -120,11 +120,11 @@ bool Hes_Cpu::run( hes_time_t end_time )
nz |= ~in & st_z;\ nz |= ~in & st_z;\
} while ( 0 ) } while ( 0 )
uint8_t status; uint_fast8_t status;
uint16_t c; // carry set if (c & 0x100) != 0 uint_fast16_t c; // carry set if (c & 0x100) != 0
uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 uint_fast16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
{ {
uint8_t temp = r.status; uint_fast8_t temp = r.status;
SET_STATUS( temp ); SET_STATUS( temp );
} }
@ -153,7 +153,7 @@ loop:
check( (unsigned) x < 0x100 ); check( (unsigned) x < 0x100 );
uint8_t const* instr = s.code_map [pc >> page_shift]; uint8_t const* instr = s.code_map [pc >> page_shift];
uint8_t opcode; uint_fast8_t opcode;
// TODO: eliminate this special case // TODO: eliminate this special case
#if BLARGG_NONPORTABLE #if BLARGG_NONPORTABLE
@ -187,7 +187,7 @@ loop:
4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F 4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F
}; // 0x00 was 8 }; // 0x00 was 8
uint16_t data; uint_fast16_t data;
data = clock_table [opcode]; data = clock_table [opcode];
if ( (s_time += data) >= 0 ) if ( (s_time += data) >= 0 )
goto possibly_out_of_time; goto possibly_out_of_time;
@ -224,7 +224,7 @@ possibly_out_of_time:
// TODO: more efficient way to handle negative branch that wraps PC around // TODO: more efficient way to handle negative branch that wraps PC around
#define BRANCH( cond )\ #define BRANCH( cond )\
{\ {\
int16_t offset = (int8_t) data;\ int_fast16_t offset = (int8_t) data;\
pc++;\ pc++;\
if ( !(cond) ) goto branch_not_taken;\ if ( !(cond) ) goto branch_not_taken;\
pc = uint16_t (pc + offset);\ pc = uint16_t (pc + offset);\
@ -277,7 +277,7 @@ possibly_out_of_time:
case 0xCF: case 0xCF:
case 0xDF: case 0xDF:
case 0xEF: { case 0xEF: {
uint16_t t = 0x101 * READ_LOW( data ); uint_fast16_t t = 0x101 * READ_LOW( data );
t ^= 0xFF; t ^= 0xFF;
pc++; pc++;
data = GET_MSB(); data = GET_MSB();
@ -305,7 +305,7 @@ possibly_out_of_time:
goto branch_taken; goto branch_taken;
case 0x20: { // JSR case 0x20: { // JSR
uint16_t temp = pc + 1; uint_fast16_t temp = pc + 1;
pc = GET_ADDR(); pc = GET_ADDR();
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 ); WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
sp = (sp - 2) | 0x100; sp = (sp - 2) | 0x100;
@ -326,7 +326,7 @@ possibly_out_of_time:
case 0xBD:{// LDA abs,X case 0xBD:{// LDA abs,X
PAGE_CROSS_PENALTY( data + x ); PAGE_CROSS_PENALTY( data + x );
uint16_t addr = GET_ADDR() + x; uint_fast16_t addr = GET_ADDR() + x;
pc += 2; pc += 2;
CPU_READ_FAST( this, addr, TIME, nz ); CPU_READ_FAST( this, addr, TIME, nz );
a = nz; a = nz;
@ -334,7 +334,7 @@ possibly_out_of_time:
} }
case 0x9D:{// STA abs,X case 0x9D:{// STA abs,X
uint16_t addr = GET_ADDR() + x; uint_fast16_t addr = GET_ADDR() + x;
pc += 2; pc += 2;
CPU_WRITE_FAST( this, addr, a, TIME ); CPU_WRITE_FAST( this, addr, a, TIME );
goto loop; goto loop;
@ -348,7 +348,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0xAE:{// LDX abs case 0xAE:{// LDX abs
uint16_t addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
CPU_READ_FAST( this, addr, TIME, nz ); CPU_READ_FAST( this, addr, TIME, nz );
x = nz; x = nz;
@ -363,7 +363,7 @@ possibly_out_of_time:
// Load/store // Load/store
{ {
uint16_t addr; uint_fast16_t addr;
case 0x91: // STA (ind),Y case 0x91: // STA (ind),Y
addr = 0x100 * READ_LOW( uint8_t (data + 1) ); addr = 0x100 * READ_LOW( uint8_t (data + 1) );
addr += READ_LOW( data ) + y; addr += READ_LOW( data ) + y;
@ -389,7 +389,7 @@ possibly_out_of_time:
} }
{ {
uint16_t addr; uint_fast16_t addr;
case 0xA1: // LDA (ind,X) case 0xA1: // LDA (ind,X)
data = uint8_t (data + x); data = uint8_t (data + x);
case 0xB2: // LDA (ind) case 0xB2: // LDA (ind)
@ -419,7 +419,7 @@ possibly_out_of_time:
case 0xBE:{// LDX abs,y case 0xBE:{// LDX abs,y
PAGE_CROSS_PENALTY( data + y ); PAGE_CROSS_PENALTY( data + y );
uint16_t addr = GET_ADDR() + y; uint_fast16_t addr = GET_ADDR() + y;
pc += 2; pc += 2;
FLUSH_TIME(); FLUSH_TIME();
x = nz = READ( addr ); x = nz = READ( addr );
@ -443,7 +443,7 @@ possibly_out_of_time:
case 0x3C: // BIT abs,x case 0x3C: // BIT abs,x
data += x; data += x;
case 0x2C:{// BIT abs case 0x2C:{// BIT abs
uint16_t addr; uint_fast16_t addr;
ADD_PAGE( addr ); ADD_PAGE( addr );
FLUSH_TIME(); FLUSH_TIME();
nz = READ( addr ); nz = READ( addr );
@ -466,7 +466,7 @@ possibly_out_of_time:
goto loop; goto loop;
{ {
uint16_t addr; uint_fast16_t addr;
case 0xB3: // TST abs,x case 0xB3: // TST abs,x
addr = GET_MSB() + x; addr = GET_MSB() + x;
@ -499,7 +499,7 @@ possibly_out_of_time:
goto loop; goto loop;
{ {
uint16_t addr; uint_fast16_t addr;
case 0x0C: // TSB abs case 0x0C: // TSB abs
case 0x1C: // TRB abs case 0x1C: // TRB abs
addr = GET_ADDR(); addr = GET_ADDR();
@ -604,7 +604,7 @@ possibly_out_of_time:
data += x; data += x;
PAGE_CROSS_PENALTY( data ); PAGE_CROSS_PENALTY( data );
case 0xAC:{// LDY abs case 0xAC:{// LDY abs
uint16_t addr = data + 0x100 * GET_MSB(); uint_fast16_t addr = data + 0x100 * GET_MSB();
pc += 2; pc += 2;
FLUSH_TIME(); FLUSH_TIME();
y = nz = READ( addr ); y = nz = READ( addr );
@ -613,7 +613,7 @@ possibly_out_of_time:
} }
{ {
uint8_t temp; uint_fast8_t temp;
case 0x8C: // STY abs case 0x8C: // STY abs
temp = y; temp = y;
goto store_abs; goto store_abs;
@ -621,7 +621,7 @@ possibly_out_of_time:
case 0x8E: // STX abs case 0x8E: // STX abs
temp = x; temp = x;
store_abs: store_abs:
uint16_t addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
FLUSH_TIME(); FLUSH_TIME();
WRITE( addr, temp ); WRITE( addr, temp );
@ -632,7 +632,7 @@ possibly_out_of_time:
// Compare // Compare
case 0xEC:{// CPX abs case 0xEC:{// CPX abs
uint16_t addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc++; pc++;
FLUSH_TIME(); FLUSH_TIME();
data = READ( addr ); data = READ( addr );
@ -651,7 +651,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0xCC:{// CPY abs case 0xCC:{// CPY abs
uint16_t addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc++; pc++;
FLUSH_TIME(); FLUSH_TIME();
data = READ( addr ); data = READ( addr );
@ -678,7 +678,7 @@ possibly_out_of_time:
data = 0x100 * READ_LOW( uint8_t (data + 1) ) + READ_LOW( data );\ data = 0x100 * READ_LOW( uint8_t (data + 1) ) + READ_LOW( data );\
goto ptr##op;\ goto ptr##op;\
case op + 0x0C:{/* (ind),y */\ case op + 0x0C:{/* (ind),y */\
uint16_t temp = READ_LOW( data ) + y;\ uint_fast16_t temp = READ_LOW( data ) + y;\
PAGE_CROSS_PENALTY( temp );\ PAGE_CROSS_PENALTY( temp );\
data = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\ data = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
goto ptr##op;\ goto ptr##op;\
@ -736,8 +736,8 @@ possibly_out_of_time:
adc_imm: { adc_imm: {
if ( status & st_d ) if ( status & st_d )
debug_printf( "Decimal mode not supported\n" ); debug_printf( "Decimal mode not supported\n" );
int16_t carry = c >> 8 & 1; int_fast16_t carry = c >> 8 & 1;
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend int_fast16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
status &= ~st_v; status &= ~st_v;
status |= ov >> 2 & 0x40; status |= ov >> 2 & 0x40;
c = nz = a + data + carry; c = nz = a + data + carry;
@ -765,7 +765,7 @@ possibly_out_of_time:
case 0x2A: { // ROL A case 0x2A: { // ROL A
nz = a << 1; nz = a << 1;
int16_t temp = c >> 8 & 1; int_fast16_t temp = c >> 8 & 1;
c = nz; c = nz;
nz |= temp; nz |= temp;
a = (uint8_t) nz; a = (uint8_t) nz;
@ -871,7 +871,7 @@ possibly_out_of_time:
case 0xD6: // DEC zp,x case 0xD6: // DEC zp,x
data = uint8_t (data + x); data = uint8_t (data + x);
case 0xC6: // DEC zp case 0xC6: // DEC zp
nz = (uint16_t) -1; nz = (unsigned) -1;
add_nz_zp: add_nz_zp:
nz += READ_LOW( data ); nz += READ_LOW( data );
write_nz_zp: write_nz_zp:
@ -896,7 +896,7 @@ possibly_out_of_time:
case 0xCE: // DEC abs case 0xCE: // DEC abs
data = GET_ADDR(); data = GET_ADDR();
dec_ptr: dec_ptr:
nz = (uint16_t) -1; nz = (unsigned) -1;
inc_common: inc_common:
FLUSH_TIME(); FLUSH_TIME();
nz += READ( data ); nz += READ( data );
@ -936,7 +936,7 @@ possibly_out_of_time:
goto loop; goto loop;
#define SWAP_REGS( r1, r2 ) {\ #define SWAP_REGS( r1, r2 ) {\
uint8_t t = r1;\ uint_fast8_t t = r1;\
r1 = r2;\ r1 = r2;\
r2 = t;\ r2 = t;\
goto loop;\ goto loop;\
@ -978,7 +978,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0x40:{// RTI case 0x40:{// RTI
uint8_t temp = READ_LOW( sp ); uint_fast8_t temp = READ_LOW( sp );
pc = READ_LOW( 0x100 | (sp - 0xFF) ); pc = READ_LOW( 0x100 | (sp - 0xFF) );
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100; pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
sp = (sp - 0xFD) | 0x100; sp = (sp - 0xFD) | 0x100;
@ -1012,8 +1012,8 @@ possibly_out_of_time:
goto loop; goto loop;
case 0x28:{// PLP case 0x28:{// PLP
uint8_t temp = POP(); uint_fast8_t temp = POP();
uint8_t changed = status ^ temp; uint_fast8_t changed = status ^ temp;
SET_STATUS( temp ); SET_STATUS( temp );
if ( !(changed & st_i) ) if ( !(changed & st_i) )
goto loop; // I flag didn't change goto loop; // I flag didn't change
@ -1024,7 +1024,7 @@ possibly_out_of_time:
#undef POP #undef POP
case 0x08: { // PHP case 0x08: { // PHP
uint8_t temp; uint_fast8_t temp;
CALC_STATUS( temp ); CALC_STATUS( temp );
PUSH( temp | st_b ); PUSH( temp | st_b );
goto loop; goto loop;
@ -1033,7 +1033,7 @@ possibly_out_of_time:
// Flags // Flags
case 0x38: // SEC case 0x38: // SEC
c = (uint16_t) ~0; c = (unsigned) ~0;
goto loop; goto loop;
case 0x18: // CLC case 0x18: // CLC
@ -1101,7 +1101,7 @@ possibly_out_of_time:
// Special // Special
case 0x53:{// TAM case 0x53:{// TAM
uint8_t const bits = data; // avoid using data across function call uint_fast8_t const bits = data; // avoid using data across function call
pc++; pc++;
for ( int i = 0; i < 8; i++ ) for ( int i = 0; i < 8; i++ )
if ( bits & (1 << i) ) if ( bits & (1 << i) )
@ -1125,7 +1125,7 @@ possibly_out_of_time:
case 0x03: // ST0 case 0x03: // ST0
case 0x13: // ST1 case 0x13: // ST1
case 0x23:{// ST2 case 0x23:{// ST2
uint16_t addr = opcode >> 4; uint_fast16_t addr = opcode >> 4;
if ( addr ) if ( addr )
addr++; addr++;
pc++; pc++;
@ -1147,7 +1147,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0xF4: { // SET case 0xF4: { // SET
//uint16_t operand = GET_MSB(); //fuint16 operand = GET_MSB();
debug_printf( "SET not handled\n" ); debug_printf( "SET not handled\n" );
//switch ( data ) //switch ( data )
//{ //{
@ -1159,10 +1159,10 @@ possibly_out_of_time:
// Block transfer // Block transfer
{ {
uint16_t in_alt; uint_fast16_t in_alt;
int16_t in_inc; int_fast16_t in_inc;
uint16_t out_alt; uint_fast16_t out_alt;
int16_t out_inc; int_fast16_t out_inc;
case 0xE3: // TIA case 0xE3: // TIA
in_alt = 0; in_alt = 0;
@ -1193,8 +1193,8 @@ possibly_out_of_time:
in_alt = 0; in_alt = 0;
out_alt = 0; out_alt = 0;
bxfer: bxfer:
uint16_t in = GET_LE16( instr + 0 ); uint_fast16_t in = GET_LE16( instr + 0 );
uint16_t out = GET_LE16( instr + 2 ); uint_fast16_t out = GET_LE16( instr + 2 );
int count = GET_LE16( instr + 4 ); int count = GET_LE16( instr + 4 );
if ( !count ) if ( !count )
count = 0x10000; count = 0x10000;
@ -1206,7 +1206,7 @@ possibly_out_of_time:
do do
{ {
// TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O // TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O
uint8_t t = READ( in ); uint_fast8_t t = READ( in );
in += in_inc; in += in_inc;
in &= 0xFFFF; in &= 0xFFFF;
s.time += 6; s.time += 6;
@ -1246,7 +1246,7 @@ interrupt:
pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ ); pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ );
sp = (sp - 3) | 0x100; sp = (sp - 3) | 0x100;
uint8_t temp; uint_fast8_t temp;
CALC_STATUS( temp ); CALC_STATUS( temp );
if ( result_ == 6 ) if ( result_ == 6 )
temp |= st_b; temp |= st_b;
@ -1283,7 +1283,7 @@ out_of_time:
r.y = y; r.y = y;
{ {
uint8_t temp; uint_fast8_t temp;
CALC_STATUS( temp ); CALC_STATUS( temp );
r.status = temp; r.status = temp;
} }
@ -1293,4 +1293,3 @@ out_of_time:
return illegal_encountered; return illegal_encountered;
} }

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/ // Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
/* /*
Last validated with zexall 2006.11.14 2:19 PM Last validated with zexall 2006.11.14 2:19 PM
@ -162,11 +162,6 @@ static byte const ed_dd_timing [0x100] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
}; };
// even on x86, using short and unsigned char was slower
typedef int fint16;
typedef unsigned fuint16;
typedef unsigned fuint8;
bool Kss_Cpu::run( cpu_time_t end_time ) bool Kss_Cpu::run( cpu_time_t end_time )
{ {
set_end_time( end_time ); set_end_time( end_time );
@ -183,10 +178,10 @@ bool Kss_Cpu::run( cpu_time_t end_time )
rg = this->r.b; rg = this->r.b;
cpu_time_t s_time = s.time; cpu_time_t s_time = s.time;
fuint16 pc = r.pc; uint_fast32_t pc = r.pc;
fuint16 sp = r.sp; uint_fast32_t sp = r.sp;
fuint16 ix = r.ix; // TODO: keep in memory for direct access? uint_fast32_t ix = r.ix; // TODO: keep in memory for direct access?
fuint16 iy = r.iy; uint_fast32_t iy = r.iy;
int flags = r.b.flags; int flags = r.b.flags;
goto loop; goto loop;
@ -208,7 +203,7 @@ loop:
uint8_t const* instr = s.read [pc >> page_shift]; uint8_t const* instr = s.read [pc >> page_shift];
#define GET_ADDR() GET_LE16( instr ) #define GET_ADDR() GET_LE16( instr )
fuint8 opcode; uint_fast8_t opcode;
// TODO: eliminate this special case // TODO: eliminate this special case
#if BLARGG_NONPORTABLE #if BLARGG_NONPORTABLE
@ -241,7 +236,7 @@ loop:
11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
}; };
fuint16 data; uint_fast16_t data;
data = base_timing [opcode]; data = base_timing [opcode];
if ( (s_time += data) >= 0 ) if ( (s_time += data) >= 0 )
goto possibly_out_of_time; goto possibly_out_of_time;
@ -297,7 +292,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0x3A:{// LD A,(addr) case 0x3A:{// LD A,(addr)
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
rg.a = READ( addr ); rg.a = READ( addr );
goto loop; goto loop;
@ -385,7 +380,7 @@ possibly_out_of_time:
case 0xCD:{// CALL addr case 0xCD:{// CALL addr
call_taken: call_taken:
fuint16 addr = pc + 2; uint_fast16_t addr = pc + 2;
pc = GET_ADDR(); pc = GET_ADDR();
sp = uint16_t (sp - 2); sp = uint16_t (sp - 2);
WRITE_WORD( sp, addr ); WRITE_WORD( sp, addr );
@ -501,7 +496,7 @@ possibly_out_of_time:
add_hl_data: { add_hl_data: {
blargg_ulong sum = rp.hl + data; blargg_ulong sum = rp.hl + data;
data ^= rp.hl; data ^= rp.hl;
rp.hl = (uint16_t)sum; rp.hl = sum;
flags = (flags & (S80 | Z40 | V04)) | flags = (flags & (S80 | Z40 | V04)) |
(sum >> 16) | (sum >> 16) |
(sum >> 8 & (F20 | F08)) | (sum >> 8 & (F20 | F08)) |
@ -691,21 +686,21 @@ possibly_out_of_time:
goto loop; goto loop;
case 0x2A:{// LD HL,(addr) case 0x2A:{// LD HL,(addr)
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
rp.hl = READ_WORD( addr ); rp.hl = READ_WORD( addr );
goto loop; goto loop;
} }
case 0x32:{// LD (addr),A case 0x32:{// LD (addr),A
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
WRITE( addr, rg.a ); WRITE( addr, rg.a );
goto loop; goto loop;
} }
case 0x22:{// LD (addr),HL case 0x22:{// LD (addr),HL
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
WRITE_WORD( addr, rp.hl ); WRITE_WORD( addr, rp.hl );
goto loop; goto loop;
@ -728,7 +723,7 @@ possibly_out_of_time:
// Rotate // Rotate
case 0x07:{// RLCA case 0x07:{// RLCA
fuint16 temp = rg.a; uint_fast16_t temp = rg.a;
temp = (temp << 1) | (temp >> 7); temp = (temp << 1) | (temp >> 7);
flags = (flags & (S80 | Z40 | P04)) | flags = (flags & (S80 | Z40 | P04)) |
(temp & (F20 | F08 | C01)); (temp & (F20 | F08 | C01));
@ -737,7 +732,7 @@ possibly_out_of_time:
} }
case 0x0F:{// RRCA case 0x0F:{// RRCA
fuint16 temp = rg.a; uint_fast16_t temp = rg.a;
flags = (flags & (S80 | Z40 | P04)) | flags = (flags & (S80 | Z40 | P04)) |
(temp & C01); (temp & C01);
temp = (temp << 7) | (temp >> 1); temp = (temp << 7) | (temp >> 1);
@ -756,7 +751,7 @@ possibly_out_of_time:
} }
case 0x1F:{// RRA case 0x1F:{// RRA
fuint16 temp = (flags << 7) | (rg.a >> 1); uint_fast16_t temp = (flags << 7) | (rg.a >> 1);
flags = (flags & (S80 | Z40 | P04)) | flags = (flags & (S80 | Z40 | P04)) |
(temp & (F20 | F08)) | (temp & (F20 | F08)) |
(rg.a & C01); (rg.a & C01);
@ -766,7 +761,7 @@ possibly_out_of_time:
// Misc // Misc
case 0x2F:{// CPL case 0x2F:{// CPL
fuint16 temp = ~rg.a; uint_fast16_t temp = ~rg.a;
flags = (flags & (S80 | Z40 | P04 | C01)) | flags = (flags & (S80 | Z40 | P04 | C01)) |
(temp & (F20 | F08)) | (temp & (F20 | F08)) |
(H10 | N02); (H10 | N02);
@ -792,21 +787,21 @@ possibly_out_of_time:
goto loop; goto loop;
case 0xE3:{// EX (SP),HL case 0xE3:{// EX (SP),HL
fuint16 temp = READ_WORD( sp ); uint_fast16_t temp = READ_WORD( sp );
WRITE_WORD( sp, rp.hl ); WRITE_WORD( sp, rp.hl );
rp.hl = temp; rp.hl = temp;
goto loop; goto loop;
} }
case 0xEB:{// EX DE,HL case 0xEB:{// EX DE,HL
fuint16 temp = rp.hl; uint_fast16_t temp = rp.hl;
rp.hl = rp.de; rp.hl = rp.de;
rp.de = temp; rp.de = temp;
goto loop; goto loop;
} }
case 0xD9:{// EXX DE,HL case 0xD9:{// EXX DE,HL
fuint16 temp = r.alt.w.bc; uint_fast16_t temp = r.alt.w.bc;
r.alt.w.bc = rp.bc; r.alt.w.bc = rp.bc;
rp.bc = temp; rp.bc = temp;
@ -847,7 +842,7 @@ possibly_out_of_time:
// Rotate left // Rotate left
#define RLC( read, write ) {\ #define RLC( read, write ) {\
fuint8 result = read;\ uint_fast8_t result = read;\
result = uint8_t (result << 1) | (result >> 7);\ result = uint8_t (result << 1) | (result >> 7);\
flags = SZ28P( result ) | (result & C01);\ flags = SZ28P( result ) | (result & C01);\
write;\ write;\
@ -866,7 +861,7 @@ possibly_out_of_time:
} }
#define RL( read, write ) {\ #define RL( read, write ) {\
fuint16 result = (read << 1) | (flags & C01);\ uint_fast16_t result = (read << 1) | (flags & C01);\
flags = SZ28PC( result );\ flags = SZ28PC( result );\
write;\ write;\
goto loop;\ goto loop;\
@ -884,7 +879,7 @@ possibly_out_of_time:
} }
#define SLA( read, add, write ) {\ #define SLA( read, add, write ) {\
fuint16 result = (read << 1) | add;\ uint_fast16_t result = (read << 1) | add;\
flags = SZ28PC( result );\ flags = SZ28PC( result );\
write;\ write;\
goto loop;\ goto loop;\
@ -915,7 +910,7 @@ possibly_out_of_time:
// Rotate right // Rotate right
#define RRC( read, write ) {\ #define RRC( read, write ) {\
fuint8 result = read;\ uint_fast8_t result = read;\
flags = result & C01;\ flags = result & C01;\
result = uint8_t (result << 7) | (result >> 1);\ result = uint8_t (result << 7) | (result >> 1);\
flags |= SZ28P( result );\ flags |= SZ28P( result );\
@ -935,8 +930,8 @@ possibly_out_of_time:
} }
#define RR( read, write ) {\ #define RR( read, write ) {\
fuint8 result = read;\ uint_fast8_t result = read;\
fuint8 temp = result & C01;\ uint_fast8_t temp = result & C01;\
result = uint8_t (flags << 7) | (result >> 1);\ result = uint8_t (flags << 7) | (result >> 1);\
flags = SZ28P( result ) | temp;\ flags = SZ28P( result ) | temp;\
write;\ write;\
@ -955,7 +950,7 @@ possibly_out_of_time:
} }
#define SRA( read, write ) {\ #define SRA( read, write ) {\
fuint8 result = read;\ uint_fast8_t result = read;\
flags = result & C01;\ flags = result & C01;\
result = (result & 0x80) | (result >> 1);\ result = (result & 0x80) | (result >> 1);\
flags |= SZ28P( result );\ flags |= SZ28P( result );\
@ -975,7 +970,7 @@ possibly_out_of_time:
} }
#define SRL( read, write ) {\ #define SRL( read, write ) {\
fuint8 result = read;\ uint_fast8_t result = read;\
flags = result & C01;\ flags = result & C01;\
result >>= 1;\ result >>= 1;\
flags |= SZ28P( result );\ flags |= SZ28P( result );\
@ -1083,7 +1078,7 @@ possibly_out_of_time:
blargg_ulong sum = temp + (flags & C01); blargg_ulong sum = temp + (flags & C01);
flags = ~data >> 2 & N02; flags = ~data >> 2 & N02;
if ( flags ) if ( flags )
sum = (blargg_ulong)-(blargg_long)sum; sum = -sum;
sum += rp.hl; sum += rp.hl;
temp ^= rp.hl; temp ^= rp.hl;
temp ^= sum; temp ^= sum;
@ -1091,7 +1086,7 @@ possibly_out_of_time:
(temp >> 8 & H10) | (temp >> 8 & H10) |
(sum >> 8 & (S80 | F20 | F08)) | (sum >> 8 & (S80 | F20 | F08)) |
((temp - -0x8000) >> 14 & V04); ((temp - -0x8000) >> 14 & V04);
rp.hl = (uint16_t)sum; rp.hl = sum;
if ( (uint16_t) sum ) if ( (uint16_t) sum )
goto loop; goto loop;
flags |= Z40; flags |= Z40;
@ -1119,7 +1114,7 @@ possibly_out_of_time:
case 0x43: // LD (ADDR),BC case 0x43: // LD (ADDR),BC
case 0x53: // LD (ADDR),DE case 0x53: // LD (ADDR),DE
temp = R16( data, 4, 0x43 ); temp = R16( data, 4, 0x43 );
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
WRITE_WORD( addr, temp ); WRITE_WORD( addr, temp );
goto loop; goto loop;
@ -1127,21 +1122,21 @@ possibly_out_of_time:
case 0x4B: // LD BC,(ADDR) case 0x4B: // LD BC,(ADDR)
case 0x5B:{// LD DE,(ADDR) case 0x5B:{// LD DE,(ADDR)
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
R16( data, 4, 0x4B ) = READ_WORD( addr ); R16( data, 4, 0x4B ) = READ_WORD( addr );
goto loop; goto loop;
} }
case 0x7B:{// LD SP,(ADDR) case 0x7B:{// LD SP,(ADDR)
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
sp = READ_WORD( addr ); sp = READ_WORD( addr );
goto loop; goto loop;
} }
case 0x67:{// RRD case 0x67:{// RRD
fuint8 temp = READ( rp.hl ); uint_fast8_t temp = READ( rp.hl );
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) ); WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
temp = (rg.a & 0xF0) | (temp & 0x0F); temp = (rg.a & 0xF0) | (temp & 0x0F);
flags = (flags & C01) | SZ28P( temp ); flags = (flags & C01) | SZ28P( temp );
@ -1150,7 +1145,7 @@ possibly_out_of_time:
} }
case 0x6F:{// RLD case 0x6F:{// RLD
fuint8 temp = READ( rp.hl ); uint_fast8_t temp = READ( rp.hl );
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) ); WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
temp = (rg.a & 0xF0) | (temp >> 4); temp = (rg.a & 0xF0) | (temp >> 4);
flags = (flags & C01) | SZ28P( temp ); flags = (flags & C01) | SZ28P( temp );
@ -1174,7 +1169,7 @@ possibly_out_of_time:
case 0xA1: // CPI case 0xA1: // CPI
case 0xB1: // CPIR case 0xB1: // CPIR
inc = +1; inc = +1;
fuint16 addr = rp.hl; uint_fast16_t addr = rp.hl;
rp.hl = addr + inc; rp.hl = addr + inc;
int temp = READ( addr ); int temp = READ( addr );
@ -1207,7 +1202,7 @@ possibly_out_of_time:
case 0xA0: // LDI case 0xA0: // LDI
case 0xB0: // LDIR case 0xB0: // LDIR
inc = +1; inc = +1;
fuint16 addr = rp.hl; uint_fast16_t addr = rp.hl;
rp.hl = addr + inc; rp.hl = addr + inc;
int temp = READ( addr ); int temp = READ( addr );
@ -1239,7 +1234,7 @@ possibly_out_of_time:
case 0xA3: // OUTI case 0xA3: // OUTI
case 0xB3: // OTIR case 0xB3: // OTIR
inc = +1; inc = +1;
fuint16 addr = rp.hl; uint_fast16_t addr = rp.hl;
rp.hl = addr + inc; rp.hl = addr + inc;
int temp = READ( addr ); int temp = READ( addr );
@ -1265,7 +1260,7 @@ possibly_out_of_time:
case 0xB2: // INIR case 0xB2: // INIR
inc = +1; inc = +1;
fuint16 addr = rp.hl; uint_fast16_t addr = rp.hl;
rp.hl = addr + inc; rp.hl = addr + inc;
int temp = IN( rp.bc ); int temp = IN( rp.bc );
@ -1330,7 +1325,7 @@ possibly_out_of_time:
//////////////////////////////////////// DD/FD prefix //////////////////////////////////////// DD/FD prefix
{ {
fuint16 ixy; uint_fast16_t ixy;
case 0xDD: case 0xDD:
ixy = ix; ixy = ix;
goto ix_prefix; goto ix_prefix;
@ -1526,7 +1521,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0x22:{// LD (ADDR),IXY case 0x22:{// LD (ADDR),IXY
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
pc += 2; pc += 2;
WRITE_WORD( addr, ixy ); WRITE_WORD( addr, ixy );
goto loop; goto loop;
@ -1538,7 +1533,7 @@ possibly_out_of_time:
goto set_ixy; goto set_ixy;
case 0x2A:{// LD IXY,(addr) case 0x2A:{// LD IXY,(addr)
fuint16 addr = GET_ADDR(); uint_fast16_t addr = GET_ADDR();
ixy = READ_WORD( addr ); ixy = READ_WORD( addr );
pc += 2; pc += 2;
goto set_ixy; goto set_ixy;
@ -1562,7 +1557,7 @@ possibly_out_of_time:
case 0x3E: goto srl_data_addr; // SRL (IXY) case 0x3E: goto srl_data_addr; // SRL (IXY)
CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
fuint8 temp = READ( data ); uint_fast8_t temp = READ( data );
int masked = temp & 1 << (data2 >> 3 & 7); int masked = temp & 1 << (data2 >> 3 & 7);
flags = (flags & C01) | H10 | flags = (flags & C01) | H10 |
(masked & S80) | (masked & S80) |
@ -1664,7 +1659,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0xE3:{// EX (SP),IXY case 0xE3:{// EX (SP),IXY
fuint16 temp = READ_WORD( sp ); uint_fast16_t temp = READ_WORD( sp );
WRITE_WORD( sp, ixy ); WRITE_WORD( sp, ixy );
ixy = temp; ixy = temp;
goto set_ixy; goto set_ixy;

View file

@ -64,6 +64,8 @@ Music_Emu::Music_Emu()
equalizer_.treble = -1.0; equalizer_.treble = -1.0;
equalizer_.bass = 60; equalizer_.bass = 60;
emu_autoload_playback_limit_ = true;
static const char* const names [] = { static const char* const names [] = {
"Voice 1", "Voice 2", "Voice 3", "Voice 4", "Voice 1", "Voice 2", "Voice 3", "Voice 4",
"Voice 5", "Voice 6", "Voice 7", "Voice 8" "Voice 5", "Voice 6", "Voice 7", "Voice 8"
@ -187,6 +189,16 @@ void Music_Emu::end_track_if_error( blargg_err_t err )
} }
} }
bool Music_Emu::autoload_playback_limit() const
{
return emu_autoload_playback_limit_;
}
void Music_Emu::set_autoload_playback_limit( bool do_autoload_limit )
{
emu_autoload_playback_limit_ = do_autoload_limit;
}
// Tell/Seek // Tell/Seek
blargg_long Music_Emu::msec_to_samples( blargg_long msec ) const blargg_long Music_Emu::msec_to_samples( blargg_long msec ) const

View file

@ -67,6 +67,13 @@ public:
// true. Fade time can be changed while track is playing. // true. Fade time can be changed while track is playing.
void set_fade( long start_msec, long length_msec = 8000 ); void set_fade( long start_msec, long length_msec = 8000 );
// Controls whether or not to automatically load and obey track length
// metadata for supported emulators.
//
// @since 0.6.2.
bool autoload_playback_limit() const;
void set_autoload_playback_limit( bool do_autoload_limit );
// Disable automatic end-of-track detection and skipping of silence at beginning // Disable automatic end-of-track detection and skipping of silence at beginning
void ignore_silence( bool disable = true ); void ignore_silence( bool disable = true );
@ -170,6 +177,7 @@ private:
blargg_long out_time; // number of samples played since start of track blargg_long out_time; // number of samples played since start of track
blargg_long emu_time; // number of samples emulator has generated since start of track blargg_long emu_time; // number of samples emulator has generated since start of track
bool emu_track_ended_; // emulator has reached end of track bool emu_track_ended_; // emulator has reached end of track
bool emu_autoload_playback_limit_; // whether to load and obey track length by default
volatile bool track_ended_; volatile bool track_ended_;
void clear_track_vars(); void clear_track_vars();
void end_track_if_error( blargg_err_t ); void end_track_if_error( blargg_err_t );

View file

@ -299,6 +299,12 @@ blargg_err_t Spc_Emu::start_track_( int track )
RETURN_ERR( apu.load_spc( file_data, file_size ) ); RETURN_ERR( apu.load_spc( file_data, file_size ) );
filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) ); filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) );
apu.clear_echo(); apu.clear_echo();
track_info_t spc_info;
RETURN_ERR( track_info_( &spc_info, track ) );
// Set a default track length, need a non-zero fadeout
if ( autoload_playback_limit() && ( spc_info.length > 0 ) )
set_fade ( spc_info.length, 50 );
return 0; return 0;
} }

View file

@ -197,6 +197,16 @@ BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sa
return err; return err;
} }
BLARGG_EXPORT void gme_set_autoload_playback_limit( Music_Emu *emu, int do_autoload_limit )
{
emu->set_autoload_playback_limit( do_autoload_limit != 0 );
}
BLARGG_EXPORT int gme_autoload_playback_limit( Music_Emu *const emu )
{
return emu->autoload_playback_limit();
}
// Used to implement gme_new_emu and gme_new_emu_multi_channel // Used to implement gme_new_emu and gme_new_emu_multi_channel
Music_Emu* gme_internal_new_emu_( gme_type_t type, int rate, bool multi_channel ) Music_Emu* gme_internal_new_emu_( gme_type_t type, int rate, bool multi_channel )
{ {

View file

@ -153,6 +153,7 @@ MusInfo *GME_OpenSong(FileReader &reader, const char *fmt)
return nullptr; return nullptr;
} }
gme_set_stereo_depth(emu, clamp(*gme_stereodepth, 0.f, 1.f)); gme_set_stereo_depth(emu, clamp(*gme_stereodepth, 0.f, 1.f));
gme_set_fade(emu, -1); // Enable infinite loop
return new GMESong(emu, sample_rate); return new GMESong(emu, sample_rate);
} }