Beispiel #1
0
/* output the last line printed as text. */
static void printer_zxp_output_as_text(void)
{
static unsigned char charset[256*8];
static unsigned char outbuf[32];
unsigned char *ptr;
int x,y,f,c,chars;

#define SYSV_CHARS	0x5c36

chars=readbyte_internal(SYSV_CHARS);
chars+=256*readbyte_internal(SYSV_CHARS+1);

memset(charset,0,sizeof(charset));
ptr=charset+32*8;
for(f=32*8;f<128*8;f++)
  *ptr++=readbyte_internal(chars+f);

for(x=0;x<32;x++)
  {
  c=-1;
  
  /* try each char */
  for(f=32;f<128 && c==-1;f++)
    {
    ptr=zxplast8+x;
    c=f;
    for(y=0;y<8;y++,ptr+=32)
      if(*ptr!=charset[f*8+y])
        {
        c=-1;
        break;
        }
    }

  /* can't do UDGs, too unreliable */

  if(c==-1) c=32;
  
  outbuf[x]=c;
  }

for(f=31;f>=0 && outbuf[f]==32;f--)
  outbuf[f]=0;

for(f=0;f<32 && outbuf[f];f++)
  printer_text_output_char(outbuf[f]);
printer_text_output_char('\n');
}
Beispiel #2
0
int
widget_memory_draw( void *data )
{
  int x, y;
  char pbuf[36];

  widget_rectangle( LC(0), LR(0), 40 * 8, 16 * 8 + 4, 1 );
  widget_rectangle( LC(0), LR(16) + 2, 320, 1, 7 );

  for( y = 0; y < 16; ++y ) {
    libspectrum_word addr = memaddr + y * 8;

    sprintf( pbuf, "%04X:", addr );
    widget_printstring_right( LC(5) - 4, LR(y), 5, pbuf );

    for( x = 0; x < 8; ++x ) {
      libspectrum_byte b = readbyte_internal( addr + x );

      widget_printchar_fixed( LC(x + 29) / 8, LR(y) / 8, 7 - (y & 1), b );
      sprintf( pbuf + x * 3, "%02X ", b );
    }
    widget_printstring_fixed( LC(5) / 8, LR(y) / 8, 7 - (y & 1), pbuf );
  }

  widget_display_lines( LR(0) / 8, 17 );

  return 0;
}
Beispiel #3
0
libspectrum_byte
readbyte( libspectrum_word address )
{
  printf( "%5d MC %04x\n", tstates, address );
  tstates += 3;
  return readbyte_internal( address );
}
Beispiel #4
0
static void
update_display( GtkCList *clist, libspectrum_word base )
{
    size_t i, j;

    gchar buffer[ 8 + 64 + 20 ];
    gchar *text[] = { &buffer[0], &buffer[ 8 ], &buffer[ 8 + 64 ] };
    char buffer2[ 8 ];

    gtk_clist_freeze( clist );
    gtk_clist_clear( clist );

    for( i = 0; i < 20; i++ ) {
        snprintf( text[0], 8, "%04X", base );

        text[1][0] = '\0';
        for( j = 0; j < 0x10; j++, base++ ) {

            libspectrum_byte b = readbyte_internal( base );

            snprintf( buffer2, 4, "%02X ", b );
            strncat( text[1], buffer2, 4 );

            text[2][j] = ( b >= 32 && b < 127 ) ? b : '.';
        }
        text[2][ 0x10 ] = '\0';

        gtk_clist_append( clist, text );
    }

    gtk_clist_thaw( clist );
}
Beispiel #5
0
/* Exit from the last CALL etc by setting a oneshot breakpoint at
   (SP) and then starting emulation */
int
debugger_breakpoint_exit( void )
{
  libspectrum_word target;

  target = readbyte_internal( SP ) + 0x100 * readbyte_internal( SP+1 );

  if( debugger_breakpoint_add_address(
        DEBUGGER_BREAKPOINT_TYPE_EXECUTE, memory_source_any, 0, target, 0,
	DEBUGGER_BREAKPOINT_LIFE_ONESHOT, NULL
      )
    )
    return 1;

  if( debugger_run() ) return 1;

  return 0;
}
Beispiel #6
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() ) 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 = malloc( length * sizeof(libspectrum_byte) );
  if( !data ) { free( block ); return 1; }
  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 #7
0
static void
do_acceleration( void )
{
  if( length_known1 ) {
    int set_b_high = length_long1;
    set_b_high ^= ( acceleration_mode == ACCELERATION_MODE_DECREASING );
    if( set_b_high ) {
      z80.bc.b.h = 0xfe;
    } else {
      z80.bc.b.h = 0x00;
    }
    z80.af.b.l |= 0x01;
    z80.pc.b.l = readbyte_internal( z80.sp.w ); z80.sp.w++;
    z80.pc.b.h = readbyte_internal( z80.sp.w ); z80.sp.w++;

    event_remove_type( tape_edge_event );
    tape_next_edge( tstates, 0, NULL );

    successive_reads = 0;
  }

  length_known1 = length_known2;
  length_long1 = length_long2;
}
Beispiel #8
0
static void
update_display( HWND hwndDlg, libspectrum_word base )
{
  size_t i, j;

  TCHAR buffer[ 8 + 64 + 20 ];
  TCHAR *text[] = { &buffer[0], &buffer[ 8 ], &buffer[ 8 + 64 ] };
  TCHAR buffer2[ 8 ];

  SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_DELETEALLITEMS, 0, 0 );

  LV_ITEM lvi;
  lvi.mask = LVIF_TEXT;

  for( i = 0; i < 20; i++ ) {
    _sntprintf( text[0], 8, TEXT( "%04X" ), base );

    text[1][0] = '\0';
    for( j = 0; j < 0x10; j++, base++ ) {

      libspectrum_byte b = readbyte_internal( base );

      _sntprintf( buffer2, 4, TEXT( "%02X " ), b );
      _tcsncat( text[1], buffer2, 4 );

      text[2][j] = ( b >= 32 && b < 127 ) ? b : '.';
    }
    text[2][ 0x10 ] = '\0';

    /* append the item */
    lvi.iItem = SendDlgItemMessage( hwndDlg, IDC_MEM_LV,
                                    LVM_GETITEMCOUNT, 0, 0 );
    lvi.iSubItem = 0;
    lvi.pszText = text[0];
    SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_INSERTITEM, 0,
                        ( LPARAM ) &lvi );
    lvi.iSubItem = 1;
    lvi.pszText = text[1];
    SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_SETITEM, 0,
                        ( LPARAM ) &lvi );
    lvi.iSubItem = 2;
    lvi.pszText = text[2];
    SendDlgItemMessage( hwndDlg, IDC_MEM_LV, LVM_SETITEM, 0,
                        ( LPARAM ) &lvi );
  }
}
Beispiel #9
0
static void
update_display( GtkTreeModel *model, libspectrum_word base )
{
  size_t i, j;
  GtkTreeIter iter;

  gchar buffer[ 8 + 64 + 20 ];
  gchar *text[] = { &buffer[0], &buffer[ 8 ], &buffer[ 8 + 64 ] };
  char buffer2[ 8 ];

  memaddr = base;
  gtk_list_store_clear( GTK_LIST_STORE( model ) );

  for( i = 0; i < 20; i++ ) {
    snprintf( text[0], 8, "%04X", base );

    text[1][0] = '\0';
    for( j = 0; j < 0x10; j++, base++ ) {

      libspectrum_byte b = readbyte_internal( base );

      snprintf( buffer2, 4, "%02X ", b );
      strncat( text[1], buffer2, 4 );

      text[2][j] = ( b >= 32 && b < 127 ) ? b : '.';
    }
    text[2][ 0x10 ] = '\0';

    /* Append a new row and fill data */
    gtk_list_store_append( GTK_LIST_STORE( model ), &iter );
    gtk_list_store_set( GTK_LIST_STORE( model ), &iter,
                        COL_ADDRESS, text[0],
                        COL_HEX,     text[1],
                        COL_DATA,    text[2],
                        -1 );
  }

}
Beispiel #10
0
static acceleration_mode_t
acceleration_detector( libspectrum_word pc )
{
  int state = 0, count = 0;
  while( 1 ) {
    libspectrum_byte b = readbyte_internal( pc ); pc++; count++;
    switch( state ) {
    case 0:
      switch( b ) {
      case 0x04: state = 1; break;	/* INC B - Many loaders */
      default: state = 13; break;	/* Possible Digital Integration */
      }
      break;
    case 1:
      switch( b ) {
      case 0xc8: state = 2; break;	/* RET Z */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 2:
      switch( b ) {
      case 0x3e: state = 3; break;	/* LD A,nn */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 3:
      switch( b ) {
      case 0x00:			/* Search Loader */
      case 0x7f:			/* ROM loader and variants */
	state = 4; break;		/* Data byte */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 4:
      switch( b ) {
      case 0xdb: state = 5; break;	/* IN A,(nn) */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 5:
      switch( b ) {
      case 0xfe: state = 6; break;	/* Data byte */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 6:
      switch( b ) {
      case 0x1f: state = 7; break;	/* RRA */
      case 0xa9: state = 24; break;	/* XOR C - Search Loader */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 7:
      switch( b ) {
      case 0x00:			/* NOP - Bleepload */
      case 0xa7:			/* AND A - Microsphere */
      case 0xc8:			/* RET Z - Paul Owens */
      case 0xd0:			/* RET NC - ROM loader */
	state = 8; break;
      case 0xa9: state = 9; break;	/* XOR C - Speedlock */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 8:
      switch( b ) {
      case 0xa9: state = 9; break;	/* XOR C */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 9:
      switch( b ) {
      case 0xe6: state = 10; break;	/* AND nn */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 10:
      switch( b ) {
      case 0x20: state = 11; break;	/* Data byte */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 11:
      switch( b ) {
      case 0x28: state = 12; break;	/* JR nn */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 12:
      if( b == 0x100 - count ) {
	return ACCELERATION_MODE_INCREASING;
      } else {
	return ACCELERATION_MODE_NONE;
      }
      break;

      /* Digital Integration loader */

    case 13:
      state = 14; break;		/* Possible Digital Integration */
    case 14:
      switch( b ) {
      case 0x05: state = 15; break;	/* DEC B - Digital Integration */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 15:
      switch( b ) {
      case 0xc8: state = 16; break;	/* RET Z */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 16:
      switch( b ) {
      case 0xdb: state = 17; break;	/* IN A,(nn) */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 17:
      switch( b ) {
      case 0xfe: state = 18; break;	/* Data byte */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 18:
      switch( b ) {
      case 0xa9: state = 19; break;	/* XOR C */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 19:
      switch( b ) {
      case 0xe6: state = 20; break;	/* AND nn */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 20:
      switch( b ) {
      case 0x40: state = 21; break;	/* Data byte */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 21:
      switch( b ) {
      case 0xca: state = 22; break;	/* JP Z,nnnn */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 22:				/* LSB of jump target */
      if( b == ( z80.pc.w - 4 ) % 0x100 ) {
	state = 23;
      } else {
	return ACCELERATION_MODE_NONE;
      }
      break;
    case 23:				/* MSB of jump target */
      if( b == ( z80.pc.w - 4 ) / 0x100 ) {
	return ACCELERATION_MODE_DECREASING;
      } else {
	return ACCELERATION_MODE_NONE;
      }

      /* Search loader */

    case 24:
      switch( b ) {
      case 0xe6: state = 25; break;	/* AND nn */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 25:
      switch( b ) {
      case 0x40: state = 26; break;	/* Data byte */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 26:
      switch( b ) {
      case 0xd8: state = 27; break;	/* RET C */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
    case 27:
      switch( b ) {
      case 0x00: state = 11; break;	/* NOP */
      default: return ACCELERATION_MODE_NONE;
      }
      break;
	
    default:
      /* Can't happen */
      break;
    }
  }

}      
Beispiel #11
0
static int
trap_load_block( libspectrum_tape_block *block )
{
  libspectrum_byte parity, *data;
  int i = 0, length, read, verify;

  /* On exit:
   *  A = calculated parity byte if parity checked, else 0 (CHECKME)
   *  F : if parity checked, all flags are modified
   *      else carry only is modified (FIXME)
   *  B = 0xB0 (success) or 0x00 (failure)
   *  C = 0x01 (confirmed), 0x21, 0xFE or 0xDE (CHECKME)
   * DE : decremented by number of bytes loaded or verified
   *  H = calculated parity byte or undefined
   *  L = last byte read, or 1 if none
   * IX : incremented by number of bytes loaded or verified
   * A' = unchanged on error + no flag byte, else 0x01
   * F' = 0x01      on error + no flag byte, else 0x45
   *  R = no point in altering it :-)
   * Other registers unchanged.
   */

  data = libspectrum_tape_block_data( block );
  length = libspectrum_tape_block_data_length( block );

  /* Number of bytes to load or verify */
  read = length - 1;
  if( read > DE )
    read = DE;

  /* If there's no data in the block (!), set L then error exit.
   * We don't need to alter H, IX or DE here */
  if( !length ) {
    L = F_ = 1;
    F &= ~FLAG_C;
    return 0;
  }

  verify =  !(F_ & FLAG_C);
  i = A_; /* i = A' (flag byte) */
  AF_ = 0x0145;
  A = 0;

  /* Initialise the parity check and L to the block ID byte */
  L = parity = *data++;

  /* If the block ID byte != the flag byte, clear carry and return */
  if( parity != i )
    goto error_ret;

  /* Now set L to the *last* byte in the block */
  L = data[read - 1];

  /* Loading or verifying determined by the carry flag of F' */
  if( verify ) {		/* verifying */
    for( i = 0; i < read; i++ ) {
      parity ^= data[i];
      if( data[i] != readbyte_internal(IX+i) ) {
        /* Verification failure */
        L = data[i];
	goto error_ret;
      }
    }
  } else {
    for( i = 0; i < read; i++ ) {
      parity ^= data[i];
      writebyte_internal( IX+i, data[i] );
    }
  }

  /* At this point, i == number of bytes actually read or verified */

  /* If |DE| bytes have been read and there's more data, do the parity check */
  if( DE == i && read + 1 < length ) {
    parity ^= data[read];
    A = parity;
    CP( 1 ); /* parity check is successful if A==0 */
    B = 0xB0;
  } else {
    /* Failure to read first bit of the next byte (ref. 48K ROM, 0x5EC) */
    B = 255;
    L = 1;
    INC( B );
error_ret:
    F &= ~FLAG_C;
  }

  /* At this point, AF, AF', B and L are already modified */
  C = 1;
  H = parity;
  DE -= i;
  IX += i;
  return 0;
}
Beispiel #12
0
/* Execute Z80 opcodes until the next event */
void
z80_do_opcodes( void )
{
#ifdef HAVE_ENOUGH_MEMORY
  libspectrum_byte opcode = 0x00;
#endif

  int even_m1 =
    machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_EVEN_M1; 

#ifdef __GNUC__

#undef SETUP_CHECK
#define SETUP_CHECK( label, condition ) \
  if( condition ) { cgoto[ next ] = &&label; next = pos_##label + 1; } \
  check++;

#undef SETUP_NEXT
#define SETUP_NEXT( label ) \
  if( next != check ) { cgoto[ next ] = &&label; } \
  next = check;

  void *cgoto[ numchecks ]; size_t next = 0; size_t check = 0;

#include "z80_checks.h"

#endif				/* #ifdef __GNUC__ */

  while( tstates < event_next_event ) {

    /* Profiler */
    CHECK( profile, profile_active )

    profile_map( PC );

    END_CHECK

    /* If we're due an end of frame from RZX playback, generate one */
    CHECK( rzx, rzx_playback )

    if( R + rzx_instructions_offset >= rzx_instruction_count ) {
      event_add( tstates, spectrum_frame_event );
      break;		/* And break out of the execution loop to let
			   the interrupt happen */
    }

    END_CHECK

    /* Check if the debugger should become active at this point */
    CHECK( debugger, debugger_mode != DEBUGGER_MODE_INACTIVE )

    if( !z80.halted && debugger_check( DEBUGGER_BREAKPOINT_TYPE_EXECUTE, PC ) )
      debugger_trap();

    END_CHECK

    CHECK( beta, beta_available )

#define NOT_128_TYPE_OR_IS_48_TYPE ( !( machine_current->capabilities & \
            LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY ) || \
            machine_current->ram.current_rom )

    if( beta_active ) {
      if( NOT_128_TYPE_OR_IS_48_TYPE && PC >= 16384 ) {
	beta_unpage();
      }
    } else if( ( PC & beta_pc_mask ) == beta_pc_value &&
               NOT_128_TYPE_OR_IS_48_TYPE ) {
      beta_page();
    }

    END_CHECK

    CHECK( plusd, plusd_available )

    if( PC == 0x0008 || PC == 0x003a || PC == 0x0066 || PC == 0x028e ) {
      plusd_page();
    }

    END_CHECK

    CHECK( didaktik80, didaktik80_available )

    if( PC == 0x0000 || PC == 0x0008 ) {
      didaktik80_page();
    } else if( PC == 0x1700 ) {
      didaktik80_unpage();
    }

    END_CHECK

    CHECK( disciple, disciple_available )

    if( PC == 0x0001 || PC == 0x0008 || PC == 0x0066 || PC == 0x028e ) {
      disciple_page();
    }

    END_CHECK

    CHECK( usource, usource_available )

    if( PC == 0x2bae ) {
      usource_toggle();
    }

    END_CHECK

    CHECK( if1p, if1_available )

    if( PC == 0x0008 || PC == 0x1708 ) {
      if1_page();
    }

    END_CHECK

    CHECK( divide_early, settings_current.divide_enabled )
    
    if( ( PC & 0xff00 ) == 0x3d00 ) {
      divide_set_automap( 1 );
    }
    
    END_CHECK

    CHECK( spectranet_page, spectranet_available && !settings_current.spectranet_disable )

    if( PC == 0x0008 || ((PC & 0xfff8) == 0x3ff8) )
      spectranet_page( 0 );

    if( PC == spectranet_programmable_trap &&
      spectranet_programmable_trap_active )
      event_add( 0, z80_nmi_event );

    END_CHECK

  opcode_delay:

    contend_read( PC, 4 );

    /* Check to see if M1 cycles happen on even tstates */
    CHECK( evenm1, even_m1 )

    if( tstates & 1 ) {
      if( ++tstates == event_next_event ) {
	break;
      }
    }

    END_CHECK

  run_opcode:
    /* Do the instruction fetch; readbyte_internal used here to avoid
       triggering read breakpoints */
    opcode = readbyte_internal( PC );

    CHECK( if1u, if1_available )

    if( PC == 0x0700 ) {
      if1_unpage();
    }

    END_CHECK

    CHECK( divide_late, settings_current.divide_enabled )

    if( ( PC & 0xfff8 ) == 0x1ff8 ) {
      divide_set_automap( 0 );
    } else if( (PC == 0x0000) || (PC == 0x0008) || (PC == 0x0038)
      || (PC == 0x0066) || (PC == 0x04c6) || (PC == 0x0562) ) {
      divide_set_automap( 1 );
    }
    
    END_CHECK

    CHECK( opus, opus_available )

    if( opus_active ) {
      if( PC == 0x1748 ) {
        opus_unpage();
      }
    } else if( PC == 0x0008 || PC == 0x0048 || PC == 0x1708 ) {
      opus_page();
    }

    END_CHECK

    CHECK( spectranet_unpage, spectranet_available )

    if( PC == 0x007c )
      spectranet_unpage();

    END_CHECK

    CHECK( z80_halted, z80.halted )

    /* Opcode read from memory is ignored and PC is left unchanged */
    R++;
    continue;

    END_CHECK

    CHECK( z80_iff2_read, z80.iff2_read )

    z80.iff2_read = 0;
    /* Execute *one* instruction before reevaluating the checks */
    event_add( tstates, z80_nmos_iff2_event );

    END_CHECK

    CHECK( didaktik80snap, didaktik80_snap )

    if( PC == 0x0066 && !didaktik80_active ) {
      opcode = 0xc7;	/* RST 00 */
      didaktik80_snap = 0; /* FIXME: this should be a time-based reset */
    }

    END_CHECK

    CHECK( svg_capture, svg_capture_active )

    svg_capture();

    END_CHECK

  end_opcode:
    PC++; R++;
    switch(opcode) {
#include "z80/opcodes_base.c"
    }

  }

}