src/mess/formats/cbm_tap.c
| r0 | r3175 | |
| 1 | /* |
| 2 | |
| 3 | Tape support for C16 / C64 / VIC20 TAP format |
| 4 | |
| 5 | |
| 6 | Credits to: |
| 7 | |
| 8 | - Peter Schepers for the informations on C64 formats |
| 9 | - Vice Team for the source of their very complete emulator |
| 10 | - Attila G. for tap2wav (both the source and the actual tool) |
| 11 | |
| 12 | |
| 13 | TODO: |
| 14 | * to verify and fix (if needed) support for .TAP v2 |
| 15 | * to implement reading (and logging) the remaining part of the header |
| 16 | * to verify if it is more accurate to use a different HIGH_WAVE value |
| 17 | when the pulse corresponds to a 0x00 in the .TAP file |
| 18 | (...) |
| 19 | * (far away in the future) can this code be merged with TZX code? |
| 20 | |
| 21 | */ |
| 22 | |
| 23 | /* Info based on http://ist.uwaterloo.ca/~schepers/formats/TAP.TXT */ |
| 24 | /* Please refer to the webpage for the latest version and for a very |
| 25 | complete listing of various cart types and their bankswitch tricks */ |
| 26 | /* |
| 27 | |
| 28 | Designed by Per Hakan Sundell (author of the CCS64 C64 emulator) in 1997, |
| 29 | this format attempts to duplicate the data stored on a C64 cassette tape, |
| 30 | bit for bit. Since it is simply a representation of the raw serial data |
| 31 | from a tape, it should handle *any* custom tape loaders that exist. |
| 32 | |
| 33 | The TAP images are generally very large, being a minimum of eight times, |
| 34 | and up to sixteen times as large as what a raw PRG file would be. This is |
| 35 | due to the way the data is stored, with each bit of the original file now |
| 36 | being one byte large in the TAP file. The layout is fairly simple, with a |
| 37 | small 14-byte header followed by file data. |
| 38 | |
| 39 | Bytes: $0000-000B: File signature "C64-TAPE-RAW" |
| 40 | 000C: TAP version (see below for description) |
| 41 | $00 - Original layout |
| 42 | 01 - Updated |
| 43 | 000D-000F: Future expansion |
| 44 | 0010-0013: File data size (not including this header, in |
| 45 | LOW/HIGH format). |
| 46 | 0014-xxxx: File data |
| 47 | |
| 48 | In TAP version $00 files, each data byte in the file data area represents |
| 49 | the length of a pulse, when the C64's hardware will trigger again. This |
| 50 | pulse length is determined by the following formula: |
| 51 | |
| 52 | pulse length (in seconds) = (8 * data byte) / (clock cycles) |
| 53 | |
| 54 | Therefore, a data value of $2F (47 in decimal) would be: |
| 55 | |
| 56 | (47 * 8) / 985248 = .00038975 seconds. |
| 57 | |
| 58 | A data value of $00 represents an "overflow" condition, any pulse length |
| 59 | which is more that 255 * 8 in length. |
| 60 | |
| 61 | The value of "clock cylces" from above (985248) is based on the PAL |
| 62 | value. Since this file format was developed in Europe, which is |
| 63 | predominantly PAL video, this is only logical. The NTSC value would be |
| 64 | 1022730, which is very close to the PAL, and therefore won't cause a |
| 65 | compatability problem converting European and NTSC tapes. I would stick to |
| 66 | using the PAL value just in case. |
| 67 | |
| 68 | |
| 69 | In TAP version $01 files, the data value of $00 has been re-coded to |
| 70 | represent values greater than 255 * 8. When a $00 is encountered, three |
| 71 | bytes will follow which are the actual time (in cycles) of a pulse, and the |
| 72 | above formula does not apply. The three bytes are stored in LOW/HIGH |
| 73 | format. |
| 74 | |
| 75 | |
| 76 | The actual interpretation of the serial data takes a little more work to |
| 77 | explain. The typical ROM tape loader (and the turbo loaders) will |
| 78 | initialize a timer with a specified value and start it counting down. If |
| 79 | either the tape data changes or the timer runs out, an IRQ will occur. The |
| 80 | loader will determine which condition caused the IRQ. If the tape data |
| 81 | changed before the timer ran out, we have a short pulse, or a "0" bit. If |
| 82 | the timer ran out first, we have a long pulse, or a "1" bit. Doing this |
| 83 | continuously and we decode the entire file. |
| 84 | |
| 85 | |
| 86 | [ Additional notes on v.2: |
| 87 | |
| 88 | I found no documents about this around, but it seems an expansion of the |
| 89 | format specifically thought for C16 tapes. In a .TAP version 2, each byte |
| 90 | only stores informations on half of the wave... |
| 91 | Unfortunately, I have no such a .tap file to test, so my implementation |
| 92 | below could be not working. FP ] |
| 93 | */ |
| 94 | |
| 95 | #include "driver.h" |
| 96 | #include "formats/cbm_tap.h" |
| 97 | |
| 98 | |
| 99 | #define CBM_WAV_FREQUENCY 44100 |
| 100 | |
| 101 | /* Systems */ |
| 102 | #define C64 0 |
| 103 | #define VIC20 1 |
| 104 | #define C16 2 |
| 105 | |
| 106 | /* Video standards */ |
| 107 | #define PAL 0 |
| 108 | #define NTSC 1 |
| 109 | |
| 110 | /* Frequencies in [Hz] to determine the length of each pulse */ |
| 111 | #define C64_PAL 123156 /* 985248 / 8 */ |
| 112 | #define C64_NTSC 127841 /* 1022727 / 8 */ |
| 113 | #define VIC20_PAL 138551 /* 1108405 / 8 */ |
| 114 | #define VIC20_NTSC 127841 /* 1022727 / 8 */ |
| 115 | #define C16_PAL 110840 /* 886724 / 8 */ |
| 116 | #define C16_NTSC 111860 /* 894886 / 8 */ |
| 117 | |
| 118 | #define PAUSE (CBM_WAV_FREQUENCY / 50) /* tap2wav uses this value for 0x00 in .TAP v0, instead of 0x100 */ |
| 119 | |
| 120 | /* These values do not really matter, as long as the produced pulses |
| 121 | go above & below 0. However, for documentation purpose it would be |
| 122 | nice to find out which values were used by Commodore tapes. I was |
| 123 | not able to find any reference on the subject. */ |
| 124 | #define WAVE_HIGH (0x5a9e >> 1) |
| 125 | #define WAVE_LOW -(0x5a9e >> 1) |
| 126 | #define WAVE_PAUSE 0x80 |
| 127 | |
| 128 | #define CBM_HEADER_SIZE 20 |
| 129 | |
| 130 | static INT16 wave_data = 0; |
| 131 | static int len; |
| 132 | |
| 133 | |
| 134 | /* This in fact gives the number of samples for half of the pulse */ |
| 135 | INLINE int tap_data_to_samplecount(int data, int frequency) |
| 136 | { |
| 137 | // return (int) (0.5 * (0.5 + (((double)CBM_WAV_FREQUENCY / frequency) * (double)data))); // MESS TZX formula |
| 138 | return (int) (0.5 * (((double)CBM_WAV_FREQUENCY / frequency) * (double)((data) + 0.5))); // tap2wav formula |
| 139 | } |
| 140 | |
| 141 | /* The version with parameters could be handy if we decide to implement a |
| 142 | different values for byte == 0x00 below (the WAVE_PAUSE) as tap2wav does. */ |
| 143 | #if 0 |
| 144 | static void toggle_wave_data(int low, int high) |
| 145 | { |
| 146 | wave_data = (wave_data == low) ? high : low; |
| 147 | } |
| 148 | #endif |
| 149 | |
| 150 | static void toggle_wave_data(void ) |
| 151 | { |
| 152 | wave_data = (wave_data == WAVE_HIGH) ? WAVE_LOW : WAVE_HIGH; |
| 153 | } |
| 154 | |
| 155 | static void cbm_output_wave( INT16 **buffer, int length ) |
| 156 | { |
| 157 | if (buffer == NULL) |
| 158 | return; |
| 159 | |
| 160 | for( ; length > 0; length-- ) |
| 161 | { |
| 162 | **buffer = wave_data; |
| 163 | *buffer = *buffer + 1; |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | |
| 168 | static int cbm_tap_do_work( INT16 **buffer, int length, const UINT8 *data ) |
| 169 | { |
| 170 | int i, j = 0; |
| 171 | int size = 0; |
| 172 | |
| 173 | int version = data[0x0c]; |
| 174 | int system = data[0x0d]; |
| 175 | int video_standard = data[0x0e]; |
| 176 | int tap_frequency = 0; |
| 177 | |
| 178 | int byte_samples = 0; |
| 179 | UINT8 over_pulse_bytes[3] = {0 , 0, 0 }; |
| 180 | int over_pulse_length = 0; |
| 181 | /* These waveamp_* values are currently stored but not used. |
| 182 | Further investigations are needed to find real pulse amplitude |
| 183 | in Commodore tapes. Implementation here would follow */ |
| 184 | int waveamp_high, waveamp_low; |
| 185 | |
| 186 | /* Log .TAP info but only once */ |
| 187 | if (!(buffer == NULL)) |
| 188 | { |
| 189 | logerror("TAP version : %d\n", version); |
| 190 | logerror("Machine type : %d\n", system); |
| 191 | logerror("Video standard : %d\n", video_standard); |
| 192 | logerror("Tape frequency : %d\n", (tap_frequency) << 3); |
| 193 | } |
| 194 | |
| 195 | |
| 196 | /* is this a supported version? */ |
| 197 | if ((version < 0) || (version > 2)) |
| 198 | { |
| 199 | logerror("Unsupported .tap version: %d \n", version); |
| 200 | return -1; |
| 201 | } |
| 202 | |
| 203 | /* is the .tap file corrupted? */ |
| 204 | if ((data == NULL) || (length <= CBM_HEADER_SIZE)) |
| 205 | return -1; |
| 206 | |
| 207 | |
| 208 | /* read the frequency from the .tap header */ |
| 209 | switch (system) |
| 210 | { |
| 211 | case VIC20: |
| 212 | tap_frequency = (video_standard == NTSC) ? VIC20_NTSC : VIC20_PAL; |
| 213 | break; |
| 214 | |
| 215 | case C16: |
| 216 | tap_frequency = (video_standard == NTSC) ? C16_NTSC : C16_PAL; |
| 217 | break; |
| 218 | |
| 219 | case C64: |
| 220 | default: |
| 221 | tap_frequency = (video_standard == NTSC) ? C64_NTSC : C64_PAL; |
| 222 | break; |
| 223 | } |
| 224 | |
| 225 | |
| 226 | for (i = CBM_HEADER_SIZE; i < length; i++) |
| 227 | { |
| 228 | UINT8 byte = data[i]; |
| 229 | |
| 230 | /* .TAP v0 */ |
| 231 | /* Here is simple: |
| 232 | if byte is != 0 -> length = byte |
| 233 | otherwise -> length = 0x100 (i.e. 0xff + 1) */ |
| 234 | if (!version) |
| 235 | { |
| 236 | if (byte != 0x00) |
| 237 | { |
| 238 | byte_samples = tap_data_to_samplecount(byte, tap_frequency); |
| 239 | waveamp_high = WAVE_HIGH; |
| 240 | } |
| 241 | else |
| 242 | { |
| 243 | byte_samples = tap_data_to_samplecount(PAUSE, tap_frequency); // tap2wav value |
| 244 | // byte_samples = tap_data_to_samplecount(0x100, tap_frequency); // vice value |
| 245 | waveamp_high = WAVE_PAUSE; |
| 246 | } |
| 247 | waveamp_low = WAVE_LOW; |
| 248 | } |
| 249 | |
| 250 | /* .TAP v1 & v2 */ |
| 251 | /* Here is a bit more complicate: |
| 252 | if byte is != 0 -> length = byte |
| 253 | otherwise -> the length of the pulse is stored as a 24bit value in the 3 bytes after the 0. |
| 254 | See below for comments on the implementation of this mechanism */ |
| 255 | if (version) |
| 256 | { |
| 257 | if ((byte != 0x00) && !j) |
| 258 | { |
| 259 | byte_samples = tap_data_to_samplecount(byte, tap_frequency); |
| 260 | waveamp_high = WAVE_HIGH; |
| 261 | } |
| 262 | else |
| 263 | { |
| 264 | /* If we have a long pulse close to the end of the .TAP, check that bytes still |
| 265 | to be read are enough to complete it. */ |
| 266 | if (length - i + j >= 4) |
| 267 | { |
| 268 | /* Here we read the 3 following bytes, using an index j |
| 269 | j = 0 -> The 0x00 byte: we simply skip everything and go on |
| 270 | j = 1,2 -> The 1st and 2nd bytes after 0x00: we store them and go on |
| 271 | j = 3 -> The final byte of the pulse length: we store it, |
| 272 | and then we pass to finally output the wave */ |
| 273 | if (j > 0) |
| 274 | { |
| 275 | over_pulse_bytes[j-1] = byte; |
| 276 | j += 1; |
| 277 | |
| 278 | if (j >= 4) |
| 279 | { |
| 280 | over_pulse_length = ((over_pulse_bytes[2] << 16) | (over_pulse_bytes[1] << 8) | over_pulse_bytes[0]) >> 3; |
| 281 | byte_samples = tap_data_to_samplecount(over_pulse_length, tap_frequency); |
| 282 | waveamp_high = WAVE_PAUSE; |
| 283 | j = 0; |
| 284 | } |
| 285 | } |
| 286 | else |
| 287 | { |
| 288 | j += 1; |
| 289 | logerror("Found a 00 byte close to the end of the .tap file.\n"); |
| 290 | logerror("This is not allowed by the format specs. \n"); |
| 291 | logerror("Check if your .tap file got corrupted when you created it!\n"); |
| 292 | } |
| 293 | } |
| 294 | else j = 1; |
| 295 | } |
| 296 | waveamp_low = WAVE_LOW; |
| 297 | } |
| 298 | |
| 299 | if (j == 0) |
| 300 | { |
| 301 | cbm_output_wave( buffer, byte_samples ); |
| 302 | size += byte_samples; |
| 303 | // toggle_wave_data(waveamp_low, waveamp_high); |
| 304 | toggle_wave_data(); |
| 305 | if (version < 2) |
| 306 | { |
| 307 | cbm_output_wave( buffer, byte_samples ); |
| 308 | size += byte_samples; |
| 309 | // toggle_wave_data(waveamp_low, waveamp_high); |
| 310 | toggle_wave_data(); |
| 311 | } |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | return size; |
| 316 | } |
| 317 | |
| 318 | |
| 319 | static int cbm_tap_to_wav_size( const UINT8 *tapdata, int taplen ) |
| 320 | { |
| 321 | int size = cbm_tap_do_work(NULL, taplen, tapdata); |
| 322 | len = taplen; |
| 323 | |
| 324 | return size; |
| 325 | } |
| 326 | |
| 327 | static int cbm_tap_fill_wave( INT16 *buffer, int length, UINT8 *bytes ) |
| 328 | { |
| 329 | INT16 *p = buffer; |
| 330 | |
| 331 | return cbm_tap_do_work(&p, len, (const UINT8 *)bytes); |
| 332 | } |
| 333 | |
| 334 | |
| 335 | |
| 336 | |
| 337 | static const struct CassetteLegacyWaveFiller cbm_legacy_fill_wave = { |
| 338 | cbm_tap_fill_wave, /* fill_wave */ |
| 339 | -1, /* chunk_size */ |
| 340 | 0, /* chunk_samples */ |
| 341 | cbm_tap_to_wav_size, /* chunk_sample_calc */ |
| 342 | CBM_WAV_FREQUENCY, /* sample_frequency */ |
| 343 | 0, /* header_samples */ |
| 344 | 0 /* trailer_samples */ |
| 345 | }; |
| 346 | |
| 347 | |
| 348 | static casserr_t cbm_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) |
| 349 | { |
| 350 | return cassette_legacy_identify( cassette, opts, &cbm_legacy_fill_wave ); |
| 351 | } |
| 352 | |
| 353 | |
| 354 | static casserr_t cbm_cassette_load( cassette_image *cassette ) |
| 355 | { |
| 356 | return cassette_legacy_construct( cassette, &cbm_legacy_fill_wave ); |
| 357 | } |
| 358 | |
| 359 | |
| 360 | static const struct CassetteFormat cbm_tap_cassette_format = { |
| 361 | "tap", |
| 362 | cbm_cassette_identify, |
| 363 | cbm_cassette_load, |
| 364 | NULL |
| 365 | }; |
| 366 | |
| 367 | |
| 368 | CASSETTE_FORMATLIST_START(cbm_cassette_formats) |
| 369 | CASSETTE_FORMAT(cbm_tap_cassette_format) |
| 370 | CASSETTE_FORMATLIST_END |
src/mess/drivers/c16.c
| r3174 | r3175 | |
| 199 | 199 | * at 0xfc00 till 0xfcff is ram or rom kernal readable |
| 200 | 200 | */ |
| 201 | 201 | |
| 202 | | static ADDRESS_MAP_START( c16_readmem , ADDRESS_SPACE_PROGRAM, 8) |
| 203 | | AM_RANGE(0x0000, 0x3fff) AM_READ( SMH_BANK9) |
| 204 | | AM_RANGE(0x4000, 0x7fff) AM_READ( SMH_BANK1) /* only ram memory configuration */ |
| 205 | | AM_RANGE(0x8000, 0xbfff) AM_READ( SMH_BANK2) |
| 206 | | AM_RANGE(0xc000, 0xfbff) AM_READ( SMH_BANK3) |
| 207 | | AM_RANGE(0xfc00, 0xfcff) AM_READ( SMH_BANK4) |
| 208 | | AM_RANGE(0xfd10, 0xfd1f) AM_READ( c16_fd1x_r) |
| 209 | | AM_RANGE(0xfd30, 0xfd3f) AM_READ( c16_6529_port_r) /* 6529 keyboard matrix */ |
| 202 | static ADDRESS_MAP_START(c16_map, ADDRESS_SPACE_PROGRAM, 8) |
| 203 | AM_RANGE(0x0000, 0x3fff) AM_RAMBANK(9) |
| 204 | AM_RANGE(0x4000, 0x7fff) AM_READWRITE(SMH_BANK1, SMH_BANK5) /* only ram memory configuration */ |
| 205 | AM_RANGE(0x8000, 0xbfff) AM_READWRITE(SMH_BANK2, SMH_BANK6) |
| 206 | AM_RANGE(0xc000, 0xfbff) AM_READ(SMH_BANK3) |
| 207 | AM_RANGE(0xfc00, 0xfcff) AM_READ(SMH_BANK4) |
| 208 | AM_RANGE(0xc000, 0xfcff) AM_WRITE(SMH_BANK7) |
| 209 | AM_RANGE(0xfd10, 0xfd1f) AM_READ(c16_fd1x_r) |
| 210 | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
| 211 | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE(c16_select_roms) /* rom chips selection */ |
| 212 | AM_RANGE(0xff00, 0xff1f) AM_READWRITE(ted7360_port_r, ted7360_port_w) |
| 213 | AM_RANGE(0xff20, 0xffff) AM_READ(SMH_BANK8) |
| 214 | AM_RANGE(0xff3e, 0xff3e) AM_WRITE(c16_switch_to_rom) |
| 215 | AM_RANGE(0xff3f, 0xff3f) AM_WRITE(c16_switch_to_ram) |
| 210 | 216 | #if 0 |
| 211 | | AM_RANGE( 0xfd40, 0xfd5f) AM_READ( sid6581_0_port_r ) /* sidcard, eoroidpro ... */ |
| 212 | | AM_RANGE(0xfec0, 0xfedf) AM_READ( c16_iec9_port_r) /* configured in c16_common_init */ |
| 213 | | AM_RANGE(0xfee0, 0xfeff) AM_READ( c16_iec8_port_r) /* configured in c16_common_init */ |
| 214 | | #endif |
| 215 | | AM_RANGE(0xff00, 0xff1f) AM_READ( ted7360_port_r) |
| 216 | | AM_RANGE(0xff20, 0xffff) AM_READ( SMH_BANK8) |
| 217 | | /* { 0x10000, 0x3ffff, SMH_ROM }, */ |
| 218 | | ADDRESS_MAP_END |
| 219 | | |
| 220 | | static ADDRESS_MAP_START( c16_writemem , ADDRESS_SPACE_PROGRAM, 8) |
| 221 | | AM_RANGE(0x0000, 0x3fff) AM_WRITE( SMH_BANK9) |
| 222 | | AM_RANGE(0x4000, 0x7fff) AM_WRITE( SMH_BANK5) |
| 223 | | AM_RANGE(0x8000, 0xbfff) AM_WRITE( SMH_BANK6) |
| 224 | | AM_RANGE(0xc000, 0xfcff) AM_WRITE( SMH_BANK7) |
| 225 | | #if 0 |
| 226 | 217 | AM_RANGE(0x4000, 0x7fff) AM_WRITE( c16_write_4000) /*configured in c16_common_init */ |
| 227 | 218 | AM_RANGE(0x8000, 0xbfff) AM_WRITE( c16_write_8000) /*configured in c16_common_init */ |
| 228 | 219 | AM_RANGE(0xc000, 0xfcff) AM_WRITE( c16_write_c000) /*configured in c16_common_init */ |
| 229 | | #endif |
| 230 | | AM_RANGE(0xfd30, 0xfd3f) AM_WRITE( c16_6529_port_w) /* 6529 keyboard matrix */ |
| 231 | | #if 0 |
| 232 | | AM_RANGE(0xfd40, 0xfd5f) AM_WRITE( sid6581_0_port_w) |
| 233 | | #endif |
| 234 | | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE( c16_select_roms) /* rom chips selection */ |
| 235 | | #if 0 |
| 236 | | AM_RANGE(0xfec0, 0xfedf) AM_WRITE( c16_iec9_port_w) /*configured in c16_common_init */ |
| 237 | | AM_RANGE(0xfee0, 0xfeff) AM_WRITE( c16_iec8_port_w) /*configured in c16_common_init */ |
| 238 | | #endif |
| 239 | | AM_RANGE(0xff00, 0xff1f) AM_WRITE( ted7360_port_w) |
| 240 | | #if 0 |
| 220 | AM_RANGE(0xfd40, 0xfd5f) AM_READWRITE(sid6581_0_port_r, sid6581_0_port_w) /* sidcard, eoroidpro ... */ |
| 221 | AM_RANGE(0xfec0, 0xfedf) AM_READWRITE(c16_iec9_port_r, c16_iec9_port_w) /*configured in c16_common_init */ |
| 222 | AM_RANGE(0xfee0, 0xfeff) AM_READWRITE(c16_iec8_port_r, c16_iec8_port_w) /*configured in c16_common_init */ |
| 241 | 223 | AM_RANGE(0xff20, 0xff3d) AM_WRITE( c16_write_ff20) /*configure in c16_common_init */ |
| 242 | | #endif |
| 243 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE( c16_switch_to_rom) |
| 244 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE( c16_switch_to_ram) |
| 245 | | #if 0 |
| 246 | 224 | AM_RANGE(0xff40, 0xffff) AM_WRITE( c16_write_ff40) /*configure in c16_common_init */ |
| 247 | | // {0x10000, 0x3ffff, SMH_ROM}, |
| 248 | 225 | #endif |
| 249 | 226 | ADDRESS_MAP_END |
| 250 | 227 | |
| 251 | | static ADDRESS_MAP_START( plus4_readmem , ADDRESS_SPACE_PROGRAM, 8) |
| 252 | | AM_RANGE(0x0000, 0x7fff) AM_READ( SMH_BANK9) |
| 253 | | AM_RANGE(0x8000, 0xbfff) AM_READ( SMH_BANK2) |
| 254 | | AM_RANGE(0xc000, 0xfbff) AM_READ( SMH_BANK3) |
| 255 | | AM_RANGE(0xfc00, 0xfcff) AM_READ( SMH_BANK4) |
| 256 | | AM_RANGE(0xfd00, 0xfd0f) AM_READ( c16_6551_port_r) |
| 257 | | AM_RANGE(0xfd10, 0xfd1f) AM_READ( plus4_6529_port_r) |
| 258 | | AM_RANGE(0xfd30, 0xfd3f) AM_READ( c16_6529_port_r) /* 6529 keyboard matrix */ |
| 259 | | #if 0 |
| 260 | | AM_RANGE( 0xfd40, 0xfd5f) AM_READ( sid6581_0_port_r ) /* sidcard, eoroidpro ... */ |
| 261 | | AM_RANGE(0xfec0, 0xfedf) AM_READ( c16_iec9_port_r) /* configured in c16_common_init */ |
| 262 | | AM_RANGE(0xfee0, 0xfeff) AM_READ( c16_iec8_port_r) /* configured in c16_common_init */ |
| 263 | | #endif |
| 264 | | AM_RANGE(0xff00, 0xff1f) AM_READ( ted7360_port_r) |
| 265 | | AM_RANGE(0xff20, 0xffff) AM_READ( SMH_BANK8) |
| 266 | | /* { 0x10000, 0x3ffff, SMH_ROM }, */ |
| 267 | | ADDRESS_MAP_END |
| 268 | | |
| 269 | | static ADDRESS_MAP_START( plus4_writemem , ADDRESS_SPACE_PROGRAM, 8) |
| 270 | | AM_RANGE(0x0000, 0xfcff) AM_WRITE( SMH_BANK9) |
| 271 | | AM_RANGE(0xfd00, 0xfd0f) AM_WRITE( c16_6551_port_w) |
| 272 | | AM_RANGE(0xfd10, 0xfd1f) AM_WRITE( plus4_6529_port_w) |
| 273 | | AM_RANGE(0xfd30, 0xfd3f) AM_WRITE( c16_6529_port_w) /* 6529 keyboard matrix */ |
| 274 | | #if 0 |
| 275 | | AM_RANGE(0xfd40, 0xfd5f) AM_WRITE( sid6581_0_port_w) |
| 276 | | #endif |
| 228 | static ADDRESS_MAP_START(plus4_map, ADDRESS_SPACE_PROGRAM, 8) |
| 229 | AM_RANGE(0x0000, 0x7fff) AM_READ(SMH_BANK9) |
| 230 | AM_RANGE(0x8000, 0xbfff) AM_READ(SMH_BANK2) |
| 231 | AM_RANGE(0xc000, 0xfbff) AM_READ(SMH_BANK3) |
| 232 | AM_RANGE(0xfc00, 0xfcff) AM_READ(SMH_BANK4) |
| 233 | AM_RANGE(0x0000, 0xfcff) AM_WRITE(SMH_BANK9) |
| 234 | AM_RANGE(0xfd00, 0xfd0f) AM_READWRITE(c16_6551_port_r, c16_6551_port_w) |
| 235 | AM_RANGE(0xfd10, 0xfd1f) AM_READWRITE(plus4_6529_port_r, plus4_6529_port_w) |
| 236 | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
| 277 | 237 | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE( c16_select_roms) /* rom chips selection */ |
| 278 | 238 | #if 0 |
| 279 | | AM_RANGE(0xfec0, 0xfedf) AM_WRITE( c16_iec9_port_w) /*configured in c16_common_init */ |
| 280 | | AM_RANGE(0xfee0, 0xfeff) AM_WRITE( c16_iec8_port_w) /*configured in c16_common_init */ |
| 239 | AM_RANGE(0xfd40, 0xfd5f) AM_READWRITE(sid6581_0_port_r, sid6581_0_port_w) /* sidcard, eoroidpro ... */ |
| 240 | AM_RANGE(0xfec0, 0xfedf) AM_READWRITE(c16_iec9_port_r, c16_iec9_port_w) /*configured in c16_common_init */ |
| 241 | AM_RANGE(0xfee0, 0xfeff) AM_READWRITE(c16_iec8_port_r, c16_iec8_port_w) /*configured in c16_common_init */ |
| 281 | 242 | #endif |
| 282 | | AM_RANGE(0xff00, 0xff1f) AM_WRITE( ted7360_port_w) |
| 283 | | AM_RANGE(0xff20, 0xff3d) AM_WRITE( SMH_RAM) |
| 284 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE( c16_switch_to_rom) |
| 285 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE( c16_switch_to_ram) |
| 286 | | AM_RANGE(0xff40, 0xffff) AM_WRITE( SMH_RAM) |
| 287 | | // {0x10000, 0x3ffff, SMH_ROM}, |
| 243 | AM_RANGE(0xff00, 0xff1f) AM_READWRITE(ted7360_port_r, ted7360_port_w) |
| 244 | AM_RANGE(0xff20, 0xffff) AM_READ(SMH_BANK8) |
| 245 | AM_RANGE(0xff20, 0xff3d) AM_WRITE(SMH_RAM) |
| 246 | AM_RANGE(0xff3e, 0xff3e) AM_WRITE(c16_switch_to_rom) |
| 247 | AM_RANGE(0xff3f, 0xff3f) AM_WRITE(c16_switch_to_ram) |
| 248 | AM_RANGE(0xff40, 0xffff) AM_WRITE(SMH_RAM) |
| 288 | 249 | ADDRESS_MAP_END |
| 289 | 250 | |
| 290 | | static ADDRESS_MAP_START( c364_readmem , ADDRESS_SPACE_PROGRAM, 8) |
| 291 | | AM_RANGE(0x0000, 0x7fff) AM_READ( SMH_BANK9) |
| 292 | | AM_RANGE(0x8000, 0xbfff) AM_READ( SMH_BANK2) |
| 293 | | AM_RANGE(0xc000, 0xfbff) AM_READ( SMH_BANK3) |
| 294 | | AM_RANGE(0xfc00, 0xfcff) AM_READ( SMH_BANK4) |
| 295 | | AM_RANGE(0xfd00, 0xfd0f) AM_READ( c16_6551_port_r) |
| 296 | | AM_RANGE(0xfd10, 0xfd1f) AM_READ( plus4_6529_port_r) |
| 297 | | AM_RANGE(0xfd20, 0xfd2f) AM_READ( c364_speech_r ) |
| 298 | | AM_RANGE(0xfd30, 0xfd3f) AM_READ( c16_6529_port_r) /* 6529 keyboard matrix */ |
| 299 | | #if 0 |
| 300 | | AM_RANGE( 0xfd40, 0xfd5f) AM_READ( sid6581_0_port_r ) /* sidcard, eoroidpro ... */ |
| 301 | | AM_RANGE(0xfec0, 0xfedf) AM_READ( c16_iec9_port_r) /* configured in c16_common_init */ |
| 302 | | AM_RANGE(0xfee0, 0xfeff) AM_READ( c16_iec8_port_r) /* configured in c16_common_init */ |
| 303 | | #endif |
| 304 | | AM_RANGE(0xff00, 0xff1f) AM_READ( ted7360_port_r) |
| 305 | | AM_RANGE(0xff20, 0xffff) AM_READ( SMH_BANK8) |
| 306 | | /* { 0x10000, 0x3ffff, SMH_ROM }, */ |
| 307 | | ADDRESS_MAP_END |
| 308 | | |
| 309 | | static ADDRESS_MAP_START( c364_writemem , ADDRESS_SPACE_PROGRAM, 8) |
| 310 | | AM_RANGE(0x0000, 0xfcff) AM_WRITE( SMH_BANK9) |
| 311 | | AM_RANGE(0xfd00, 0xfd0f) AM_WRITE( c16_6551_port_w) |
| 312 | | AM_RANGE(0xfd10, 0xfd1f) AM_WRITE( plus4_6529_port_w) |
| 313 | | AM_RANGE(0xfd20, 0xfd2f) AM_WRITE( c364_speech_w ) |
| 314 | | AM_RANGE(0xfd30, 0xfd3f) AM_WRITE( c16_6529_port_w) /* 6529 keyboard matrix */ |
| 315 | | #if 0 |
| 316 | | AM_RANGE(0xfd40, 0xfd5f) AM_WRITE( sid6581_0_port_w) |
| 317 | | #endif |
| 251 | static ADDRESS_MAP_START(c364_map , ADDRESS_SPACE_PROGRAM, 8) |
| 252 | AM_RANGE(0x0000, 0x7fff) AM_READ(SMH_BANK9) |
| 253 | AM_RANGE(0x8000, 0xbfff) AM_READ(SMH_BANK2) |
| 254 | AM_RANGE(0xc000, 0xfbff) AM_READ(SMH_BANK3) |
| 255 | AM_RANGE(0xfc00, 0xfcff) AM_READ(SMH_BANK4) |
| 256 | AM_RANGE(0x0000, 0xfcff) AM_WRITE(SMH_BANK9) |
| 257 | AM_RANGE(0xfd00, 0xfd0f) AM_READWRITE(c16_6551_port_r, c16_6551_port_w) |
| 258 | AM_RANGE(0xfd10, 0xfd1f) AM_READWRITE(plus4_6529_port_r, plus4_6529_port_w) |
| 259 | AM_RANGE(0xfd20, 0xfd2f) AM_READWRITE(c364_speech_r, c364_speech_w) |
| 260 | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
| 318 | 261 | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE( c16_select_roms) /* rom chips selection */ |
| 319 | 262 | #if 0 |
| 320 | | AM_RANGE(0xfec0, 0xfedf) AM_WRITE( c16_iec9_port_w) /*configured in c16_common_init */ |
| 321 | | AM_RANGE(0xfee0, 0xfeff) AM_WRITE( c16_iec8_port_w) /*configured in c16_common_init */ |
| 263 | AM_RANGE(0xfd40, 0xfd5f) AM_READWRITE(sid6581_0_port_r, sid6581_0_port_w) /* sidcard, eoroidpro ... */ |
| 264 | AM_RANGE(0xfec0, 0xfedf) AM_READWRITE(c16_iec9_port_r, c16_iec9_port_w) /*configured in c16_common_init */ |
| 265 | AM_RANGE(0xfee0, 0xfeff) AM_READWRITE(c16_iec8_port_r, c16_iec8_port_w) /*configured in c16_common_init */ |
| 322 | 266 | #endif |
| 323 | | AM_RANGE(0xff00, 0xff1f) AM_WRITE( ted7360_port_w) |
| 324 | | AM_RANGE(0xff20, 0xff3d) AM_WRITE( SMH_RAM) |
| 325 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE( c16_switch_to_rom) |
| 326 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE( c16_switch_to_ram) |
| 327 | | AM_RANGE(0xff40, 0xffff) AM_WRITE( SMH_RAM) |
| 328 | | // {0x10000, 0x3ffff, SMH_ROM}, |
| 267 | AM_RANGE(0xff00, 0xff1f) AM_READWRITE(ted7360_port_r, ted7360_port_w) |
| 268 | AM_RANGE(0xff20, 0xffff) AM_READ(SMH_BANK8) |
| 269 | AM_RANGE(0xff20, 0xff3d) AM_WRITE(SMH_RAM) |
| 270 | AM_RANGE(0xff3e, 0xff3e) AM_WRITE(c16_switch_to_rom) |
| 271 | AM_RANGE(0xff3f, 0xff3f) AM_WRITE(c16_switch_to_ram) |
| 272 | AM_RANGE(0xff40, 0xffff) AM_WRITE(SMH_RAM) |
| 329 | 273 | ADDRESS_MAP_END |
| 330 | 274 | |
| 331 | 275 | |
| r3174 | r3175 | |
| 570 | 514 | static MACHINE_DRIVER_START( c16 ) |
| 571 | 515 | /* basic machine hardware */ |
| 572 | 516 | MDRV_CPU_ADD("main", M7501, 1400000) /* 7.8336 Mhz */ |
| 573 | | MDRV_CPU_PROGRAM_MAP(c16_readmem, c16_writemem) |
| 517 | MDRV_CPU_PROGRAM_MAP(c16_map, 0) |
| 574 | 518 | MDRV_CPU_VBLANK_INT("main", c16_frame_interrupt) |
| 575 | 519 | MDRV_CPU_PERIODIC_INT(ted7360_raster_interrupt, TED7360_HRETRACERATE) |
| 576 | 520 | MDRV_INTERLEAVE(1) |
| r3174 | r3175 | |
| 628 | 572 | static MACHINE_DRIVER_START( plus4 ) |
| 629 | 573 | MDRV_IMPORT_FROM( c16 ) |
| 630 | 574 | MDRV_CPU_REPLACE( "main", M7501, 1200000) |
| 631 | | MDRV_CPU_PROGRAM_MAP( plus4_readmem, plus4_writemem ) |
| 575 | MDRV_CPU_PROGRAM_MAP(plus4_map, 0) |
| 632 | 576 | MDRV_SCREEN_MODIFY("main") |
| 633 | 577 | MDRV_SCREEN_REFRESH_RATE(TED7360NTSC_VRETRACERATE) |
| 634 | 578 | |
| r3174 | r3175 | |
| 668 | 612 | MDRV_SCREEN_MODIFY("main") |
| 669 | 613 | MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ |
| 670 | 614 | MDRV_CPU_MODIFY( "main" ) |
| 671 | | MDRV_CPU_PROGRAM_MAP(c364_readmem, c364_writemem) |
| 615 | MDRV_CPU_PROGRAM_MAP(c364_map, 0) |
| 672 | 616 | MACHINE_DRIVER_END |
| 673 | 617 | |
| 674 | 618 | static DRIVER_INIT( c16 ) { c16_driver_init(machine); } |