static void
scld_to_snapshot( libspectrum_snap *snap )
{
  size_t i;
  libspectrum_byte *buffer;

  libspectrum_snap_set_out_scld_hsr( snap, scld_last_hsr );
  libspectrum_snap_set_out_scld_dec( snap, scld_last_dec.byte );

  if( dck_active ) {

    libspectrum_snap_set_dock_active( snap, 1 );

    for( i = 0; i < 8; i++ ) {

      memory_page *exrom_base = &timex_exrom[i * MEMORY_PAGES_IN_8K],
        *dock_base = &timex_dock[i * MEMORY_PAGES_IN_8K];
      int j;

      /* In theory, Fuse could somehow have set up a memory map in which the
         first 4Kb of a DOCK page is writable, but the second 4Kb is not, and
         this structure is not representable in a snapshot.

         However, there's currently no code which could produce this situation
         so for simplicity's sake, we assume the properties of the lowest page
         in the 8Kb chunk apply to all the pages */

      if( exrom_base->save_to_snapshot || exrom_base->writable ) {
        buffer = libspectrum_new( libspectrum_byte, 0x2000 );

        libspectrum_snap_set_exrom_ram( snap, i, exrom_base->writable );
        for( j = 0; j < MEMORY_PAGES_IN_8K; j++ ) {
          memory_page *page = exrom_base + j;
          memcpy( buffer + j * MEMORY_PAGE_SIZE, page->page, MEMORY_PAGE_SIZE );
        }
        libspectrum_snap_set_exrom_cart( snap, i, buffer );
      }

      if( dock_base->save_to_snapshot || dock_base->writable ) {
        buffer = libspectrum_new( libspectrum_byte, 0x2000 );

        libspectrum_snap_set_dock_ram( snap, i, dock_base->writable );
        for( j = 0; j < MEMORY_PAGES_IN_8K; j++ ) {
          memory_page *page = dock_base + j;
          memcpy( buffer + j * MEMORY_PAGE_SIZE, page->page, MEMORY_PAGE_SIZE );
        }
        libspectrum_snap_set_dock_cart( snap, i, buffer );
      }

    }

  }
}
/* Given a 48K memory dump `data', place it into the
   appropriate bits of `snap' for a 48K machine */
libspectrum_error
libspectrum_split_to_48k_pages( libspectrum_snap *snap,
				const libspectrum_byte* data )
{
  libspectrum_byte *buffer[3];
  size_t i;

  /* If any of the three pages are already occupied, barf */
  if( libspectrum_snap_pages( snap, 5 ) ||
      libspectrum_snap_pages( snap, 2 ) ||
      libspectrum_snap_pages( snap, 0 )    ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_LOGIC,
      "libspectrum_split_to_48k_pages: RAM page already in use"
    );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  for( i = 0; i < 3; i++ )
    buffer[i] = libspectrum_new( libspectrum_byte, 0x4000 );

  libspectrum_snap_set_pages( snap, 5, buffer[0] );
  libspectrum_snap_set_pages( snap, 2, buffer[1] );
  libspectrum_snap_set_pages( snap, 0, buffer[2] );

  /* Finally, do the copies... */
  memcpy( libspectrum_snap_pages( snap, 5 ), &data[0x0000], 0x4000 );
  memcpy( libspectrum_snap_pages( snap, 2 ), &data[0x4000], 0x4000 );
  memcpy( libspectrum_snap_pages( snap, 0 ), &data[0x8000], 0x4000 );

  return LIBSPECTRUM_ERROR_NONE;
}
Beispiel #3
0
nic_w5100_t*
nic_w5100_alloc( void )
{
  int error;
  int i;
  nic_w5100_t *self;
  
  compat_socket_networking_init();

  self = libspectrum_new( nic_w5100_t, 1 );

  self->selfpipe = compat_socket_selfpipe_alloc();

  for( i = 0; i < 4; i++ )
    nic_w5100_socket_init( &self->socket[i], i );

  nic_w5100_reset( self );

  self->stop_io_thread = 0;

  error = pthread_create( &self->thread, NULL, w5100_io_thread, self );
  if( error ) {
    ui_error( UI_ERROR_ERROR, "w5100: error %d creating thread", error );
    fuse_abort();
  }

  return self;
}
libspectrum_tape_block*
libspectrum_tape_block_alloc( libspectrum_tape_type type )
{
  libspectrum_tape_block *block = libspectrum_new( libspectrum_tape_block, 1 );
  libspectrum_tape_block_set_type( block, type );
  return block;
}
wd_fdc *
wd_fdc_alloc_fdc( wd_type_t type, int hlt_time, unsigned int flags )
{
  wd_fdc *fdc = libspectrum_new( wd_fdc, 1 );

  switch( type ) {
  default:
    type = WD1770;			/* illegal type converted to wd_fdc */
  case FD1793:
  case WD1773:
  case WD1770:
  case WD2797:
    fdc->rates[ 0 ] = 6;
    fdc->rates[ 1 ] = 12;
    fdc->rates[ 2 ] = 20;
    fdc->rates[ 3 ] = 30;
    break;
  case WD1772:
    fdc->rates[ 0 ] = 2;
    fdc->rates[ 1 ] = 3;
    fdc->rates[ 2 ] = 5;
    fdc->rates[ 3 ] = 6;
    break;
  }
  fdc->type = type;
  fdc->current_drive = NULL;
  fdc->hlt_time = hlt_time;
  fdc->flags = flags;			/* Beta128 connect HLD out to READY in and MOTOR ON */
  wd_fdc_master_reset( fdc );
  return fdc;
}
libspectrum_byte*
memory_pool_allocate_persistent( size_t length, int persistent )
{
  memory_pool_entry_t *entry;
  libspectrum_byte *memory;

  memory = libspectrum_new( libspectrum_byte, length );

  entry = libspectrum_new( memory_pool_entry_t, 1 );

  entry->persistent = persistent;
  entry->memory = memory;

  pool = g_slist_prepend( pool, entry );

  return memory;
}
static void
didaktik_to_snapshot( libspectrum_snap *snap )
{
  libspectrum_byte *buffer;
  int drive_count = 0;
  int i;
  size_t memory_length;

  if( !periph_is_active( PERIPH_TYPE_DIDAKTIK80 ) ) return;

  libspectrum_snap_set_didaktik80_active( snap, 1 );

  memory_length = ROM_SIZE;

  libspectrum_snap_set_didaktik80_custom_rom( snap, 1 );
  libspectrum_snap_set_didaktik80_rom_length( snap, 0, memory_length );

  buffer = libspectrum_new( libspectrum_byte, memory_length );

  for( i = 0; i < MEMORY_PAGES_IN_14K; i++ )
    memcpy( buffer + i * MEMORY_PAGE_SIZE,
            didaktik_memory_map_romcs_rom[ i ].page, MEMORY_PAGE_SIZE );

  libspectrum_snap_set_didaktik80_rom( snap, 0, buffer );

  memory_length = RAM_SIZE;
  buffer = libspectrum_new( libspectrum_byte, memory_length );

  for( i = 0; i < MEMORY_PAGES_IN_2K; i++ )
    memcpy( buffer + i * MEMORY_PAGE_SIZE,
            didaktik_memory_map_romcs_ram[ i ].page, MEMORY_PAGE_SIZE );
  libspectrum_snap_set_didaktik80_ram( snap, 0, buffer );

  drive_count++; /* Drive 1 is not removable */
  if( option_enumerate_diskoptions_drive_didaktik80b_type() > 0 ) drive_count++;
  libspectrum_snap_set_didaktik80_drive_count( snap, drive_count );

  libspectrum_snap_set_didaktik80_paged ( snap, didaktik80_active );
  libspectrum_snap_set_didaktik80_direction( snap, didaktik_fdc->direction );
  libspectrum_snap_set_didaktik80_status( snap, didaktik_fdc->status_register );
  libspectrum_snap_set_didaktik80_track ( snap, didaktik_fdc->track_register );
  libspectrum_snap_set_didaktik80_sector( snap, didaktik_fdc->sector_register );
  libspectrum_snap_set_didaktik80_data  ( snap, didaktik_fdc->data_register );
  libspectrum_snap_set_didaktik80_aux   ( snap, aux_register );
}
static void
spectranet_to_snapshot( libspectrum_snap *snap )
{
  libspectrum_byte *snap_buffer, *src;

  int active = periph_is_active( PERIPH_TYPE_SPECTRANET );
  libspectrum_snap_set_spectranet_active( snap, active );

  if( !active )
    return;

  libspectrum_snap_set_spectranet_paged( snap, spectranet_paged );
  libspectrum_snap_set_spectranet_paged_via_io( snap, spectranet_paged_via_io );
  libspectrum_snap_set_spectranet_programmable_trap( snap,
    spectranet_programmable_trap );
  libspectrum_snap_set_spectranet_programmable_trap_active( snap,
    spectranet_programmable_trap_active );
  libspectrum_snap_set_spectranet_programmable_trap_msb( snap, trap_write_msb );
  libspectrum_snap_set_spectranet_deny_downstream_a15( snap, 0 );
  libspectrum_snap_set_spectranet_nmi_flipflop( snap, nmi_flipflop );

  libspectrum_snap_set_spectranet_all_traps_disabled( snap,
    settings_current.spectranet_disable );
  libspectrum_snap_set_spectranet_rst8_trap_disabled( snap, 0 );
  libspectrum_snap_set_spectranet_page_a(
    snap, spectranet_current_map[1 * MEMORY_PAGES_IN_4K].page_num );
  libspectrum_snap_set_spectranet_page_b(
    snap, spectranet_current_map[2 * MEMORY_PAGES_IN_4K].page_num );

  libspectrum_snap_set_spectranet_w5100( snap, 0,
    nic_w5100_to_snapshot( w5100 ) );

  snap_buffer = libspectrum_new( libspectrum_byte, SPECTRANET_ROM_LENGTH );

  src = spectranet_full_map[SPECTRANET_ROM_BASE * MEMORY_PAGES_IN_4K].page;
  memcpy( snap_buffer, src, SPECTRANET_ROM_LENGTH );
  libspectrum_snap_set_spectranet_flash( snap, 0, snap_buffer );

  snap_buffer = libspectrum_new( libspectrum_byte, SPECTRANET_RAM_LENGTH );

  src = spectranet_full_map[SPECTRANET_RAM_BASE * MEMORY_PAGES_IN_4K].page;
  memcpy( snap_buffer, src, SPECTRANET_RAM_LENGTH );
  libspectrum_snap_set_spectranet_ram( snap, 0, snap_buffer );
}
Beispiel #9
0
libspectrum_rzx*
libspectrum_rzx_alloc( void )
{
  libspectrum_rzx *rzx = libspectrum_new( libspectrum_rzx, 1 );
  rzx->blocks = NULL;
  rzx->current_block = NULL;
  rzx->current_input = NULL;
  rzx->signed_start = NULL;
  return rzx;
}
Beispiel #10
0
/* Append to the current tape file in memory; returns 0 if a block was
   saved or non-zero if there was an error at the emulator level, or tape
   traps are not active */
int tape_save_trap( void )
{
  libspectrum_tape_block *block;
  libspectrum_byte parity, *data;
  size_t length;

  int i;

  /* Do nothing if tape traps aren't active */
  if( !settings_current.tape_traps || tape_recording ) return 2;

  /* Check we're in the right ROM */
  if( !trap_check_rom( CHECK_TAPE_ROM ) ) return 3;

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_ROM );
  
  /* The +2 here is for the flag and parity bytes */
  length = DE + 2;
  libspectrum_tape_block_set_data_length( block, length );

  data = libspectrum_new( libspectrum_byte, length );
  libspectrum_tape_block_set_data( block, data );

  /* First, store the flag byte (and initialise the parity counter) */
  data[0] = parity = A;

  /* then the main body of the data, counting parity along the way */
  for( i=0; i<DE; i++) {
    libspectrum_byte b = readbyte_internal( IX+i );
    parity ^= b;
    data[i+1] = b;
  }

  /* And finally the parity byte */
  data[ DE+1 ] = parity;

  /* Give a 1 second pause after this block */
  libspectrum_tape_block_set_pause( block, 1000 );

  libspectrum_tape_append_block( tape, block );

  tape_modified = 1;
  ui_tape_browser_update( UI_TAPE_BROWSER_NEW_BLOCK, block );

  /* And then return via the RET at #053E, except on Timex 2068 at #00E4 */
  if ( machine_current->machine == LIBSPECTRUM_MACHINE_TC2068 ||
       machine_current->machine == LIBSPECTRUM_MACHINE_TS2068 ) {
    PC = 0x00e4;
  } else {
    PC = 0x053e;
  }

  return 0;

}
Beispiel #11
0
libspectrum_byte*
nic_w5100_to_snapshot( nic_w5100_t *self )
{
  libspectrum_byte *data = libspectrum_new( libspectrum_byte, 0x30 );
  int i;

  for( i = 0; i < 0x30; i++ )
    data[i] = nic_w5100_read( self, i );

  return data;
}
Beispiel #12
0
static libspectrum_error
rzx_read_frames( input_block_t *block, const libspectrum_byte **ptr,
		 const libspectrum_byte *end )
{
  size_t i, j;

  /* And read in the frames */
  for( i=0; i < block->count; i++ ) {

    /* Check the two length bytes exist */
    if( end - (*ptr) < 4 ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "rzx_read_frames: not enough data in buffer" );
      for( j=0; j<i; j++ ) {
	if( !block->frames[i].repeat_last ) libspectrum_free( block->frames[j].in_bytes );
      }
      return LIBSPECTRUM_ERROR_CORRUPT;
    }

    block->frames[i].instructions = libspectrum_read_word( ptr );
    block->frames[i].count        = libspectrum_read_word( ptr );

    if( block->frames[i].count == libspectrum_rzx_repeat_frame ) {
      block->frames[i].repeat_last = 1;
      continue;
    }

    block->frames[i].repeat_last = 0;

    if( end - (*ptr) < (ptrdiff_t)block->frames[i].count ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "rzx_read_frames: not enough data in buffer" );
      for( j=0; j<i; j++ ) {
	if( !block->frames[i].repeat_last ) libspectrum_free( block->frames[j].in_bytes );
      }
      return LIBSPECTRUM_ERROR_CORRUPT;
    }

    if( block->frames[i].count ) {

      block->frames[i].in_bytes =
	libspectrum_new( libspectrum_byte, block->frames[i].count );
      memcpy( block->frames[i].in_bytes, *ptr, block->frames[i].count );

    } else {
      block->frames[i].in_bytes = NULL;
    }

    (*ptr) += block->frames[i].count;
  }

  return LIBSPECTRUM_ERROR_NONE;
}
libspectrum_error
libspectrum_tape_block_read_symbol_table(
  libspectrum_tape_generalised_data_symbol_table *table,
  const libspectrum_byte **ptr, size_t length )
{
  if( table->symbols_in_block ) {
    
    libspectrum_tape_generalised_data_symbol *symbol;
    size_t i, j;

    /* Sanity check */
    if( length < ( 2 * table->max_pulses + 1 ) * table->symbols_in_table ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "%s: not enough data in buffer", __func__ );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }


    table->symbols =
      libspectrum_new( libspectrum_tape_generalised_data_symbol,
                       table->symbols_in_table );

    for( i = 0, symbol = table->symbols;
	 i < table->symbols_in_table;
	 i++, symbol++ ) {
      symbol->edge_type = **ptr; (*ptr)++;
      symbol->lengths = libspectrum_new( libspectrum_word, table->max_pulses );
      for( j = 0; j < table->max_pulses; j++ ) {
	symbol->lengths[ j ] = (*ptr)[0] + (*ptr)[1] * 0x100;
	(*ptr) += 2;
      }
    }

  }
  
  return LIBSPECTRUM_ERROR_NONE;
}
Beispiel #14
0
upd_fdc *
upd_fdc_alloc_fdc( upd_type_t type, upd_clock_t clock )
{
  int i;
  
  upd_fdc *f = libspectrum_new( upd_fdc, 1 );

  f->type = type != UPD765B ? UPD765A : UPD765B;
  f->clock = clock != UPD_CLOCK_4MHZ ? UPD_CLOCK_8MHZ : UPD_CLOCK_4MHZ;
  for( i = 0; i < 4; i++ )
    f->drive[i] = NULL;
  f->current_drive = NULL;
  f->speedlock = 0;
  upd_fdc_master_reset( f );
  return f;
}
Beispiel #15
0
compat_socket_selfpipe_t* compat_socket_selfpipe_alloc( void )
{
  int error;
  int pipefd[2];

  compat_socket_selfpipe_t *self =
    libspectrum_new( compat_socket_selfpipe_t, 1 );

  error = pipe( pipefd );
  if( error ) {
    ui_error( UI_ERROR_ERROR, "%s: %d: error %d creating pipe", __FILE__, __LINE__, error );
    fuse_abort();
  }

  self->read_fd = pipefd[0];
  self->write_fd = pipefd[1];

  return self;
}
Beispiel #16
0
libspectrum_error
libspectrum_z80em_read( libspectrum_tape *tape,
			const libspectrum_byte *buffer, size_t length )
{
  libspectrum_tape_block *block;
  libspectrum_tape_rle_pulse_block *z80em_block;

  static const char id[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Raw tape sample";

  if( length < sizeof( id ) ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_z80em_read: not enough data in buffer"
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  if( memcmp( id, buffer, sizeof( id ) ) ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE,
			     "libspectrum_z80em_read: wrong signature" );
    return LIBSPECTRUM_ERROR_SIGNATURE;
  }

  block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE );

  z80em_block = &block->types.rle_pulse;
  z80em_block->scale = 7; /* 1 time unit == 7 clock ticks */

  buffer += sizeof( id );
  length -= sizeof( id );

  /* Claim memory for the data (it's one big lump) */
  z80em_block->length = length;
  z80em_block->data = libspectrum_new( libspectrum_byte, length );

  /* Copy the data across */
  memcpy( z80em_block->data, buffer, length );

  libspectrum_tape_append_block( tape, block );

  return LIBSPECTRUM_ERROR_NONE;
}
static int machine_add_machine( int (*init_function)( fuse_machine_info *machine ) )
{
  fuse_machine_info *machine;
  int error;

  machine_count++;

  machine_types =
    libspectrum_renew( fuse_machine_info *, machine_types, machine_count );

  machine_types[ machine_count - 1 ] = libspectrum_new( fuse_machine_info, 1 );
  machine = machine_types[ machine_count - 1 ];

  error = init_function( machine ); if( error ) return error;

  machine_set_const_timings( machine );

  machine->capabilities = libspectrum_machine_capabilities( machine->machine );

  return 0;
}
Beispiel #18
0
void
tape_record_start( void )
{
  /* sample rate will be 44.1KHz */
  rec_state.tstates_per_sample =
    machine_current->timings.processor_speed/44100;

  rec_state.tape_buffer_size = 8192;
  rec_state.tape_buffer = libspectrum_new(libspectrum_byte,
					  rec_state.tape_buffer_size);
  rec_state.tape_buffer_used = 0;

  /* start scheduling events that record into a buffer that we
     start allocating here */
  event_add( tstates + rec_state.tstates_per_sample, record_event );

  rec_state.last_level = ula_tape_level();
  rec_state.last_level_count = 1;

  tape_recording = 1;

  /* Also want to disable other tape actions */
  ui_menu_activate( UI_MENU_ITEM_TAPE_RECORDING, 1 );
}
Beispiel #19
0
libspectrum_error
libspectrum_bzip2_inflate( const libspectrum_byte *bzptr, size_t bzlength,
			   libspectrum_byte **outptr, size_t *outlength )
{
  int error;
  unsigned int length2;

  /* Known length, so we can use the easy method */
  if( *outlength ) {

    *outptr = libspectrum_new( libspectrum_byte, *outlength );
    length2 = *outlength;

    error = BZ2_bzBuffToBuffDecompress( (char*)*outptr, &length2, (char*)bzptr,
					bzlength, 0, 0 );
    if( error != BZ_OK ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			       "error decompressing bzip data" );
      return LIBSPECTRUM_ERROR_LOGIC;
    }

    *outlength = length2;

    return LIBSPECTRUM_ERROR_NONE;

  } else {			/* Unknown length, have to stream */

    bz_stream stream;
    libspectrum_byte *ptr; size_t length;

    length = bzlength;

    *outptr = libspectrum_new( libspectrum_byte, length );

    /* Use standard memory allocation/free routines */
    stream.bzalloc = NULL; stream.bzfree = NULL; stream.opaque = NULL;

    error = BZ2_bzDecompressInit( &stream, 0, 0 );
    if( error != BZ_OK ) {
      switch( error ) {

      case BZ_MEM_ERROR:
	libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
				 "out of memory at %s:%d",
				 __FILE__, __LINE__ );
	libspectrum_free( *outptr );
	return LIBSPECTRUM_ERROR_MEMORY;

      default:
	libspectrum_print_error(
          LIBSPECTRUM_ERROR_LOGIC,
	  "bzip2_inflate: serious error from BZ2_bzDecompressInit: %d", error
	);
	libspectrum_free( *outptr );
	return LIBSPECTRUM_ERROR_LOGIC;

      }
    }

    stream.next_in = (char*)bzptr; stream.avail_in = bzlength;
    stream.next_out = (char*)*outptr; stream.avail_out = bzlength;

    while( 1 ) {

      error = BZ2_bzDecompress( &stream );

      switch( error ) {

      case BZ_STREAM_END:	/* Finished decompression */
	error = BZ2_bzDecompressEnd( &stream );
	if( error ) {
	  libspectrum_print_error(
	    LIBSPECTRUM_ERROR_LOGIC,
	    "bzip2_inflate: error from BZ2_bzDecompressEnd: %d", error
	  );
	  libspectrum_free( *outptr );
	  return LIBSPECTRUM_ERROR_LOGIC;
	}
	*outlength = stream.total_out_lo32;
	*outptr = libspectrum_renew( libspectrum_byte, *outptr, *outlength );
	return LIBSPECTRUM_ERROR_NONE;

      case BZ_OK:		/* More output space required */

	length += bzlength;
	ptr = libspectrum_renew( libspectrum_byte, *outptr, length );
	*outptr = ptr;
	stream.next_out = (char*)*outptr + stream.total_out_lo32;
	stream.avail_out += bzlength;
	break;

      default:
	libspectrum_print_error(
	  LIBSPECTRUM_ERROR_LOGIC,
	  "bzip2_inflate: serious error from BZ2_bzDecompress: %d", error
	);
	BZ2_bzDecompressEnd( &stream );
	libspectrum_free( *outptr );
	return LIBSPECTRUM_ERROR_LOGIC;
      }
    }				/* Matches while( 1 ) { ... } */

  }				/* Matches if( *outlength ) { ... } */
}
Beispiel #20
0
static int
libspectrum_sna_read_data( const libspectrum_byte *buffer,
			   size_t buffer_length, libspectrum_snap *snap )
{
  int error, page, i;
  libspectrum_word sp, offset;

  if( buffer_length < 0xc000 ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_sna_read_data: not enough data in buffer"
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  switch( libspectrum_snap_machine( snap ) ) {

  case LIBSPECTRUM_MACHINE_48:

    sp = libspectrum_snap_sp( snap );
    if( sp < 0x4000 || sp == 0xffff ) {
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_CORRUPT,
        "libspectrum_sna_read_data: SP invalid (0x%04x)", sp
      );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }

    /* Rescue PC from the stack */
    offset = sp - 0x4000;
    libspectrum_snap_set_pc( snap, buffer[offset] + 0x100 * buffer[offset+1] );

    /* Increase SP as PC has been unstacked */
    libspectrum_snap_set_sp( snap, libspectrum_snap_sp( snap ) + 2 );

    /* And split the pages up */
    error = libspectrum_split_to_48k_pages( snap, buffer );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    break;

  case LIBSPECTRUM_MACHINE_PENT:
    
    for( i=0; i<8; i++ ) {
      libspectrum_byte *ram = libspectrum_new( libspectrum_byte, 0x4000 );
      libspectrum_snap_set_pages( snap, i, ram );
    }

    memcpy( libspectrum_snap_pages( snap, 5 ), &buffer[0x0000], 0x4000 );
    memcpy( libspectrum_snap_pages( snap, 2 ), &buffer[0x4000], 0x4000 );

    error = libspectrum_sna_read_128_header( buffer + 0xc000,
					     buffer_length - 0xc000, snap );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    page = libspectrum_snap_out_128_memoryport( snap ) & 0x07;
    if( page == 5 || page == 2 ) {
      if( memcmp( libspectrum_snap_pages( snap, page ),
		  &buffer[0x8000], 0x4000 ) ) {
	libspectrum_print_error(
          LIBSPECTRUM_ERROR_CORRUPT,
	  "libspectrum_sna_read_data: duplicated page not identical"
	);
	return LIBSPECTRUM_ERROR_CORRUPT;
      }
    } else {
      memcpy( libspectrum_snap_pages( snap, page ), &buffer[0x8000], 0x4000 );
    }

    buffer += 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH;
    buffer_length -= 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH;
    error = libspectrum_sna_read_128_data( buffer, buffer_length, snap );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    break;

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "libspectrum_sna_read_data: unknown machine" );
    return LIBSPECTRUM_ERROR_LOGIC;
  }
  
  return LIBSPECTRUM_ERROR_NONE;
}
Beispiel #21
0
flash_am29f010_t*
flash_am29f010_alloc( void )
{
  return libspectrum_new( flash_am29f010_t, 1 );
}
Beispiel #22
0
static void
block_alloc( rzx_block_t **block, libspectrum_rzx_block_id type )
{
  *block = libspectrum_new( rzx_block_t, 1 );
  (*block)->type = type;
}
Beispiel #23
0
static libspectrum_error
inflate_block( libspectrum_byte **uncompressed, size_t *uncompressed_length,
	       const libspectrum_byte **compressed, size_t compressed_length )
{

#ifdef HAVE_ZLIB_H

  libspectrum_dword header_length, expected_crc32, actual_crc32;
  libspectrum_byte *zlib_buffer;
  unsigned long actual_length;
  int error;

  /* First, look at the compression header */
  header_length = libspectrum_read_dword( compressed );
  if( header_length != 12 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "zxs_inflate_block: unknown header length %lu",
			     (unsigned long)header_length );
    return LIBSPECTRUM_ERROR_UNKNOWN;
  }
  compressed_length -= 12;

  expected_crc32 = libspectrum_read_dword( compressed );
  *uncompressed_length = libspectrum_read_dword( compressed );

  /* Some space to put the zlib header for decompression */
  zlib_buffer = libspectrum_new( libspectrum_byte, ( compressed_length + 6 ) );

  /* zlib's header */
  zlib_buffer[0] = 0x78; zlib_buffer[1] = 0xda;

  memcpy( &zlib_buffer[2], *compressed, compressed_length );
  *compressed += compressed_length;

  *uncompressed = libspectrum_new( libspectrum_byte, *uncompressed_length );

  actual_length = *uncompressed_length;
  error = uncompress( *uncompressed, &actual_length, zlib_buffer,
		      compressed_length + 6 );

  /* At this point, we expect to get a Z_DATA_ERROR, as we don't have
     the Adler-32 checksum of the data. There is a 1 in 65521 chance
     that the random bytes will match, so we might (very rarely) get
     Z_OK */
  if( error != Z_DATA_ERROR && error != Z_OK ) {
    libspectrum_free( *uncompressed ); libspectrum_free( zlib_buffer );
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "zxs_inflate_block: unexpected zlib error" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  if( *uncompressed_length != actual_length ) {
    libspectrum_free( *uncompressed ); libspectrum_free( zlib_buffer );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "zxs_inflate_block: block expanded to 0x%04lx, not the expected 0x%04lx bytes",
      actual_length, (unsigned long)*uncompressed_length
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  libspectrum_free( zlib_buffer );

  actual_crc32 = crc32( 0, Z_NULL, 0 );
  actual_crc32 = crc32( actual_crc32, *uncompressed, *uncompressed_length );

  if( actual_crc32 != expected_crc32 ) {
    libspectrum_free( *uncompressed );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "zxs_inflate_block: crc 0x%08x does not match expected 0x%08x",
      actual_crc32, expected_crc32
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  return LIBSPECTRUM_ERROR_NONE;

#else				/* #ifdef HAVE_ZLIB_H */

  /* No zlib, so can't inflate the block */
  return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

}
Beispiel #24
0
static libspectrum_error
rzx_read_input( libspectrum_rzx *rzx,
		const libspectrum_byte **ptr, const libspectrum_byte *end )
{
  size_t blocklength;
  libspectrum_dword flags; int compressed;
  libspectrum_error error;
  rzx_block_t *rzx_block;
  input_block_t *block;

  /* Check we've got enough data for the block */
  if( end - (*ptr) < 18 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_input: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  block_alloc( &rzx_block, LIBSPECTRUM_RZX_INPUT_BLOCK );

  block = &( rzx_block->types.input );

  /* Get the length and number of frames */
  blocklength = libspectrum_read_dword( ptr );
  block->count = libspectrum_read_dword( ptr );

  /* Frame size is undefined, so just skip it */
  (*ptr)++;

  /* Allocate memory for the frames */
  block->frames = libspectrum_new( libspectrum_rzx_frame_t, block->count );
  block->allocated = block->count;

  /* Fetch the T-state counter and the flags */
  block->tstates = libspectrum_read_dword( ptr );

  flags = libspectrum_read_dword( ptr );
  compressed = flags & 0x02;

  if( compressed ) {

#ifdef HAVE_ZLIB_H

    libspectrum_byte *data; const libspectrum_byte *data_ptr;
    size_t data_length = 0;

    /* Discount the block intro */
    blocklength -= 18;

    /* Check that we've got enough compressed data */
    if( end - (*ptr) < (ptrdiff_t)blocklength ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "rzx_read_input: not enough data in buffer" );
      libspectrum_free( rzx_block );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }

    error = libspectrum_zlib_inflate( *ptr, blocklength, &data, &data_length );
    if( error != LIBSPECTRUM_ERROR_NONE ) {
      block_free( rzx_block );
      return error;
    }

    *ptr += blocklength;

    data_ptr = data;

    error = rzx_read_frames( block, &data_ptr, data + data_length );
    if( error ) { libspectrum_free( rzx_block ); libspectrum_free( data ); return error; }

    libspectrum_free( data );

#else				/* #ifdef HAVE_ZLIB_H */

    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "rzx_read_input: zlib needed for decompression" );
    libspectrum_free( rzx_block );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

  } else {			/* Data not compressed */

    error = rzx_read_frames( block, ptr, end );
    if( error ) { libspectrum_free( rzx_block ); return error; }
  }

  rzx->blocks = g_slist_append( rzx->blocks, rzx_block );

  return LIBSPECTRUM_ERROR_NONE;
}
Beispiel #25
0
libspectrum_error
libspectrum_rzx_store_frame( libspectrum_rzx *rzx, size_t instructions,
			     size_t count, libspectrum_byte *in_bytes )
{
  input_block_t *input;
  libspectrum_rzx_frame_t *frame;
  libspectrum_error error;

  input = rzx->current_input;

  /* Check we've got an IRB to record to */
  if( !input ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_INVALID,
      "libspectrum_rzx_store_frame called with no active input block"
    );
    return LIBSPECTRUM_ERROR_INVALID;
  }

  /* Get more space if we need it */
  if( input->allocated == input->count ) {
    error = input_block_resize( input, input->count + 1 );
    if( error ) return error;
  }

  frame = &input->frames[ input->count ];

  frame->instructions = instructions;

  /* Check for repeated frames */
  if( input->count != 0 && count != 0 &&
      count == input->frames[ input->non_repeat ].count &&
      !memcmp( in_bytes, input->frames[ input->non_repeat ].in_bytes,
	       count )
    ) {
	
    frame->repeat_last = 1;
    frame->count = 0;
    frame->in_bytes = NULL;

  } else {

    frame->repeat_last = 0;
    frame->count = count;

    /* Note this as the last non-repeated frame */
    input->non_repeat = input->count;

    if( count ) {

      frame->in_bytes = libspectrum_new( libspectrum_byte, count );

      memcpy( frame->in_bytes, in_bytes,
	      count * sizeof( *( frame->in_bytes ) ) );

    } else {

      frame->in_bytes = NULL;

    }
  }

  /* Move along to the next frame */
  input->count++;

  return 0;
}
Beispiel #26
0
libspectrum_error
libspectrum_csw_read( libspectrum_tape *tape,
                      const libspectrum_byte *buffer, size_t length )
{
    libspectrum_tape_block *block = NULL;
    libspectrum_tape_rle_pulse_block *csw_block;

    int compressed;

    size_t signature_length = strlen( csw_signature );

    if( length < signature_length + 2 ) goto csw_short;

    if( memcmp( csw_signature, buffer, signature_length ) ) {
        libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE,
                                 "libspectrum_csw_read: wrong signature" );
        return LIBSPECTRUM_ERROR_SIGNATURE;
    }

    /* Claim memory for the block */
    block = libspectrum_new( libspectrum_tape_block, 1 );

    /* Set the block type */
    block->type = LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE;
    csw_block = &block->types.rle_pulse;

    buffer += signature_length;
    length -= signature_length;

    switch( buffer[0] ) {

    case 1:
        if( length < 9 ) goto csw_short;
        csw_block->scale = buffer[2] | buffer[3] << 8;
        if( buffer[4] != 1 ) goto csw_bad_compress;
        compressed = 0;
        buffer += 9;
        length -= 9;
        break;

    case 2:
        if( length < 29 ) goto csw_short;

        csw_block->scale =
            buffer[2]       |
            buffer[3] <<  8 |
            buffer[4] << 16 |
            buffer[5] << 24;
        compressed = buffer[10] - 1;

        if( compressed != 0 && compressed != 1 ) goto csw_bad_compress;

        if( length < 29 - buffer[12] ) goto csw_short;
        length -= 29 - buffer[12];
        buffer += 29 + buffer[12];

        break;

    default:
        libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
                                 "libspectrum_csw_read: unknown CSW version" );
        return LIBSPECTRUM_ERROR_SIGNATURE;
    }

    if (csw_block->scale)
        csw_block->scale = 3500000 / csw_block->scale; /* approximate CPU speed */

    if( csw_block->scale < 0 || csw_block->scale >= 0x80000 ) {
        libspectrum_print_error (LIBSPECTRUM_ERROR_MEMORY,
                                 "libspectrum_csw_read: bad sample rate" );
        return LIBSPECTRUM_ERROR_UNKNOWN;
    }

    if( !length ) goto csw_empty;

    if( compressed ) {
        /* Compressed data... */
#ifdef HAVE_ZLIB_H
        libspectrum_error error;

        csw_block->data = NULL;
        csw_block->length = 0;
        error = libspectrum_zlib_inflate( buffer, length, &csw_block->data,
                                          &csw_block->length );
        if( error != LIBSPECTRUM_ERROR_NONE ) return error;
#else
        libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
                                 "zlib not available to decompress gzipped file" );
        return LIBSPECTRUM_ERROR_UNKNOWN;
#endif
    } else {
        /* Claim memory for the data (it's one big lump) */
        csw_block->length = length;
        csw_block->data = libspectrum_new( libspectrum_byte, length );

        /* Copy the data across */
        memcpy( csw_block->data, buffer, length );
    }

    libspectrum_tape_append_block( tape, block );

    /* Successful completion */
    return LIBSPECTRUM_ERROR_NONE;

    /* Error returns */

csw_bad_compress:
    libspectrum_free( block );
    libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
                             "libspectrum_csw_read: unknown compression type" );
    return LIBSPECTRUM_ERROR_CORRUPT;

csw_short:
    libspectrum_free( block );
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
                             "libspectrum_csw_read: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;

csw_empty:
    libspectrum_free( block );
    /* Successful completion */
    return LIBSPECTRUM_ERROR_NONE;
}