bool Tape::LoadTrap () { if (!IsInserted()) return false; // If traps are disabled, try normal loading if (!GetOption(tapetraps)) { Play(); return false; } // Skip over any metadata blocks libspectrum_tape_block *block = libspectrum_tape_current_block(pTape); while (block && libspectrum_tape_block_metadata(block)) block = libspectrum_tape_select_next_block(pTape); // Nothing else to process? if (!block) return false; libspectrum_tape_type type = libspectrum_tape_block_type(block); libspectrum_tape_state_type state = libspectrum_tape_state(pTape); // Consider both ROM blocks (normal speed) and turbo blocks, as used by custom SAM tape speeds (DEVICE tX) if ((type != LIBSPECTRUM_TAPE_BLOCK_ROM && type != LIBSPECTRUM_TAPE_BLOCK_TURBO) || state != LIBSPECTRUM_TAPE_STATE_PILOT) { // Fall back on non-trap loading for anything else Play(); return false; } libspectrum_byte *pbData = libspectrum_tape_block_data(block); size_t nData = libspectrum_tape_block_data_length(block); // Base load address and load request size WORD wDest = HL; int nWanted = (read_byte(0x5ac8) << 16) | DE; // Fetch block type H = *pbData++; nData--; // Spectrum header? if (H == 0) { // Override request length nWanted = (nWanted & ~0xff) | 17; } // Otherwise the type byte must match the request else if (H != A_) { // Advance to next block libspectrum_tape_select_next_block(pTape); // Failed, exit via: RET NZ F &= ~(FLAG_C|FLAG_Z); PC = 0xe6f6; return true; } // Parity byte initialised to type byte L = H; // More still to load? while (nWanted >= 0) { // Are we out of source data? (ToDo: support continuation blocks?) if (!nData) { // Advance to next block libspectrum_tape_select_next_block(pTape); // Failed, exit via: RET NZ F &= ~(FLAG_C|FLAG_Z); PC = 0xe6f6; return true; } // Read next byte and update parity L ^= (H = *pbData++); nData--; // Request complete? if (!nWanted) break; // Write new byte write_byte(wDest, H); wDest++; nWanted--; // Destination now in the top 16K? if (wDest >= 0xc000) { // Slide paging up and move pointer back IO::OutHmpr(hmpr+1); wDest -= 0x4000; } } // Advance to next block libspectrum_tape_select_next_block(pTape); // Exit via: LD A,L ; CP 1 ; RET PC = 0xe739; return true; }
/* Load the next tape block into memory; returns 0 if a block was loaded (even if it had an tape loading error or equivalent) or non-zero if there was an error at the emulator level, or tape traps are not active */ int tape_load_trap(Z80Regs * regs) { libspectrum_tape_block *block, *next_block; int error; /* Do nothing if tape traps aren't active, or the tape is already playing */ if( !mconfig.flash_loading || tape_playing ) return 1; /* Do nothing if we're not in the correct ROM */ //if( ! trap_check_rom() ) return 3; /* Return with error if no tape file loaded */ if( !libspectrum_tape_present( tape ) ) return 1; block = libspectrum_tape_current_block( tape ); /* Skip over any meta-data blocks */ while( libspectrum_tape_block_metadata( block ) ) { block = libspectrum_tape_select_next_block( tape ); if( !block ) return 1; } /* If this block isn't a ROM loader, start the block playing. After that, return with `error' so that we actually do whichever instruction it was that caused the trap to hit */ if( libspectrum_tape_block_type( block ) != LIBSPECTRUM_TAPE_BLOCK_ROM || libspectrum_tape_state( tape ) != LIBSPECTRUM_TAPE_STATE_PILOT ) { tape_play( 1 ); return /*-1*/1; } /* We don't properly handle the case of partial loading, so don't run the traps in that situation *///Esto hace cascar algunos games /* if( libspectrum_tape_block_data_length( block ) != regs->DE.W + 2 ) { tape_play( 1 ); return 1; } */ error = trap_load_block( block , regs);//carga el bloque if( error ) return -1; /* Peek at the next block. If it's a ROM block, move along, initialise the block, and return */ next_block = libspectrum_tape_peek_next_block( tape ); if( libspectrum_tape_block_type(next_block) == LIBSPECTRUM_TAPE_BLOCK_ROM ) { next_block = libspectrum_tape_select_next_block( tape ); if( !next_block ) return 1; //ui_tape_browser_update( UI_TAPE_BROWSER_SELECT_BLOCK, NULL ); return 0;//FLASHLOADED! } /* If the next block isn't a ROM block, set ourselves up such that the next thing to occur is the pause at the end of the current block */ libspectrum_tape_set_state( tape, LIBSPECTRUM_TAPE_STATE_PAUSE );//TODO ? autodetect, sino no tira? //libspectrum_tape_block_set_state( block, LIBSPECTRUM_TAPE_STATE_PAUSE ); /* error = tape_play(1); if( error ) return -1; */ return 0; }
/* Load the next tape block into memory; returns 0 if a block was loaded (even if it had an tape loading error or equivalent) or non-zero if there was an error at the emulator level, or tape traps are not active */ int tape_load_trap( void ) { libspectrum_tape_block *block, *next_block; int error; /* Do nothing if tape traps aren't active, or the tape is already playing */ if( !settings_current.tape_traps || tape_playing ) return 2; /* Do nothing if we're not in the correct ROM */ if( !trap_check_rom( CHECK_TAPE_ROM ) ) return 3; /* Return with error if no tape file loaded */ if( !libspectrum_tape_present( tape ) ) return 1; block = libspectrum_tape_current_block( tape ); /* Skip over any meta-data blocks */ while( libspectrum_tape_block_metadata( block ) ) { block = libspectrum_tape_select_next_block( tape ); if( !block ) return 1; } /* If this block isn't a ROM loader, start the block playing. After that, return with `error' so that we actually do whichever instruction it was that caused the trap to hit */ if( libspectrum_tape_block_type( block ) != LIBSPECTRUM_TAPE_BLOCK_ROM || libspectrum_tape_state( tape ) != LIBSPECTRUM_TAPE_STATE_PILOT ) { tape_play( 1 ); return -1; } /* We don't properly handle the case of partial loading, so don't run the traps in that situation */ if( libspectrum_tape_block_data_length( block ) != DE + 2 ) { tape_play( 1 ); return -1; } /* All returns made via the RET at #05E2, except on Timex 2068 at #0136 */ if ( machine_current->machine == LIBSPECTRUM_MACHINE_TC2068 || machine_current->machine == LIBSPECTRUM_MACHINE_TS2068 ) { PC = 0x0136; } else { PC = 0x05e2; } error = trap_load_block( block ); if( error ) return error; /* Peek at the next block. If it's a ROM block, move along, initialise the block, and return */ next_block = libspectrum_tape_peek_next_block( tape ); if( libspectrum_tape_block_type(next_block) == LIBSPECTRUM_TAPE_BLOCK_ROM ) { next_block = libspectrum_tape_select_next_block( tape ); if( !next_block ) return 1; ui_tape_browser_update( UI_TAPE_BROWSER_SELECT_BLOCK, NULL ); return 0; } /* If the next block isn't a ROM block, set ourselves up such that the next thing to occur is the pause at the end of the current block */ libspectrum_tape_set_state( tape, LIBSPECTRUM_TAPE_STATE_PAUSE ); return 0; }
int tape_next_edge(Z80Regs *regs, int *edge_tstates, int *bit) { int error; libspectrum_error libspec_error; libspectrum_tape_block *block; //libspectrum_dword edge_tstates; int flags; *edge_tstates = 0; *bit=-1; int one_value=0; /* If the tape's not playing, just return */ if( ! tape_playing ) return 0; block = libspectrum_tape_current_block( tape ); int type = libspectrum_tape_block_type( block ); if(type==LIBSPECTRUM_TAPE_BLOCK_ROM || type==LIBSPECTRUM_TAPE_BLOCK_TURBO || type==LIBSPECTRUM_TAPE_BLOCK_PURE_DATA /*|| type==LIBSPECTRUM_TAPE_BLOCK_RAW_DATA*/) { int state = libspectrum_tape_state( tape ); if(state==LIBSPECTRUM_TAPE_STATE_DATA1 || state==LIBSPECTRUM_TAPE_STATE_DATA2) { if(block->type==LIBSPECTRUM_TAPE_BLOCK_TURBO) { one_value = block->types.turbo.bit1_length; } else if(block->type==LIBSPECTRUM_TAPE_BLOCK_PURE_DATA) { one_value = block->types.pure_data.bit1_length; } else { one_value = 1710; } } } /* Get the time until the next edge */ libspectrum_dword tmp = 0; libspec_error = libspectrum_tape_get_next_edge(&tmp, &flags, tape); *edge_tstates = tmp; if(one_value!=0) *bit = *edge_tstates == one_value ? 1 : 0; //edge_tstates_target = edge_tstates_target+*edge_tstates; if( libspec_error != LIBSPECTRUM_ERROR_NONE ) return libspec_error; /* Invert the microphone state */ if( *edge_tstates || ( flags & LIBSPECTRUM_TAPE_FLAGS_STOP ) ) { if( flags & LIBSPECTRUM_TAPE_FLAGS_NO_EDGE ) { // Do nothing } else if( flags & LIBSPECTRUM_TAPE_FLAGS_LEVEL_LOW ) { tape_microphone = 0; } else if( flags & LIBSPECTRUM_TAPE_FLAGS_LEVEL_HIGH ) { tape_microphone = 1; } else { tape_microphone = !tape_microphone; } if(regs!=NULL) sound_beeper_1(tape_microphone,regs->IPeriod-regs->ICount);//TODO: poner pref } /* If we've been requested to stop the tape, do so and then return without stacking another edge */ int zx48=0; if(regs!=NULL) zx48=regs->IPeriod==69888; if((flags & LIBSPECTRUM_TAPE_FLAGS_STOP) || ( zx48 && (flags & LIBSPECTRUM_TAPE_FLAGS_STOP48) ) ) { error = tape_stop(); if( error ) return error; return 0; } /* If that was the end of a block, update the browser */ if( flags & LIBSPECTRUM_TAPE_FLAGS_BLOCK ) { //ui_tape_browser_update( UI_TAPE_BROWSER_SELECT_BLOCK, NULL ); /* If the tape was started automatically, tape traps are active and the new block is a ROM loader, stop the tape and return without putting another event into the queue */ block = libspectrum_tape_current_block( tape ); if( /*tape_autoplay &&*/ mconfig.flash_loading && libspectrum_tape_block_type( block ) == LIBSPECTRUM_TAPE_BLOCK_ROM ) { error = tape_stop(); if( error ) return error; return 0;//TODO: devolver valor que nos diga que nos diga que no hay que devolver otro edge? } } /* Otherwise, put this into the event queue; remember that this edge should occur 'edge_tstates' after the last edge, not after the current time (these will be slightly different as we only process events between instructions). */ return 0; }