libspectrum 0.4.0 ================= libspectrum is a fairly simple library designed to make the handling of various ZX Spectrum emulator-related file formats easy. So far it handles: * Snapshots: .z80, .szx, .sna (all read/write), .zxs, .sp., .snp and +D snapshots (read only). * Tape images: .tzx, .tap, .spc, .sta and .ltp (read/write) and Warajevo .tap, Z80Em and CSW version 1 (read only). * Input recordings: .rzx (read/write). * Timex cartridges: .dck (read only). * IDE hard disk images: .hdf (read/write). There are also some subsidiary functions which may be generally useful for Spectrum-related utilities. General conventions =================== Naming conventions: *_alloc: give us a new object *_free: we're done with this object *_read: restore object from serialised form *_write: serialise object Calling conventions: * In general, all output parameters (those which may be changed by the function) should be before all input parameters Library capabilities ==================== If the library supports zlib compression (as is used, for instance in SZX snapshots), then then the constant LIBSPECTRUM_SUPPORTS_ZLIB_COMPRESSION will be defined and non-zero. If the library does not support zlib compression, then the constant will not be defined. Defined types ============= libspectrum defines eight standard types which may be of use: libspectrum_byte An unsigned 8-bit integer libspectrum_signed_byte A signed 8-bit integer libspectrum_word An unsigned 16-bit integer libspectrum_signed_word A signed 16-bit integer libspectrum_dword An unsigned 32-bit integer libspectrum_signed_dword A signed 32-bit integer libspectrum_qword An unsigned 64-bit integer libspectrum_signed_qword A signed 64-bit integer Initialisation etc ================== libspectrum_error libspectrum_init( void ) This routine must be called before any other libspectrum routines, other than `libspectrum_version' and `libspectrum_check_version' to initialise the library. If it isn't called, undefined behaviour may result. const char *libspectrum_version( void ) This routine returns the version of libspectrum in use, in a "x.y.z.a" format. const char *libspectrum_gcrypt_version( void ) This routine returns the version of libgcrypt being used by libspectrum, or NULL if an appropriate version of libgcrypt is not available. int libspectrum_check_version( const char *version ) This routine checks whether the version of libspectrum is at least `version', which should be specified in an "x.y.z.a" format. It returns non-zero if the libspectrum version in use is at least `version' or zero if it is not. Error handling ============== All libspectrum functions signal errors in two ways: by returning an non-zero error code of type `libspectrum_error' and by calling `libspectrum_error_function'. The `libspectrum_error' enum can take the following values: LIBSPECTRUM_ERROR_NONE No error; guaranteed to have value 0 LIBSPECTRUM_ERROR_WARNING A warning, rather than a real error LIBSPECTRUM_ERROR_MEMORY Out of memory LIBSPECTRUM_ERROR_UNKNOWN Data not recognised LIBSPECTRUM_ERROR_CORRUPT Invalid data LIBSPECTRUM_ERROR_SIGNATURE File does not have the right signature LIBSPECTRUM_ERROR_SLT Ugly kludge used to indicate that a .z80 file contains .slt data LIBSPECTRUM_ERROR_INVALID An invalid parameter was supplied to a function LIBSPECTRUM_ERROR_LOGIC An internal logic error has occurred; should never be seen `libspectrum_error_function' is an object of type `libspectrum_error_function_t': libspectrum_error (*libspectrum_error_function_t)( libspectrum_error error, const char *format, va_list ap ) On error, `libspectrum_error_function' will be called, with `error' being one of the standard codes, and `format' and `ap' are the standard arguments suitable for passing to one of the v*printf functions to create a text message giving more details on the error. If `libspectrum_error_function' is not set by the user code, `libspectrum_default_error_function' will be used: this simply outputs the message to stderr, prefixed with "libspectrum error: " and ending with a newline. (Additionally, it will call abort() if the error was of type LIBSPECTRUM_ERROR_LOGIC, but that shouldn't happen...) General functions ================= Functions which don't relate directly to one file type or another. Machine types and capabilities ------------------------------ In some places (notably in the `libspectrum_snap' structure), libspectrum needs to identify the Spectrum variant in use. This is done with the `libspectrum_machine' enum, which can take the following values: LIBSPECTRUM_MACHINE_16 16K Spectrum LIBSPECTRUM_MACHINE_48 48K Spectrum LIBSPECTRUM_MACHINE_128 (Original) 128K Spectrum LIBSPECTRUM_MACHINE_PLUS2 Spectrum +2 (the grey one) LIBSPECTRUM_MACHINE_PLUS2A Spectrum +2A (the black one) LIBSPECTRUM_MACHINE_PLUS3 Spectrum +3 LIBSPECTRUM_MACHINE_PLUS3E Spectrum +3e LIBSPECTRUM_MACHINE_TC2048 Timex TC2048 LIBSPECTRUM_MACHINE_TC2068 Timex TC2068 LIBSPECTRUM_MACHINE_TS2068 Timex TS2068 LIBSPECTRUM_MACHINE_PENT Pentagon 128 LIBSPECTRUM_MACHINE_PENT512 Pentagon 512 LIBSPECTRUM_MACHINE_PENT1024 Pentagon 1024 LIBSPECTRUM_MACHINE_SCORP Scorpion ZS 256 LIBSPECTRUM_MACHINE_SE Spectrum SE The `libspectrum_machine_name' function: const char* libspectrum_machine_name( libspectrum_machine type ) will return a text string giving the name of the machine (or "unknown" if it doesn't recognise the type). This string is statically allocated and so should not be modified by user code in any way. The `libspectrum_machine_capabilities' function: int libspectrum_machine_capabilities( libspectrum_machine type ) will tell you which features (above and beyond those found on the base 48K machine) a given `libspectrum_machine' has. It returns a bitwise OR of the following constants: LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY This machine has 128K of memory accessible as on the 128K machine. LIBSPECTRUM_MACHINE_CAPABILITY_AY This machine has an AY-3-8912 sound chip (as in the 128K and later machines). LIBSPECTRUM_MACHINE_CAPABILITY_EVEN_M1 Processor M1 cycles on this machine always start on even tstate counts. LIBSPECTRUM_MACHINE_CAPABILITY_KEMPSTON_JOYSTICK This machine has built-in Kempston joystick ports as on the TC2048. LIBSPECTRUM_MACHINE_CAPABILITY_NTSC This machine has an NTSC video output. LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY This machine can change into all-RAM configurations as the +2A/+3. LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_DISK This machine has a disk drive similar to that on the +3. LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY This machine has memory paging capabilities like those found on the Scorpion ZS 256. LIBSPECTRUM_MACHINE_CAPABILITY_SE_MEMORY This machine has memory paging capabilities like those found on the Spectrum SE. LIBSPECTRUM_MACHINE_CAPABILITY_SINCLAIR_JOYSTICK This machine has built-in Sinclair joystick ports as on the +2/+2A/+3. LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_DOCK This machine has a `dock' (cartridge port) similar to that found on the TC2068. LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_MEMORY This machine has memory paging capabilities similar to that of the TC2048 and TC2068. LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_VIDEO This machine has additional video modes as found on the TC2048 and TC2068. LIBSPECTRUM_MACHINE_CAPABILITY_TRDOS_DISK This machine has a disk drive similar to a TR-DOS device File identification ------------------- The `libspectrum_identify_file_raw' function will, if given a file's contents and optionally its filename, will make a `best guess' as to what sort of file it is: libspectrum_error libspectrum_identify_file_raw( libspectrum_id_t *type, const char *filename, const unsigned char *buffer, size_t length ) `filename' should be the name of the file to be identified, or NULL if it is unknown. `buffer' and `length' are the contents and length of the file respectively. The type of file will be returned in the `type' parameter, and can take the following values: LIBSPECTRUM_ID_UNKNOWN Couldn't identify this file LIBSPECTRUM_ID_CARTRIDGE_DCK A .dck Timex dock image LIBSPECTRUM_ID_CARTRIDGE_IF2 A .rom Interface II cartridge LIBSPECTRUM_ID_COMPRESSED_BZ2 A bzip2 compressed file LIBSPECTRUM_ID_COMPRESSED_GZ A gzip compressed file LIBSPECTRUM_ID_DISK_DSK A .dsk +3 disk file LIBSPECTRUM_ID_DISK_SCL A .scl TRDOS disk file LIBSPECTRUM_ID_DISK_TRD A .trd TRDOS disk file LIBSPECTRUM_ID_HARDDISK_HDF A .hdf IDE hard disk image LIBSPECTRUM_ID_MICRODRIVE_MDR A .mdf microdrive cartridge LIBSPECTRUM_ID_RECORDING_RZX A .rzx input recording LIBSPECTRUM_ID_SNAPSHOT_PLUSD A +D snapshot LIBSPECTRUM_ID_SNAPSHOT_SNA A .sna snapshot LIBSPECTRUM_ID_SNAPSHOT_SNP A .snp snapshot LIBSPECTRUM_ID_SNAPSHOT_SP A .sp snapshot LIBSPECTRUM_ID_SNAPSHOT_SZX A .szx snapshot (as used by Spectaculator) LIBSPECTRUM_ID_SNAPSHOT_Z80 A .z80 snapshot LIBSPECTRUM_ID_SNAPSHOT_ZXS A .zxs snapshot (as used by zx32) LIBSPECTRUM_ID_TAPE_CSW A .csw tape image LIBSPECTRUM_ID_TAPE_TAP A `normal' (Z80-style) .tap tape image LIBSPECTRUM_ID_TAPE_TZX A .tzx tape image LIBSPECTRUM_ID_TAPE_WARAJEVO A Warajevo-style .tap tape image LIBSPECTRUM_ID_TAPE_Z80EM A Z80Em tape image LIBSPECTRUM_ID_TAPE_SPC An SP-style .spc tape image LIBSPECTRUM_ID_TAPE_STA A Speculator-style .sta tape image LIBSPECTRUM_ID_TAPE_LTP A Nuclear ZX-style .ltp tape image `libspectrum_identify_file_raw' looks for defined signatures in the file as well as the extension of the filename and a couple of heuristics in its attempts to identify the file. It's not perfect (especially when given files with the wrong extension), but it should work in most cases. When dealing with compressed files, you are probably interested in the data after it has been decompressed rather the original file. This can be accomplished with the `libspectrum_identify_file' function: libspectrum_error libspectrum_identify_file( libspectrum_id_t *type, const char *filename, const unsigned char *buffer, size_t length ) The parameters are the same as for `libspectrum_identify_file_raw'. What in many cases may be more useful than the specific type of the file is whether the file is a snapshot, a tape image or whatever. This can be done with the `libspectrum_identify_class' function: libspectrum_error libspectrum_identify_class( libspectrum_class_t *class, libspectrum_id_t type ) which returns the type of file represented by the `type' parameter in `*class'. The available values are: LIBSPECTRUM_CLASS_UNKNOWN An unknown file type LIBSPECTRUM_CLASS_CARTRIDGE_TIMEX A Timex dock cartridge LIBSPECTRUM_CLASS_CARTRIDGE_IF2 An Interface II cartridge LIBSPECTRUM_CLASS_DISK_PLUS3 A +3 disk image LIBSPECTRUM_CLASS_DISK_TRDOS A TRDOS disk image LIBSPECTRUM_CLASS_HARDDISK An IDE hard disk image LIBSPECTRUM_CLASS_MICRODRIVE A microdrive cartridge LIBSPECTRUM_CLASS_RECORDING An input recording LIBSPECTRUM_CLASS_SNAPSHOT A snapshot LIBSPECTRUM_CLASS_TAPE A tape image One final routine, `libspectrum_identify_file_with_class', libspectrum_error libspectrum_identify_file_with_class( libspectrum_id_t *type, libspectrum_class_t *libspectrum_class, const char *filename, const unsigned char *buffer, size_t length ) simply combines the calls to `libspectrum_identify_file' and `libspectrum_identify_class', returning the file type in `*type' and the file class in `*class'. Machine timings --------------- The `libspectrum_machine_timings_*' functions give information about the speed and various timings constants used by the machines. Some of these timings are almost certainly wrong; if you have any corrections, please send them in. Each of the functions takes one of the LIBSPECTRUM_MACHINE_* constants listed above and returns a timing for that machine. libspectrum_dword libspectrum_timings_processor_speed( libspectrum_machine machine ) libspectrum_dword libspectrum_timings_ay_speed( libspectrum_machine machine ) The speed in Hz of the main processor and of the AY clock. libspectrum_word libspectrum_timings_left_border( libspectrum_machine machine ) libspectrum_word libspectrum_timings_horizontal_screen( libspectrum_machine machine ) libspectrum_word libspectrum_timings_right_border( libspectrum_machine machine ) libspectrum_word libspectrum_timings_horizontal_retrace( libspectrum_machine machine ) The length in tstates of the different parts of one scanline. libspectrum_word libspectrum_timings_tstates_per_line( libspectrum_machine machine ) The sum of the previous four numbers. libspectrum_word libspectrum_timings_top_border( libspectrum_machine machine ) libspectrum_word libspectrum_timings_vertical_screen( libspectrum_machine machine ) libspectrum_word libspectrum_timings_bottom_border( libspectrum_machine machine ) libspectrum_word libspectrum_timings_vertical_retrace( libspectrum_machine machine ) The number of scanlines in the different parts of the screen. libspectrum_word libspectrum_timings_lines_per_frame( libspectrum_machine machine ) The sum of the previous four numbers. libspectrum_dword libspectrum_timings_tstates_per_frame( libspectrum_machine machine ) tstates_per_line * lines_per_frame. libspectrum_word libspectrum_timings_top_left_pixel( libspectrum_machine machine ) How many tstates after interrupt is the top-left pixel of the screen displayed. libspectrum_word libspectrum_timings_interrupt_length( libspectrum_machine machine ) How about t-states the machine holds /INT low for on a maskable interrupt. Creator information ------------------- Some formats (.szx snapshots and .rzx input recordings) allow utilities to store some information regarding the creator of the file. libspectrum provides a `libspectrum_creator' structure to store this information. libspectrum_error libspectrum_creator_alloc( libspectrum_creator **creator ) Allocate a new `libspectrum_creator' structure. libspectrum_error libspectrum_creator_free( libspectrum_creator *creator ) Free the memory used by a `libspectrum_creator' structure. libspectrum_error libspectrum_creator_set_program( libspectrum_creator *creator, const char *program ) const libspectrum_byte* libspectrum_creator_program( libspectrum_creator *creator ) Set and retrieve the name of the program which created this file. libspectrum_error libspectrum_creator_set_major( libspectrum_creator *creator, libspectrum_word major ) libspectrum_word libspectrum_creator_major( libspectrum_creator *creator ) Set and retrieve the major version number of the program which created this file. libspectrum_error libspectrum_creator_set_minor( libspectrum_creator *creator, libspectrum_word minor ) libspectrum_word libspectrum_creator_minor( libspectrum_creator *creator ) Set and retrieve the minor version number of the program which created this file. libspectrum_error libspectrum_creator_set_competition_code( libspectrum_creator *creator, libspectrum_dword competition_code ) libspectrum_dword libspectrum_creator_competition_code( libspectrum_creator *creator ) Set and retrieve the `competition code' of the program which created this file. The competition code can be used for on-line tournaments to determine that a certain file was made after a specific code was released. If you don't understand the previous, you almost certainly don't need to worry about it! libspectrum_error libspectrum_creator_set_custom( libspectrum_creator *creator, libspectrum_byte *data, size_t length ) libspectrum_byte* libspectrum_creator_custom( libspectrum_creator *creator ) size_t libspectrum_creator_custom_length( libspectrum_creator *creator ) Set and retrieve the (arbitrary) custom data from the program which created this file. Snapshot functions ================== Functions for dealing with snapshot files. These act on an opaque `libspectrum_snap' structure, which can be accessed via the following routines: libspectrum_error libspectrum_snap_alloc( libspectrum_snap **snap ) Allocate a new libspectrum_snap structure. libspectrum_error libspectrum_snap_free( libspectrum_snap *snap ) Release a structure allocated with `libspectrum_snap_alloc'. There is a family of functions which can be used to retrieve and set the properties of a snapshot. The `retrieve' functions have the form libspectrum_snap_( libspectrum_snap *snap ) which retrieves the value of the property , while the `set' functions have the form void libspectrum_snap_set_( libspectrum_snap *snap, new_value ) which sets the value of to `new_value'. For array properties, the retrieval function has the form libspectrum_snap_( libspectrum_snap *snap, int idx ) which retrieves the [`idx'] and the set function has the form void libspectrum_snap_set_( libspectrum_snap *snap, int idx, new_value ) which sets [`idx']. The available properties (along with their types) are: * libspectrum_machine machine * libspectrum_byte a * libspectrum_byte f * libspectrum_word bc * libspectrum_word de * libspectrum_word hl * libspectrum_byte a_ * libspectrum_byte f_ * libspectrum_word bc_ * libspectrum_word de_ * libspectrum_word hl_ * libspectrum_word ix * libspectrum_word iy * libspectrum_byte i * libspectrum_byte r * libspectrum_word sp * libspectrum_word pc * libspectrum_byte iff1 * libspectrum_byte iff2 * libspectrum_byte im * libspectrum_dword tstates * int halted * int last_instruction_ei * libspectrum_byte out_ula * libspectrum_byte out_128_memoryport * libspectrum_byte out_plus3_memoryport * libspectrum_byte out_ay_registerport * libspectrum_byte ay_registers[16] * int beta_paged * int beta_direction * libspectrum_byte beta_system * libspectrum_byte beta_track * libspectrum_byte beta_sector * libspectrum_byte beta_data * libspectrum_byte beta_status * libspectrum_byte out_scld_hsr * libspectrum_byte out_scld_dec * libspectrum_byte* pages[8] * libspectrum_byte* slt[256] * size_t slt_length[256] * libspectrum_byte* slt_screen * int slt_screen_level * int zxatasp_active * int zxatasp_upload * int zxatasp_writeprotect * libspectrum_byte zxatasp_port_a * libspectrum_byte zxatasp_port_b * libspectrum_byte zxatasp_port_c * libspectrum_byte zxatasp_control * size_t zxatasp_pages * size_t zxatasp_current_page * libspectrum_byte* zxatasp_ram[32] * int zxcf_active * int zxcf_upload * libspectrum_byte zxcf_memctl * size_t zxcf_pages * libspectrum_byte* zxcf_ram[64] * int interface2_active * libspectrum_byte* interface2_rom[1] * size_t dock_active * libspectrum_byte exrom_ram[8] * libspectrum_byte* exrom_cart[8] * libspectrum_byte dock_ram[8] * libspectrum_byte* dock_cart[8] * size_t joystick_active_count * libspectrum_joystick joystick_list[ SNAPSHOT_JOYSTICKS ] * int joystick_inputs[ SNAPSHOT_JOYSTICKS ] Most of those should be fairly self-explanatory; those which may not be are: * `a_', `f_', `bc_', `de_' and `hl_' functions represent the A', F', BC', DE' and HL' registers. * For 48K snaps, 0x4000 to 0x7fff is stored in `pages[5]', 0x8000 to 0xbfff in `pages[2]' and 0xc000 to 0xffff in `pages[0]' (This is equivalent to the default mapping on the 128K machines). * `last_instruction_ei' being non-zero signals that the opcode previously executed was an EI and thus interrupts should not be accepted at this point, but will be after the next opcode. * `out_plus3_memoryport' should also be used to save the state of the Scorpion's secondary memory control port (0x1ffd). * The `beta_*' functions represent the Betadisk interface. `beta_paged' is non-zero if the Betadisk ROM is currently paged in between 0x0000 and 0x3fff and `beta_direction' is non-zero if the current seek direction is towards higher cylinders (rimwards). The other `beta_*' functions represent the current values of the Betadisk interface registers. * The `zxatasp_*' and `zxcf_*' functions give the state of the ZXATASP and ZXCF interfaces. `zxatasp_pages' and `zxcf_pages' give the number of 16K RAM pages attached to the interface. `zxatasp_current_page' gives the page which is currently paged in via the ZXATASP, or 255 if no page is currently selected. * `exrom_ram' and `dock_ram' are non-zero if the corresponding 8K page of the Timex EXROM or DOCK are writable. * `joystick_active_count' is the number of joysticks connected to the emulated Spectrum. `joystick_list' gives the type of the joysticks and `joystick_inputs' gives the corresponding connections to the real machines keyboard and joysticks. The available joystick types are defined by the libspectrum_joystick enum, which can take the following values: LIBSPECTRUM_JOYSTICK_NONE No joystick connected LIBSPECTRUM_JOYSTICK_CURSOR Cursor joystick LIBSPECTRUM_JOYSTICK_KEMPSTON Kempston joystick LIBSPECTRUM_JOYSTICK_SINCLAIR_1 Sinclair joystick 1 LIBSPECTRUM_JOYSTICK_SINCLAIR_2 Sinclair joystick 2 LIBSPECTRUM_JOYSTICK_TIMEX_1 Timex joystick 1 LIBSPECTRUM_JOYSTICK_TIMEX_2 Timex joystick 2 LIBSPECTRUM_JOYSTICK_FULLER Fuller joystick The joystick input values can be any of: LIBSPECTRUM_JOYSTICK_INPUT_NONE Not connected LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD Input from the real keyboard LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 Input from real joystick 1 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 Input from real joystick 2 With all those housekeeping routines out of the way, there are two main workhorses of the snapshot routines: libspectrum_error libspectrum_snap_read( libspectrum_snap *snap, const libspectrum_byte *buffer, size_t length, libspectrum_id_t type, const char *filename ) Take the snapshot of type `type' of `length' bytes starting at `buffer' and convert it to a `libspectrum_snap' structure. If `type' is `LIBSPECTRUM_ID_UNKNOWN', guess the file format via `libspectrum_identify_file'; `filename' is used only to help with the identification process and can be set to NULL (or anything else) if `type' is not `LIBSPECTRUM_ID_UNKNOWN'. Snapshots compressed with bzip2 or gzip will be automatically and transparently decompressed. libspectrum_error libspectrum_snap_write( libspectrum_byte **buffer, size_t *length, int *out_flags, libspectrum_snap *snap, libspectrum_id_t type, libspectrum_creator *creator, int in_flags ) Take the snapshot in `snap' and serialise it into `*buffer' as a snapshot of `type'. On entry, '*buffer' is assumed to be allocated '*length' bytes, and will grow if necessary; if '*length' is zero, '*buffer' can be uninitialised on entry. `in_flags' can be used specify minor changes to the snapshot; currently there are two options: LIBSPECTRUM_FLAG_SNAPSHOT_NO_COMPRESSION This flag specifies that the snapshot should not be compressed for formats where it would normally be (.z80 and .szx). LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS This flag specifies that all the snapshot components should be compressed for formats which would normally use some uncompressed components when the file size would end up smaller. This is useful for compatibility with programs that have problems with uncompressed .z80 files, but also works with .szx snapshots. `out_flags' will return the logical OR of some extra information from the serialisation: LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS A small amount of information was lost in serialisation. The resultant snapshot may not work correctly. LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS A large amount of information was lost in serialisation. It is highly likely that the resultant snapshot won't work. `creator' gives the information which will be written into the snapshot to specify the creator of the file. This can be NULL, in which case no information will be written. Currently, only the .szx format will make any use of this information. The only formats for which serialisation is supported are .sna, .szx and .z80. Deprecated snapshot routines ---------------------------- There are also three format-specific functions. However, *these functions are deprecated and should not be used in new code*: libspectrum_error libspectrum_sna_read( libspectrum_snap *snap, const libspectrum_byte *buffer, size_t buffer_length ) Take the .sna snapshot of length `buffer_length' bytes at `buffer' and convert it to a `libspectrum_snap' structure. libspectrum_error libspectrum_z80_read( libspectrum_snap *snap, const libspectrum_byte *buffer, size_t buffer_length ) Similarly for a .z80 snapshot. libspectrum_error libspectrum_z80_write( libspectrum_byte **buffer, size_t *length, libspectrum_snap *snap ) Take the snapshot in `snap' and serialise it into a .z80 file at '*buffer'. On entry, '*buffer' is assumed to be allocated '*length' bytes, and will grow if necessary; if '*length' is zero, '*buffer' can be uninitialised on entry. Tape functions ============== libspectrum uses the opaque `libspectrum_tape' structure to represent a tape image. Essentially, a `libspectrum_tape' is a list of tape blocks, which are of the `libspectrum_tape_block' type detailed below. The routines for dealing with tapes are: libspectrum_error libspectrum_tape_alloc( libspectrum_tape **tape ) Allocate a new libspectrum_tape object. libspectrum_error libspectrum_tape_free( libspectrum_tape *tape ) Free the memory used by a libspectrum_tape objects; libspectrum_error libspectrum_tape_clear( libspectrum_tape *tape ) Free the memory used by the blocks in a libspectrum_tape object, but not the object itself; useful if you're about to read a new tape into a current object. libspectrum_error libspectrum_tape_read( libspectrum_tape *tape, const libspectrum_byte *buffer, size_t length, libspectrum_id_t type, const char *filename ) Take the tape image of type `type' of `length' bytes starting at `buffer' and convert it to a `libspectrum_tape' structure. If `type' is `LIBSPECTRUM_ID_UNKNOWN', guess the file format via `libspectrum_identify_file'; `filename' is generally used only to help with the identification process and can be set to NULL (or anything else) if `type' is not `LIBSPECTRUM_ID_UNKNOWN' unless the tape is a WAV file where the underlying audiofile library will reread the file and will not use the buffer. Tape images compressed with bzip2 or gzip will be automatically and transparently decompressed. libspectrum_error libspectrum_tape_write( libspectrum_byte **buffer, size_t *length, libspectrum_tape *tape, libspectrum_id_t type ) Take the snapshot in `tape and serialise it as a `type' format file into `*buffer'. On entry, '*buffer' is assumed to be allocated '*length' bytes, and will grow if necessary; if '*length' is zero, '*buffer' can be uninitialised on entry. libspectrum_error libspectrum_tape_get_next_edge( libspectrum_dword *tstates, int *flags, libspectrum_tape *tape ) This is the main workhorse function of the tape routines and will return in `tstates' the number of tstates until the next edge should occur from `tape'. `flags' will be set to the bitwise or of the following: LIBSPECTRUM_TAPE_FLAGS_BLOCK The current block ends with this edge LIBSPECTRUM_TAPE_FLAGS_STOP User code should stop playing the tape after this edge LIBSPECTRUM_TAPE_FLAGS_STOP48 User code should stop playing the tape after this edge if it was emulating a 48K machine. The desired behaviour for things like the TC2048 is undefined in the .tzx format :-( LIBSPECTRUM_TAPE_FLAGS_LEVEL_LOW The input signal from the tape should be forced low at this edge LIBSPECTRUM_TAPE_FLAGS_LEVEL_HIGH The input signal from the tape should be forced high at this edge LIBSPECTRUM_TAPE_FLAGS_NO_EDGE This "edge" isn't really an edge and doesn't change the input signal from the tape. int libspectrum_tape_present( libspectrum_tape *tape ) Returns non-zero if `tape' currently contains a tape image and zero otherwise. libspectrum_error libspectrum_tape_position( int *n, libspectrum_tape *tape ) Return in `n' the position of the current block on the tape. The first block is block 0, the second block 1, etc. libspectrum_error libspectrum_tape_nth_block( libspectrum_tape *tape, int n ) Set the current block on the tape to be the `n'th block and initialise it. Again, the first block on the tape is block 0. libspectrum_error libspectrum_tape_append_block( libspectrum_tape *tape, libspectrum_tape_block *block ) Append `block' to `tape'. libspectrum_tape_block* libspectrum_tape_current_block( libspectrum_tape *tape ) Get the currently active block on the tape. libspectrum_tape_block* libspectrum_tape_peek_next_block( libspectrum_tape *tape ) Get the next block on the tape, but don't move the tape along or initialise the block. libspectrum_tape_block* libspectrum_tape_select_next_block( libspectrum_tape *tape ) Move the tape along so it points to the next block, initialise that block and return it. Deprecated tape routines ------------------------ *These functions are deprecated and should not be used in new code*: libspectrum_error libspectrum_tap_read( libspectrum_tape *tape, const libspectrum_byte *buffer, const size_t length ) Form a tape object in `tape' from the .tap file of `length' bytes starting at `buffer'. This routine deals with the `normal' (Z80-style) .tap files, not with Warajevo .tap files. libspectrum_error libspectrum_tap_write( libspectrum_byte **buffer, size_t *length, libspectrum_tape *tape ) Attempt to convert the tape in `tape' to a .tap file in `*buffer', which has previously been allocated `*length' bytes by user code. The .tap format can handle only standard speed loading blocks; a best guess attempt will be made to convert other blocks, but the resultant .tap file probably won't work. libspectrum_error libspectrum_tzx_read( libspectrum_tape *tape, const libspectrum_byte *buffer, const size_t length ) Just as `libspectrum_tap_read', but for .tzx format files. libspectrum_error libspectrum_tzx_write( libspectrum_byte **buffer, size_t *length, libspectrum_tape *tape ) Just as `libspectrum_tap_write', but for .tzx files. The conversion to .tzx format is not lossy as it is with converting to .tap. libspectrum_error libspectrum_warajevo_read( libspectrum_tape *tape, const libspectrum_byte *buffer, const size_t length ) Just as `libspectrum_tap_read', but for Warajevo-style .tap files. There is no currently no function to write a Warajevo-style .tap file. Tape iterators -------------- In some circumstances, a program may wish to look through all the blocks in a tape, but not actually change the state of the tape at all. This can be done with a `libspectrum_tape_iterator'. There are two routines for dealing with iterators: libspectrum_tape_block* libspectrum_tape_iterator_init( libspectrum_tape_iterator *iterator, libspectrum_tape *tape ) Initialise `iterator' to point to the first block of `tape' and return that block. Returns NULL if the tape has no blocks. libspectrum_tape_block* libspectrum_tape_iterator_next( libspectrum_tape_iterator *iterator ) Make the already initialised `iterator' point to the next block of `tape' and return that block (or NULL if there are no more blocks). Tape blocks ----------- The block format used by libspectrum is very similar to that used by the TZX format itself; see http://www.worldofspectrum.org/TZXformat.html The block types supported by libspectrum (along with their block ID in the TZX format) are the following: LIBSPECTRUM_TAPE_BLOCK_ROM 0x10 LIBSPECTRUM_TAPE_BLOCK_TURBO 0x11 LIBSPECTRUM_TAPE_BLOCK_PURE_TONE 0x12 LIBSPECTRUM_TAPE_BLOCK_PULSES 0x13 LIBSPECTRUM_TAPE_BLOCK_PURE_DATA 0x14 LIBSPECTRUM_TAPE_BLOCK_RAW_DATA 0x15 LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA 0x19 LIBSPECTRUM_TAPE_BLOCK_PAUSE 0x20 LIBSPECTRUM_TAPE_BLOCK_GROUP_START 0x21 LIBSPECTRUM_TAPE_BLOCK_GROUP_END 0x22 LIBSPECTRUM_TAPE_BLOCK_JUMP 0x23 LIBSPECTRUM_TAPE_BLOCK_LOOP_START 0x24 LIBSPECTRUM_TAPE_BLOCK_LOOP_END 0x25 LIBSPECTRUM_TAPE_BLOCK_SELECT 0x28 LIBSPECTRUM_TAPE_BLOCK_STOP48 0x2a LIBSPECTRUM_TAPE_BLOCK_COMMENT 0x30 LIBSPECTRUM_TAPE_BLOCK_MESSAGE 0x31 LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO 0x32 LIBSPECTRUM_TAPE_BLOCK_HARDWARE 0x33 LIBSPECTRUM_TAPE_BLOCK_CUSTOM 0x35 LIBSPECTRUM_TAPE_BLOCK_CONCAT 0x5a The following block is not defined in the TZX format LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE A run-length encoded list of pulses These values are defined in the `libspectrum_tape_type' enumeration. The `concatenation' block (0x5a) is recognised on input, but just skipped; hence it will never appear in a libspectrum_tape_block. The basic routines for dealing with tape blocks are: libspectrum_error libspectrum_tape_block_alloc( libspectrum_tape_block **block, libspectrum_tape_type type ) Allocate a new tape block of `type'. libspectrum_error libspectrum_tape_block_free( libspectrum_tape_block *block ) Free a tape block. libspectrum_tape_type libspectrum_tape_block_type( libspectrum_tape_block *block ) Return the type of `block'. libspectrum_error libspectrum_tape_block_set_type( libspectrum_tape_block *block, libspectrum_tape_type type ) Set the type of `block' to `type'. libspectrum_error libspectrum_tape_block_init( libspectrum_tape_block *block ) Initialise `block' such that it is ready for playback (with `libspectrum_tape_get_next_edge'). libspectrum_error libspectrum_tape_block_description( char *buffer, size_t length, libspectrum_tape_block *block ) Copy into `buffer' (which has been allocated at least `length' bytes by the user code) a text description of the type of `block'. Similar to the snapshot structure, there is a large family of routines for setting and retrieving the parameters of individual block types. For tape blocks, this becomes more complicated still as different block types possess different parameters. If a `set' function is called for a parameter which is not relevant to the current block type, an error will be printed and LIBSPECTRUM_ERROR_INVALID returned. For the `get' functions, an error will be printed and an undefined value returned. int libspectrum_tape_block_metadata( libspectrum_tape_block *block ) Returns 1 if the block consists solely of metadata (comments, etc.) or 0 if it contains real data. The `get' and `set' functions follow the same pattern as for the snapshot routines: the `get' functions are like libspectrum_tape_block_( libspectrum_tape_block *block ) or libspectrum_tape_block_( libspectrum_tape_block *block, size_t index ) for array values and the `set' functions like libspectrum_error libspectrum_tape_block_set_( libspectrum_tape_block *block, new_value ) or libspectrum_error libspectrum_tape_block_set_( libspectrum_tape_block *block, size_t index, new_value ) The parameters, their types, and the LIBSPECTRUM_TAPE_BLOCK_* types for which it is relevant are: libspectrum_dword bit_length RAW_DATA libspectrum_dword bit0_length PURE_DATA TURBO libspectrum_dword bit1_length PURE_DATA TURBO size_t bits_in_last_byte PURE_DATA RAW_DATA TURBO size_t count PURE_TONE PULSES LOOP_START SELECT ARCHIVE_INFO HARDWARE libspectrum_byte* data CUSTOM PURE_DATA RAW_DATA ROW TURBO size_t data_length CUSTOM PURE_DATA RAW_DATA ROM TURBO libspectrum_tape_generalised_data_symbol_table data_table GENERALISED_DATA int ids[] ARCHIVE_INFO HARDWARE int offset JUMP int offsets[] SELECT libspectrum_dword pause MESSAGE PAUSE PURE_DATA RAW_DATA ROM TURBO libspectrum_dword pilot_length TURBO size_t pilot_pulses TURBO libspectrum_word pilot_repeats GENERALISED_DATA libspectrum_word pilot_symbols GENERALISED_DATA libspectrum_tape_generalised_data_symbol_table pilot_table GENERALISED_DATA libspectrum_dword pulse_length LENGTH libspectrum_dword pulse_lengths[] PULSES libspectrum_dword sync1_length TURBO libspectrum_dword sync2_length TURBO char* text GROUP_START COMMENT MESSAGE CUSTOM char* texts[] ARCHIVE_INFO SELECT int types[] HARDWARE int values[] HARDWARE There is one further parameter which can be accessed for PURE_DATA, RAW_DATA, ROM and TURBO blocks, which is `libspectrum_tape_state_type state'. This determines the part of the block which is currently being played, and can have the following values: LIBSPECTRUM_TAPE_STATE_INVALID /* Should never be seen */ LIBSPECTRUM_TAPE_STATE_PILOT /* Pilot pulses */ LIBSPECTRUM_TAPE_STATE_SYNC1 /* First sync pulse */ LIBSPECTRUM_TAPE_STATE_SYNC2 /* Second sync pulse */ LIBSPECTRUM_TAPE_STATE_DATA1 /* First edge of a data bit */ LIBSPECTRUM_TAPE_STATE_DATA2 /* Second edge of a data bit */ LIBSPECTRUM_TAPE_STATE_PAUSE /* The pause at the end of a block */ Setting this value to anything other than `LIBSPECTRUM_TAPE_STATE_PAUSE' will produce undefined results. Exposing this parameter is an ugly hack needed by Fuse to allow for flash-loading of tape blocks, and setting it should not be used unless absolutely necessary. The libspectrum_tape_generalised_data_symbol_table is an opaque data structure which represents the "symbol table" used in the TZX generalised data block (ID 0x19). It can be accessed with the following routines: libspectrum_dword libspectrum_tape_generalised_data_symbol_table_symbols_in_block( const libspectrum_tape_generalised_data_symbol_table *table ) libspectrum_byte libspectrum_tape_generalised_data_symbol_table_max_pulses( const libspectrum_tape_generalised_data_symbol_table *table ) libspectrum_word libspectrum_tape_generalised_data_symbol_table_symbols_in_table (const libspectrum_tape_generalised_data_symbol_table *table ) libspectrum_tape_generalised_data_symbol* libspectrum_tape_generalised_data_symbol_table_symbol( const libspectrum_tape_generalised_data_symbol_table *table, size_t which ) The libspectrum_tape_generalised_data_symbol represents one of the symbols used in the generalised data block and can be accessed with the following routines: libspectrum_tape_generalised_data_symbol_edge_type libspectrum_tape_generalised_data_symbol_type( const libspectrum_tape_generalised_data_symbol *symbol ) libspectrum_word libspectrum_tape_generalised_data_symbol_pulse( const libspectrum_tape_generalised_data_symbol *symbol, size_t which ) The following edge types are available: LIBSPECTRUM_TAPE_GENERALISED_DATA_SYMBOL_EDGE Invert signal polarity LIBSPECTRUM_TAPE_GENERALISED_DATA_SYMBOL_NO_EDGE No polarity change LIBSPECTRUM_TAPE_GENERALISED_DATA_SYMBOL_LOW Set signal low LIBSPECTRUM_TAPE_GENERALISED_DATA_SYMBOL_HIGH Set signal high Input recording functions ========================= All input recording routines are accessed through the opaque `libspectrum_rzx' structure. libspectrum_error libspectrum_rzx_alloc( libspectrum_rzx **rzx ) Allocate a new input recording object. libspectrum_error libspectrum_rzx_free( libspectrum_rzx *rzx ) Free the memory used by an input recording object as allocated by `libspectrum_rzx_alloc'. libspectrum_error libspectrum_rzx_start_input( libspectrum_rzx *rzx, libspectrum_dword tstates ) Start an input recording block int the object. libspectrum_error libspectrum_rzx_stop_input( libspectrum_rzx *rzx ) Stop the current input recording block. libspectrum_error libspectrum_rzx_add_snap( libspectrum_rzx *rzx, libspectrum_snap *snap ) Add `snap' to the input recording at this point. libspectrum_error libspectrum_rzx_rollback( libspectrum_rzx *rzx, libspectrum_snap **snap ) Return the input recording to the state it was at which the last snapshot was inserted. That state is set up in `snap'. libspectrum_error libspectrum_rzx_rollback_to( libspectrum_rzx *rzx, libspectrum_snap **snap, size_t which ) Return the input recording to the state it was at which the th snapshot was inserted, where n is specified by `which'. That state is set up in `snap'. libspectrum_error libspectrum_rzx_store_frame( libspectrum_rzx *rzx, size_t instructions, size_t count, libspectrum_byte *in_bytes ) Add a frame to `rzx' in which `instructions' opcodes where fetched, and `count' bytes, specified in `in_bytes', were read from the IO ports. libspectrum_error libspectrum_rzx_start_playback( libspectrum_rzx *rzx ) Prepare to start playback of the input recording `rzx'. libspectrum_error libspectrum_rzx_playback_frame( libspectrum_rzx *rzx, int *finished, libspectrum_snap **snap ) Move onto the next frame of playback from the input recording `rzx'. If the last frame has now been played, `*finished' will be non-zero, otherwise it will be zero. If a snap is present in the input recording before the next frame, this will be returned in `*snap', otherwise `*snap' will be NULL. If the correct number of bytes were not read from `rzx' during the frame via `libspectrum_rzx_playback', an error will be given. libspectrum_error libspectrum_rzx_playback( libspectrum_rzx *rzx, libspectrum_byte *byte ) Return in `*byte' the next byte to be read from the IO ports from the current frame of `rzx'. size_t libspectrum_rzx_tstates( libspectrum_rzx *rzx ) Return the 'starting tstates' field of `rzx'. size_t libspectrum_rzx_set_tstates( libspectrum_rzx *rzx, size_t tstates ) Set (and return the new value of) the 'starting tstates' field of `rzx'. size_t libspectrum_rzx_instructions( libspectrum_rzx *rzx ) Return the number of opcode fetches to be performed during the current frame of `rzx'. libspectrum_error libspectrum_rzx_read( libspectrum_rzx *rzx, libspectrum_snap **snap, const libspectrum_byte *buffer, const size_t length, libspectrum_rzx_signature *signature ) Given a .rzx file of `length' bytes starting at `buffer', extract the input recording data into `rzx' and the embedded snapshot into `*snap'. If there is no embedded snapshot, `*snap' will be NULL after the call. If the RZX file contains a digital signature, `*signature' will contain the information from that signature; see below for information on this. Files compressed with bzip2 or gzip will be automatically and transparently decompressed. libspectrum_error libspectrum_rzx_write2( libspectrum_byte **buffer, size_t *length, libspectrum_rzx *rzx, libspectrum_byte *snap, libspectrum_id_t snap_format, libspectrum_creator *creator, int compress, libspectrum_rzx_dsa_key *key ) Given input recording data in `rzx' and a snapshot in `snap', create a .rzx file in `*buffer'. If no embedded snapshot is required, set `snap' to be NULL. Before the call, `*buffer' should be allocated at least `*length' bytes (can be zero). After the call, `*length' contains the length of the .rzx file. `snap format' specifies the format for the embedded snap. This can be any of the formats supported by `libspectrum_snap_write' or LIBSPECTRUM_ID_UNKNOWN, in which case the snap will be embedded as a .z80 file, _unless_ that would result in major information loss, in which case a .szx file will be embedded instead. `creator' contains the creator information which should be written into the RZX file. If `key' is non-NULL, the RZX file will be digitally signed using the specified DSA key; see below for more details. void libspectrum_rzx_insert_snap( libspectrum_rzx *rzx, libspectrum_snap *snap, int where ) Insert `snap' into the RZX recording in position `where'. A `where' value of zero is the first block in the file, before any current content. void libspectrum_rzx_iterator_delete( libspectrum_rzx *rzx, libspectrum_rzx_iterator *it ) Delete the block pointed to by `it' from the RZX file `rzx'. libspectrum_snap* libspectrum_rzx_iterator_get_snap( libspectrum_rzx_iterator it ) Get the snapshot pointed to by `it'. If `it' does not point to a snapshot, NULL is returned. Input recording iterators ------------------------- As with tapes, iterators are available to allow an application to examine the structure of an input recording file. Such an iterator is initialised via libspectrum_rzx_iterator libspectrum_rzx_iterator_begin( libspectrum_rzx *rzx ) and moved to the next block via libspectrum_rzx_iterator libspectrum_rzx_iterator_next( libspectrum_rzx_iterator it ) The type of block pointed to by the iterator can be obtained via the libspectrum_rzx_block_id libspectrum_rzx_iterator_get_type( libspectrum_rzx_iterator it ) function. The return value will be one of: LIBSPECTRUM_RZX_CREATOR_BLOCK Creator information LIBSPECTRUM_RZX_SIGN_START_BLOCK Start of signed information LIBSPECTRUM_RZX_SIGN_END_BLOCK End of signed information LIBSPECTRUM_RZX_SNAPSHOT_BLOCK Snapshot LIBSPECTRUM_RZX_INPUT_BLOCK Input recording block If the iterator is pointing to a block of type LIBSPECTRUM_RZX_INPUT_BLOCK, then the function size_t libspectrum_rzx_iterator_get_frames( libspectrum_rzx_iterator it ) can be used to obtain the number of frames stored in the block. Digital signatures in RZX files ------------------------------- One use of input recording files is to allow a `best Spectrum games player' tournament to be held: everybody records themselves playing a game, sends in input recordings of themselves doing this, and then everyone can see who is the best player. When using an emulator, it is obviously rather easy to cheat at this by using snapshots, slowing down the emulator and all sorts of other ways. Fundamentally, there's no way round this problem except by running the emulator on trusted hardware, which is a whole different kettle of fish. One such `best player' tournament, the Speccy Tour 2003 (see http://www.speccy.org/SpeccyTour03/ ) required that for an emulator to be `allowable' for the Tour, it must implement a `competition mode' in which snapshot saving etc is forbidden and must then `prove' that the RZX file was made in competition mode by digitally signing the RZX file. This is clearly still insecure as the key must be present in the emulator to allow it to sign files, but that's what the organisers wanted, so it's implemented in libspectrum. What information you wish to draw from the presence or absence of a digital signature on an RZX file is entirely up to you. The digital signature routines use libgcrypt to provide the necessary support. If this is not present when libspectrum is compiled, the signature routines will not available. If you're not aware of the DSA algorithm, the rest of this section probably won't make much sense to you; go and read a good cryptography textbook :-) To sign an RZX file, all that is required is a DSA key. libspectrum uses a `libspectrum_rzx_dsa_key' structure to represent this: typedef struct libspectrum_rzx_dsa_key { const char *p, *q, *g, *y, *x; } libspectrum_rzx_dsa_key; Each of the fields is one of the standard DSA parameters, stored as a hex string with the MSB first. `x' should be set to NULL for a public key. When a digitally signed RZX file is read, the signature information will be read into a `libspectrum_rzx_signature' structure: typedef struct libspectrum_rzx_signature { libspectrum_dword key_id; const libspectrum_byte *start; ptrdiff_t length; GcryMPI r, s; } libspectrum_rzx_signature; `key_id' is the low 32-bits of the `y' parameter of the key used to sign this file; you'll have to implement your own lookup table to find the rest of the key. `start' points to the signed data, which is `length' bytes long. `r' and `s' are the standard DSA signature parameters, stored in libgcrypt's native MPI format. (If libgcrypt is not available, these parameters are simply not present in the structure). To verify a signature, simply call `libspectrum_verify_signature': libspectrum_error libspectrum_verify_signature( libspectrum_rzx_signature *signature, libspectrum_rzx_dsa_key *key ) This will return LIBSPECTRUM_ERROR_NONE if the signature is valid or LIBSPECTRUM_ERROR_SIGNATURE if it is invalid. Once you're done with a signature, `libspectrum_signature_free' will release the memory it was using: libspectrum_error libspectrum_signature_free( libspectrum_rzx_signature *signature ) Note this will not free the data pointed to by `start'. Deprecated RZX function ----------------------- libspectrum_error libspectrum_rzx_write( libspectrum_byte **buffer, size_t *length, libspectrum_rzx *rzx, libspectrum_byte *snap, libspectrum_creator *creator, int compress, libspectrum_rzx_dsa_key *key ) Exactly equivalent to libspectrum_rzx_write2( buffer, length, rzx, snap, LIBSPECTRUM_ID_SNAPSHOT_Z80, creator, compress, key ). Microdrive handling functions ============================= Constants --------- These are all #defines. LIBSPECTRUM_MICRODRIVE_BLOCK_MAX The maximum number of blocks which can be on a microdrive (254). LIBSPECTRUM_MICRODRIVE_HEAD_LEN The length in bytes of the header for a microdrive block in bytes (15). LIBSPECTRUM_MICRODRIVE_DATA_LEN The length in bytes of the data for a microdrive block (512). LIBSPECTRUM_MICRODRIVE_BLOCK_LEN The total length in bytes of a microdrive block (2 * LIBSPECTRUM_MICRODRIVE_HEAD_LEN + LIBSPECTRUM_MICRODRIVE_DATA_LEN + 1 = 543). LIBSPECTRUM_MICRODRIVE_CARTRIDGE_LENGTH The maximum length in bytes of a microdrive cartridge (LIBSPECTRUM_MICRODRIVE_BLOCK_MAX * LIBSPECTRUM_MICRODRIVE_BLOCK_LEN = 137922). Routines -------- Routines for handling images of microdrive cartridges. As usual, these are accessed through an opaque structure, libspectrum_microdrive. libspectrum_error libspectrum_microdrive_alloc( libspectrum_microdrive **microdrive ) Allocate a microdrive structure. libspectrum_error libspectrum_microdrive_free( libspectrum_microdrive *microdrive ) Free a microdrive structure. libspectrum_byte libspectrum_microdrive_data( const libspectrum_microdrive *microdrive, size_t which ) void libspectrum_microdrive_set_data( libspectrum_microdrive *microdrive, size_t which, libspectrum_byte data ) Return or set (respectively) the byte of data at offset `which' into the cartridge. libspectrum_byte libspectrum_microdrive_write_protect( const libspectrum_microdrive *microdrive ) void libspectrum_microdrive_set_write_protect( libspectrum_microdrive *microdrive, int write_protect ) Return or set the state of the write protect tab of the microdrive. libspectrum_byte libspectrum_microdrive_cartridge_len( const libspectrum_microdrive *microdrive ) void libspectrum_microdrive_set_cartridge_len( libspectrum_microdrive *microdrive, libspectrum_byte len ) Return or set the length in bytes of the cartridge in the drive. int libspectrum_microdrive_checksum( libspectrum_microdrive *microdrive, libspectrum_byte which ) Check whether the checksum for the th block on the microdrive is correct, where is specified by `which'. .mdr file handling ------------------ libspectrum_error libspectrum_microdrive_mdr_read( libspectrum_microdrive *microdrive, libspectrum_byte *buffer, size_t length ) libspectrum_error libspectrum_microdrive_mdr_write( const libspectrum_microdrive *microdrive, libspectrum_byte **buffer, size_t *length ) Read and write an image of a microdrive cartridge to a .mdr file. Timex dock/exrom handling functions =================================== The Timex TS2068 and TC2068 featured a cartridge port (the `dock') for which a few pieces of software were made available. The Warajevo emulator includes support for this feature, and uses the `.dck' extension for images of these cartridges. Documentation on this format is available at http://www.worldofspectrum.org/warajevo/Fformats.html#dck Each .dck file can hold multiple 64Kb RAM banks, which are stored in a `libspectrum_dck' structure: typedef struct libspectrum_dck { libspectrum_dck_block *dck[256]; } libspectrum_dck; Each 64Kb bank is stored in a `libspectrum_dck_block' structure: typedef struct libspectrum_dck_block { libspectrum_dck_bank bank; libspectrum_dck_page_type access[8]; libspectrum_byte *pages[8]; } libspectrum_dck_block; The `bank' field specifies which type of memory this bank represents, and takes one of the following values: LIBSPECTRUM_DCK_BANK_DOCK The dock LIBSPECTRUM_DCK_BANK_EXROM The EXROM LIBSPECTRUM_DCK_BANK_HOME The normal memory space The `access' field gives the type of memory stored in each 8Kb page within the 64 Kb bank, and take be: LIBSPECTRUM_DCK_PAGE_NULL Not present in this bank LIBSPECTRUM_DCK_PAGE_RAM_EMPTY Uninitialised RAM LIBSPECTRUM_DCK_PAGE_ROM ROM LIBSPECTRUM_DCK_PAGE_RAM Initialised RAM Any ROM or initialised RAM banks are in the `pages' field. The actual routines for handling dock files: libspectrum_error libspectrum_dck_alloc( libspectrum_dck **dck ) Allocate a dock structure. libspectrum_error libspectrum_dck_free( libspectrum_dck *dck, int keep_pages ) Free a dock structure; if `keep_pages' is non-zero, any memory allocated to the structure will not be freed and can then be used by the calling program. Do remember to free it when you're finished with it! libspectrum_error libspectrum_dck_read( libspectrum_dck *dck, const libspectrum_byte *buffer, size_t length ) Read in a dock structure from the `length' byte long `buffer'. Images compressed with bzip2 or gzip will be automatically and transparently decompressed. IDE hard disk images ==================== Libspectrum contains various routines for handling IDE hard disk images. Due to the (potential) large size of these files, hard disk images are not handled entirely in memory as are the other file types, but require a real file. libspectrum_error libspectrum_ide_alloc( libspectrum_ide_channel **chn, libspectrum_ide_database databus ) Allocate a new IDE channel in `*chn' of type `databus'. `databus' can take the following values: LIBSPECTRUM_IDE_DATA8 A simple 8-bit interface which accesses only the low byte of each word on the hard disk. LIBSPECTRUM_IDE_DATA16 A full 16-bit interface which can access all data on the hard disk. LIBSPECTRUM_IDE_DATA16_BYTESWAP A full 16-bit interface which accesses the data in byte-swapped order. LIBSPECTRUM_IDE_DATA16_DATA2 A full 16-bit interface which returns the high byte of each word in the secondary data register. libspectrum_error libspectrum_ide_free( libspectrum_ide_channel *chn ) Deallocate the IDE channel in `chn'. libspectrum_error libspectrum_ide_insert( libspectrum_ide_channel *chn, libspectrum_ide_unit unit, const char *filename ) Cause the IDE hard disk image in `filename' to be attached to `unit' of the IDE channel `chn'. `unit' can take the following values: LIBSPECTRUM_IDE_MASTER The IDE master unit LIBSPECTRUM_IDE_SLAVE The IDE slave unit libspectrum_error libspectrum_ide_commit( libspectrum_ide_channel *chn, libspectrum_ide_unit unit ) Cause any changes made to the image attached to `unit' of `chn' to be written back to the image. libspectrum_error libspectrum_ide_eject( libspectrum_ide_channel *chn, libspectrum_ide_unit unit ) Cause the image attached to `unit' of `chn' to be detached. Note that any changes made to the image will be lost unless `libspectrum_ide_commit' is called first. libspectrum_error libspectrum_ide_reset( libspectrum_ide_channel *chn ) Reset the IDE channel `chn'. libspectrum_byte libspectrum_ide_read( libspectrum_ide_channel *chn, libspectrum_ide_register reg ) Returns the current value of register `reg' of the IDE channel `chn'. `reg' can take the following values: LIBSPECTRUM_IDE_REGISTER_DATA LIBSPECTRUM_IDE_REGISTER_ERROR_FEATURE LIBSPECTRUM_IDE_REGISTER_SECTOR_COUNT LIBSPECTRUM_IDE_REGISTER_SECTOR LIBSPECTRUM_IDE_REGISTER_CYLINDER_LOW LIBSPECTRUM_IDE_REGISTER_CYLINDER_HIGH LIBSPECTRUM_IDE_REGISTER_HEAD_DRIVE LIBSPECTRUM_IDE_REGISTER_COMMAND_STATUS LIBSPECTRUM_IDE_REGISTER_DATA2 The correspondence between these names and the actual IDE registers is hopefully obvious; LIBSPECTRUM_IDE_REGISTER_DATA2 refers to the secondary data register. void libspectrum_ide_write( libspectrum_ide_channel *chn, libspectrum_ide_register reg, libspectrum_byte data ) Write `data' to register `reg' of the IDE channel `chn'. $Id: libspectrum.txt 3426 2007-12-18 19:29:30Z zubzero $