src/mess/machine/thomson.c
| r3248 | r3249 | |
| 21 | 21 | #include "devices/printer.h" |
| 22 | 22 | #include "includes/serial.h" |
| 23 | 23 | #include "devices/cassette.h" |
| 24 | | #include "formats/thom_cas.h" |
| 25 | 24 | #include "devices/thomflop.h" |
| 26 | 25 | #include "formats/thom_dsk.h" |
| 27 | 26 | |
| r3248 | r3249 | |
| 36 | 35 | #define PRINT(x) mame_printf_info x |
| 37 | 36 | |
| 38 | 37 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) |
| 38 | #define VLOG(x) do { if (VERBOSE > 1) logerror x; } while (0) |
| 39 | 39 | #define LOG_IRQ(x) do { if (VERBOSE_IRQ) logerror x; } while (0) |
| 40 | 40 | #define LOG_KBD(x) do { if (VERBOSE_KBD) logerror x; } while (0) |
| 41 | 41 | #define LOG_BANK(x) do { if (VERBOSE_BANK) logerror x; } while (0) |
| r3248 | r3249 | |
| 43 | 43 | #define LOG_IO(x) do { if (VERBOSE_IO) logerror x; } while (0) |
| 44 | 44 | #define LOG_MIDI(x) do { if (VERBOSE_MIDI) logerror x; } while (0) |
| 45 | 45 | |
| 46 | /* This set to 1 handle the .k7 files without passing through .wav */ |
| 47 | /* It must be set accordingly in formats/thom_cas.c */ |
| 48 | #define K7_SPEED_HACK 0 |
| 49 | |
| 50 | /********************* common cassette code ***************************/ |
| 51 | |
| 52 | INLINE const device_config* thom_cassette_img( running_machine *machine ) |
| 53 | { return device_list_find_by_tag( machine->config->devicelist, CASSETTE, "cassette" ); } |
| 54 | |
| 55 | /*-------------- TO7 ------------*/ |
| 56 | |
| 57 | |
| 58 | /* On the TO7 & compatible (TO7/70,TO8,TO9, but not MO5,MO6), bits are coded |
| 59 | in FM format with a 1.1 ms period (900 bauds): |
| 60 | - 0 is 5 periods at 4.5 KHz |
| 61 | - 1 is 7 periods at 6.3 KHz |
| 62 | |
| 63 | Moreover, a byte is represented using 11 bits: |
| 64 | - one 0 start bit |
| 65 | - eight data bits (low bit first) |
| 66 | - two 1 stop bits |
| 67 | |
| 68 | There are also long (1 s) sequences of 1 bits to re-synchronize the |
| 69 | cassette at places the motor can be cut off and back on (e.g., between |
| 70 | files). |
| 71 | |
| 72 | The computer outputs a modulated wave that is directly put on the cassette. |
| 73 | However, the input is demodulated by the cassette-reader before being |
| 74 | sent to the computer: we got 0 when the signal is around 4.5 KHz and |
| 75 | 1 when the signal is around 6.3 KHz. |
| 76 | */ |
| 77 | |
| 78 | #define TO7_BIT_LENGTH 0.001114 |
| 79 | |
| 80 | /* buffer storing demodulated bits, only for k7 and with speed hack */ |
| 81 | static UINT32 to7_k7_bitsize; |
| 82 | static UINT8* to7_k7_bits; |
| 83 | |
| 84 | |
| 85 | /* 1-bit cassette input to the computer |
| 86 | inside the controller, two frequency filters (adjusted to 6.3 and 4.5 KHz) |
| 87 | and a comparator demodulate the raw signal into 0s and 1s. |
| 88 | */ |
| 89 | static int to7_get_cassette ( running_machine *machine ) |
| 90 | { |
| 91 | const device_config* img = thom_cassette_img(machine); |
| 92 | |
| 93 | if ( image_exists( img ) ) |
| 94 | { |
| 95 | cassette_image* cass = cassette_get_image( img ); |
| 96 | cassette_state state = cassette_get_state( img ); |
| 97 | double pos = cassette_get_position( img ); |
| 98 | int bitpos = pos / TO7_BIT_LENGTH; |
| 99 | |
| 100 | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED ) |
| 101 | return 1; |
| 102 | |
| 103 | if ( K7_SPEED_HACK && to7_k7_bits ) |
| 104 | { |
| 105 | /* hack, feed existing bits */ |
| 106 | if ( bitpos >= to7_k7_bitsize ) |
| 107 | bitpos = to7_k7_bitsize -1; |
| 108 | VLOG (( "$%04x %f to7_get_cassette: state=$%X pos=%f samppos=%i bit=%i\n", |
| 109 | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), state, pos, bitpos, |
| 110 | to7_k7_bits[ bitpos ] )); |
| 111 | return to7_k7_bits[ bitpos ]; |
| 112 | } |
| 113 | else |
| 114 | { |
| 115 | /* demodulate wave signal on-the-fly */ |
| 116 | /* we simply count sign changes... */ |
| 117 | int k, chg; |
| 118 | INT8 data[40]; |
| 119 | cassette_get_samples( cass, 0, pos, TO7_BIT_LENGTH * 15. / 14., 40, 1, data, 0 ); |
| 120 | |
| 121 | for ( k = 1, chg = 0; k < 40; k++ ) |
| 122 | { |
| 123 | if ( data[ k - 1 ] >= 0 && data[ k ] < 0 ) |
| 124 | chg++; |
| 125 | if ( data[ k - 1 ] <= 0 && data[ k ] > 0 ) |
| 126 | chg++; |
| 127 | } |
| 128 | k = ( chg >= 13 ) ? 1 : 0; |
| 129 | VLOG (( "$%04x %f to7_get_cassette: state=$%X pos=%f samppos=%i bit=%i (%i)\n", |
| 130 | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), state, pos, bitpos, |
| 131 | k, chg )); |
| 132 | return k; |
| 133 | } |
| 134 | |
| 135 | } |
| 136 | else |
| 137 | return 0; |
| 138 | } |
| 139 | |
| 140 | |
| 141 | |
| 142 | /* 1-bit cassette output */ |
| 143 | static void to7_set_cassette ( running_machine *machine, int data ) |
| 144 | { |
| 145 | const device_config* img = thom_cassette_img(machine); |
| 146 | cassette_output( img, data ? 1. : -1. ); |
| 147 | } |
| 148 | |
| 149 | |
| 150 | |
| 151 | static WRITE8_HANDLER ( to7_set_cassette_motor ) |
| 152 | { |
| 153 | const device_config* img = thom_cassette_img(machine); |
| 154 | cassette_state state = cassette_get_state( img ); |
| 155 | double pos = cassette_get_position(img); |
| 156 | |
| 157 | LOG (( "$%04x %f to7_set_cassette_motor: cassette motor %s bitpos=%i\n", |
| 158 | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), data ? "off" : "on", |
| 159 | (int) (pos / TO7_BIT_LENGTH) )); |
| 160 | |
| 161 | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED && !data && pos > 0.3 ) |
| 162 | { |
| 163 | /* rewind a little before starting the motor */ |
| 164 | cassette_seek( img, -0.3, SEEK_CUR ); |
| 165 | } |
| 166 | |
| 167 | cassette_change_state( img, data ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR ); |
| 168 | } |
| 169 | |
| 170 | |
| 171 | |
| 172 | /*-------------- MO5 ------------*/ |
| 173 | |
| 174 | |
| 175 | /* Each byte is represented as 8 bits without start or stop bit (unlike TO7). |
| 176 | Bits are coded in MFM, and the MFM signal is directly fed to the |
| 177 | computer which has to decode it in software (unlike TO7). |
| 178 | A 1 bit is one period at 1200 Hz; a 0 bit is one half-period at 600 Hz. |
| 179 | Bit-order is most significant bit first (unlike TO7). |
| 180 | |
| 181 | Double-density MO6 cassettes follow the exact same mechanism, but with |
| 182 | at double frequency (perdiods at 2400 Hz, and half-perdios at 1200 Hz). |
| 183 | */ |
| 184 | |
| 185 | |
| 186 | #define MO5_BIT_LENGTH 0.000833 |
| 187 | #define MO5_HBIT_LENGTH (MO5_BIT_LENGTH / 2.) |
| 188 | |
| 189 | |
| 190 | static int mo5_get_cassette ( running_machine *machine ) |
| 191 | { |
| 192 | const device_config* img = thom_cassette_img(machine); |
| 193 | |
| 194 | if ( image_exists( img ) ) |
| 195 | { |
| 196 | cassette_image* cass = cassette_get_image( img ); |
| 197 | cassette_state state = cassette_get_state( img ); |
| 198 | double pos = cassette_get_position( img ); |
| 199 | INT32 hbit; |
| 200 | |
| 201 | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED ) |
| 202 | return 1; |
| 203 | |
| 204 | cassette_get_sample( cass, 0, pos, 0, &hbit ); |
| 205 | hbit = hbit >= 0; |
| 206 | |
| 207 | VLOG (( "$%04x %f mo5_get_cassette: state=$%X pos=%f hbitpos=%i hbit=%i\n", |
| 208 | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), state, pos, |
| 209 | (int) (pos / MO5_HBIT_LENGTH), hbit )); |
| 210 | return hbit; |
| 211 | } |
| 212 | else |
| 213 | return 0; |
| 214 | } |
| 215 | |
| 216 | |
| 217 | |
| 218 | static void mo5_set_cassette ( running_machine *machine, int data ) |
| 219 | { |
| 220 | const device_config* img = thom_cassette_img(machine); |
| 221 | cassette_output( img, data ? 1. : -1. ); |
| 222 | } |
| 223 | |
| 224 | |
| 225 | |
| 226 | static WRITE8_HANDLER ( mo5_set_cassette_motor ) |
| 227 | { |
| 228 | const device_config* img = thom_cassette_img(machine); |
| 229 | cassette_state state = cassette_get_state( img ); |
| 230 | double pos = cassette_get_position(img); |
| 231 | |
| 232 | LOG (( "$%04x %f mo5_set_cassette_motor: cassette motor %s hbitpos=%i\n", |
| 233 | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), data ? "off" : "on", |
| 234 | (int) (pos / MO5_HBIT_LENGTH) )); |
| 235 | |
| 236 | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED && !data && pos > 0.3 ) |
| 237 | { |
| 238 | /* rewind a little before starting the motor */ |
| 239 | cassette_seek( img, -0.3, SEEK_CUR ); |
| 240 | } |
| 241 | |
| 242 | cassette_change_state( img, data ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR ); |
| 243 | } |
| 244 | |
| 245 | |
| 246 | |
| 247 | |
| 46 | 248 | /*************************** utilities ********************************/ |
| 47 | 249 | |
| 48 | 250 | |
| r3248 | r3249 | |
| 380 | 582 | static READ8_HANDLER ( to7_timer_port_in ) |
| 381 | 583 | { |
| 382 | 584 | int lightpen = (input_port_read(machine, "lightpen_button") & 1) ? 2 : 0; |
| 383 | | int cass = to7_get_cassette() ? 0x80 : 0; |
| 585 | int cass = to7_get_cassette(machine) ? 0x80 : 0; |
| 384 | 586 | return lightpen | cass; |
| 385 | 587 | } |
| 386 | 588 | |
| r3248 | r3249 | |
| 389 | 591 | static WRITE8_HANDLER ( to7_timer_tco_out ) |
| 390 | 592 | { |
| 391 | 593 | /* 1-bit cassette output */ |
| 392 | | to7_set_cassette( data ); |
| 594 | to7_set_cassette( machine, data ); |
| 393 | 595 | } |
| 394 | 596 | |
| 395 | 597 | |
| r3248 | r3249 | |
| 1642 | 1844 | |
| 1643 | 1845 | static WRITE8_HANDLER ( mo5_sys_porta_out ) |
| 1644 | 1846 | { |
| 1645 | | thom_set_mode_point( data & 1 ); /* bit 0: video bank switch */ |
| 1646 | | thom_set_border_color( (data >> 1) & 15 ); /* bit 1-4: border color */ |
| 1647 | | mo5_set_cassette( (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */ |
| 1847 | thom_set_mode_point( data & 1 ); /* bit 0: video bank switch */ |
| 1848 | thom_set_border_color( (data >> 1) & 15 ); /* bit 1-4: border color */ |
| 1849 | mo5_set_cassette( machine, (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */ |
| 1648 | 1850 | } |
| 1649 | 1851 | |
| 1650 | 1852 | |
| r3248 | r3249 | |
| 1652 | 1854 | static READ8_HANDLER ( mo5_sys_porta_in ) |
| 1653 | 1855 | { |
| 1654 | 1856 | return |
| 1655 | | (mo5_get_cassette() ? 0x80 : 0) | /* bit 7: cassette input */ |
| 1857 | (mo5_get_cassette(machine) ? 0x80 : 0) | /* bit 7: cassette input */ |
| 1656 | 1858 | ((input_port_read(machine, "lightpen_button") & 1) ? 0x20 : 0) |
| 1657 | 1859 | /* bit 5: lightpen button */; |
| 1658 | 1860 | } |
| r3248 | r3249 | |
| 3735 | 3937 | static READ8_HANDLER ( to8_timer_port_in ) |
| 3736 | 3938 | { |
| 3737 | 3939 | int lightpen = (input_port_read(machine, "lightpen_button") & 1) ? 2 : 0; |
| 3738 | | int cass = to7_get_cassette() ? 0x80 : 0; |
| 3940 | int cass = to7_get_cassette(machine) ? 0x80 : 0; |
| 3739 | 3941 | int dtr = (centronics_read_handshake( 0 ) & CENTRONICS_NOT_BUSY) ? 0 : 0x40; |
| 3740 | 3942 | int lock = to8_kbd_caps ? 0 : 8; /* undocumented! */ |
| 3741 | 3943 | return lightpen | cass | dtr | lock; |
| r3248 | r3249 | |
| 3931 | 4133 | static READ8_HANDLER ( to9p_timer_port_in ) |
| 3932 | 4134 | { |
| 3933 | 4135 | int lightpen = (input_port_read(machine, "lightpen_button") & 1) ? 2 : 0; |
| 3934 | | int cass = to7_get_cassette() ? 0x80 : 0; |
| 4136 | int cass = to7_get_cassette(machine) ? 0x80 : 0; |
| 3935 | 4137 | int dtr = (centronics_read_handshake( 0 ) & CENTRONICS_NOT_BUSY) ? 0 : 0x40; |
| 3936 | 4138 | return lightpen | cass | dtr; |
| 3937 | 4139 | } |
| r3248 | r3249 | |
| 4317 | 4519 | static READ8_HANDLER ( mo6_sys_porta_in ) |
| 4318 | 4520 | { |
| 4319 | 4521 | return |
| 4320 | | (mo5_get_cassette() ? 0x80 : 0) | /* bit 7: cassette input */ |
| 4522 | (mo5_get_cassette(machine) ? 0x80 : 0) | /* bit 7: cassette input */ |
| 4321 | 4523 | 8 | /* bit 3: kbd-line float up to 1 */ |
| 4322 | 4524 | ((input_port_read(machine, "lightpen_button") & 1) ? 2 : 0); |
| 4323 | 4525 | /* bit 1: lightpen button */; |
| r3248 | r3249 | |
| 4347 | 4549 | |
| 4348 | 4550 | static WRITE8_HANDLER ( mo6_sys_porta_out ) |
| 4349 | 4551 | { |
| 4350 | | thom_set_mode_point( data & 1 ); /* bit 0: video bank switch */ |
| 4351 | | to7_game_mute = data & 4; /* bit 2: sound mute */ |
| 4352 | | thom_set_caps_led( (data & 16) ? 0 : 1 ) ; /* bit 4: keyboard led */ |
| 4353 | | mo5_set_cassette( (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */ |
| 4354 | | mo6_update_cart_bank(machine); /* bit 5: rom bank */ |
| 4552 | thom_set_mode_point( data & 1 ); /* bit 0: video bank switch */ |
| 4553 | to7_game_mute = data & 4; /* bit 2: sound mute */ |
| 4554 | thom_set_caps_led( (data & 16) ? 0 : 1 ) ; /* bit 4: keyboard led */ |
| 4555 | mo5_set_cassette( machine, (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */ |
| 4556 | mo6_update_cart_bank(machine); /* bit 5: rom bank */ |
| 4355 | 4557 | to7_game_sound_update(); |
| 4356 | 4558 | } |
| 4357 | 4559 | |
| r3248 | r3249 | |
| 4768 | 4970 | static WRITE8_HANDLER ( mo5nr_sys_porta_out ) |
| 4769 | 4971 | { |
| 4770 | 4972 | /* no keyboard LED */ |
| 4771 | | thom_set_mode_point( data & 1 ); /* bit 0: video bank switch */ |
| 4772 | | to7_game_mute = data & 4; /* bit 2: sound mute */ |
| 4773 | | mo5_set_cassette( (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */ |
| 4774 | | mo6_update_cart_bank(machine); /* bit 5: rom bank */ |
| 4973 | thom_set_mode_point( data & 1 ); /* bit 0: video bank switch */ |
| 4974 | to7_game_mute = data & 4; /* bit 2: sound mute */ |
| 4975 | mo5_set_cassette( machine, (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */ |
| 4976 | mo6_update_cart_bank(machine); /* bit 5: rom bank */ |
| 4775 | 4977 | to7_game_sound_update(); |
| 4776 | 4978 | } |
| 4777 | 4979 | |
src/mess/formats/thom_cas.c
| r3248 | r3249 | |
| 17 | 17 | |
| 18 | 18 | /***************************** configuration **************************/ |
| 19 | 19 | |
| 20 | | #define K7_SPEED_HACK 1 |
| 20 | #define K7_SPEED_HACK |
| 21 | 21 | /* When set to 1, bits extracted from k7 files are not transformed into a |
| 22 | 22 | raw wave. It saves some time & memory but disables the ability to "hear" the |
| 23 | 23 | cassette. |
| 24 | 24 | This does not affect raw wave files. |
| 25 | 25 | Also, we do not do this for k5 files because the the corresponding wave |
| 26 | | files are more compact anyway. |
| 27 | | */ |
| 26 | files are more compact anyway. */ |
| 27 | /* It must be set accordingly in machine/thomson.c */ |
| 28 | 28 | |
| 29 | 29 | #define VERBOSE 0 /* 0, 1 or 2 */ |
| 30 | 30 | |
| 31 | 31 | |
| 32 | | |
| 33 | 32 | /***************************** utilities **************************/ |
| 34 | 33 | |
| 35 | 34 | #define PRINT(x) mame_printf_info x |
| r3248 | r3249 | |
| 38 | 37 | #define VLOG(x) do { if (VERBOSE > 1) logerror x; } while (0) |
| 39 | 38 | |
| 40 | 39 | |
| 41 | | |
| 42 | | /*************************** I / O **************************/ |
| 43 | | |
| 44 | | |
| 45 | | INLINE const device_config* thom_cassette_img( void ) |
| 46 | | { return image_from_devtype_and_index(IO_CASSETTE, 0); } |
| 47 | | |
| 48 | | |
| 49 | | |
| 50 | | /*-------------- TO7 ------------*/ |
| 51 | | |
| 52 | | |
| 53 | | /* On the TO7 & compatible (TO7/70,TO8,TO9, but not MO5,MO6), bits are coded |
| 54 | | in FM format with a 1.1 ms period (900 bauds): |
| 55 | | - 0 is 5 periods at 4.5 KHz |
| 56 | | - 1 is 7 periods at 6.3 KHz |
| 57 | | |
| 58 | | Moreover, a byte is represented using 11 bits: |
| 59 | | - one 0 start bit |
| 60 | | - eight data bits (low bit first) |
| 61 | | - two 1 stop bits |
| 62 | | |
| 63 | | There are also long (1 s) sequences of 1 bits to re-synchronize the |
| 64 | | cassette at places the motor can be cut off and back on (e.g., between |
| 65 | | files). |
| 66 | | |
| 67 | | The computer outputs a modulated wave that is directly put on the cassette. |
| 68 | | However, the input is demodulated by the cassette-reader before being |
| 69 | | sent to the computer: we got 0 when the signal is around 4.5 KHz and |
| 70 | | 1 when the signal is around 6.3 KHz. |
| 71 | | */ |
| 72 | | |
| 73 | 40 | #define TO7_BIT_LENGTH 0.001114 |
| 74 | 41 | |
| 75 | 42 | #define TO7_FREQ_CASS_0 4500. |
| r3248 | r3249 | |
| 78 | 45 | #define TO7_PERIOD_CASS_0 ( 1. / TO7_FREQ_CASS_0 ) |
| 79 | 46 | #define TO7_PERIOD_CASS_1 ( 1. / TO7_FREQ_CASS_1 ) |
| 80 | 47 | |
| 81 | | /* buffer storing demodulated bits, only for k7 and with speed hack */ |
| 82 | 48 | static UINT32 to7_k7_bitsize; |
| 83 | 49 | static UINT8* to7_k7_bits; |
| 84 | 50 | |
| 85 | | |
| 86 | | /* 1-bit cassette input to the computer |
| 87 | | inside the controller, two frequency filters (adjusted to 6.3 and 4.5 KHz) |
| 88 | | and a comparator demodulate the raw signal into 0s and 1s. |
| 89 | | */ |
| 90 | | int to7_get_cassette ( void ) |
| 91 | | { |
| 92 | | const device_config* img = thom_cassette_img(); |
| 93 | | |
| 94 | | if ( image_exists( img ) ) |
| 95 | | { |
| 96 | | cassette_image* cass = cassette_get_image( img ); |
| 97 | | cassette_state state = cassette_get_state( img ); |
| 98 | | double pos = cassette_get_position( img ); |
| 99 | | int bitpos = pos / TO7_BIT_LENGTH; |
| 100 | | |
| 101 | | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED ) |
| 102 | | return 1; |
| 103 | | |
| 104 | | if ( K7_SPEED_HACK && to7_k7_bits ) |
| 105 | | { |
| 106 | | /* hack, feed existing bits */ |
| 107 | | if ( bitpos >= to7_k7_bitsize ) |
| 108 | | bitpos = to7_k7_bitsize -1; |
| 109 | | VLOG (( "$%04x %f to7_get_cassette: state=$%X pos=%f samppos=%i bit=%i\n", |
| 110 | | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), state, pos, bitpos, |
| 111 | | to7_k7_bits[ bitpos ] )); |
| 112 | | return to7_k7_bits[ bitpos ]; |
| 113 | | } |
| 114 | | else |
| 115 | | { |
| 116 | | /* demodulate wave signal on-the-fly */ |
| 117 | | /* we simply count sign changes... */ |
| 118 | | int k, chg; |
| 119 | | INT8 data[40]; |
| 120 | | cassette_get_samples( cass, 0, pos, TO7_BIT_LENGTH * 15. / 14., 40, 1, data, 0 ); |
| 121 | | |
| 122 | | for ( k = 1, chg = 0; k < 40; k++ ) |
| 123 | | { |
| 124 | | if ( data[ k - 1 ] >= 0 && data[ k ] < 0 ) |
| 125 | | chg++; |
| 126 | | if ( data[ k - 1 ] <= 0 && data[ k ] > 0 ) |
| 127 | | chg++; |
| 128 | | } |
| 129 | | k = ( chg >= 13 ) ? 1 : 0; |
| 130 | | VLOG (( "$%04x %f to7_get_cassette: state=$%X pos=%f samppos=%i bit=%i (%i)\n", |
| 131 | | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), state, pos, bitpos, |
| 132 | | k, chg )); |
| 133 | | return k; |
| 134 | | } |
| 135 | | |
| 136 | | } |
| 137 | | else |
| 138 | | return 0; |
| 139 | | } |
| 140 | | |
| 141 | | |
| 142 | | |
| 143 | | /* 1-bit cassette output */ |
| 144 | | void to7_set_cassette ( int data ) |
| 145 | | { |
| 146 | | const device_config* img = thom_cassette_img(); |
| 147 | | cassette_output( img, data ? 1. : -1. ); |
| 148 | | } |
| 149 | | |
| 150 | | |
| 151 | | |
| 152 | | WRITE8_HANDLER ( to7_set_cassette_motor ) |
| 153 | | { |
| 154 | | const device_config* img = thom_cassette_img(); |
| 155 | | cassette_state state = cassette_get_state( img ); |
| 156 | | double pos = cassette_get_position(img); |
| 157 | | |
| 158 | | LOG (( "$%04x %f to7_set_cassette_motor: cassette motor %s bitpos=%i\n", |
| 159 | | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), data ? "off" : "on", |
| 160 | | (int) (pos / TO7_BIT_LENGTH) )); |
| 161 | | |
| 162 | | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED && !data && pos > 0.3 ) |
| 163 | | { |
| 164 | | /* rewind a little before starting the motor */ |
| 165 | | cassette_seek( img, -0.3, SEEK_CUR ); |
| 166 | | } |
| 167 | | |
| 168 | | cassette_change_state( img, data ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR ); |
| 169 | | } |
| 170 | | |
| 171 | | |
| 172 | | |
| 173 | | /*-------------- MO5 ------------*/ |
| 174 | | |
| 175 | | |
| 176 | | /* Each byte is represented as 8 bits without start or stop bit (unlike TO7). |
| 177 | | Bits are coded in MFM, and the MFM signal is directly fed to the |
| 178 | | computer which has to decode it in software (unlike TO7). |
| 179 | | A 1 bit is one period at 1200 Hz; a 0 bit is one half-period at 600 Hz. |
| 180 | | Bit-order is most significant bit first (unlike TO7). |
| 181 | | |
| 182 | | Double-density MO6 cassettes follow the exact same mechanism, but with |
| 183 | | at double frequency (perdiods at 2400 Hz, and half-perdios at 1200 Hz). |
| 184 | | */ |
| 185 | | |
| 186 | | |
| 187 | 51 | #define MO5_BIT_LENGTH 0.000833 |
| 188 | 52 | #define MO5_HBIT_LENGTH (MO5_BIT_LENGTH / 2.) |
| 189 | 53 | |
| 190 | | |
| 191 | | int mo5_get_cassette ( void ) |
| 192 | | { |
| 193 | | const device_config* img = thom_cassette_img(); |
| 194 | | |
| 195 | | if ( image_exists( img ) ) |
| 196 | | { |
| 197 | | cassette_image* cass = cassette_get_image( img ); |
| 198 | | cassette_state state = cassette_get_state( img ); |
| 199 | | double pos = cassette_get_position( img ); |
| 200 | | INT32 hbit; |
| 201 | | |
| 202 | | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED ) |
| 203 | | return 1; |
| 204 | | |
| 205 | | cassette_get_sample( cass, 0, pos, 0, &hbit ); |
| 206 | | hbit = hbit >= 0; |
| 207 | | |
| 208 | | VLOG (( "$%04x %f mo5_get_cassette: state=$%X pos=%f hbitpos=%i hbit=%i\n", |
| 209 | | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), state, pos, |
| 210 | | (int) (pos / MO5_HBIT_LENGTH), hbit )); |
| 211 | | return hbit; |
| 212 | | } |
| 213 | | else |
| 214 | | return 0; |
| 215 | | } |
| 216 | | |
| 217 | | |
| 218 | | |
| 219 | | void mo5_set_cassette ( int data ) |
| 220 | | { |
| 221 | | const device_config* img = thom_cassette_img(); |
| 222 | | cassette_output( img, data ? 1. : -1. ); |
| 223 | | } |
| 224 | | |
| 225 | | |
| 226 | | |
| 227 | | WRITE8_HANDLER ( mo5_set_cassette_motor ) |
| 228 | | { |
| 229 | | const device_config* img = thom_cassette_img(); |
| 230 | | cassette_state state = cassette_get_state( img ); |
| 231 | | double pos = cassette_get_position(img); |
| 232 | | |
| 233 | | LOG (( "$%04x %f mo5_set_cassette_motor: cassette motor %s hbitpos=%i\n", |
| 234 | | activecpu_get_previouspc(), attotime_to_double(timer_get_time()), data ? "off" : "on", |
| 235 | | (int) (pos / MO5_HBIT_LENGTH) )); |
| 236 | | |
| 237 | | if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED && !data && pos > 0.3 ) |
| 238 | | { |
| 239 | | /* rewind a little before starting the motor */ |
| 240 | | cassette_seek( img, -0.3, SEEK_CUR ); |
| 241 | | } |
| 242 | | |
| 243 | | cassette_change_state( img, data ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR ); |
| 244 | | } |
| 245 | | |
| 246 | | |
| 247 | | |
| 248 | 54 | /************************* k7 format *************************/ |
| 249 | 55 | |
| 250 | 56 | /* The k7 format is widespread among existing Thomson emulators. |