trunk/src/mess/devices/kermit.c
| r17575 | r17576 | |
| 1 | | /* Kermit protocol implementation. |
| 2 | | |
| 3 | | Transfer between an emulated machine and an image using the kermit protocol. |
| 4 | | |
| 5 | | Used in the HP48 S/SX/G/GX emulation. |
| 6 | | |
| 7 | | Based on the 'KERMIT PROTOCOL MANUAL', Sixth Edition, by Frank da Cruz, |
| 8 | | Columbia University Center for Computing Activities, New York, June 1986. |
| 9 | | Available at: http://www-vs.informatik.uni-ulm.de/teach/ws05/rn1/Kermit%20Protocol.pdf |
| 10 | | |
| 11 | | Used in the HP48 S/SX/G/GX emulation. |
| 12 | | For HP48 specific kermit notes, see http://www.columbia.edu/kermit/hp48.html |
| 13 | | |
| 14 | | Only the basic protocol is implemented. |
| 15 | | The following features are NOT supported: |
| 16 | | - 8-bit quoting (QBIN) |
| 17 | | - 2- or 3-byte checksums (only 1-byte supported) |
| 18 | | - repeat count |
| 19 | | - file attribute packets |
| 20 | | - sliding window |
| 21 | | - extended length packets |
| 22 | | - server mode |
| 23 | | |
| 24 | | Author: Antoine Mine' |
| 25 | | Date: 29/03/2008 |
| 26 | | */ |
| 27 | | |
| 28 | | |
| 29 | | #include "emu.h" |
| 30 | | #include "kermit.h" |
| 31 | | |
| 32 | | |
| 33 | | /* debugging */ |
| 34 | | #define VERBOSE 0 |
| 35 | | |
| 36 | | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) |
| 37 | | |
| 38 | | /* protocol bytes */ |
| 39 | | #define KERMIT_SOH 0x01 /* (default) start of header */ |
| 40 | | |
| 41 | | /* packet types */ |
| 42 | | #define KERMIT_DATA 'D' /* data packet */ |
| 43 | | #define KERMIT_ACK 'Y' /* acknowledge */ |
| 44 | | #define KERMIT_NAK 'N' /* negative acknowledge */ |
| 45 | | #define KERMIT_SEND 'S' /* send initiate (exchange parameters) */ |
| 46 | | #define KERMIT_EOT 'B' /* break transmission */ |
| 47 | | #define KERMIT_FILE 'F' /* file header */ |
| 48 | | #define KERMIT_EOF 'Z' /* end of file */ |
| 49 | | #define KERMIT_ERR 'E' /* error */ |
| 50 | | |
| 51 | | #define KERMIT_QCTL '#' /* default escape character */ |
| 52 | | #define KERMIT_EOL 15 /* default terminator: carriage-return */ |
| 53 | | #define KERMIT_MAXL 80 /* default maximum packet length */ |
| 54 | | |
| 55 | | /* protocol state, to drive action */ |
| 56 | | #define KERMIT_IDLE 0 /* nothing to do */ |
| 57 | | #define KERMIT_RESET 1 /* reset after sending the last packet */ |
| 58 | | #define KERMIT_RECEIVE 2 /* receiving */ |
| 59 | | #define KERMIT_SEND_DATA 3 /* sending data */ |
| 60 | | #define KERMIT_SEND_EOF 4 /* sending EOF */ |
| 61 | | #define KERMIT_SEND_EOT 5 /* sendinf EOT */ |
| 62 | | |
| 63 | | /* packet retry parameters */ |
| 64 | | #define KERMIT_MAX_RETRIES 5 |
| 65 | | #define KERMIT_RETRY_DELAY attotime::from_seconds( 10 ) |
| 66 | | |
| 67 | | |
| 68 | | /* packet format is: |
| 69 | | |
| 70 | | <mark> <len> <seq> <type> <data0> ... <datan> <check> |
| 71 | | |
| 72 | | - <mark> KERMIT_SOH |
| 73 | | - <len> number of bytes after <len> (max=94), plus 32 |
| 74 | | - <seq> sequence number, modulo 63, plus 32 |
| 75 | | - <type> one of KERMIT_ packet types |
| 76 | | - <data> payload, with control characters escaped with KERMIT_QCTL |
| 77 | | - <check> checksum, from <len> to <datan>, excluding <mark> |
| 78 | | |
| 79 | | the packet may be followed by arbitrary (non KERMIT_SOH) data, not counted |
| 80 | | in <len>, <check>, and not interpreted |
| 81 | | there is generally at least one KERMIT_EOL |
| 82 | | */ |
| 83 | | |
| 84 | | typedef struct { |
| 85 | | |
| 86 | | UINT8 pin[1024]; /* packet received */ |
| 87 | | UINT8 pout[1024]; /* packet sent */ |
| 88 | | UINT32 seq; /* sequence number, starting at 0 */ |
| 89 | | UINT16 posin; /* position in pin */ |
| 90 | | UINT16 posout; /* position in pout */ |
| 91 | | UINT16 nbout; /* size of pout */ |
| 92 | | |
| 93 | | UINT8 state; /* current protocol state */ |
| 94 | | UINT8 retries; /* packet retries remaining */ |
| 95 | | |
| 96 | | /* (relevant) configuration information, sent in S and D packet */ |
| 97 | | UINT8 maxl; /* max packet length (value of <len>) */ |
| 98 | | UINT8 npad; /* number of padding characters before packet */ |
| 99 | | UINT8 padc; /* padding character */ |
| 100 | | UINT8 eol; /* character to add after packet */ |
| 101 | | UINT8 qctl; /* escape character */ |
| 102 | | |
| 103 | | emu_timer* resend; /* auto-resend packet */ |
| 104 | | |
| 105 | | device_image_interface* image; /* underlying image */ |
| 106 | | |
| 107 | | running_machine *machine; |
| 108 | | kermit_config* conf; |
| 109 | | |
| 110 | | } kermit; |
| 111 | | |
| 112 | | |
| 113 | | INLINE kermit *get_safe_token(device_t *device) |
| 114 | | { |
| 115 | | assert(device != NULL); |
| 116 | | assert(device->type() == KERMIT); |
| 117 | | |
| 118 | | return (kermit*)downcast<legacy_device_base *>(device)->token(); |
| 119 | | } |
| 120 | | |
| 121 | | static int kermit_is_char( UINT8 data ) |
| 122 | | { |
| 123 | | return data >= 32 && data <= 126; |
| 124 | | } |
| 125 | | |
| 126 | | |
| 127 | | static UINT8 kermit_tochar( UINT8 data ) |
| 128 | | { |
| 129 | | if ( data > 94 ) |
| 130 | | { |
| 131 | | logerror( "kermit: tochar: %i not in the range 0-94\n", data ); |
| 132 | | } |
| 133 | | return data + 32; |
| 134 | | } |
| 135 | | |
| 136 | | static UINT8 kermit_unchar( UINT8 data ) |
| 137 | | { |
| 138 | | if ( data < 32 || data > 126 ) |
| 139 | | { |
| 140 | | logerror( "kermit: unchar: %i not in the range 32-126\n", data ); |
| 141 | | } |
| 142 | | return data - 32; |
| 143 | | } |
| 144 | | |
| 145 | | #define kermit_ctl(x) ((x) ^ 0x40) |
| 146 | | |
| 147 | | static int kermit_is_ctl( UINT8 x ) |
| 148 | | { |
| 149 | | x &= 0x7f; |
| 150 | | return (x < 32) || (x == 127); |
| 151 | | } |
| 152 | | |
| 153 | | static UINT8 kermit_checksum( UINT8* packet ) |
| 154 | | { |
| 155 | | int i, len = kermit_unchar( packet[1] ); |
| 156 | | UINT8 sum = 0; |
| 157 | | for ( i = 0; i < len; i++ ) |
| 158 | | sum += packet[ i + 1 ]; |
| 159 | | sum = kermit_tochar( (sum + (sum >> 6)) & 63 ); |
| 160 | | return sum; |
| 161 | | } |
| 162 | | |
| 163 | | /* starts sending a new packet */ |
| 164 | | static void kermit_start_sending( kermit* state ) |
| 165 | | { |
| 166 | | int i; |
| 167 | | |
| 168 | | for (i=1;i<state->nbout;i++) |
| 169 | | if (kermit_is_ctl(state->pout[i])) |
| 170 | | logerror( "send: not char %i at pos %i\n", state->pout[i], i ); |
| 171 | | |
| 172 | | if ( state->nbout <= 0 ) return; |
| 173 | | |
| 174 | | /* prepend padding and append eol */ |
| 175 | | if ( state->npad > 0 ) |
| 176 | | { |
| 177 | | memmove( state->pout + state->npad, state->pout, state->nbout ); |
| 178 | | memset( state->pout, state->padc, state->npad ); |
| 179 | | state->nbout += state->npad; |
| 180 | | } |
| 181 | | state->pout[ state->nbout ] = state->eol; |
| 182 | | state->nbout++; |
| 183 | | |
| 184 | | if ( state->conf && state->conf->send ) |
| 185 | | { |
| 186 | | state->conf->send( *state->machine, state->pout[ 0 ] ); |
| 187 | | } |
| 188 | | state->posout = 1; |
| 189 | | |
| 190 | | state->retries = KERMIT_MAX_RETRIES; |
| 191 | | state->resend->adjust( KERMIT_RETRY_DELAY, 0, KERMIT_RETRY_DELAY ); |
| 192 | | } |
| 193 | | |
| 194 | | static void kermit_reset( kermit* state ); |
| 195 | | |
| 196 | | static void kermit_resend( kermit* state ) |
| 197 | | { |
| 198 | | if ( state->conf && state->conf->send ) |
| 199 | | { |
| 200 | | /* retry */ |
| 201 | | if ( state->nbout == 0 ) return; |
| 202 | | if ( state->retries <= 0 ) |
| 203 | | { |
| 204 | | kermit_reset( state ); |
| 205 | | return; |
| 206 | | } |
| 207 | | |
| 208 | | state->conf->send( *state->machine, state->pout[ 0 ] ); |
| 209 | | |
| 210 | | state->posout = 1; |
| 211 | | state->retries--; |
| 212 | | LOG(( "kermit: resend packet (%i tries left)\n", state->retries )); |
| 213 | | } |
| 214 | | } |
| 215 | | |
| 216 | | /* resend packet periodically */ |
| 217 | | static TIMER_CALLBACK( kermit_resend_cb ) |
| 218 | | { |
| 219 | | kermit* state = (kermit*) ptr; |
| 220 | | if ( state->posout >= state->nbout) |
| 221 | | { |
| 222 | | kermit_resend( state ); |
| 223 | | } |
| 224 | | } |
| 225 | | |
| 226 | | /* fetches image data and wrap it into a kermit data packet */ |
| 227 | | static void kermit_send_data_packet( kermit* state ) |
| 228 | | { |
| 229 | | int len; |
| 230 | | LOG(( "kermit: send data packet\n" )); |
| 231 | | for ( len = 2; len < state->maxl-2; len++ ) |
| 232 | | { |
| 233 | | UINT8 c; |
| 234 | | if ( state->image->image_feof() ) break; |
| 235 | | c = state->image->fgetc(); |
| 236 | | if ( kermit_is_ctl( c ) ) |
| 237 | | { |
| 238 | | /* escape control char */ |
| 239 | | state->pout[ 2 + len ] = state->qctl; |
| 240 | | len++; |
| 241 | | state->pout[ 2 + len ] = kermit_ctl( c ); |
| 242 | | } |
| 243 | | else if ( (c & 0x7f) == state->qctl ) |
| 244 | | { |
| 245 | | /* escape escape char */ |
| 246 | | state->pout[ 2 + len ] = state->qctl; |
| 247 | | len++; |
| 248 | | state->pout[ 2 + len ] = c; |
| 249 | | } |
| 250 | | else |
| 251 | | { |
| 252 | | state->pout[ 2 + len ] = c; |
| 253 | | } |
| 254 | | } |
| 255 | | state->pout[ 0 ] = KERMIT_SOH; |
| 256 | | state->pout[ 1 ] = kermit_tochar( len + 1 ); |
| 257 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
| 258 | | state->pout[ 3 ] = KERMIT_DATA; |
| 259 | | state->pout[ 2 + len ] = kermit_checksum( state->pout ); |
| 260 | | state->nbout = len + 3; |
| 261 | | kermit_start_sending( state ); |
| 262 | | } |
| 263 | | |
| 264 | | /* write data from packet to the image */ |
| 265 | | static void kermit_write_data_packet( kermit* state ) |
| 266 | | { |
| 267 | | int i, len = kermit_unchar( state->pin[1] ); |
| 268 | | LOG(( "kermit: received data pack, len=%i\n", len )); |
| 269 | | for ( i = 4; i <= len; i++ ) |
| 270 | | { |
| 271 | | UINT8 c = state->pin[i]; |
| 272 | | if ( (c /*& 0x7f*/) == state->qctl ) |
| 273 | | { |
| 274 | | /* unescape */ |
| 275 | | i++; |
| 276 | | c = state->pin[i]; |
| 277 | | if ( kermit_is_ctl( kermit_ctl( c ) ) ) |
| 278 | | { |
| 279 | | c = kermit_ctl( c ); |
| 280 | | } |
| 281 | | } |
| 282 | | state->image->fwrite(&c, 1 ); |
| 283 | | } |
| 284 | | } |
| 285 | | |
| 286 | | /* validate received packet and acquire seq number, <0 if error */ |
| 287 | | static int kermit_validate_packet( kermit* state ) |
| 288 | | { |
| 289 | | int len; |
| 290 | | if ( state->pin[ 0 ] != KERMIT_SOH ) return -1; |
| 291 | | if ( !kermit_is_char( state->pin[1] ) ) return -1; |
| 292 | | if ( !kermit_is_char( state->pin[2] ) ) return -1; |
| 293 | | len = kermit_unchar( state->pin[1] ); |
| 294 | | if ( state->pin[ 1 + len ] != kermit_checksum( state->pin ) ) return -1; |
| 295 | | return 0; |
| 296 | | } |
| 297 | | |
| 298 | | /* interpret configuration packet, <0 if error */ |
| 299 | | static int kermit_get_conf( kermit* state ) |
| 300 | | { |
| 301 | | int len = kermit_unchar( state->pin[1] ); |
| 302 | | if ( len >= 4 ) state->maxl = kermit_unchar( state->pin[ 4 ] ); |
| 303 | | if ( len >= 6 ) state->npad = kermit_unchar( state->pin[ 6 ] ); |
| 304 | | if ( len >= 7 ) state->padc = kermit_ctl( state->pin[ 7 ] ); |
| 305 | | if ( len >= 8 ) state->eol = kermit_unchar( state->pin[ 8 ] ); |
| 306 | | if ( len >= 9 ) state->qctl = state->pin[ 9 ]; |
| 307 | | |
| 308 | | LOG(( "kermit: get conf: len=%i, maxl=%i, npad=%i, padc=%i, eol=%i, qctl=%i\n", |
| 309 | | len, state->maxl, state->npad, state->padc, state->eol, state->qctl )); |
| 310 | | |
| 311 | | /* validation */ |
| 312 | | if ( state->maxl < 10 || state->maxl > 94 ) return -1; |
| 313 | | return 0; |
| 314 | | } |
| 315 | | |
| 316 | | /* create a configuration packet, with header h */ |
| 317 | | static void kermit_send_conf_packet( kermit* state, UINT8 h ) |
| 318 | | { |
| 319 | | LOG(( "kermit: send conf packet of type %c\n", h )); |
| 320 | | state->seq = 0; |
| 321 | | state->pout[ 0 ] = KERMIT_SOH; |
| 322 | | state->pout[ 1 ] = kermit_tochar( 13 ); |
| 323 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
| 324 | | state->pout[ 3 ] = h; |
| 325 | | state->pout[ 4 ] = kermit_tochar( state->maxl ); /* maxl */ |
| 326 | | state->pout[ 5 ] = kermit_tochar( 1 ); /* time: 1 sec */ |
| 327 | | state->pout[ 6 ] = kermit_tochar( state->npad ); /* npad */ |
| 328 | | state->pout[ 7 ] = kermit_ctl( state->padc ); /* padc */ |
| 329 | | state->pout[ 8 ] = kermit_tochar( state->eol ); /* eol */ |
| 330 | | state->pout[ 9 ] = state->qctl; /* qtcl */ |
| 331 | | state->pout[ 10 ] = 'N'; /* qbin: no 8-bit quoting */ |
| 332 | | state->pout[ 11 ] = '1'; /* chkt: single character checksum */ |
| 333 | | state->pout[ 12 ] = ' '; /* rept: no repeat count */ |
| 334 | | state->pout[ 13 ] = kermit_tochar( 0 ); /* capas: no capabilities */ |
| 335 | | state->pout[ 14 ] = kermit_checksum( state->pout ); |
| 336 | | state->nbout = 15; |
| 337 | | kermit_start_sending( state ); |
| 338 | | } |
| 339 | | |
| 340 | | /* sends a packet with no data */ |
| 341 | | static void kermit_send_simple_packet( kermit* state, UINT8 h ) |
| 342 | | { |
| 343 | | LOG(( "kermit: send empty packet of type %c, seq=%i\n", h, state->seq & 63 )); |
| 344 | | state->pout[ 0 ] = KERMIT_SOH; |
| 345 | | state->pout[ 1 ] = kermit_tochar( 3 ); |
| 346 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
| 347 | | state->pout[ 3 ] = h; |
| 348 | | state->pout[ 4 ] = kermit_checksum( state->pout ); |
| 349 | | state->nbout = 5; |
| 350 | | kermit_start_sending( state ); |
| 351 | | } |
| 352 | | |
| 353 | | /* sends a packet with string data */ |
| 354 | | static void kermit_send_string_packet( kermit* state, UINT8 h, const char* data ) |
| 355 | | { |
| 356 | | int i, len; |
| 357 | | LOG(( "kermit: send string packet of type %c, data=%s, seq=%i\n", h, data, state->seq & 63 )); |
| 358 | | for ( len = i = 0; (len < state->maxl - 5) && data[i]; i++ ) |
| 359 | | { |
| 360 | | char c = data[i]; |
| 361 | | if ( kermit_is_char( c ) && ( c != '_' ) && ( c != ' ' ) ) |
| 362 | | { |
| 363 | | state->pout[ 4 + len ] = c; |
| 364 | | len++; |
| 365 | | } |
| 366 | | } |
| 367 | | state->pout[ 0 ] = KERMIT_SOH; |
| 368 | | state->pout[ 1 ] = kermit_tochar( len + 3 ); |
| 369 | | state->pout[ 2 ] = kermit_tochar( state->seq & 63 ); |
| 370 | | state->pout[ 3 ] = h; |
| 371 | | state->pout[ 4 + len ] = kermit_checksum( state->pout ); |
| 372 | | state->nbout = len + 5; |
| 373 | | kermit_start_sending( state ); |
| 374 | | } |
| 375 | | |
| 376 | | /* extract the string contained in received packet */ |
| 377 | | static char* kermit_string_in_packet( kermit* state ) |
| 378 | | { |
| 379 | | int len = kermit_unchar( state->pin[1] ); |
| 380 | | state->pin[ len + 1 ] = 0; |
| 381 | | return (char*) state->pin + 4; |
| 382 | | } |
| 383 | | |
| 384 | | static void kermit_reset( kermit* state ) |
| 385 | | { |
| 386 | | /* default config */ |
| 387 | | state->maxl = KERMIT_MAXL; |
| 388 | | state->npad = 0; |
| 389 | | state->padc = 0; |
| 390 | | state->eol = KERMIT_EOL; |
| 391 | | state->qctl = KERMIT_QCTL; |
| 392 | | |
| 393 | | state->retries = KERMIT_MAX_RETRIES; |
| 394 | | state->posin = 0; |
| 395 | | state->posout = 0; |
| 396 | | state->nbout = 0; |
| 397 | | state->state = KERMIT_IDLE; |
| 398 | | state->seq = 0; |
| 399 | | |
| 400 | | if ( state->image ) |
| 401 | | { |
| 402 | | state->image->fseek( SEEK_SET, 0 ); |
| 403 | | } |
| 404 | | |
| 405 | | state->resend->adjust( attotime::never, 0, attotime::never ); |
| 406 | | } |
| 407 | | |
| 408 | | |
| 409 | | /* emulated machine sends a byte to the outside (us) */ |
| 410 | | void kermit_receive_byte( device_t *device, UINT8 data ) |
| 411 | | { |
| 412 | | kermit* state = get_safe_token(device); |
| 413 | | |
| 414 | | LOG(( "get %i %2x %c (%i)\n", data, data, data, state->posin )); |
| 415 | | |
| 416 | | /* get SOH */ |
| 417 | | if ( (data == KERMIT_SOH) && (state->posin <= 1) ) |
| 418 | | { |
| 419 | | state->pin[ 0 ] = data; |
| 420 | | state->posin = 1; |
| 421 | | } |
| 422 | | |
| 423 | | /* get packet contents */ |
| 424 | | else if ( state->posin > 0 ) |
| 425 | | { |
| 426 | | if ( state->posin >= sizeof( state->pout ) ) |
| 427 | | { |
| 428 | | LOG(( "kermit: too many bytes received\n" )); |
| 429 | | state->posin = 0; |
| 430 | | kermit_send_simple_packet( state, KERMIT_NAK ); |
| 431 | | return; |
| 432 | | } |
| 433 | | |
| 434 | | if (kermit_is_ctl(data)) |
| 435 | | logerror( "received: not char %i at pos %i\n", data, state->posin ); |
| 436 | | |
| 437 | | state->pin[ state->posin ] = data; |
| 438 | | state->posin++; |
| 439 | | |
| 440 | | if ( state->posin > 5 ) |
| 441 | | { |
| 442 | | int len, seq, typ; |
| 443 | | if ( !kermit_is_char( state->pin[1] ) || |
| 444 | | (kermit_unchar( state->pin[1] ) < 3) || |
| 445 | | (kermit_unchar( state->pin[1] ) > state->maxl) ) |
| 446 | | { |
| 447 | | LOG(( "kermit: invalid packet size %i-32, not in 3-%i\n", state->pin[1], state->maxl )); |
| 448 | | kermit_resend( state ); |
| 449 | | return; |
| 450 | | } |
| 451 | | |
| 452 | | len = kermit_unchar( state->pin[1] ); |
| 453 | | |
| 454 | | if ( state->posin >= len + 2 ) |
| 455 | | { |
| 456 | | /* got packet! */ |
| 457 | | state->posin = 0; |
| 458 | | if ( kermit_validate_packet( state ) ) |
| 459 | | { |
| 460 | | LOG(( "kermit: invalid packet\n" )); |
| 461 | | kermit_resend( state ); |
| 462 | | return; |
| 463 | | } |
| 464 | | |
| 465 | | typ = state->pin[3]; |
| 466 | | seq = kermit_unchar( state->pin[2] ); |
| 467 | | |
| 468 | | LOG(( "kermit: received packet type=%c, seq=%i, len=%i\n", typ, seq, len )); |
| 469 | | |
| 470 | | if ( !state->image ) |
| 471 | | { |
| 472 | | kermit_send_string_packet( state, KERMIT_ERR, "NO IMAGE" ); |
| 473 | | return; |
| 474 | | } |
| 475 | | |
| 476 | | |
| 477 | | switch ( typ ) |
| 478 | | { |
| 479 | | |
| 480 | | /* receiving */ |
| 481 | | |
| 482 | | case KERMIT_SEND: |
| 483 | | kermit_get_conf( state ); |
| 484 | | if ( state->maxl >= KERMIT_MAXL ) |
| 485 | | { |
| 486 | | state->maxl = KERMIT_MAXL; |
| 487 | | } |
| 488 | | kermit_send_conf_packet( state, KERMIT_ACK ); |
| 489 | | state->state = KERMIT_RECEIVE; |
| 490 | | break; |
| 491 | | |
| 492 | | case KERMIT_FILE: |
| 493 | | LOG(( "kermit: got file name '%s'\n", kermit_string_in_packet( state ) )); |
| 494 | | state->seq = seq; |
| 495 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
| 496 | | break; |
| 497 | | |
| 498 | | case KERMIT_DATA: |
| 499 | | case KERMIT_EOF: |
| 500 | | if ( seq == ((state->seq + 1) & 63) ) |
| 501 | | { |
| 502 | | /* next packet */ |
| 503 | | if ( typ == KERMIT_DATA ) |
| 504 | | { |
| 505 | | kermit_write_data_packet( state ); |
| 506 | | } |
| 507 | | state->seq = seq; |
| 508 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
| 509 | | } |
| 510 | | else if ( seq == (state->seq & 63) ) |
| 511 | | { |
| 512 | | /* same packet */ |
| 513 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
| 514 | | } |
| 515 | | else |
| 516 | | { |
| 517 | | /* unexpected sequence number */ |
| 518 | | LOG(( "kermit: got seq=%i, expected %i\n", seq, (state->seq + 1) & 63 )); |
| 519 | | state->seq++; |
| 520 | | kermit_send_simple_packet( state, KERMIT_NAK ); |
| 521 | | state->seq--; |
| 522 | | } |
| 523 | | break; |
| 524 | | |
| 525 | | case KERMIT_EOT: |
| 526 | | /* send ack and reset */ |
| 527 | | state->seq = seq; |
| 528 | | kermit_send_simple_packet( state, KERMIT_ACK ); |
| 529 | | state->state = KERMIT_RESET; |
| 530 | | break; |
| 531 | | |
| 532 | | |
| 533 | | /* sending */ |
| 534 | | |
| 535 | | case KERMIT_NAK: |
| 536 | | case KERMIT_ACK: |
| 537 | | |
| 538 | | if ( (typ == KERMIT_NAK) && (seq == 0) && (state->state == KERMIT_IDLE) ) |
| 539 | | { |
| 540 | | /* transfer start */ |
| 541 | | kermit_send_conf_packet( state, KERMIT_SEND ); |
| 542 | | break; |
| 543 | | } |
| 544 | | |
| 545 | | if ( ((seq == (state->seq & 63)) && (typ == KERMIT_ACK)) || |
| 546 | | ((seq == ((state->seq + 1) & 63)) && (typ == KERMIT_NAK)) ) |
| 547 | | { |
| 548 | | /* send next packet */ |
| 549 | | |
| 550 | | state->seq = state->seq + 1; |
| 551 | | |
| 552 | | switch ( state->state ) |
| 553 | | { |
| 554 | | case KERMIT_IDLE: |
| 555 | | /* get conf & send file name */ |
| 556 | | kermit_get_conf( state ); |
| 557 | | kermit_send_string_packet( state, KERMIT_FILE, state->image->basename() ); |
| 558 | | state->state = KERMIT_SEND_DATA; |
| 559 | | break; |
| 560 | | |
| 561 | | case KERMIT_SEND_DATA: |
| 562 | | /* send next data packet or EOF */ |
| 563 | | if ( state->image->image_feof() ) |
| 564 | | { |
| 565 | | kermit_send_simple_packet( state, KERMIT_EOF ); |
| 566 | | state->state = KERMIT_SEND_EOF; |
| 567 | | } |
| 568 | | else |
| 569 | | { |
| 570 | | kermit_send_data_packet( state ); |
| 571 | | } |
| 572 | | break; |
| 573 | | |
| 574 | | case KERMIT_SEND_EOF: |
| 575 | | /* send EOT */ |
| 576 | | kermit_send_simple_packet( state, KERMIT_EOT ); |
| 577 | | state->state = KERMIT_SEND_EOT; |
| 578 | | break; |
| 579 | | |
| 580 | | case KERMIT_SEND_EOT: |
| 581 | | /* reset */ |
| 582 | | kermit_reset( state ); |
| 583 | | state->state = KERMIT_RESET; |
| 584 | | break; |
| 585 | | |
| 586 | | } |
| 587 | | } |
| 588 | | |
| 589 | | else if ( (seq == (state->seq & 63)) && (typ == KERMIT_NAK) ) |
| 590 | | { |
| 591 | | /* resend last packet */ |
| 592 | | kermit_resend( state ); |
| 593 | | } |
| 594 | | else |
| 595 | | { |
| 596 | | /* bad */ |
| 597 | | LOG(( "kermit: expected to send %i, got seq=%i\n", (state->seq + 1) & 63, seq )); |
| 598 | | kermit_reset( state ); |
| 599 | | } |
| 600 | | break; |
| 601 | | |
| 602 | | /* errors */ |
| 603 | | |
| 604 | | case KERMIT_ERR: |
| 605 | | LOG(( "kermit: got error '%s'\n", kermit_string_in_packet( state ) )); |
| 606 | | state->seq = seq; |
| 607 | | kermit_reset( state ); |
| 608 | | break; |
| 609 | | |
| 610 | | default: |
| 611 | | LOG(( "kermit: ignoring packet type %c\n", state->pin[ 3 ] )); |
| 612 | | /* no abort, just ignoring */ |
| 613 | | } |
| 614 | | } |
| 615 | | } |
| 616 | | } |
| 617 | | } |
| 618 | | |
| 619 | | void kermit_byte_transmitted( device_t *device ) |
| 620 | | { |
| 621 | | kermit* state = get_safe_token(device); |
| 622 | | |
| 623 | | LOG(( "transmitted %i %2x %c, %i / %i\n", state->pout[ state->posout-1 ], state->pout[ state->posout-1 ], state->pout[ state->posout-1 ], state->posout - 1, state->nbout - 1 )); |
| 624 | | |
| 625 | | /* at end of packet */ |
| 626 | | if ( state->posout >= state->nbout ) |
| 627 | | { |
| 628 | | if ( state->state == KERMIT_RESET ) |
| 629 | | { |
| 630 | | kermit_reset( state ); |
| 631 | | } |
| 632 | | return; |
| 633 | | } |
| 634 | | |
| 635 | | if ( state->conf && state->conf->send ) |
| 636 | | { |
| 637 | | state->conf->send(*state->machine, state->pout[ state->posout ] ); |
| 638 | | } |
| 639 | | state->posout++; |
| 640 | | } |
| 641 | | |
| 642 | | static DEVICE_START( kermit ) |
| 643 | | { |
| 644 | | kermit* state = get_safe_token(device); |
| 645 | | LOG(( "kermit: start\n" )); |
| 646 | | state->image = NULL; |
| 647 | | state->conf = (kermit_config*) device->static_config(); |
| 648 | | state->machine = &device->machine(); |
| 649 | | state->resend = device->machine().scheduler().timer_alloc(FUNC(kermit_resend_cb), state ); |
| 650 | | kermit_reset( state ); |
| 651 | | } |
| 652 | | |
| 653 | | static DEVICE_RESET( kermit ) |
| 654 | | { |
| 655 | | kermit* state = get_safe_token(device); |
| 656 | | LOG(( "kermit: reset\n" )); |
| 657 | | kermit_reset( state ); |
| 658 | | } |
| 659 | | |
| 660 | | static DEVICE_IMAGE_LOAD( kermit ) |
| 661 | | { |
| 662 | | kermit* state = get_safe_token(&image.device()); |
| 663 | | LOG(( "kermit: image load\n" )); |
| 664 | | state->image = ℑ |
| 665 | | kermit_reset( state ); |
| 666 | | return IMAGE_INIT_PASS; |
| 667 | | } |
| 668 | | |
| 669 | | static DEVICE_IMAGE_CREATE( kermit ) |
| 670 | | { |
| 671 | | kermit* state = get_safe_token(&image.device()); |
| 672 | | LOG(( "kermit: image create\n" )); |
| 673 | | state->image = ℑ |
| 674 | | kermit_reset( state ); |
| 675 | | return IMAGE_INIT_PASS; |
| 676 | | } |
| 677 | | |
| 678 | | static DEVICE_IMAGE_UNLOAD( kermit ) |
| 679 | | { |
| 680 | | kermit* state = get_safe_token(&image.device()); |
| 681 | | LOG(( "kermit: image unload\n" )); |
| 682 | | state->image = NULL; |
| 683 | | kermit_reset( state ); |
| 684 | | } |
| 685 | | |
| 686 | | DEVICE_GET_INFO( kermit ) |
| 687 | | |
| 688 | | { |
| 689 | | switch ( state ) { |
| 690 | | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof( kermit ); break; |
| 691 | | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 692 | | case DEVINFO_INT_IMAGE_TYPE: info->i = IO_SERIAL; break; |
| 693 | | case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break; |
| 694 | | case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break; |
| 695 | | case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break; |
| 696 | | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( kermit ); break; |
| 697 | | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( kermit ); break; |
| 698 | | case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( kermit ); break; |
| 699 | | case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME( kermit ); break; |
| 700 | | case DEVINFO_FCT_IMAGE_CREATE: info->f = (genf *) DEVICE_IMAGE_CREATE_NAME( kermit ); break; |
| 701 | | case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "k"); break; |
| 702 | | case DEVINFO_STR_IMAGE_INSTANCE_NAME: |
| 703 | | case DEVINFO_STR_NAME: strcpy(info->s, "Kermit"); break; |
| 704 | | case DEVINFO_STR_FAMILY: strcpy(info->s, "Serial protocol"); break; |
| 705 | | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 706 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, ""); break; |
| 707 | | } |
| 708 | | } |
| 709 | | |
| 710 | | DEFINE_LEGACY_IMAGE_DEVICE(KERMIT, kermit); |
trunk/src/mess/audio/ted7360.c
| r17575 | r17576 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | TExt Display 7360 |
| 4 | | PeT mess@utanet.at |
| 5 | | |
| 6 | | |
| 7 | | 2010-02: Converted to be a device and merged video/audio emulation |
| 8 | | |
| 9 | | TODO: |
| 10 | | - Plenty of clean-ups |
| 11 | | |
| 12 | | ***************************************************************************/ |
| 13 | | /* |
| 14 | | Metal Oxid Semicontuctor MOS |
| 15 | | Commodore Business Machine CBM |
| 16 | | Textured Display Ted7360 |
| 17 | | ------------------------ |
| 18 | | |
| 19 | | 7360/8360 (NTSC-M, PAL-B by same chip ?) |
| 20 | | 8365 PAL-N |
| 21 | | 8366 PAL-M |
| 22 | | |
| 23 | | Ted7360 used in Commodore C16 |
| 24 | | Ted8360 used in Commodore C116/Plus4 |
| 25 | | should be 100% software compatible with Ted7360 |
| 26 | | |
| 27 | | video unit (without sprites), dram controller seams to be much like vic6567 |
| 28 | | |
| 29 | | PAL/NTSC variants |
| 30 | | |
| 31 | | functions of this chip: |
| 32 | | memory controller |
| 33 | | dram controller |
| 34 | | cpu clock generation with single and double clock switching |
| 35 | | 3 timer |
| 36 | | 1 8bit latched input |
| 37 | | 2 channel sound/noise generator |
| 38 | | video controller |
| 39 | | interrupt controller for timer and video |
| 40 | | |
| 41 | | Reasons for this document: |
| 42 | | document state in mess c16/plus4 emulator |
| 43 | | base to discuss ted7360 with others (i have no c16 computer anymore) |
| 44 | | |
| 45 | | pal: |
| 46 | | clock 17734470 |
| 47 | | divided by 5 for base clock (pixel clock changing edges?) |
| 48 | | 312 lines |
| 49 | | 50 hertz vertical refresh |
| 50 | | |
| 51 | | ntsc: |
| 52 | | clock 14318180 |
| 53 | | divided by 4 for base clock (pixel clock changing edges?) |
| 54 | | 262 lines |
| 55 | | 60 hertz vertical refresh |
| 56 | | |
| 57 | | registers: |
| 58 | | 0xff00 timer 1 low byte |
| 59 | | 0xff01 timer 1 high byte |
| 60 | | 0xff02 timer 2 low byte |
| 61 | | 0xff03 timer 2 high byte |
| 62 | | 0xff04 timer 3 low byte |
| 63 | | 0xff05 timer 3 high byte |
| 64 | | 0xff06 |
| 65 | | bit 7 test? |
| 66 | | bit 6 ecm on |
| 67 | | bit 5 hires on |
| 68 | | bit 4 screen on |
| 69 | | bit 3 25 raws (0 24 raws) |
| 70 | | bit 2-0 vertical position |
| 71 | | 0xff07 |
| 72 | | bit 7 reverse off (0 on) |
| 73 | | bit 6 read only NTSC (0 PAL) |
| 74 | | bit 5 freeze horicontal position? |
| 75 | | bit 4 multicolor on |
| 76 | | bit 3 40 columns (0 38 columns) |
| 77 | | bit 2-0 horicontal pos |
| 78 | | 0xff08 input latch (0 input low), write reloads latch |
| 79 | | 0xff09 interrupt request |
| 80 | | 7: interrupt |
| 81 | | 6: timer 3 |
| 82 | | 5: ? |
| 83 | | 4: timer 2 |
| 84 | | 3: timer 1 |
| 85 | | 2: lightpen |
| 86 | | 1: rasterline |
| 87 | | 0: 1 (asl quitting) |
| 88 | | 0xff0a interrupt enable |
| 89 | | 7: ? |
| 90 | | 6: timer 3 |
| 91 | | 5: ? |
| 92 | | 4: timer 2 |
| 93 | | 3: timer 1 |
| 94 | | 2: lightpen |
| 95 | | 1: rasterline |
| 96 | | 0: irq rasterline bit 8 |
| 97 | | 0xff0b |
| 98 | | 7-0: irq rasterline 7-0 |
| 99 | | 0xff0c |
| 100 | | 7-2: 1? |
| 101 | | 1,0: cursorpos bit 9,8 |
| 102 | | 0xff0d cursorpos bit 7-0 |
| 103 | | 0xff0e tone channel 1: frequency 7-0 |
| 104 | | 0xff0f tone channel 2: frequency 7-0 |
| 105 | | 0xff10 |
| 106 | | 7-2: ? |
| 107 | | 1,0: tone channel 2 bit 9,8 |
| 108 | | 0xff11 |
| 109 | | 7: sound reload |
| 110 | | 6: tone 2 noise on (tone 2 must be off for noise) |
| 111 | | 5: tone 2 tone on |
| 112 | | 4: tone 1 on |
| 113 | | 3-0: volume 8?-0 |
| 114 | | 0xff12 |
| 115 | | 7,6: ? |
| 116 | | 5-3: bitmap address bit 15-13 |
| 117 | | 2: bitmapmemory?, charactermemory in rom (0 ram) |
| 118 | | 1,0: tone 1 frequency bit 9,8 |
| 119 | | 0xff13 |
| 120 | | 7-2: chargen address bit 15-11 |
| 121 | | 2: chargen address bit 10 (only used when reverse is off) |
| 122 | | 1: single clock in overscan area (0 double clock) |
| 123 | | 0: ram (0)/rom status |
| 124 | | 0xff14 |
| 125 | | 7-2: video address bit 15-10 |
| 126 | | 1,0: ? |
| 127 | | 0xff15 |
| 128 | | 7: ? |
| 129 | | 6-0: backgroundcolor |
| 130 | | 0xff16 |
| 131 | | 7: ? |
| 132 | | 6-0: color1 |
| 133 | | 0xff17 |
| 134 | | 7: ? |
| 135 | | 6-0: color2 |
| 136 | | 0xff18 |
| 137 | | 7: ? |
| 138 | | 6-0: color3 |
| 139 | | 0xff19 |
| 140 | | 7: ? |
| 141 | | 6-0: framecolor |
| 142 | | 0xff1a |
| 143 | | 7-2: ? |
| 144 | | 1,0: bitmap reload(cursorpos2) bit 9-8 |
| 145 | | 0xff1b bitmap reload bit 7-0 |
| 146 | | 0xff1c |
| 147 | | 7-1: 1? (matrix expects this) |
| 148 | | 0: current rasterline bit 8 |
| 149 | | 0xff1d current rasterline bit 7-0 |
| 150 | | 0xff1e |
| 151 | | 7-0: current rastercolumn /2 (0 begin visible area?) |
| 152 | | 0xff1f cursorblink? |
| 153 | | 7: ? |
| 154 | | 6-3: blink counter |
| 155 | | 2-0: vsub |
| 156 | | 0xff3e write switches to rom |
| 157 | | 0xff3f write switches to dram |
| 158 | | |
| 159 | | memory controller |
| 160 | | 0x8000-0xfcff, 0xff20-0xffff |
| 161 | | read selection between dram and rom |
| 162 | | 0xff3e-0xff3f write nothing (would change main memory in 16k ram c16) |
| 163 | | |
| 164 | | clock generator |
| 165 | | in displayed area ted need 3 memory cycles to get data for video chip |
| 166 | | memory system runs at approximately 4 megahertz |
| 167 | | so only 1 megahertz is available for the cpu |
| 168 | | in the other area the clock can be doubled for the cpu |
| 169 | | |
| 170 | | dram controller |
| 171 | | generator of refresh cycles |
| 172 | | when are these occuring? |
| 173 | | vic6567 in each rasterline reads 5 refresh addresses |
| 174 | | |
| 175 | | sound generator |
| 176 | | 2 channels |
| 177 | | channel 2 can be switched to generate noise |
| 178 | | volume control (0-8?) |
| 179 | | tone reload bit? |
| 180 | | samples ton/noise? |
| 181 | | frequency=(base clock/32)/(1024-value) |
| 182 | | |
| 183 | | timer |
| 184 | | timer count down |
| 185 | | when reaching 0 |
| 186 | | they restart from 0xffff |
| 187 | | set the interrupt request flag |
| 188 | | writing to low byte stops timer |
| 189 | | writing to high byte restarts timer with current value |
| 190 | | |
| 191 | | interrupt controller |
| 192 | | interrupt sources must be enabled in the enable register to generate |
| 193 | | an interrupt |
| 194 | | request flag are set also when not enabled |
| 195 | | interrupt is generated when rising edge on request and enable |
| 196 | | quitting of interrupt is done via writing 1 to the request bit |
| 197 | | what happens with request interrupts when the are enabled? |
| 198 | | |
| 199 | | Video part |
| 200 | | colors |
| 201 | | bit 3-0 color |
| 202 | | black, white, red, cyan |
| 203 | | purple, green, blue, yellow |
| 204 | | orange, light orange, pink, light cyan, |
| 205 | | light violett, light green, light blue, light yellow |
| 206 | | bit 6-4 luminance (0 dark) |
| 207 | | r,g,b values from 0 to 127 |
| 208 | | taken from digitized tv screen shot |
| 209 | | 0x06,0x01,0x03, 0x2b,0x2b,0x2b, 0x67,0x0e,0x0f, 0x00,0x3f,0x42, |
| 210 | | 0x57,0x00,0x6d, 0x00,0x4e,0x00, 0x19,0x1c,0x94, 0x38,0x38,0x00, |
| 211 | | 0x56,0x20,0x00, 0x4b,0x28,0x00, 0x16,0x48,0x00, 0x69,0x07,0x2f, |
| 212 | | 0x00,0x46,0x26, 0x06,0x2a,0x80, 0x2a,0x14,0x9b, 0x0b,0x49,0x00, |
| 213 | | |
| 214 | | 0x00,0x03,0x02, 0x3d,0x3d,0x3d, 0x75,0x1e,0x20, 0x00,0x50,0x4f, |
| 215 | | 0x6a,0x10,0x78, 0x04,0x5c,0x00, 0x2a,0x2a,0xa3, 0x4c,0x47,0x00, |
| 216 | | 0x69,0x2f,0x00, 0x59,0x38,0x00, 0x26,0x56,0x00, 0x75,0x15,0x41, |
| 217 | | 0x00,0x58,0x3d, 0x15,0x3d,0x8f, 0x39,0x22,0xae, 0x19,0x59,0x00, |
| 218 | | |
| 219 | | 0x00,0x03,0x04, 0x42,0x42,0x42, 0x7b,0x28,0x20, 0x02,0x56,0x59, |
| 220 | | 0x6f,0x1a,0x82, 0x0a,0x65,0x09, 0x30,0x34,0xa7, 0x50,0x51,0x00, |
| 221 | | 0x6e,0x36,0x00, 0x65,0x40,0x00, 0x2c,0x5c,0x00, 0x7d,0x1e,0x45, |
| 222 | | 0x01,0x61,0x45, 0x1c,0x45,0x99, 0x42,0x2d,0xad, 0x1d,0x62,0x00, |
| 223 | | |
| 224 | | 0x05,0x00,0x02, 0x56,0x55,0x5a, 0x90,0x3c,0x3b, 0x17,0x6d,0x72, |
| 225 | | 0x87,0x2d,0x99, 0x1f,0x7b,0x15, 0x46,0x49,0xc1, 0x66,0x63,0x00, |
| 226 | | 0x84,0x4c,0x0d, 0x73,0x55,0x00, 0x40,0x72,0x00, 0x91,0x33,0x5e, |
| 227 | | 0x19,0x74,0x5c, 0x32,0x59,0xae, 0x59,0x3f,0xc3, 0x32,0x76,0x00, |
| 228 | | |
| 229 | | 0x02,0x01,0x06, 0x84,0x7e,0x85, 0xbb,0x67,0x68, 0x45,0x96,0x96, |
| 230 | | 0xaf,0x58,0xc3, 0x4a,0xa7,0x3e, 0x73,0x73,0xec, 0x92,0x8d,0x11, |
| 231 | | 0xaf,0x78,0x32, 0xa1,0x80,0x20, 0x6c,0x9e,0x12, 0xba,0x5f,0x89, |
| 232 | | 0x46,0x9f,0x83, 0x61,0x85,0xdd, 0x84,0x6c,0xef, 0x5d,0xa3,0x29, |
| 233 | | |
| 234 | | 0x02,0x00,0x0a, 0xb2,0xac,0xb3, 0xe9,0x92,0x92, 0x6c,0xc3,0xc1, |
| 235 | | 0xd9,0x86,0xf0, 0x79,0xd1,0x76, 0x9d,0xa1,0xff, 0xbd,0xbe,0x40, |
| 236 | | 0xdc,0xa2,0x61, 0xd1,0xa9,0x4c, 0x93,0xc8,0x3d, 0xe9,0x8a,0xb1, |
| 237 | | 0x6f,0xcd,0xab, 0x8a,0xb4,0xff, 0xb2,0x9a,0xff, 0x88,0xcb,0x59, |
| 238 | | |
| 239 | | 0x02,0x00,0x0a, 0xc7,0xca,0xc9, 0xff,0xac,0xac, 0x85,0xd8,0xe0, |
| 240 | | 0xf3,0x9c,0xff, 0x92,0xea,0x8a, 0xb7,0xba,0xff, 0xd6,0xd3,0x5b, |
| 241 | | 0xf3,0xbe,0x79, 0xe6,0xc5,0x65, 0xb0,0xe0,0x57, 0xff,0xa4,0xcf, |
| 242 | | 0x89,0xe5,0xc8, 0xa4,0xca,0xff, 0xca,0xb3,0xff, 0xa2,0xe5,0x7a, |
| 243 | | |
| 244 | | 0x01,0x01,0x01, 0xff,0xff,0xff, 0xff,0xf6,0xf2, 0xd1,0xff,0xff, |
| 245 | | 0xff,0xe9,0xff, 0xdb,0xff,0xd3, 0xfd,0xff,0xff, 0xff,0xff,0xa3, |
| 246 | | 0xff,0xff,0xc1, 0xff,0xff,0xb2, 0xfc,0xff,0xa2, 0xff,0xee,0xff, |
| 247 | | 0xd1,0xff,0xff, 0xeb,0xff,0xff, 0xff,0xf8,0xff, 0xed,0xff,0xbc |
| 248 | | |
| 249 | | video generation |
| 250 | | column counter from 0 to 39 |
| 251 | | line counter from 0 to 199 |
| 252 | | |
| 253 | | character pointer position/hires: color 0-15 position |
| 254 | | videoaddr+0x400+(line/8)*40+column |
| 255 | | color position/hires: color luminance position |
| 256 | | videoaddr+(line/8)*40+column |
| 257 | | character bitmap position |
| 258 | | chargenaddr+(character pointer)+(line&7) |
| 259 | | bitmap position |
| 260 | | bitmapaddr+(line/8)*40+column+(line&7) |
| 261 | | |
| 262 | | normal text mode (reverse off, ecm off, multicolor off, hires off) |
| 263 | | character pointer based |
| 264 | | fetch character pointer, fetch character bitmap, fetch color |
| 265 | | pixel on color (color)&0x7f |
| 266 | | pixel off color backgroundcolor |
| 267 | | blinking (synchron to cursor) (color&0x80) |
| 268 | | reverse text mode (reverse on, ecm off, multicolor off, hires off) |
| 269 | | character pointer &0x7f |
| 270 | | character pointer bit 7 |
| 271 | | set |
| 272 | | pixel off color attribut &0x7f |
| 273 | | pixel on color backgroundcolor |
| 274 | | clear |
| 275 | | like normal text mode |
| 276 | | blinking (synchron to cursor) (color&0x80) |
| 277 | | multicolor text mode (ecm off, multicolor on, hires off) |
| 278 | | reverse ? |
| 279 | | attribut bit 3 character in multicolor (else monocolor character) |
| 280 | | pixel on color attribut 0x77 |
| 281 | | 0 backgroundcolor |
| 282 | | 1 color1 |
| 283 | | 2 color2 |
| 284 | | 3 attribut &0x77 |
| 285 | | (color&0x80) ? |
| 286 | | ecm text mode (ecm on) |
| 287 | | reverse ? |
| 288 | | multicolor ? (c64/vic6567 black display?) |
| 289 | | hires ? (c64/vic6567 black display?) |
| 290 | | character pointer &0x3f |
| 291 | | character pointer bit 7,6 select pixel off color |
| 292 | | 0 backgroundcolor ? |
| 293 | | 1 color1? |
| 294 | | 2 color2? |
| 295 | | 3 color3? |
| 296 | | (color&0x80)? |
| 297 | | hires (ecm off, multicolor off, hires on) |
| 298 | | bitmap based |
| 299 | | fetch bitmap, fetch color, fetch color luminance |
| 300 | | reverse ? |
| 301 | | pixel on color |
| 302 | | 6-4: (color luminance) bit 2-0 |
| 303 | | 3-0: (color) bit 7-4 |
| 304 | | pixel off color |
| 305 | | 6-4: (color luminance) bit 6-4 |
| 306 | | 3-0: (color) bit 3-0 |
| 307 | | (color) bit 7? |
| 308 | | (color luminance) bit 7? |
| 309 | | hires multicolor (ecm off, multicolor on, hires on) |
| 310 | | reverse ? |
| 311 | | 0 backgroundcolor |
| 312 | | 1 |
| 313 | | 6-4: (color luminance) bit 2-0 |
| 314 | | 3-0: (color) bit 7-4 |
| 315 | | 2 |
| 316 | | 6-4: (color luminance) bit 6-4 |
| 317 | | 3-0: (color) bit 3-0 |
| 318 | | 3 color1 |
| 319 | | (color) bit 7? |
| 320 | | (color luminance) bit 7? |
| 321 | | scrolling support |
| 322 | | visible part of the display in fixed position |
| 323 | | columns 38 mode left 7 and right 9 pixel less displayed |
| 324 | | but line generation start at the same position as in columns 40 mode |
| 325 | | lines25 flag top and bottom 4 pixel less displayed ? |
| 326 | | horicontal scrolling support |
| 327 | | in columns 38 mode |
| 328 | | horicontal position 1-7: pixel later started line generation |
| 329 | | horicontal position 0: 8 pixels later started line generation |
| 330 | | in columns 40 mode ? |
| 331 | | vertical scrolling support |
| 332 | | in lines 24 mode |
| 333 | | vertical position 1-7: lines later started line generation |
| 334 | | vertical position 0: 8 lines later started line generation |
| 335 | | in lines 25 mode? |
| 336 | | vertial position 3: for correct display |
| 337 | | |
| 338 | | hardware cursor |
| 339 | | full 8x8 in (color) color |
| 340 | | flashing when in multicolor, hires ? |
| 341 | | flashes with about 1 hertz |
| 342 | | bitmap reload? |
| 343 | | |
| 344 | | rasterline/rastercolumn |
| 345 | | values in registers begin visible area 0 |
| 346 | | vic 6567 |
| 347 | | pal line 0 beginning of vertical refresh |
| 348 | | ntsc line 0 in bottom frame |
| 349 | | beginning of 25 lines screen 0x33 (24 lines screen 0x37) |
| 350 | | beginning of 40 columns line 0x18 (38 columns 0x1f) |
| 351 | | |
| 352 | | lightpen |
| 353 | | (where to store values?) |
| 354 | | i found a lightpen hardware description with a demo and drawing program |
| 355 | | lightpen must be connected to joy0 (button) |
| 356 | | demo program: |
| 357 | | disables interrupt, polles joy0 button (0xfd0d? plus 4 related???) |
| 358 | | and reads the rasterline value! |
| 359 | | so i no exact column value reachable! |
| 360 | | */ |
| 361 | | #include "emu.h" |
| 362 | | #include "audio/ted7360.h" |
| 363 | | |
| 364 | | |
| 365 | | typedef struct _ted7360_state ted7360_state; |
| 366 | | struct _ted7360_state |
| 367 | | { |
| 368 | | ted_type type; |
| 369 | | |
| 370 | | screen_device *screen; // screen which sets bitmap properties |
| 371 | | |
| 372 | | UINT8 reg[0x20]; |
| 373 | | |
| 374 | | bitmap_ind16 *bitmap; |
| 375 | | |
| 376 | | int rom; |
| 377 | | |
| 378 | | int frame_count; |
| 379 | | |
| 380 | | int lines; |
| 381 | | int timer1_active, timer2_active, timer3_active; |
| 382 | | emu_timer *timer1, *timer2, *timer3; |
| 383 | | int cursor1; |
| 384 | | |
| 385 | | ted7360_dma_read dma_read; |
| 386 | | ted7360_dma_read_rom dma_read_rom; |
| 387 | | ted7360_irq interrupt; // c16_interrupt |
| 388 | | ted7360_key_cb keyboard_cb; // c16_read_keyboard |
| 389 | | |
| 390 | | int chargenaddr, bitmapaddr, videoaddr; |
| 391 | | |
| 392 | | int x_begin, x_end; |
| 393 | | int y_begin, y_end; |
| 394 | | |
| 395 | | UINT16 c16_bitmap[2], bitmapmulti[4], mono[2], monoinversed[2], multi[4], ecmcolor[2], colors[5]; |
| 396 | | |
| 397 | | int rasterline, lastline; |
| 398 | | double rastertime; |
| 399 | | |
| 400 | | |
| 401 | | /* sound part */ |
| 402 | | int tone1pos, tone2pos, |
| 403 | | tone1samples, tone2samples, |
| 404 | | noisesize, /* number of samples */ |
| 405 | | noisepos, /* pos of tone */ |
| 406 | | noisesamples; /* count of samples to give out per tone */ |
| 407 | | |
| 408 | | sound_stream *channel; |
| 409 | | UINT8 *noise; |
| 410 | | }; |
| 411 | | |
| 412 | | /***************************************************************************** |
| 413 | | CONSTANTS |
| 414 | | *****************************************************************************/ |
| 415 | | |
| 416 | | |
| 417 | | #define VERBOSE_LEVEL 0 |
| 418 | | #define DBG_LOG(N,M,A) \ |
| 419 | | do { \ |
| 420 | | if(VERBOSE_LEVEL >= N) \ |
| 421 | | { \ |
| 422 | | if( M ) \ |
| 423 | | logerror("%11.6f: %-24s", device->machine().time().as_double(), (char*) M ); \ |
| 424 | | logerror A; \ |
| 425 | | } \ |
| 426 | | } while(0) |
| 427 | | |
| 428 | | |
| 429 | | #define VREFRESHINLINES 28 |
| 430 | | |
| 431 | | #define TIMER1HELPER (ted7360->reg[0] | (ted7360->reg[1] << 8)) |
| 432 | | #define TIMER2HELPER (ted7360->reg[2] | (ted7360->reg[3] << 8)) |
| 433 | | #define TIMER3HELPER (ted7360->reg[4] | (ted7360->reg[5] << 8)) |
| 434 | | #define TIMER1 (TIMER1HELPER ? TIMER1HELPER : 0x10000) |
| 435 | | #define TIMER2 (TIMER2HELPER ? TIMER2HELPER : 0x10000) |
| 436 | | #define TIMER3 (TIMER3HELPER ? TIMER3HELPER : 0x10000) |
| 437 | | |
| 438 | | #define TED7360_YPOS 40 |
| 439 | | #define RASTERLINE_2_C16(a) ((a + ted7360->lines - TED7360_YPOS - 5) % ted7360->lines) |
| 440 | | #define C16_2_RASTERLINE(a) ((a + TED7360_YPOS + 5) % ted7360->lines) |
| 441 | | #define XPOS 8 |
| 442 | | #define YPOS 8 |
| 443 | | |
| 444 | | #define SCREENON (ted7360->reg[6] & 0x10) |
| 445 | | #define TEST (ted7360->reg[6] & 0x80) |
| 446 | | #define VERTICALPOS (ted7360->reg[6] & 0x07) |
| 447 | | #define HORICONTALPOS (ted7360->reg[7] & 0x07) |
| 448 | | #define ECMON (ted7360->reg[6] & 0x40) |
| 449 | | #define HIRESON (ted7360->reg[6] & 0x20) |
| 450 | | #define MULTICOLORON (ted7360->reg[7] & 0x10) |
| 451 | | #define REVERSEON (!(ted7360->reg[7] & 0x80)) |
| 452 | | |
| 453 | | /* hardware inverts character when bit 7 set (character taken &0x7f) */ |
| 454 | | /* instead of fetching character with higher number! */ |
| 455 | | #define LINES25 (ted7360->reg[6] & 0x08) /* else 24 Lines */ |
| 456 | | #define LINES (LINES25 ? 25 : 24) |
| 457 | | #define YSIZE (LINES * 8) |
| 458 | | #define COLUMNS40 (ted7360->reg[7] & 0x08) /* else 38 Columns */ |
| 459 | | #define COLUMNS (COLUMNS40 ? 40 : 38) |
| 460 | | #define XSIZE (COLUMNS * 8) |
| 461 | | |
| 462 | | #define INROM (ted7360->reg[0x12] & 0x04) |
| 463 | | #define CHARGENADDR (REVERSEON && !HIRESON && !MULTICOLORON ? ((ted7360->reg[0x13] & 0xfc) << 8) : ((ted7360->reg[0x13] & 0xf8) << 8)) |
| 464 | | #define BITMAPADDR ((ted7360->reg[0x12] & 0x38) << 10) |
| 465 | | #define VIDEOADDR ((ted7360->reg[0x14] & 0xf8) << 8) |
| 466 | | |
| 467 | | #define RASTERLINE (((ted7360->reg[0xa] & 0x01) << 8) | ted7360->reg[0xb]) |
| 468 | | #define CURSOR1POS (ted7360->reg[0xd] | ((ted7360->reg[0xc] & 0x03) << 8)) |
| 469 | | #define CURSOR2POS (ted7360->reg[0x1b] | ((ted7360->reg[0x1a] & 0x03) << 8)) |
| 470 | | #define CURSORRATE ((ted7360->reg[0x1f] & 0x7c) >> 2) |
| 471 | | |
| 472 | | #define BACKGROUNDCOLOR (ted7360->reg[0x15] & 0x7f) |
| 473 | | #define FOREGROUNDCOLOR (ted7360->reg[0x16] & 0x7f) |
| 474 | | #define MULTICOLOR1 (ted7360->reg[0x17] & 0x7f) |
| 475 | | #define MULTICOLOR2 (ted7360->reg[0x18] & 0x7f) |
| 476 | | #define FRAMECOLOR (ted7360->reg[0x19] & 0x7f) |
| 477 | | |
| 478 | | #define TED7360_VRETRACERATE ((ted7360->type == TED7360_PAL) ? TED7360PAL_VRETRACERATE : TED7360NTSC_VRETRACERATE) |
| 479 | | #define TED7360_CLOCK (((ted7360->type == TED7360_PAL) ? TED7360PAL_CLOCK : TED7360NTSC_CLOCK) / 4) |
| 480 | | #define TED7360_LINES ((ted7360->type == TED7360_PAL) ? TED7360PAL_LINES : TED7360NTSC_LINES) |
| 481 | | |
| 482 | | static attotime TEDTIME_IN_CYCLES(int pal, int cycles) |
| 483 | | { |
| 484 | | double d = (double)(cycles) / (pal ? TED7360PAL_CLOCK : TED7360NTSC_CLOCK); |
| 485 | | return attotime::from_double(d); |
| 486 | | } |
| 487 | | |
| 488 | | static int TEDTIME_TO_CYCLES(int pal, attotime t) |
| 489 | | { |
| 490 | | double d = t.as_double(); |
| 491 | | return (int)((d) * (pal ? TED7360PAL_CLOCK : TED7360NTSC_CLOCK)); |
| 492 | | } |
| 493 | | |
| 494 | | /***************************************************************************** |
| 495 | | INLINE FUNCTIONS |
| 496 | | *****************************************************************************/ |
| 497 | | |
| 498 | | INLINE ted7360_state *get_safe_token( device_t *device ) |
| 499 | | { |
| 500 | | assert(device != NULL); |
| 501 | | assert(device->type() == TED7360); |
| 502 | | |
| 503 | | return (ted7360_state *)downcast<legacy_device_base *>(device)->token(); |
| 504 | | } |
| 505 | | |
| 506 | | INLINE const ted7360_interface *get_interface( device_t *device ) |
| 507 | | { |
| 508 | | assert(device != NULL); |
| 509 | | assert(device->type() == TED7360); |
| 510 | | |
| 511 | | return (const ted7360_interface *) device->static_config(); |
| 512 | | } |
| 513 | | |
| 514 | | /***************************************************************************** |
| 515 | | IMPLEMENTATION |
| 516 | | *****************************************************************************/ |
| 517 | | |
| 518 | | static void ted7360_soundport_w( device_t *device, int offset, int data ); |
| 519 | | |
| 520 | | static void ted7360_set_interrupt( running_machine &machine, int mask, ted7360_state *ted7360 ) |
| 521 | | { |
| 522 | | /* kernel itself polls for timer 2 shot (interrupt disabled!) when cassette loading */ |
| 523 | | ted7360->reg[9] |= mask; |
| 524 | | if ((ted7360->reg[0xa] & ted7360->reg[9] & 0x5e)) |
| 525 | | { |
| 526 | | if (!(ted7360->reg[9] & 0x80)) |
| 527 | | { |
| 528 | | //DBG_LOG(1, "ted7360", ("irq start %.2x\n", mask)); |
| 529 | | ted7360->reg[9] |= 0x80; |
| 530 | | ted7360->interrupt(machine, 1); |
| 531 | | } |
| 532 | | } |
| 533 | | ted7360->reg[9] |= mask; |
| 534 | | } |
| 535 | | |
| 536 | | static void ted7360_clear_interrupt( device_t *device, int mask ) |
| 537 | | { |
| 538 | | ted7360_state *ted7360 = get_safe_token(device); |
| 539 | | |
| 540 | | ted7360->reg[9] &= ~mask; |
| 541 | | if ((ted7360->reg[9] & 0x80) && !(ted7360->reg[9] & ted7360->reg[0xa] & 0x5e)) |
| 542 | | { |
| 543 | | DBG_LOG(1, "ted7360", ("irq end %.2x\n", mask)); |
| 544 | | ted7360->reg[9] &= ~0x80; |
| 545 | | ted7360->interrupt(device->machine(), 0); |
| 546 | | } |
| 547 | | } |
| 548 | | |
| 549 | | static int ted7360_rastercolumn( device_t *device ) |
| 550 | | { |
| 551 | | ted7360_state *ted7360 = get_safe_token(device); |
| 552 | | return (int) ((device->machine().time().as_double() - ted7360->rastertime) * TED7360_VRETRACERATE * ted7360->lines * 57 * 8 + 0.5); |
| 553 | | } |
| 554 | | |
| 555 | | static TIMER_CALLBACK(ted7360_timer_timeout) |
| 556 | | { |
| 557 | | ted7360_state *ted7360 = (ted7360_state *)ptr; |
| 558 | | int which = param; |
| 559 | | |
| 560 | | //DBG_LOG(3, "ted7360 ", ("timer %d timeout\n", which)); |
| 561 | | switch (which) |
| 562 | | { |
| 563 | | case 1: |
| 564 | | // proved by digisound of several intros like eoroidpro |
| 565 | | ted7360->timer1->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER1), 1); |
| 566 | | ted7360->timer1_active = 1; |
| 567 | | ted7360_set_interrupt(machine, 0x08, ted7360); |
| 568 | | break; |
| 569 | | case 2: |
| 570 | | ted7360->timer2->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), 0x10000), 2); |
| 571 | | ted7360->timer2_active = 1; |
| 572 | | ted7360_set_interrupt(machine, 0x10, ted7360); |
| 573 | | break; |
| 574 | | case 3: |
| 575 | | ted7360->timer3->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), 0x10000), 3); |
| 576 | | ted7360->timer3_active = 1; |
| 577 | | ted7360_set_interrupt(machine, 0x40, ted7360); |
| 578 | | break; |
| 579 | | } |
| 580 | | } |
| 581 | | |
| 582 | | static void ted7360_draw_character( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color ) |
| 583 | | { |
| 584 | | ted7360_state *ted7360 = get_safe_token(device); |
| 585 | | int y, code; |
| 586 | | |
| 587 | | for (y = ybegin; y <= yend; y++) |
| 588 | | { |
| 589 | | if (INROM) |
| 590 | | code = ted7360->dma_read_rom(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
| 591 | | else |
| 592 | | code = ted7360->dma_read(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
| 593 | | |
| 594 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = color[code >> 7]; |
| 595 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = color[(code >> 6) & 1]; |
| 596 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = color[(code >> 5) & 1]; |
| 597 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = color[(code >> 4) & 1]; |
| 598 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = color[(code >> 3) & 1]; |
| 599 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = color[(code >> 2) & 1]; |
| 600 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = color[(code >> 1) & 1]; |
| 601 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = color[code & 1]; |
| 602 | | } |
| 603 | | } |
| 604 | | |
| 605 | | static void ted7360_draw_character_multi( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff ) |
| 606 | | { |
| 607 | | ted7360_state *ted7360 = get_safe_token(device); |
| 608 | | int y, code; |
| 609 | | |
| 610 | | for (y = ybegin; y <= yend; y++) |
| 611 | | { |
| 612 | | if (INROM) |
| 613 | | code = ted7360->dma_read_rom(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
| 614 | | else |
| 615 | | code = ted7360->dma_read(device->machine(), ted7360->chargenaddr + ch * 8 + y); |
| 616 | | |
| 617 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = |
| 618 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = ted7360->multi[code >> 6]; |
| 619 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = |
| 620 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = ted7360->multi[(code >> 4) & 3]; |
| 621 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = |
| 622 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = ted7360->multi[(code >> 2) & 3]; |
| 623 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = |
| 624 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = ted7360->multi[code & 3]; |
| 625 | | } |
| 626 | | } |
| 627 | | |
| 628 | | static void ted7360_draw_bitmap( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff ) |
| 629 | | { |
| 630 | | ted7360_state *ted7360 = get_safe_token(device); |
| 631 | | int y, code; |
| 632 | | |
| 633 | | for (y = ybegin; y <= yend; y++) |
| 634 | | { |
| 635 | | code = ted7360->dma_read(device->machine(), ted7360->bitmapaddr + ch * 8 + y); |
| 636 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = ted7360->c16_bitmap[code >> 7]; |
| 637 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = ted7360->c16_bitmap[(code >> 6) & 1]; |
| 638 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = ted7360->c16_bitmap[(code >> 5) & 1]; |
| 639 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = ted7360->c16_bitmap[(code >> 4) & 1]; |
| 640 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = ted7360->c16_bitmap[(code >> 3) & 1]; |
| 641 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = ted7360->c16_bitmap[(code >> 2) & 1]; |
| 642 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = ted7360->c16_bitmap[(code >> 1) & 1]; |
| 643 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = ted7360->c16_bitmap[code & 1]; |
| 644 | | } |
| 645 | | } |
| 646 | | |
| 647 | | static void ted7360_draw_bitmap_multi( device_t *device, int ybegin, int yend, int ch, int yoff, int xoff ) |
| 648 | | { |
| 649 | | ted7360_state *ted7360 = get_safe_token(device); |
| 650 | | int y, code; |
| 651 | | |
| 652 | | for (y = ybegin; y <= yend; y++) |
| 653 | | { |
| 654 | | code = ted7360->dma_read(device->machine(), ted7360->bitmapaddr + ch * 8 + y); |
| 655 | | |
| 656 | | ted7360->bitmap->pix16(y + yoff, 0 + xoff) = |
| 657 | | ted7360->bitmap->pix16(y + yoff, 1 + xoff) = ted7360->bitmapmulti[code >> 6]; |
| 658 | | ted7360->bitmap->pix16(y + yoff, 2 + xoff) = |
| 659 | | ted7360->bitmap->pix16(y + yoff, 3 + xoff) = ted7360->bitmapmulti[(code >> 4) & 3]; |
| 660 | | ted7360->bitmap->pix16(y + yoff, 4 + xoff) = |
| 661 | | ted7360->bitmap->pix16(y + yoff, 5 + xoff) = ted7360->bitmapmulti[(code >> 2) & 3]; |
| 662 | | ted7360->bitmap->pix16(y + yoff, 6 + xoff) = |
| 663 | | ted7360->bitmap->pix16(y + yoff, 7 + xoff) = ted7360->bitmapmulti[code & 3]; |
| 664 | | } |
| 665 | | } |
| 666 | | |
| 667 | | #ifndef memset16 |
| 668 | | static void *memset16 (void *dest, int value, size_t size) |
| 669 | | { |
| 670 | | register int i; |
| 671 | | |
| 672 | | for (i = 0; i < size; i++) |
| 673 | | ((short *) dest)[i] = value; |
| 674 | | return dest; |
| 675 | | } |
| 676 | | #endif |
| 677 | | |
| 678 | | static void ted7360_draw_cursor( device_t *device, int ybegin, int yend, int yoff, int xoff, int color ) |
| 679 | | { |
| 680 | | ted7360_state *ted7360 = get_safe_token(device); |
| 681 | | int y; |
| 682 | | |
| 683 | | for (y = ybegin; y <= yend; y++) |
| 684 | | { |
| 685 | | memset16(&ted7360->bitmap->pix16(yoff + y, xoff), color, 8); |
| 686 | | } |
| 687 | | } |
| 688 | | |
| 689 | | static void ted7360_drawlines( device_t *device, int first, int last ) |
| 690 | | { |
| 691 | | ted7360_state *ted7360 = get_safe_token(device); |
| 692 | | int line, vline, end; |
| 693 | | int attr, ch, c1, c2, ecm; |
| 694 | | int offs, yoff, xoff, ybegin, yend, xbegin, xend; |
| 695 | | int i; |
| 696 | | |
| 697 | | ted7360->lastline = last; |
| 698 | | |
| 699 | | /* top part of display not rastered */ |
| 700 | | first -= TED7360_YPOS; |
| 701 | | last -= TED7360_YPOS; |
| 702 | | if ((first >= last) || (last <= 0)) |
| 703 | | return; |
| 704 | | if (first < 0) |
| 705 | | first = 0; |
| 706 | | |
| 707 | | if (!SCREENON) |
| 708 | | { |
| 709 | | for (line = first; (line < last) && (line < ted7360->bitmap->height()); line++) |
| 710 | | memset16(&ted7360->bitmap->pix16(line), 0, ted7360->bitmap->width()); |
| 711 | | return; |
| 712 | | } |
| 713 | | |
| 714 | | if (COLUMNS40) |
| 715 | | xbegin = XPOS, xend = xbegin + 320; |
| 716 | | else |
| 717 | | xbegin = XPOS + 7, xend = xbegin + 304; |
| 718 | | |
| 719 | | if (last < ted7360->y_begin) |
| 720 | | end = last; |
| 721 | | else |
| 722 | | end = ted7360->y_begin + YPOS; |
| 723 | | { |
| 724 | | for (line = first; line < end; line++) |
| 725 | | memset16(&ted7360->bitmap->pix16(line), FRAMECOLOR, ted7360->bitmap->width()); |
| 726 | | } |
| 727 | | if (LINES25) |
| 728 | | vline = line - ted7360->y_begin - YPOS; |
| 729 | | else |
| 730 | | vline = line - ted7360->y_begin - YPOS + 8 - VERTICALPOS; |
| 731 | | |
| 732 | | if (last < ted7360->y_end + YPOS) |
| 733 | | end = last; |
| 734 | | else |
| 735 | | end = ted7360->y_end + YPOS; |
| 736 | | |
| 737 | | for (; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin) |
| 738 | | { |
| 739 | | offs = (vline >> 3) * 40; |
| 740 | | ybegin = vline & 7; |
| 741 | | yoff = line - ybegin; |
| 742 | | yend = (yoff + 7 < end) ? 7 : (end - yoff - 1); |
| 743 | | /* rendering 39 characters */ |
| 744 | | /* left and right borders are overwritten later */ |
| 745 | | |
| 746 | | for (xoff = ted7360->x_begin + XPOS; xoff < ted7360->x_end + XPOS; xoff += 8, offs++) |
| 747 | | { |
| 748 | | if (HIRESON) |
| 749 | | { |
| 750 | | ch = ted7360->dma_read(device->machine(), (ted7360->videoaddr | 0x400) + offs); |
| 751 | | attr = ted7360->dma_read(device->machine(), ted7360->videoaddr + offs); |
| 752 | | c1 = ((ch >> 4) & 0xf) | (attr << 4); |
| 753 | | c2 = (ch & 0xf) | (attr & 0x70); |
| 754 | | ted7360->bitmapmulti[1] = ted7360->c16_bitmap[1] = c1 & 0x7f; |
| 755 | | ted7360->bitmapmulti[2] = ted7360->c16_bitmap[0] = c2 & 0x7f; |
| 756 | | if (MULTICOLORON) |
| 757 | | { |
| 758 | | ted7360_draw_bitmap_multi(device, ybegin, yend, offs, yoff, xoff); |
| 759 | | } |
| 760 | | else |
| 761 | | { |
| 762 | | ted7360_draw_bitmap(device, ybegin, yend, offs, yoff, xoff); |
| 763 | | } |
| 764 | | } |
| 765 | | else |
| 766 | | { |
| 767 | | ch = ted7360->dma_read(device->machine(), (ted7360->videoaddr | 0x400) + offs); |
| 768 | | attr = ted7360->dma_read(device->machine(), ted7360->videoaddr + offs); |
| 769 | | // levente harsfalvi's docu says cursor off in ecm and multicolor |
| 770 | | if (ECMON) |
| 771 | | { |
| 772 | | // hardware reverse off |
| 773 | | ecm = ch >> 6; |
| 774 | | ted7360->ecmcolor[0] = ted7360->colors[ecm]; |
| 775 | | ted7360->ecmcolor[1] = attr & 0x7f; |
| 776 | | ted7360_draw_character(device, ybegin, yend, ch & ~0xc0, yoff, xoff, ted7360->ecmcolor); |
| 777 | | } |
| 778 | | else if (MULTICOLORON) |
| 779 | | { |
| 780 | | // hardware reverse off |
| 781 | | if (attr & 8) |
| 782 | | { |
| 783 | | ted7360->multi[3] = attr & 0x77; |
| 784 | | ted7360_draw_character_multi(device, ybegin, yend, ch, yoff, xoff); |
| 785 | | } |
| 786 | | else |
| 787 | | { |
| 788 | | ted7360->mono[1] = attr & 0x7f; |
| 789 | | ted7360_draw_character(device, ybegin, yend, ch, yoff, xoff, ted7360->mono); |
| 790 | | } |
| 791 | | } |
| 792 | | else if (ted7360->cursor1 && (offs == CURSOR1POS)) |
| 793 | | { |
| 794 | | ted7360_draw_cursor(device, ybegin, yend, yoff, xoff, attr & 0x7f); |
| 795 | | } |
| 796 | | else if (REVERSEON && (ch & 0x80)) |
| 797 | | { |
| 798 | | ted7360->monoinversed[0] = attr & 0x7f; |
| 799 | | if (ted7360->cursor1 && (attr & 0x80)) |
| 800 | | ted7360_draw_cursor(device, ybegin, yend, yoff, xoff, ted7360->monoinversed[0]); |
| 801 | | else |
| 802 | | ted7360_draw_character(device, ybegin, yend, ch & ~0x80, yoff, xoff, ted7360->monoinversed); |
| 803 | | } |
| 804 | | else |
| 805 | | { |
| 806 | | ted7360->mono[1] = attr & 0x7f; |
| 807 | | if (ted7360->cursor1 && (attr & 0x80)) |
| 808 | | ted7360_draw_cursor(device, ybegin, yend, yoff, xoff, ted7360->mono[0]); |
| 809 | | else |
| 810 | | ted7360_draw_character(device, ybegin, yend, ch, yoff, xoff, ted7360->mono); |
| 811 | | } |
| 812 | | } |
| 813 | | } |
| 814 | | |
| 815 | | for (i = ybegin; i <= yend; i++) |
| 816 | | { |
| 817 | | memset16(&ted7360->bitmap->pix16(yoff + i), FRAMECOLOR, xbegin); |
| 818 | | memset16(&ted7360->bitmap->pix16(yoff + i, xend), FRAMECOLOR, ted7360->bitmap->width() - xend); |
| 819 | | } |
| 820 | | } |
| 821 | | |
| 822 | | if (last < ted7360->bitmap->height()) |
| 823 | | end = last; |
| 824 | | else |
| 825 | | end = ted7360->bitmap->height(); |
| 826 | | |
| 827 | | for (; line < end; line++) |
| 828 | | { |
| 829 | | memset16(&ted7360->bitmap->pix16(line), FRAMECOLOR, ted7360->bitmap->width()); |
| 830 | | } |
| 831 | | } |
| 832 | | |
| 833 | | |
| 834 | | WRITE8_DEVICE_HANDLER( ted7360_port_w ) |
| 835 | | { |
| 836 | | ted7360_state *ted7360 = get_safe_token(device); |
| 837 | | int old; |
| 838 | | |
| 839 | | if ((offset != 8) && ((offset < 0x15) || (offset > 0x19))) |
| 840 | | { |
| 841 | | DBG_LOG(1, "ted7360_port_w", ("%.2x:%.2x\n", offset, data)); |
| 842 | | } |
| 843 | | |
| 844 | | switch (offset) |
| 845 | | { |
| 846 | | case 0xe: |
| 847 | | case 0xf: |
| 848 | | case 0x10: |
| 849 | | case 0x11: |
| 850 | | case 0x12: |
| 851 | | ted7360_soundport_w(device, offset, data); |
| 852 | | break; |
| 853 | | } |
| 854 | | switch (offset) |
| 855 | | { |
| 856 | | case 0: /* stop timer 1 */ |
| 857 | | ted7360->reg[offset] = data; |
| 858 | | |
| 859 | | if (ted7360->timer1_active) |
| 860 | | { |
| 861 | | ted7360->reg[1] = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer1->remaining()) >> 8; |
| 862 | | ted7360->timer1->reset(); |
| 863 | | ted7360->timer1_active = 0; |
| 864 | | } |
| 865 | | break; |
| 866 | | case 1: /* start timer 1 */ |
| 867 | | ted7360->reg[offset] = data; |
| 868 | | ted7360->timer1->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER1), 1); |
| 869 | | ted7360->timer1_active = 1; |
| 870 | | break; |
| 871 | | case 2: /* stop timer 2 */ |
| 872 | | ted7360->reg[offset] = data; |
| 873 | | if (ted7360->timer2_active) |
| 874 | | { |
| 875 | | ted7360->reg[3] = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer2->remaining()) >> 8; |
| 876 | | ted7360->timer2->reset(); |
| 877 | | ted7360->timer2_active = 0; |
| 878 | | } |
| 879 | | break; |
| 880 | | case 3: /* start timer 2 */ |
| 881 | | ted7360->reg[offset] = data; |
| 882 | | ted7360->timer2->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER2), 2); |
| 883 | | ted7360->timer2_active = 1; |
| 884 | | break; |
| 885 | | case 4: /* stop timer 3 */ |
| 886 | | ted7360->reg[offset] = data; |
| 887 | | if (ted7360->timer3_active) |
| 888 | | { |
| 889 | | ted7360->reg[5] = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer3->remaining()) >> 8; |
| 890 | | ted7360->timer3->reset(); |
| 891 | | ted7360->timer3_active = 0; |
| 892 | | } |
| 893 | | break; |
| 894 | | case 5: /* start timer 3 */ |
| 895 | | ted7360->reg[offset] = data; |
| 896 | | ted7360->timer3->adjust(TEDTIME_IN_CYCLES((ted7360->type == TED7360_PAL), TIMER3), 3); |
| 897 | | ted7360->timer3_active = 1; |
| 898 | | break; |
| 899 | | case 6: |
| 900 | | if (ted7360->reg[offset] != data) |
| 901 | | { |
| 902 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 903 | | ted7360->reg[offset] = data; |
| 904 | | if (LINES25) |
| 905 | | { |
| 906 | | ted7360->y_begin = 0; |
| 907 | | ted7360->y_end = ted7360->y_begin + 200; |
| 908 | | } |
| 909 | | else |
| 910 | | { |
| 911 | | ted7360->y_begin = 4; |
| 912 | | ted7360->y_end = ted7360->y_begin + 192; |
| 913 | | } |
| 914 | | ted7360->chargenaddr = CHARGENADDR; |
| 915 | | } |
| 916 | | break; |
| 917 | | case 7: |
| 918 | | if (ted7360->reg[offset] != data) |
| 919 | | { |
| 920 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 921 | | ted7360->reg[offset] = data; |
| 922 | | if (COLUMNS40) |
| 923 | | { |
| 924 | | ted7360->x_begin = 0; |
| 925 | | ted7360->x_end = ted7360->x_begin + 320; |
| 926 | | } |
| 927 | | else |
| 928 | | { |
| 929 | | ted7360->x_begin = HORICONTALPOS; |
| 930 | | ted7360->x_end = ted7360->x_begin + 320; |
| 931 | | } |
| 932 | | DBG_LOG(3, "ted7360_port_w", ("%s %s\n", data & 0x40 ? "ntsc" : "pal", data & 0x20 ? "hori freeze" : "")); |
| 933 | | ted7360->chargenaddr = CHARGENADDR; |
| 934 | | } |
| 935 | | break; |
| 936 | | case 8: |
| 937 | | ted7360->reg[offset] = ted7360->keyboard_cb(device->machine(), data); |
| 938 | | break; |
| 939 | | case 9: |
| 940 | | if (data & 0x08) |
| 941 | | ted7360_clear_interrupt(device, 8); |
| 942 | | if (data & 0x10) |
| 943 | | ted7360_clear_interrupt(device, 0x10); |
| 944 | | if (data & 0x40) |
| 945 | | ted7360_clear_interrupt(device, 0x40); |
| 946 | | if (data & 0x02) |
| 947 | | ted7360_clear_interrupt(device, 2); |
| 948 | | break; |
| 949 | | case 0xa: |
| 950 | | old = data; |
| 951 | | ted7360->reg[offset] = data | 0xa0; |
| 952 | | #if 0 |
| 953 | | ted7360->reg[9] = (ted7360->reg[9] & 0xa1) | (ted7360->reg[9] & data & 0x5e); |
| 954 | | if (ted7360->reg[9] & 0x80) |
| 955 | | ted7360_clear_interrupt(device, 0); |
| 956 | | #endif |
| 957 | | if ((data ^ old) & 1) |
| 958 | | { |
| 959 | | /* DBG_LOG(1,"set rasterline hi",("soll:%d\n",RASTERLINE)); */ |
| 960 | | } |
| 961 | | break; |
| 962 | | case 0xb: |
| 963 | | if (data != ted7360->reg[offset]) |
| 964 | | { |
| 965 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 966 | | ted7360->reg[offset] = data; |
| 967 | | /* DBG_LOG(1,"set rasterline lo",("soll:%d\n",RASTERLINE)); */ |
| 968 | | } |
| 969 | | break; |
| 970 | | case 0xc: |
| 971 | | case 0xd: |
| 972 | | if (ted7360->reg[offset] != data) |
| 973 | | { |
| 974 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 975 | | ted7360->reg[offset] = data; |
| 976 | | } |
| 977 | | break; |
| 978 | | case 0x12: |
| 979 | | if (ted7360->reg[offset] != data) |
| 980 | | { |
| 981 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 982 | | ted7360->reg[offset] = data; |
| 983 | | ted7360->bitmapaddr = BITMAPADDR; |
| 984 | | ted7360->chargenaddr = CHARGENADDR; |
| 985 | | DBG_LOG(3, "ted7360_port_w", ("bitmap %.4x %s\n", BITMAPADDR, INROM ? "rom" : "ram")); |
| 986 | | } |
| 987 | | break; |
| 988 | | case 0x13: |
| 989 | | if (ted7360->reg[offset] != data) |
| 990 | | { |
| 991 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 992 | | ted7360->reg[offset] = data; |
| 993 | | ted7360->chargenaddr = CHARGENADDR; |
| 994 | | DBG_LOG(3, "ted7360_port_w", ("chargen %.4x %s %d\n", CHARGENADDR, data & 2 ? "" : "doubleclock", data & 1)); |
| 995 | | } |
| 996 | | break; |
| 997 | | case 0x14: |
| 998 | | if (ted7360->reg[offset] != data) |
| 999 | | { |
| 1000 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1001 | | ted7360->reg[offset] = data; |
| 1002 | | ted7360->videoaddr = VIDEOADDR; |
| 1003 | | DBG_LOG(3, "ted7360_port_w", ("videoram %.4x\n", VIDEOADDR)); |
| 1004 | | } |
| 1005 | | break; |
| 1006 | | case 0x15: /* backgroundcolor */ |
| 1007 | | if (ted7360->reg[offset] != data) |
| 1008 | | { |
| 1009 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1010 | | ted7360->reg[offset] = data; |
| 1011 | | ted7360->monoinversed[1] = ted7360->mono[0] = ted7360->bitmapmulti[0] = ted7360->multi[0] = ted7360->colors[0] = BACKGROUNDCOLOR; |
| 1012 | | } |
| 1013 | | break; |
| 1014 | | case 0x16: /* foregroundcolor */ |
| 1015 | | if (ted7360->reg[offset] != data) |
| 1016 | | { |
| 1017 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1018 | | ted7360->reg[offset] = data; |
| 1019 | | ted7360->bitmapmulti[3] = ted7360->multi[1] = ted7360->colors[1] = FOREGROUNDCOLOR; |
| 1020 | | } |
| 1021 | | break; |
| 1022 | | case 0x17: /* multicolor 1 */ |
| 1023 | | if (ted7360->reg[offset] != data) |
| 1024 | | { |
| 1025 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1026 | | ted7360->reg[offset] = data; |
| 1027 | | ted7360->multi[2] = ted7360->colors[2] = MULTICOLOR1; |
| 1028 | | } |
| 1029 | | break; |
| 1030 | | case 0x18: /* multicolor 2 */ |
| 1031 | | if (ted7360->reg[offset] != data) |
| 1032 | | { |
| 1033 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1034 | | ted7360->reg[offset] = data; |
| 1035 | | ted7360->colors[3] = MULTICOLOR2; |
| 1036 | | } |
| 1037 | | break; |
| 1038 | | case 0x19: /* framecolor */ |
| 1039 | | if (ted7360->reg[offset] != data) |
| 1040 | | { |
| 1041 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1042 | | ted7360->reg[offset] = data; |
| 1043 | | ted7360->colors[4] = FRAMECOLOR; |
| 1044 | | } |
| 1045 | | break; |
| 1046 | | case 0x1c: |
| 1047 | | ted7360->reg[offset] = data; /*? */ |
| 1048 | | DBG_LOG(1, "ted7360_port_w", ("write to rasterline high %.2x\n", |
| 1049 | | data)); |
| 1050 | | break; |
| 1051 | | case 0x1f: |
| 1052 | | ted7360->reg[offset] = data; |
| 1053 | | DBG_LOG(1, "ted7360_port_w", ("write to cursorblink %.2x\n", data)); |
| 1054 | | break; |
| 1055 | | default: |
| 1056 | | ted7360->reg[offset] = data; |
| 1057 | | break; |
| 1058 | | } |
| 1059 | | } |
| 1060 | | |
| 1061 | | READ8_DEVICE_HANDLER( ted7360_port_r ) |
| 1062 | | { |
| 1063 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1064 | | int val = 0; |
| 1065 | | |
| 1066 | | switch (offset) |
| 1067 | | { |
| 1068 | | case 0: |
| 1069 | | if (ted7360->timer1) |
| 1070 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer1->remaining()) & 0xff; |
| 1071 | | else |
| 1072 | | val = ted7360->reg[offset]; |
| 1073 | | break; |
| 1074 | | case 1: |
| 1075 | | if (ted7360->timer1) |
| 1076 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer1->remaining()) >> 8; |
| 1077 | | else |
| 1078 | | val = ted7360->reg[offset]; |
| 1079 | | break; |
| 1080 | | case 2: |
| 1081 | | if (ted7360->timer2) |
| 1082 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer2->remaining()) & 0xff; |
| 1083 | | else |
| 1084 | | val = ted7360->reg[offset]; |
| 1085 | | break; |
| 1086 | | case 3: |
| 1087 | | if (ted7360->timer2) |
| 1088 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer2->remaining()) >> 8; |
| 1089 | | else |
| 1090 | | val = ted7360->reg[offset]; |
| 1091 | | break; |
| 1092 | | case 4: |
| 1093 | | if (ted7360->timer3) |
| 1094 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer3->remaining()) & 0xff; |
| 1095 | | else |
| 1096 | | val = ted7360->reg[offset]; |
| 1097 | | break; |
| 1098 | | case 5: |
| 1099 | | if (ted7360->timer3) |
| 1100 | | val = TEDTIME_TO_CYCLES((ted7360->type == TED7360_PAL), ted7360->timer3->remaining()) >> 8; |
| 1101 | | else |
| 1102 | | val = ted7360->reg[offset]; |
| 1103 | | break; |
| 1104 | | case 7: |
| 1105 | | val = (ted7360->reg[offset] & ~0x40); |
| 1106 | | if (ted7360->type == TED7360_NTSC) |
| 1107 | | val |= 0x40; |
| 1108 | | break; |
| 1109 | | case 9: |
| 1110 | | val = ted7360->reg[offset] | 1; |
| 1111 | | break; |
| 1112 | | case 0xa: |
| 1113 | | val = ted7360->reg[offset]; |
| 1114 | | break; |
| 1115 | | case 0xb: |
| 1116 | | val = ted7360->reg[offset]; |
| 1117 | | break; |
| 1118 | | case 0x0c: |
| 1119 | | val = ted7360->reg[offset] |= 0xfc; |
| 1120 | | break; |
| 1121 | | case 0x13: |
| 1122 | | val = ted7360->reg[offset] & ~1; |
| 1123 | | if (ted7360->rom) |
| 1124 | | val |= 1; |
| 1125 | | break; |
| 1126 | | case 0x1c: /*rasterline */ |
| 1127 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1128 | | val = ((RASTERLINE_2_C16(ted7360->rasterline) & 0x100) >> 8) | 0xfe; /* expected by matrix */ |
| 1129 | | break; |
| 1130 | | case 0x1d: /*rasterline */ |
| 1131 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1132 | | val = RASTERLINE_2_C16(ted7360->rasterline) & 0xff; |
| 1133 | | break; |
| 1134 | | case 0x1e: /*rastercolumn */ |
| 1135 | | val = ted7360_rastercolumn(device) / 2; /* pengo >=0x99 */ |
| 1136 | | break; |
| 1137 | | case 0x1f: |
| 1138 | | val = ((ted7360->rasterline & 7) << 4) | (ted7360->reg[offset] & 0x0f); |
| 1139 | | DBG_LOG(1, "ted7360_port_w", ("read from cursorblink %.2x\n", val)); |
| 1140 | | break; |
| 1141 | | default: |
| 1142 | | val = ted7360->reg[offset]; |
| 1143 | | break; |
| 1144 | | } |
| 1145 | | |
| 1146 | | if ((offset != 8) && (offset >= 6) && (offset != 0x1c) && (offset != 0x1d) && (offset != 9) && ((offset < 0x15) || (offset > 0x19))) |
| 1147 | | { |
| 1148 | | DBG_LOG(1, "ted7360_port_r", ("%.2x:%.2x\n", offset, val)); |
| 1149 | | } |
| 1150 | | |
| 1151 | | return val; |
| 1152 | | } |
| 1153 | | |
| 1154 | | WRITE_LINE_DEVICE_HANDLER( ted7360_rom_switch_w ) |
| 1155 | | { |
| 1156 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1157 | | ted7360->rom = state; |
| 1158 | | } |
| 1159 | | |
| 1160 | | READ_LINE_DEVICE_HANDLER( ted7360_rom_switch_r ) |
| 1161 | | { |
| 1162 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1163 | | return ted7360->rom; |
| 1164 | | } |
| 1165 | | |
| 1166 | | void ted7360_frame_interrupt_gen( device_t *device ) |
| 1167 | | { |
| 1168 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1169 | | |
| 1170 | | if ((ted7360->reg[0x1f] & 0xf) >= 0x0f) |
| 1171 | | { |
| 1172 | | /* if (ted7360->frame_count >= CURSORRATE) */ |
| 1173 | | ted7360->cursor1 ^= 1; |
| 1174 | | ted7360->reg[0x1f] &= ~0xf; |
| 1175 | | ted7360->frame_count = 0; |
| 1176 | | } |
| 1177 | | else |
| 1178 | | ted7360->reg[0x1f]++; |
| 1179 | | } |
| 1180 | | |
| 1181 | | void ted7360_raster_interrupt_gen( device_t *device ) |
| 1182 | | { |
| 1183 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1184 | | |
| 1185 | | ted7360->rasterline++; |
| 1186 | | ted7360->rastertime = device->machine().time().as_double(); |
| 1187 | | if (ted7360->rasterline >= ted7360->lines) |
| 1188 | | { |
| 1189 | | ted7360->rasterline = 0; |
| 1190 | | ted7360_drawlines(device, ted7360->lastline, TED7360_LINES); |
| 1191 | | ted7360->lastline = 0; |
| 1192 | | } |
| 1193 | | |
| 1194 | | if (ted7360->rasterline == C16_2_RASTERLINE(RASTERLINE)) |
| 1195 | | { |
| 1196 | | ted7360_drawlines(device, ted7360->lastline, ted7360->rasterline); |
| 1197 | | ted7360_set_interrupt(device->machine(), 2, ted7360); |
| 1198 | | } |
| 1199 | | } |
| 1200 | | |
| 1201 | | UINT32 ted7360_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect ) |
| 1202 | | { |
| 1203 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1204 | | |
| 1205 | | copybitmap(bitmap, *ted7360->bitmap, 0, 0, 0, 0, cliprect); |
| 1206 | | return 0; |
| 1207 | | } |
| 1208 | | |
| 1209 | | |
| 1210 | | /* Sound emulation */ |
| 1211 | | |
| 1212 | | #define NOISE_BUFFER_SIZE_SEC 5 |
| 1213 | | |
| 1214 | | #define TONE_ON (!(ted7360->reg[0x11] & 0x80)) /* or tone update!? */ |
| 1215 | | #define TONE1_ON ((ted7360->reg[0x11] & 0x10)) |
| 1216 | | #define TONE1_VALUE (ted7360->reg[0x0e] | ((ted7360->reg[0x12] & 3) << 8)) |
| 1217 | | #define TONE2_ON ((ted7360->reg[0x11] & 0x20)) |
| 1218 | | #define TONE2_VALUE (ted7360->reg[0x0f] | ((ted7360->reg[0x10] & 3) << 8)) |
| 1219 | | #define VOLUME (ted7360->reg[0x11] & 0x0f) |
| 1220 | | #define NOISE_ON (ted7360->reg[0x11] & 0x40) |
| 1221 | | |
| 1222 | | /* |
| 1223 | | * pal 111860.781 |
| 1224 | | * ntsc 111840.45 |
| 1225 | | */ |
| 1226 | | #define TONE_FREQUENCY(reg) ((TED7360_CLOCK >> 3) / (1024 - reg)) |
| 1227 | | #define TONE_FREQUENCY_MIN (TONE_FREQUENCY(0)) |
| 1228 | | #define NOISE_FREQUENCY (TED7360_CLOCK / 8 / (1024 - TONE2_VALUE)) |
| 1229 | | #define NOISE_FREQUENCY_MAX (TED7360_CLOCK / 8) |
| 1230 | | |
| 1231 | | |
| 1232 | | static void ted7360_soundport_w( device_t *device, int offset, int data ) |
| 1233 | | { |
| 1234 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1235 | | |
| 1236 | | // int old = ted7360->reg[offset]; |
| 1237 | | ted7360->channel->update(); |
| 1238 | | |
| 1239 | | switch (offset) |
| 1240 | | { |
| 1241 | | case 0x0e: |
| 1242 | | case 0x12: |
| 1243 | | if (offset == 0x12) |
| 1244 | | ted7360->reg[offset] = (ted7360->reg[offset] & ~3) | (data & 3); |
| 1245 | | else |
| 1246 | | ted7360->reg[offset] = data; |
| 1247 | | |
| 1248 | | ted7360->tone1samples = device->machine().sample_rate() / TONE_FREQUENCY (TONE1_VALUE); |
| 1249 | | DBG_LOG(1, "ted7360", ("tone1 %d %d sample:%d\n", TONE1_VALUE, TONE_FREQUENCY(TONE1_VALUE), ted7360->tone1samples)); |
| 1250 | | break; |
| 1251 | | |
| 1252 | | case 0xf: |
| 1253 | | case 0x10: |
| 1254 | | ted7360->reg[offset] = data; |
| 1255 | | |
| 1256 | | ted7360->tone2samples = device->machine().sample_rate() / TONE_FREQUENCY (TONE2_VALUE); |
| 1257 | | DBG_LOG (1, "ted7360", ("tone2 %d %d sample:%d\n", TONE2_VALUE, TONE_FREQUENCY(TONE2_VALUE), ted7360->tone2samples)); |
| 1258 | | |
| 1259 | | ted7360->noisesamples = (int) ((double) NOISE_FREQUENCY_MAX * device->machine().sample_rate() * NOISE_BUFFER_SIZE_SEC / NOISE_FREQUENCY); |
| 1260 | | DBG_LOG (1, "ted7360", ("noise %d sample:%d\n", NOISE_FREQUENCY, ted7360->noisesamples)); |
| 1261 | | |
| 1262 | | if (!NOISE_ON || ((double) ted7360->noisepos / ted7360->noisesamples >= 1.0)) |
| 1263 | | ted7360->noisepos = 0; |
| 1264 | | break; |
| 1265 | | |
| 1266 | | case 0x11: |
| 1267 | | ted7360->reg[offset] = data; |
| 1268 | | DBG_LOG(1, "ted7360", ("%s volume %d, %s %s %s\n", TONE_ON?"on":"off", |
| 1269 | | VOLUME, TONE1_ON?"tone1":"", TONE2_ON?"tone2":"", NOISE_ON?"noise":"")); |
| 1270 | | |
| 1271 | | if (!TONE_ON||!TONE1_ON) ted7360->tone1pos = 0; |
| 1272 | | if (!TONE_ON||!TONE2_ON) ted7360->tone2pos = 0; |
| 1273 | | if (!TONE_ON||!NOISE_ON) ted7360->noisepos = 0; |
| 1274 | | break; |
| 1275 | | } |
| 1276 | | } |
| 1277 | | |
| 1278 | | |
| 1279 | | /************************************/ |
| 1280 | | /* Sound handler update */ |
| 1281 | | /************************************/ |
| 1282 | | |
| 1283 | | static STREAM_UPDATE( ted7360_update ) |
| 1284 | | { |
| 1285 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1286 | | int i, v, a; |
| 1287 | | stream_sample_t *buffer = outputs[0]; |
| 1288 | | |
| 1289 | | for (i = 0; i < samples; i++) |
| 1290 | | { |
| 1291 | | v = 0; |
| 1292 | | |
| 1293 | | if (TONE1_ON) |
| 1294 | | { |
| 1295 | | if (ted7360->tone1pos <= ted7360->tone1samples / 2 || !TONE_ON) |
| 1296 | | v += 0x2ff; // depends on the volume between sound and noise |
| 1297 | | |
| 1298 | | ted7360->tone1pos++; |
| 1299 | | |
| 1300 | | if (ted7360->tone1pos > ted7360->tone1samples) |
| 1301 | | ted7360->tone1pos = 0; |
| 1302 | | } |
| 1303 | | |
| 1304 | | if (TONE2_ON || NOISE_ON ) |
| 1305 | | { |
| 1306 | | if (TONE2_ON) |
| 1307 | | { /*higher priority ?! */ |
| 1308 | | if (ted7360->tone2pos <= ted7360->tone2samples / 2 || !TONE_ON) |
| 1309 | | v += 0x2ff; |
| 1310 | | |
| 1311 | | ted7360->tone2pos++; |
| 1312 | | |
| 1313 | | if (ted7360->tone2pos > ted7360->tone2samples) |
| 1314 | | ted7360->tone2pos = 0; |
| 1315 | | } |
| 1316 | | else |
| 1317 | | { |
| 1318 | | v += ted7360->noise[(int) ((double) ted7360->noisepos * ted7360->noisesize / ted7360->noisesamples)]; |
| 1319 | | ted7360->noisepos++; |
| 1320 | | |
| 1321 | | if ((double) ted7360->noisepos / ted7360->noisesamples >= 1.0) |
| 1322 | | ted7360->noisepos = 0; |
| 1323 | | } |
| 1324 | | } |
| 1325 | | |
| 1326 | | a = VOLUME; |
| 1327 | | if (a > 8) |
| 1328 | | a = 8; |
| 1329 | | |
| 1330 | | v = v * a; |
| 1331 | | |
| 1332 | | buffer[i] = v; |
| 1333 | | } |
| 1334 | | } |
| 1335 | | |
| 1336 | | /***************************************************************************** |
| 1337 | | DEVICE INTERFACE |
| 1338 | | *****************************************************************************/ |
| 1339 | | |
| 1340 | | /************************************/ |
| 1341 | | /* Sound handler start */ |
| 1342 | | /************************************/ |
| 1343 | | |
| 1344 | | static void ted7360_sound_start( device_t *device ) |
| 1345 | | { |
| 1346 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1347 | | int i; |
| 1348 | | |
| 1349 | | ted7360->channel = device->machine().sound().stream_alloc(*device, 0, 1, device->machine().sample_rate(), 0, ted7360_update); |
| 1350 | | |
| 1351 | | /* buffer for fastest played sample for 5 second so we have enough data for min 5 second */ |
| 1352 | | ted7360->noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC; |
| 1353 | | ted7360->noise = auto_alloc_array(device->machine(), UINT8, ted7360->noisesize); |
| 1354 | | |
| 1355 | | { |
| 1356 | | int noiseshift = 0x7ffff8; |
| 1357 | | UINT8 data; |
| 1358 | | |
| 1359 | | for (i = 0; i < ted7360->noisesize; i++) |
| 1360 | | { |
| 1361 | | data = 0; |
| 1362 | | if (noiseshift & 0x400000) |
| 1363 | | data |= 0x80; |
| 1364 | | if (noiseshift & 0x100000) |
| 1365 | | data |= 0x40; |
| 1366 | | if (noiseshift & 0x010000) |
| 1367 | | data |= 0x20; |
| 1368 | | if (noiseshift & 0x002000) |
| 1369 | | data |= 0x10; |
| 1370 | | if (noiseshift & 0x000800) |
| 1371 | | data |= 0x08; |
| 1372 | | if (noiseshift & 0x000080) |
| 1373 | | data |= 0x04; |
| 1374 | | if (noiseshift & 0x000010) |
| 1375 | | data |= 0x02; |
| 1376 | | if (noiseshift & 0x000004) |
| 1377 | | data |= 0x01; |
| 1378 | | ted7360->noise[i] = data; |
| 1379 | | if (((noiseshift & 0x400000) == 0) != ((noiseshift & 0x002000) == 0)) |
| 1380 | | noiseshift = (noiseshift << 1) | 1; |
| 1381 | | else |
| 1382 | | noiseshift <<= 1; |
| 1383 | | } |
| 1384 | | } |
| 1385 | | } |
| 1386 | | |
| 1387 | | static DEVICE_START( ted7360 ) |
| 1388 | | { |
| 1389 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1390 | | const ted7360_interface *intf = (ted7360_interface *)device->static_config(); |
| 1391 | | int width, height; |
| 1392 | | |
| 1393 | | ted7360->screen = device->machine().device<screen_device>(intf->screen); |
| 1394 | | width = ted7360->screen->width(); |
| 1395 | | height = ted7360->screen->height(); |
| 1396 | | |
| 1397 | | ted7360->bitmap = auto_bitmap_ind16_alloc(device->machine(), width, height); |
| 1398 | | |
| 1399 | | ted7360->type = intf->type; |
| 1400 | | |
| 1401 | | ted7360->dma_read = intf->dma_read; |
| 1402 | | ted7360->dma_read_rom = intf->dma_read_rom; |
| 1403 | | ted7360->interrupt = intf->irq; |
| 1404 | | |
| 1405 | | ted7360->keyboard_cb = intf->keyb_cb; |
| 1406 | | |
| 1407 | | ted7360->timer1 = device->machine().scheduler().timer_alloc(FUNC(ted7360_timer_timeout), ted7360); |
| 1408 | | ted7360->timer2 = device->machine().scheduler().timer_alloc(FUNC(ted7360_timer_timeout), ted7360); |
| 1409 | | ted7360->timer3 = device->machine().scheduler().timer_alloc(FUNC(ted7360_timer_timeout), ted7360); |
| 1410 | | |
| 1411 | | ted7360_sound_start(device); |
| 1412 | | |
| 1413 | | device->save_item(NAME(ted7360->reg)); |
| 1414 | | |
| 1415 | | device->save_item(NAME(*ted7360->bitmap)); |
| 1416 | | |
| 1417 | | device->save_item(NAME(ted7360->rom)); |
| 1418 | | device->save_item(NAME(ted7360->lines)); |
| 1419 | | device->save_item(NAME(ted7360->chargenaddr)); |
| 1420 | | device->save_item(NAME(ted7360->bitmapaddr)); |
| 1421 | | device->save_item(NAME(ted7360->videoaddr)); |
| 1422 | | device->save_item(NAME(ted7360->timer1_active)); |
| 1423 | | device->save_item(NAME(ted7360->timer2_active)); |
| 1424 | | device->save_item(NAME(ted7360->timer3_active)); |
| 1425 | | device->save_item(NAME(ted7360->cursor1)); |
| 1426 | | device->save_item(NAME(ted7360->rasterline)); |
| 1427 | | device->save_item(NAME(ted7360->lastline)); |
| 1428 | | device->save_item(NAME(ted7360->rastertime)); |
| 1429 | | device->save_item(NAME(ted7360->frame_count)); |
| 1430 | | device->save_item(NAME(ted7360->x_begin)); |
| 1431 | | device->save_item(NAME(ted7360->x_end)); |
| 1432 | | device->save_item(NAME(ted7360->y_begin)); |
| 1433 | | device->save_item(NAME(ted7360->y_end)); |
| 1434 | | |
| 1435 | | device->save_item(NAME(ted7360->c16_bitmap)); |
| 1436 | | device->save_item(NAME(ted7360->bitmapmulti)); |
| 1437 | | device->save_item(NAME(ted7360->mono)); |
| 1438 | | device->save_item(NAME(ted7360->monoinversed)); |
| 1439 | | device->save_item(NAME(ted7360->multi)); |
| 1440 | | device->save_item(NAME(ted7360->ecmcolor)); |
| 1441 | | device->save_item(NAME(ted7360->colors)); |
| 1442 | | |
| 1443 | | device->save_item(NAME(ted7360->tone1pos)); |
| 1444 | | device->save_item(NAME(ted7360->tone2pos)); |
| 1445 | | device->save_item(NAME(ted7360->tone1samples)); |
| 1446 | | device->save_item(NAME(ted7360->tone2samples)); |
| 1447 | | device->save_item(NAME(ted7360->noisepos)); |
| 1448 | | device->save_item(NAME(ted7360->noisesamples)); |
| 1449 | | } |
| 1450 | | |
| 1451 | | static DEVICE_RESET( ted7360 ) |
| 1452 | | { |
| 1453 | | ted7360_state *ted7360 = get_safe_token(device); |
| 1454 | | |
| 1455 | | memset(ted7360->reg, 0, ARRAY_LENGTH(ted7360->reg)); |
| 1456 | | |
| 1457 | | ted7360->rom = 1; // FIXME: at start should be RAM or ROM? old c16 code set it to ROM at init: is it correct? |
| 1458 | | |
| 1459 | | ted7360->lines = TED7360_LINES; |
| 1460 | | ted7360->chargenaddr = ted7360->bitmapaddr = ted7360->videoaddr = 0; |
| 1461 | | ted7360->timer1_active = ted7360->timer2_active = ted7360->timer3_active = 0; |
| 1462 | | ted7360->cursor1 = 0; |
| 1463 | | |
| 1464 | | ted7360->rasterline = 0; |
| 1465 | | ted7360->lastline = 0; |
| 1466 | | |
| 1467 | | ted7360->rastertime = 0.0; |
| 1468 | | |
| 1469 | | ted7360->frame_count = 0; |
| 1470 | | |
| 1471 | | ted7360->x_begin = 0; |
| 1472 | | ted7360->x_end = 0; |
| 1473 | | ted7360->y_begin = 0; |
| 1474 | | ted7360->y_end = 0; |
| 1475 | | |
| 1476 | | memset(ted7360->c16_bitmap, 0, ARRAY_LENGTH(ted7360->c16_bitmap)); |
| 1477 | | memset(ted7360->bitmapmulti, 0, ARRAY_LENGTH(ted7360->bitmapmulti)); |
| 1478 | | memset(ted7360->mono, 0, ARRAY_LENGTH(ted7360->mono)); |
| 1479 | | memset(ted7360->monoinversed, 0, ARRAY_LENGTH(ted7360->monoinversed)); |
| 1480 | | memset(ted7360->multi, 0, ARRAY_LENGTH(ted7360->multi)); |
| 1481 | | memset(ted7360->ecmcolor, 0, ARRAY_LENGTH(ted7360->ecmcolor)); |
| 1482 | | memset(ted7360->colors, 0, ARRAY_LENGTH(ted7360->colors)); |
| 1483 | | |
| 1484 | | ted7360->tone1pos = 0; |
| 1485 | | ted7360->tone2pos = 0; |
| 1486 | | ted7360->tone1samples = 1; |
| 1487 | | ted7360->tone2samples = 1; |
| 1488 | | ted7360->noisepos = 0; |
| 1489 | | ted7360->noisesamples = 1; |
| 1490 | | } |
| 1491 | | |
| 1492 | | |
| 1493 | | /*------------------------------------------------- |
| 1494 | | device definition |
| 1495 | | -------------------------------------------------*/ |
| 1496 | | |
| 1497 | | static const char DEVTEMPLATE_SOURCE[] = __FILE__; |
| 1498 | | |
| 1499 | | #define DEVTEMPLATE_ID(p,s) p##ted7360##s |
| 1500 | | #define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET |
| 1501 | | #define DEVTEMPLATE_NAME "CBM TED 7360" |
| 1502 | | #define DEVTEMPLATE_FAMILY "CBM Text Display Video Chip" |
| 1503 | | #include "devtempl.h" |
| 1504 | | |
| 1505 | | DEFINE_LEGACY_SOUND_DEVICE(TED7360, ted7360); |
trunk/src/mess/machine/c16.c
| r17575 | r17576 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | commodore c16 home computer |
| 4 | | |
| 5 | | peter.trauner@jk.uni-linz.ac.at |
| 6 | | documentation |
| 7 | | www.funet.fi |
| 8 | | |
| 9 | | ***************************************************************************/ |
| 10 | | |
| 11 | | #include "emu.h" |
| 12 | | #include "audio/ted7360.h" |
| 13 | | #include "cpu/m6502/m6502.h" |
| 14 | | #include "imagedev/cassette.h" |
| 15 | | #include "imagedev/cartslot.h" |
| 16 | | #include "machine/ram.h" |
| 17 | | #include "includes/c16.h" |
| 18 | | #include "machine/cbmiec.h" |
| 19 | | #include "sound/sid6581.h" |
| 20 | | |
| 21 | | #define VERBOSE_LEVEL 0 |
| 22 | | #define DBG_LOG( MACHINE, N, M, A ) \ |
| 23 | | do { \ |
| 24 | | if(VERBOSE_LEVEL >= N) \ |
| 25 | | { \ |
| 26 | | if( M ) \ |
| 27 | | logerror("%11.6f: %-24s", MACHINE.time().as_double(), (char*) M ); \ |
| 28 | | logerror A; \ |
| 29 | | } \ |
| 30 | | } while (0) |
| 31 | | |
| 32 | | |
| 33 | | /* |
| 34 | | * tia6523 |
| 35 | | * |
| 36 | | * connector to floppy c1551 (delivered with c1551 as c16 expansion) |
| 37 | | * port a for data read/write |
| 38 | | * port b |
| 39 | | * 0 status 0 |
| 40 | | * 1 status 1 |
| 41 | | * port c |
| 42 | | * 6 dav output edge data on port a available |
| 43 | | * 7 ack input edge ready for next datum |
| 44 | | */ |
| 45 | | |
| 46 | | /* |
| 47 | | ddr bit 1 port line is output |
| 48 | | port bit 1 port line is high |
| 49 | | |
| 50 | | serial bus |
| 51 | | 1 serial srq in (ignored) |
| 52 | | 2 gnd |
| 53 | | 3 atn out (pull up) |
| 54 | | 4 clock in/out (pull up) |
| 55 | | 5 data in/out (pull up) |
| 56 | | 6 /reset (pull up) hardware |
| 57 | | |
| 58 | | |
| 59 | | p0 negated serial bus pin 5 /data out |
| 60 | | p1 negated serial bus pin 4 /clock out, cassette write |
| 61 | | p2 negated serial bus pin 3 /atn out |
| 62 | | p3 cassette motor out |
| 63 | | |
| 64 | | p4 cassette read |
| 65 | | p5 not connected (or not available on MOS7501?) |
| 66 | | p6 serial clock in |
| 67 | | p7 serial data in, serial bus 5 |
| 68 | | */ |
| 69 | | |
| 70 | | WRITE8_DEVICE_HANDLER(c16_m7501_port_write) |
| 71 | | { |
| 72 | | c16_state *state = device->machine().driver_data<c16_state>(); |
| 73 | | |
| 74 | | /* bit zero then output 0 */ |
| 75 | | state->m_iec->atn_w(!BIT(data, 2)); |
| 76 | | state->m_iec->clk_w(!BIT(data, 1)); |
| 77 | | state->m_iec->data_w(!BIT(data, 0)); |
| 78 | | |
| 79 | | state->m_cassette->output(!BIT(data, 1) ? -(0x5a9e >> 1) : +(0x5a9e >> 1)); |
| 80 | | |
| 81 | | state->m_cassette->change_state(BIT(data, 7) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); |
| 82 | | } |
| 83 | | |
| 84 | | READ8_DEVICE_HANDLER(c16_m7501_port_read) |
| 85 | | { |
| 86 | | c16_state *state = device->machine().driver_data<c16_state>(); |
| 87 | | UINT8 data = 0xff; |
| 88 | | UINT8 c16_port7501 = m6510_get_port(state->m_maincpu); |
| 89 | | |
| 90 | | if (BIT(c16_port7501, 0) || !state->m_iec->data_r()) |
| 91 | | data &= ~0x80; |
| 92 | | |
| 93 | | if (BIT(c16_port7501, 1) || !state->m_iec->clk_r()) |
| 94 | | data &= ~0x40; |
| 95 | | |
| 96 | | // data &= ~0x20; // port bit not in pinout |
| 97 | | |
| 98 | | if (state->m_cassette->input() > +0.0) |
| 99 | | data |= 0x10; |
| 100 | | else |
| 101 | | data &= ~0x10; |
| 102 | | |
| 103 | | return data; |
| 104 | | } |
| 105 | | |
| 106 | | static void c16_bankswitch( running_machine &machine ) |
| 107 | | { |
| 108 | | c16_state *state = machine.driver_data<c16_state>(); |
| 109 | | UINT8 *rom = state->memregion("maincpu")->base(); |
| 110 | | state->membank("bank9")->set_base(state->m_messram->pointer()); |
| 111 | | |
| 112 | | switch (state->m_lowrom) |
| 113 | | { |
| 114 | | case 0: |
| 115 | | state->membank("bank2")->set_base(rom + 0x10000); |
| 116 | | break; |
| 117 | | case 1: |
| 118 | | state->membank("bank2")->set_base(rom + 0x18000); |
| 119 | | break; |
| 120 | | case 2: |
| 121 | | state->membank("bank2")->set_base(rom + 0x20000); |
| 122 | | break; |
| 123 | | case 3: |
| 124 | | state->membank("bank2")->set_base(rom + 0x28000); |
| 125 | | break; |
| 126 | | } |
| 127 | | |
| 128 | | switch (state->m_highrom) |
| 129 | | { |
| 130 | | case 0: |
| 131 | | state->membank("bank3")->set_base(rom + 0x14000); |
| 132 | | state->membank("bank8")->set_base(rom + 0x17f20); |
| 133 | | break; |
| 134 | | case 1: |
| 135 | | state->membank("bank3")->set_base(rom + 0x1c000); |
| 136 | | state->membank("bank8")->set_base(rom + 0x1ff20); |
| 137 | | break; |
| 138 | | case 2: |
| 139 | | state->membank("bank3")->set_base(rom + 0x24000); |
| 140 | | state->membank("bank8")->set_base(rom + 0x27f20); |
| 141 | | break; |
| 142 | | case 3: |
| 143 | | state->membank("bank3")->set_base(rom + 0x2c000); |
| 144 | | state->membank("bank8")->set_base(rom + 0x2ff20); |
| 145 | | break; |
| 146 | | } |
| 147 | | state->membank("bank4")->set_base(rom + 0x17c00); |
| 148 | | } |
| 149 | | |
| 150 | | WRITE8_HANDLER( c16_switch_to_rom ) |
| 151 | | { |
| 152 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 153 | | |
| 154 | | ted7360_rom_switch_w(state->m_ted7360, 1); |
| 155 | | c16_bankswitch(space->machine()); |
| 156 | | } |
| 157 | | |
| 158 | | /* write access to fddX load data flipflop |
| 159 | | * and selects roms |
| 160 | | * a0 a1 |
| 161 | | * 0 0 basic |
| 162 | | * 0 1 plus4 low |
| 163 | | * 1 0 c1 low |
| 164 | | * 1 1 c2 low |
| 165 | | * |
| 166 | | * a2 a3 |
| 167 | | * 0 0 kernal |
| 168 | | * 0 1 plus4 hi |
| 169 | | * 1 0 c1 high |
| 170 | | * 1 1 c2 high */ |
| 171 | | WRITE8_HANDLER( c16_select_roms ) |
| 172 | | { |
| 173 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 174 | | |
| 175 | | state->m_lowrom = offset & 0x03; |
| 176 | | state->m_highrom = (offset & 0x0c) >> 2; |
| 177 | | if (ted7360_rom_switch_r(state->m_ted7360)) |
| 178 | | c16_bankswitch(space->machine()); |
| 179 | | } |
| 180 | | |
| 181 | | WRITE8_HANDLER( c16_switch_to_ram ) |
| 182 | | { |
| 183 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 184 | | UINT8 *ram = state->m_messram->pointer(); |
| 185 | | UINT32 ram_size = state->m_messram->size(); |
| 186 | | |
| 187 | | ted7360_rom_switch_w(state->m_ted7360, 0); |
| 188 | | |
| 189 | | state->membank("bank2")->set_base(ram + (0x8000 % ram_size)); |
| 190 | | state->membank("bank3")->set_base(ram + (0xc000 % ram_size)); |
| 191 | | state->membank("bank4")->set_base(ram + (0xfc00 % ram_size)); |
| 192 | | state->membank("bank8")->set_base(ram + (0xff20 % ram_size)); |
| 193 | | } |
| 194 | | |
| 195 | | UINT8 c16_read_keyboard( running_machine &machine, int databus ) |
| 196 | | { |
| 197 | | c16_state *state = machine.driver_data<c16_state>(); |
| 198 | | UINT8 value = 0xff; |
| 199 | | int i; |
| 200 | | |
| 201 | | for (i = 0; i < 8; i++) |
| 202 | | { |
| 203 | | if (!BIT(state->m_port6529, i)) |
| 204 | | value &= state->m_keyline[i]; |
| 205 | | } |
| 206 | | |
| 207 | | /* looks like joy 0 needs dataline2 low |
| 208 | | * and joy 1 needs dataline1 low |
| 209 | | * write to 0xff08 (value on databus) reloads latches */ |
| 210 | | if (!BIT(databus, 2)) |
| 211 | | value &= state->m_keyline[8]; |
| 212 | | |
| 213 | | if (!BIT(databus, 1)) |
| 214 | | value &= state->m_keyline[9]; |
| 215 | | |
| 216 | | return value; |
| 217 | | } |
| 218 | | |
| 219 | | /* |
| 220 | | * mos 6529 |
| 221 | | * simple 1 port 8bit input output |
| 222 | | * output with pull up resistors, 0 means low |
| 223 | | * input, 0 means low |
| 224 | | */ |
| 225 | | /* |
| 226 | | * ic used as output, |
| 227 | | * output low means keyboard line selected |
| 228 | | * keyboard line is then read into the ted7360 latch |
| 229 | | */ |
| 230 | | WRITE8_HANDLER( c16_6529_port_w ) |
| 231 | | { |
| 232 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 233 | | state->m_port6529 = data; |
| 234 | | } |
| 235 | | |
| 236 | | READ8_HANDLER( c16_6529_port_r ) |
| 237 | | { |
| 238 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 239 | | return state->m_port6529 & (c16_read_keyboard (space->machine(), 0xff /*databus */ ) | (state->m_port6529 ^ 0xff)); |
| 240 | | } |
| 241 | | |
| 242 | | /* |
| 243 | | * p0 Userport b |
| 244 | | * p1 Userport k |
| 245 | | * p2 Userport 4, cassette sense |
| 246 | | * p3 Userport 5 |
| 247 | | * p4 Userport 6 |
| 248 | | * p5 Userport 7 |
| 249 | | * p6 Userport j |
| 250 | | * p7 Userport f |
| 251 | | */ |
| 252 | | WRITE8_HANDLER( plus4_6529_port_w ) |
| 253 | | { |
| 254 | | } |
| 255 | | |
| 256 | | READ8_HANDLER( plus4_6529_port_r ) |
| 257 | | { |
| 258 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 259 | | int data = 0x00; |
| 260 | | |
| 261 | | if ((state->m_cassette->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) |
| 262 | | data &= ~0x04; |
| 263 | | else |
| 264 | | data |= 0x04; |
| 265 | | |
| 266 | | return data; |
| 267 | | } |
| 268 | | |
| 269 | | READ8_HANDLER( c16_fd1x_r ) |
| 270 | | { |
| 271 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 272 | | int data = 0x00; |
| 273 | | |
| 274 | | if ((state->m_cassette->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) |
| 275 | | data &= ~0x04; |
| 276 | | else |
| 277 | | data |= 0x04; |
| 278 | | |
| 279 | | return data; |
| 280 | | } |
| 281 | | |
| 282 | | /** |
| 283 | | 0 write: transmit data |
| 284 | | 0 read: receiver data |
| 285 | | 1 write: programmed rest (data is dont care) |
| 286 | | 1 read: status register |
| 287 | | 2 command register |
| 288 | | 3 control register |
| 289 | | control register (offset 3) |
| 290 | | cleared by hardware reset, not changed by programmed reset |
| 291 | | 7: 2 stop bits (0 1 stop bit) |
| 292 | | 6,5: data word length |
| 293 | | 00 8 bits |
| 294 | | 01 7 |
| 295 | | 10 6 |
| 296 | | 11 5 |
| 297 | | 4: ?? clock source |
| 298 | | 0 external receiver clock |
| 299 | | 1 baud rate generator |
| 300 | | 3-0: baud rate generator |
| 301 | | 0000 use external clock |
| 302 | | 0001 60 |
| 303 | | 0010 75 |
| 304 | | 0011 |
| 305 | | 0100 |
| 306 | | 0101 |
| 307 | | 0110 300 |
| 308 | | 0111 600 |
| 309 | | 1000 1200 |
| 310 | | 1001 |
| 311 | | 1010 2400 |
| 312 | | 1011 3600 |
| 313 | | 1100 4800 |
| 314 | | 1101 7200 |
| 315 | | 1110 9600 |
| 316 | | 1111 19200 |
| 317 | | control register |
| 318 | | */ |
| 319 | | WRITE8_HANDLER( c16_6551_port_w ) |
| 320 | | { |
| 321 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 322 | | |
| 323 | | offset &= 0x03; |
| 324 | | DBG_LOG(space->machine(), 3, "6551", ("port write %.2x %.2x\n", offset, data)); |
| 325 | | state->m_port6529 = data; |
| 326 | | } |
| 327 | | |
| 328 | | READ8_HANDLER( c16_6551_port_r ) |
| 329 | | { |
| 330 | | int data = 0x00; |
| 331 | | |
| 332 | | offset &= 0x03; |
| 333 | | DBG_LOG(space->machine(), 3, "6551", ("port read %.2x %.2x\n", offset, data)); |
| 334 | | return data; |
| 335 | | } |
| 336 | | |
| 337 | | int c16_dma_read( running_machine &machine, int offset ) |
| 338 | | { |
| 339 | | c16_state *state = machine.driver_data<c16_state>(); |
| 340 | | return state->m_messram->pointer()[offset % state->m_messram->size()]; |
| 341 | | } |
| 342 | | |
| 343 | | int c16_dma_read_rom( running_machine &machine, int offset ) |
| 344 | | { |
| 345 | | c16_state *state = machine.driver_data<c16_state>(); |
| 346 | | |
| 347 | | /* should read real c16 system bus from 0xfd00 -ff1f */ |
| 348 | | if (offset >= 0xc000) |
| 349 | | { /* rom address in rom */ |
| 350 | | if ((offset >= 0xfc00) && (offset < 0xfd00)) |
| 351 | | return state->m_mem10000[offset]; |
| 352 | | |
| 353 | | switch (state->m_highrom) |
| 354 | | { |
| 355 | | case 0: |
| 356 | | return state->m_mem10000[offset & 0x7fff]; |
| 357 | | case 1: |
| 358 | | return state->m_mem18000[offset & 0x7fff]; |
| 359 | | case 2: |
| 360 | | return state->m_mem20000[offset & 0x7fff]; |
| 361 | | case 3: |
| 362 | | return state->m_mem28000[offset & 0x7fff]; |
| 363 | | } |
| 364 | | } |
| 365 | | |
| 366 | | if (offset >= 0x8000) |
| 367 | | { /* rom address in rom */ |
| 368 | | switch (state->m_lowrom) |
| 369 | | { |
| 370 | | case 0: |
| 371 | | return state->m_mem10000[offset & 0x7fff]; |
| 372 | | case 1: |
| 373 | | return state->m_mem18000[offset & 0x7fff]; |
| 374 | | case 2: |
| 375 | | return state->m_mem20000[offset & 0x7fff]; |
| 376 | | case 3: |
| 377 | | return state->m_mem28000[offset & 0x7fff]; |
| 378 | | } |
| 379 | | } |
| 380 | | |
| 381 | | return state->m_messram->pointer()[offset % state->m_messram->size()]; |
| 382 | | } |
| 383 | | |
| 384 | | void c16_interrupt( running_machine &machine, int level ) |
| 385 | | { |
| 386 | | c16_state *state = machine.driver_data<c16_state>(); |
| 387 | | |
| 388 | | if (level != state->m_old_level) |
| 389 | | { |
| 390 | | DBG_LOG(machine, 3, "mos7501", ("irq %s\n", level ? "start" : "end")); |
| 391 | | device_set_input_line(state->m_maincpu, M6510_IRQ_LINE, level); |
| 392 | | state->m_old_level = level; |
| 393 | | } |
| 394 | | } |
| 395 | | |
| 396 | | static void c16_common_driver_init( running_machine &machine ) |
| 397 | | { |
| 398 | | c16_state *state = machine.driver_data<c16_state>(); |
| 399 | | UINT8 *rom = state->memregion("maincpu")->base(); |
| 400 | | |
| 401 | | /* initial bankswitch (notice that TED7360 is init to ROM) */ |
| 402 | | state->membank("bank2")->set_base(rom + 0x10000); |
| 403 | | state->membank("bank3")->set_base(rom + 0x14000); |
| 404 | | state->membank("bank4")->set_base(rom + 0x17c00); |
| 405 | | state->membank("bank8")->set_base(rom + 0x17f20); |
| 406 | | |
| 407 | | state->m_mem10000 = rom + 0x10000; |
| 408 | | state->m_mem14000 = rom + 0x14000; |
| 409 | | state->m_mem18000 = rom + 0x18000; |
| 410 | | state->m_mem1c000 = rom + 0x1c000; |
| 411 | | state->m_mem20000 = rom + 0x20000; |
| 412 | | state->m_mem24000 = rom + 0x24000; |
| 413 | | state->m_mem28000 = rom + 0x28000; |
| 414 | | state->m_mem2c000 = rom + 0x2c000; |
| 415 | | } |
| 416 | | |
| 417 | | DRIVER_INIT_MEMBER(c16_state,c16) |
| 418 | | { |
| 419 | | c16_common_driver_init(machine()); |
| 420 | | |
| 421 | | m_sidcard = 0; |
| 422 | | m_pal = 1; |
| 423 | | } |
| 424 | | |
| 425 | | DRIVER_INIT_MEMBER(c16_state,plus4) |
| 426 | | { |
| 427 | | c16_common_driver_init(machine()); |
| 428 | | |
| 429 | | m_sidcard = 0; |
| 430 | | m_pal = 0; |
| 431 | | } |
| 432 | | |
| 433 | | DRIVER_INIT_MEMBER(c16_state,c16sid) |
| 434 | | { |
| 435 | | c16_common_driver_init(machine()); |
| 436 | | |
| 437 | | m_sidcard = 1; |
| 438 | | m_pal = 1; |
| 439 | | } |
| 440 | | |
| 441 | | DRIVER_INIT_MEMBER(c16_state,plus4sid) |
| 442 | | { |
| 443 | | c16_common_driver_init(machine()); |
| 444 | | |
| 445 | | m_sidcard = 1; |
| 446 | | m_pal = 0; |
| 447 | | } |
| 448 | | |
| 449 | | MACHINE_RESET( c16 ) |
| 450 | | { |
| 451 | | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); |
| 452 | | c16_state *state = machine.driver_data<c16_state>(); |
| 453 | | UINT8 *ram = state->m_messram->pointer(); |
| 454 | | UINT32 ram_size = state->m_messram->size(); |
| 455 | | |
| 456 | | memset(state->m_keyline, 0xff, ARRAY_LENGTH(state->m_keyline)); |
| 457 | | |
| 458 | | state->m_lowrom = 0; |
| 459 | | state->m_highrom = 0; |
| 460 | | state->m_old_level = 0; |
| 461 | | state->m_port6529 = 0; |
| 462 | | |
| 463 | | if (state->m_pal) |
| 464 | | { |
| 465 | | state->membank("bank1")->set_base(ram + (0x4000 % ram_size)); |
| 466 | | |
| 467 | | state->membank("bank5")->set_base(ram + (0x4000 % ram_size)); |
| 468 | | state->membank("bank6")->set_base(ram + (0x8000 % ram_size)); |
| 469 | | state->membank("bank7")->set_base(ram + (0xc000 % ram_size)); |
| 470 | | |
| 471 | | space->install_write_bank(0xff20, 0xff3d,"bank10"); |
| 472 | | space->install_write_bank(0xff40, 0xffff, "bank11"); |
| 473 | | state->membank("bank10")->set_base(ram + (0xff20 % ram_size)); |
| 474 | | state->membank("bank11")->set_base(ram + (0xff40 % ram_size)); |
| 475 | | } |
| 476 | | else |
| 477 | | { |
| 478 | | space->install_write_bank(0x4000, 0xfcff, "bank10"); |
| 479 | | state->membank("bank10")->set_base(ram + (0x4000 % ram_size)); |
| 480 | | } |
| 481 | | } |
| 482 | | |
| 483 | | #if 0 |
| 484 | | // FIXME |
| 485 | | // in very old MESS versions, we had these handlers to enable SID writes to 0xd400. |
| 486 | | // would a real SID Card allow for this? If not, this should be removed completely |
| 487 | | static WRITE8_HANDLER( c16_sidcart_16k ) |
| 488 | | { |
| 489 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 490 | | UINT8 *ram = state->m_messram->pointer(); |
| 491 | | |
| 492 | | ram[0x1400 + offset] = data; |
| 493 | | ram[0x5400 + offset] = data; |
| 494 | | ram[0x9400 + offset] = data; |
| 495 | | ram[0xd400 + offset] = data; |
| 496 | | |
| 497 | | sid6581_w(state->m_sid, offset, data); |
| 498 | | } |
| 499 | | |
| 500 | | static WRITE8_HANDLER( c16_sidcart_64k ) |
| 501 | | { |
| 502 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 503 | | |
| 504 | | state->m_messram->pointer()[0xd400 + offset] = data; |
| 505 | | |
| 506 | | sid6581_w(state->m_sid, offset, data); |
| 507 | | } |
| 508 | | |
| 509 | | static TIMER_CALLBACK( c16_sidhack_tick ) |
| 510 | | { |
| 511 | | address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); |
| 512 | | c16_state *state = space->machine().driver_data<c16_state>(); |
| 513 | | |
| 514 | | if (machine.root_device().ioport("SID")->read_safe(0x00) & 0x02) |
| 515 | | { |
| 516 | | if (state->m_pal) |
| 517 | | space->install_legacy_write_handler(0xd400, 0xd41f, FUNC(c16_sidcart_16k)); |
| 518 | | else |
| 519 | | space->install_legacy_write_handler(0xd400, 0xd41f, FUNC(c16_sidcart_64k)); |
| 520 | | } |
| 521 | | else |
| 522 | | { |
| 523 | | space->unmap_write(0xd400, 0xd41f); |
| 524 | | } |
| 525 | | } |
| 526 | | #endif |
| 527 | | |
| 528 | | static TIMER_CALLBACK( c16_sidcard_tick ) |
| 529 | | { |
| 530 | | c16_state *state = machine.driver_data<c16_state>(); |
| 531 | | address_space *space = state->m_maincpu->memory().space(AS_PROGRAM); |
| 532 | | |
| 533 | | if (machine.root_device().ioport("SID")->read_safe(0x00) & 0x01) |
| 534 | | space->install_legacy_readwrite_handler(*state->m_sid, 0xfe80, 0xfe9f, FUNC(sid6581_r), FUNC(sid6581_w)); |
| 535 | | else |
| 536 | | space->install_legacy_readwrite_handler(*state->m_sid, 0xfd40, 0xfd5f, FUNC(sid6581_r), FUNC(sid6581_w)); |
| 537 | | } |
| 538 | | |
| 539 | | INTERRUPT_GEN( c16_frame_interrupt ) |
| 540 | | { |
| 541 | | c16_state *state = device->machine().driver_data<c16_state>(); |
| 542 | | int value, i; |
| 543 | | static const char *const c16ports[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7" }; |
| 544 | | |
| 545 | | /* Lines 0-7 : common keyboard */ |
| 546 | | for (i = 0; i < 8; i++) |
| 547 | | { |
| 548 | | value = 0xff; |
| 549 | | value &= ~device->machine().root_device().ioport(c16ports[i])->read(); |
| 550 | | |
| 551 | | /* Shift Lock is mapped on Left/Right Shift */ |
| 552 | | if ((i == 1) && (device->machine().root_device().ioport("SPECIAL")->read() & 0x80)) |
| 553 | | value &= ~0x80; |
| 554 | | |
| 555 | | state->m_keyline[i] = value; |
| 556 | | } |
| 557 | | |
| 558 | | if (device->machine().root_device().ioport("CTRLSEL")->read() & 0x01) |
| 559 | | { |
| 560 | | value = 0xff; |
| 561 | | if (device->machine().root_device().ioport("JOY0")->read() & 0x10) /* Joypad1_Button */ |
| 562 | | { |
| 563 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
| 564 | | value &= ~0x80; |
| 565 | | else |
| 566 | | value &= ~0x40; |
| 567 | | } |
| 568 | | |
| 569 | | value &= ~(device->machine().root_device().ioport("JOY0")->read() & 0x0f); /* Other Inputs Joypad1 */ |
| 570 | | |
| 571 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
| 572 | | state->m_keyline[9] = value; |
| 573 | | else |
| 574 | | state->m_keyline[8] = value; |
| 575 | | } |
| 576 | | |
| 577 | | if (device->machine().root_device().ioport("CTRLSEL")->read() & 0x10) |
| 578 | | { |
| 579 | | value = 0xff; |
| 580 | | if (device->machine().root_device().ioport("JOY1")->read() & 0x10) /* Joypad2_Button */ |
| 581 | | { |
| 582 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
| 583 | | value &= ~0x40; |
| 584 | | else |
| 585 | | value &= ~0x80; |
| 586 | | } |
| 587 | | |
| 588 | | value &= ~(device->machine().root_device().ioport("JOY1")->read() & 0x0f); /* Other Inputs Joypad2 */ |
| 589 | | |
| 590 | | if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40) |
| 591 | | state->m_keyline[8] = value; |
| 592 | | else |
| 593 | | state->m_keyline[9] = value; |
| 594 | | } |
| 595 | | |
| 596 | | ted7360_frame_interrupt_gen(state->m_ted7360); |
| 597 | | |
| 598 | | if (state->m_sidcard) |
| 599 | | { |
| 600 | | /* if we are emulating the SID card, check which memory area should be accessed */ |
| 601 | | device->machine().scheduler().timer_set(attotime::zero, FUNC(c16_sidcard_tick)); |
| 602 | | #if 0 |
| 603 | | /* if we are emulating the SID card, check if writes to 0xd400 have been enabled */ |
| 604 | | device->machine().scheduler().timer_set(attotime::zero, FUNC(c16_sidhack_tick)); |
| 605 | | #endif |
| 606 | | } |
| 607 | | |
| 608 | | set_led_status(device->machine(), 1, device->machine().root_device().ioport("SPECIAL")->read() & 0x80 ? 1 : 0); /* Shift Lock */ |
| 609 | | set_led_status(device->machine(), 0, device->machine().root_device().ioport("SPECIAL")->read() & 0x40 ? 1 : 0); /* Joystick Swap */ |
| 610 | | } |
| 611 | | |
| 612 | | |
| 613 | | /*********************************************** |
| 614 | | |
| 615 | | C16 Cartridges |
| 616 | | |
| 617 | | ***********************************************/ |
| 618 | | |
| 619 | | static void plus4_software_list_cartridge_load(device_image_interface &image) |
| 620 | | { |
| 621 | | UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base(); |
| 622 | | |
| 623 | | size_t size = image.get_software_region_length("c1l"); |
| 624 | | if (size) |
| 625 | | memcpy(mem + 0x20000, image.get_software_region("c1l"), size); |
| 626 | | |
| 627 | | size = image.get_software_region_length("c1h"); |
| 628 | | if (size) |
| 629 | | memcpy(mem + 0x24000, image.get_software_region("c1h"), size); |
| 630 | | |
| 631 | | size = image.get_software_region_length("c2l"); |
| 632 | | if (size) |
| 633 | | memcpy(mem + 0x28000, image.get_software_region("c2l"), size); |
| 634 | | |
| 635 | | size = image.get_software_region_length("c2h"); |
| 636 | | if (size) |
| 637 | | memcpy(mem + 0x2c000, image.get_software_region("c2h"), size); |
| 638 | | } |
| 639 | | |
| 640 | | static int plus4_crt_load( device_image_interface &image ) |
| 641 | | { |
| 642 | | UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base(); |
| 643 | | int size = image.length(), test; |
| 644 | | const char *filetype; |
| 645 | | int address = 0; |
| 646 | | |
| 647 | | /* magic lowrom at offset 7: $43 $42 $4d */ |
| 648 | | /* if at offset 6 stands 1 it will immediatly jumped to offset 0 (0x8000) */ |
| 649 | | static const unsigned char magic[] = {0x43, 0x42, 0x4d}; |
| 650 | | unsigned char buffer[sizeof (magic)]; |
| 651 | | |
| 652 | | image.fseek(7, SEEK_SET); |
| 653 | | image.fread( buffer, sizeof (magic)); |
| 654 | | image.fseek(0, SEEK_SET); |
| 655 | | |
| 656 | | /* Check if our cart has the magic string, and set its loading address */ |
| 657 | | if (!memcmp(buffer, magic, sizeof (magic))) |
| 658 | | address = 0x20000; |
| 659 | | |
| 660 | | /* Give a loading address to non .bin / non .rom carts as well */ |
| 661 | | filetype = image.filetype(); |
| 662 | | |
| 663 | | /* We would support .hi and .lo files, but currently I'm not sure where to load them. |
| 664 | | We simply load them at 0x20000 at this stage, even if it's probably wrong! |
| 665 | | It could also well be that they both need to be loaded at the same time, but this |
| 666 | | is now impossible since I reduced to 1 the number of cart slots. |
| 667 | | More investigations are in order if any .hi, .lo dump would surface! */ |
| 668 | | if (!mame_stricmp(filetype, "hi")) |
| 669 | | address = 0x20000; /* FIX ME! */ |
| 670 | | |
| 671 | | else if (!mame_stricmp(filetype, "lo")) |
| 672 | | address = 0x20000; /* FIX ME! */ |
| 673 | | |
| 674 | | /* As a last try, give a reasonable loading address also to .bin/.rom without the magic string */ |
| 675 | | else if (!address) |
| 676 | | { |
| 677 | | logerror("Cart %s does not contain the magic string: it may be loaded at the wrong memory address!\n", image.filename()); |
| 678 | | address = 0x20000; |
| 679 | | } |
| 680 | | |
| 681 | | logerror("Loading cart %s at %.5x size:%.4x\n", image.filename(), address, size); |
| 682 | | |
| 683 | | /* Finally load the cart */ |
| 684 | | test = image.fread( mem + address, size); |
| 685 | | |
| 686 | | if (test != size) |
| 687 | | return IMAGE_INIT_FAIL; |
| 688 | | |
| 689 | | return IMAGE_INIT_PASS; |
| 690 | | } |
| 691 | | |
| 692 | | static DEVICE_IMAGE_LOAD( c16_cart ) |
| 693 | | { |
| 694 | | int result = IMAGE_INIT_PASS; |
| 695 | | |
| 696 | | if (image.software_entry() != NULL) |
| 697 | | { |
| 698 | | plus4_software_list_cartridge_load(image); |
| 699 | | } |
| 700 | | else |
| 701 | | { |
| 702 | | result = plus4_crt_load(image); |
| 703 | | } |
| 704 | | |
| 705 | | return result; |
| 706 | | } |
| 707 | | |
| 708 | | MACHINE_CONFIG_FRAGMENT( c16_cartslot ) |
| 709 | | MCFG_CARTSLOT_ADD("cart") |
| 710 | | MCFG_CARTSLOT_EXTENSION_LIST("bin,rom,hi,lo") |
| 711 | | MCFG_CARTSLOT_NOT_MANDATORY |
| 712 | | MCFG_CARTSLOT_INTERFACE("plus4_cart") |
| 713 | | MCFG_CARTSLOT_LOAD(c16_cart) |
| 714 | | MCFG_SOFTWARE_LIST_ADD("cart_list", "plus4_cart") |
| 715 | | MACHINE_CONFIG_END |
trunk/src/mess/machine/ti85_ser.c
| r17575 | r17576 | |
| 1 | | |
| 2 | | #include "emu.h" |
| 3 | | #include "emuopts.h" |
| 4 | | #include "ti85_ser.h" |
| 5 | | |
| 6 | | enum |
| 7 | | { |
| 8 | | TI85_SEND_STOP, |
| 9 | | TI85_SEND_HEADER, |
| 10 | | TI85_RECEIVE_OK_1, |
| 11 | | TI85_RECEIVE_ANSWER_1, |
| 12 | | TI85_RECEIVE_ANSWER_2, |
| 13 | | TI85_RECEIVE_ANSWER_3, |
| 14 | | TI85_SEND_OK, |
| 15 | | TI85_SEND_DATA, |
| 16 | | TI85_RECEIVE_OK_2, |
| 17 | | TI85_SEND_END, |
| 18 | | TI85_RECEIVE_OK_3, |
| 19 | | TI85_RECEIVE_HEADER_1, |
| 20 | | TI85_PREPARE_VARIABLE_DATA, |
| 21 | | TI85_RECEIVE_HEADER_2, |
| 22 | | TI85_SEND_OK_1, |
| 23 | | TI85_SEND_CONTINUE, |
| 24 | | TI85_RECEIVE_OK, |
| 25 | | TI85_RECEIVE_DATA, |
| 26 | | TI85_SEND_OK_2, |
| 27 | | TI85_RECEIVE_END_OR_HEADER_1, |
| 28 | | TI85_SEND_OK_3, |
| 29 | | TI85_PREPARE_SCREEN_REQUEST, |
| 30 | | TI85_SEND_SCREEN_REQUEST |
| 31 | | }; |
| 32 | | |
| 33 | | //supported image formats |
| 34 | | enum |
| 35 | | { |
| 36 | | TI_FILE_UNK, |
| 37 | | TI_FILE_V1, //used for TI-85 and TI-86 image |
| 38 | | TI_FILE_V2, //used for TI-82, TI-83 and TI-73 image |
| 39 | | TI_FILE_V3 //used for TI-83+ and TI-84+ image |
| 40 | | }; |
| 41 | | |
| 42 | | #define TI85_HEADER_SIZE 0x37 |
| 43 | | |
| 44 | | #define TI85_SEND_VARIABLES 1 |
| 45 | | #define TI85_SEND_BACKUP 2 |
| 46 | | #define TI85_RECEIVE_BACKUP 3 |
| 47 | | #define TI85_RECEIVE_VARIABLES 4 |
| 48 | | #define TI85_RECEIVE_SCREEN 5 |
| 49 | | |
| 50 | | #define TI85_PC_OK_PACKET_SIZE 4 |
| 51 | | #define TI85_PC_END_PACKET_SIZE 4 |
| 52 | | |
| 53 | | #define TI82_BACKUP_ID 0x0f //used by the TI-82 |
| 54 | | #define TI85_BACKUP_ID 0x1d //used by the TI-85 and TI-86 |
| 55 | | #define TI83_BACKUP_ID 0x13 //used by the TI-73, TI-83 and TI-83+ |
| 56 | | |
| 57 | | //known tranfer ID |
| 58 | | #define TI_TRANFER_ID_TI73 0x07 |
| 59 | | #define TI_TRANFER_ID_TI82 0x02 |
| 60 | | #define TI_TRANFER_ID_TI83 0x03 |
| 61 | | #define TI_TRANFER_ID_TI83P 0x23 |
| 62 | | #define TI_TRANFER_ID_TI85 0x05 |
| 63 | | #define TI_TRANFER_ID_TI86 0x06 |
| 64 | | |
| 65 | | //packet type |
| 66 | | #define TI_OK_PACKET 0x56 |
| 67 | | #define TI_CONTINUE_PACKET 0x09 |
| 68 | | #define TI_SCREEN_REQUEST_PACKET 0x6d |
| 69 | | #define TI_END_PACKET 0x92 |
| 70 | | |
| 71 | | static const UINT8 ti73_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x37, 0x33, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
| 72 | | static const UINT8 ti85_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x35, 0x2a, 0x2a, 0x1a, 0x0c, 0x00}; |
| 73 | | static const UINT8 ti82_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x32, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
| 74 | | static const UINT8 ti83_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x33, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
| 75 | | static const UINT8 ti83p_file_signature[]= {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x33, 0x46, 0x2a, 0x1a, 0x0a, 0x00}; |
| 76 | | static const UINT8 ti86_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x36, 0x2a, 0x2a, 0x1a, 0x0a, 0x00}; |
| 77 | | |
| 78 | | typedef struct { |
| 79 | | UINT16 head_size; |
| 80 | | UINT16 data_size; |
| 81 | | unsigned char type; |
| 82 | | unsigned char name_size; |
| 83 | | unsigned int offset; |
| 84 | | } ti85_entry; |
| 85 | | |
| 86 | | |
| 87 | | typedef struct { |
| 88 | | UINT8* header; |
| 89 | | UINT16 header_size; |
| 90 | | UINT8* ok; |
| 91 | | UINT16 ok_size; |
| 92 | | UINT8* data; |
| 93 | | UINT32 data_size; |
| 94 | | } ti85_serial_variable; |
| 95 | | |
| 96 | | |
| 97 | | typedef struct { |
| 98 | | ti85_serial_variable * variables; |
| 99 | | UINT8* end; |
| 100 | | UINT16 end_size; |
| 101 | | UINT16 number_of_variables; |
| 102 | | } ti85_serial_data; |
| 103 | | |
| 104 | | |
| 105 | | typedef struct |
| 106 | | { |
| 107 | | UINT8 status; |
| 108 | | int transfer_type; |
| 109 | | UINT8 image_type; |
| 110 | | UINT8 send_id; /* ID used for PC to TI transfer */ |
| 111 | | UINT8 receive_id; /* ID used for TI to PC transfer */ |
| 112 | | UINT8 red_out; /* signal line from machine */ |
| 113 | | UINT8 white_out; /* signal line from machine */ |
| 114 | | UINT8 red_in; /* signal line to machine */ |
| 115 | | UINT8 white_in; /* signal line to machine */ |
| 116 | | UINT8 *receive_buffer; |
| 117 | | UINT8 *receive_data; |
| 118 | | ti85_serial_data stream; |
| 119 | | /* receive_data_counter and send_data_counter can be combined? */ |
| 120 | | UINT32 receive_data_counter; /* from ti85_receive_serial */ |
| 121 | | UINT32 send_data_counter; /* from ti85_send_serial */ |
| 122 | | /* variables_variable_number, send_backup_variable_number, and backup_variable_number can be combined? */ |
| 123 | | UINT16 variables_variable_number; /* from ti85_send_variables */ |
| 124 | | UINT16 send_backup_variable_number; /* from ti85_send_backup */ |
| 125 | | int variable_number; /* from ti85_receive_variables */ |
| 126 | | UINT8 *var_data; /* from ti85_receive_variables */ |
| 127 | | UINT32 var_file_number; /* from ti85_receive_variables */ |
| 128 | | UINT8 *var_file_data; /* from ti85_receive_variables */ |
| 129 | | int var_file_size; /* from ti85_receive_variables */ |
| 130 | | int backup_variable_number; /* from ti85_receive_backup */ |
| 131 | | int backup_data_size[3]; /* from ti85_receive_backup */ |
| 132 | | UINT8 *backup_file_data; /* from ti85_receive_backup */ |
| 133 | | UINT32 backup_file_number; /* from ti85_receive_backup */ |
| 134 | | UINT32 image_file_number; /* from ti85_receive_screen */ |
| 135 | | } ti85serial_state; |
| 136 | | |
| 137 | | |
| 138 | | INLINE ti85serial_state *get_token(device_t *device) |
| 139 | | { |
| 140 | | assert(device != NULL); |
| 141 | | assert((device->type() == TI82SERIAL) || |
| 142 | | (device->type() == TI73SERIAL) || |
| 143 | | (device->type() == TI83PSERIAL) || |
| 144 | | (device->type() == TI85SERIAL) || |
| 145 | | (device->type() == TI86SERIAL)); |
| 146 | | return (ti85serial_state *) downcast<legacy_device_base *>(device)->token(); |
| 147 | | } |
| 148 | | |
| 149 | | |
| 150 | | static UINT16 ti85_calculate_checksum(const UINT8* data, unsigned int size) |
| 151 | | { |
| 152 | | UINT16 checksum = 0; |
| 153 | | unsigned int i; |
| 154 | | |
| 155 | | for (i = 0; i<size; i++) |
| 156 | | checksum += data[i]; |
| 157 | | return checksum; |
| 158 | | } |
| 159 | | |
| 160 | | |
| 161 | | static UINT16 ti85_variables_count (const UINT8 * ti85_data, unsigned int ti85_data_size) |
| 162 | | { |
| 163 | | unsigned int pos, head_size, var_size; |
| 164 | | UINT16 number_of_entries = 0; |
| 165 | | pos = TI85_HEADER_SIZE; |
| 166 | | while (pos < ti85_data_size-2) |
| 167 | | { |
| 168 | | head_size = ti85_data[pos+0x00] + ti85_data[pos+0x01]*256; |
| 169 | | var_size = ti85_data[pos+0x02] + ti85_data[pos+0x03]*256; |
| 170 | | pos += head_size+var_size+4; |
| 171 | | number_of_entries++; |
| 172 | | } |
| 173 | | return number_of_entries; |
| 174 | | } |
| 175 | | |
| 176 | | |
| 177 | | static void ti85_free_serial_data_memory (device_t *device) |
| 178 | | { |
| 179 | | ti85serial_state *ti85serial = get_token( device ); |
| 180 | | |
| 181 | | if (ti85serial->receive_buffer) |
| 182 | | { |
| 183 | | free (ti85serial->receive_buffer); |
| 184 | | ti85serial->receive_buffer = NULL; |
| 185 | | } |
| 186 | | if (ti85serial->receive_data) |
| 187 | | { |
| 188 | | free (ti85serial->receive_data); |
| 189 | | ti85serial->receive_data = NULL; |
| 190 | | } |
| 191 | | } |
| 192 | | |
| 193 | | |
| 194 | | static int ti85_alloc_serial_data_memory (device_t *device, UINT32 size) |
| 195 | | { |
| 196 | | ti85serial_state *ti85serial = get_token( device ); |
| 197 | | |
| 198 | | if (!ti85serial->receive_buffer) |
| 199 | | { |
| 200 | | ti85serial->receive_buffer = (UINT8*) malloc (8*size*sizeof(UINT8)); |
| 201 | | if (!ti85serial->receive_buffer) |
| 202 | | return 0; |
| 203 | | } |
| 204 | | |
| 205 | | if (!ti85serial->receive_data) |
| 206 | | { |
| 207 | | ti85serial->receive_data = (UINT8*) malloc (size * sizeof(UINT8)); |
| 208 | | if (!ti85serial->receive_data) |
| 209 | | { |
| 210 | | free (ti85serial->receive_buffer); |
| 211 | | ti85serial->receive_buffer = NULL; |
| 212 | | return 0; |
| 213 | | } |
| 214 | | } |
| 215 | | return 1; |
| 216 | | } |
| 217 | | |
| 218 | | |
| 219 | | static void ti85_backup_read (const UINT8 * ti85_data, unsigned int ti85_data_size, ti85_entry * ti85_entries) |
| 220 | | { |
| 221 | | unsigned int pos = 0x42+2; |
| 222 | | |
| 223 | | ti85_entries[0].head_size = 0x09; |
| 224 | | ti85_entries[0].data_size = ti85_data[0x39] + ti85_data[0x3a]*256; |
| 225 | | ti85_entries[0].offset = pos; |
| 226 | | pos += ti85_entries[0].data_size + 2; |
| 227 | | ti85_entries[1].head_size = 0; |
| 228 | | ti85_entries[1].data_size = ti85_data[0x3c] + ti85_data[0x3d]*256; |
| 229 | | ti85_entries[1].offset = pos; |
| 230 | | pos += ti85_entries[1].data_size + 2; |
| 231 | | ti85_entries[2].head_size = 0; |
| 232 | | ti85_entries[2].data_size = ti85_data[0x3e] + ti85_data[0x3f]*256; |
| 233 | | ti85_entries[2].offset = pos; |
| 234 | | } |
| 235 | | |
| 236 | | |
| 237 | | static void ti85_variables_read (device_t *device, const UINT8 * ti85_data, unsigned int ti85_data_size, ti85_entry * ti85_entries) |
| 238 | | { |
| 239 | | ti85serial_state *ti85serial = get_token( device ); |
| 240 | | unsigned int pos, i=0; |
| 241 | | |
| 242 | | pos = TI85_HEADER_SIZE; |
| 243 | | while (pos < ti85_data_size-2) |
| 244 | | { |
| 245 | | ti85_entries[i].head_size = ti85_data[pos+0x00] + ti85_data[pos+0x01]*256; |
| 246 | | ti85_entries[i].data_size = ti85_data[pos+0x02] + ti85_data[pos+0x03]*256; |
| 247 | | ti85_entries[i].type = ti85_data[pos+0x04]; |
| 248 | | ti85_entries[i].name_size = (ti85serial->image_type != TI_FILE_V1) ? 8 : ti85_data[pos+0x05]; |
| 249 | | ti85_entries[i].offset = pos; |
| 250 | | pos += ti85_entries[i].head_size+ti85_entries[i].data_size+4; |
| 251 | | i++; |
| 252 | | } |
| 253 | | } |
| 254 | | |
| 255 | | |
| 256 | | static int ti85_receive_serial (device_t *device, UINT8* received_data, UINT32 received_data_size) |
| 257 | | { |
| 258 | | ti85serial_state *ti85serial = get_token( device ); |
| 259 | | |
| 260 | | if (ti85serial->receive_data_counter >= received_data_size) |
| 261 | | { |
| 262 | | if (!ti85serial->red_out && !ti85serial->white_out) |
| 263 | | { |
| 264 | | ti85serial->red_in = ti85serial->white_in = 1; |
| 265 | | ti85serial->receive_data_counter = 0; |
| 266 | | return 0; |
| 267 | | } |
| 268 | | return 1; |
| 269 | | } |
| 270 | | |
| 271 | | if (ti85serial->red_in && ti85serial->white_in && (ti85serial->red_out!=ti85serial->white_out)) |
| 272 | | { |
| 273 | | ti85serial->white_in = ti85serial->white_out; |
| 274 | | ti85serial->red_in = ti85serial->red_out; |
| 275 | | received_data[ti85serial->receive_data_counter] = ti85serial->white_out; |
| 276 | | return 1; |
| 277 | | } |
| 278 | | |
| 279 | | if (ti85serial->red_in!=ti85serial->white_in && !ti85serial->red_out && !ti85serial->white_out) |
| 280 | | { |
| 281 | | ti85serial->red_in = ti85serial->white_in = 1; |
| 282 | | ti85serial->receive_data_counter ++; |
| 283 | | return 1; |
| 284 | | } |
| 285 | | return 1; |
| 286 | | } |
| 287 | | |
| 288 | | |
| 289 | | static int ti85_send_serial(device_t *device, UINT8* serial_data, UINT32 serial_data_size) |
| 290 | | { |
| 291 | | ti85serial_state *ti85serial = get_token( device ); |
| 292 | | |
| 293 | | if (ti85serial->send_data_counter>=serial_data_size) |
| 294 | | { |
| 295 | | if (!ti85serial->red_out && !ti85serial->white_out) |
| 296 | | { |
| 297 | | ti85serial->red_in = ti85serial->white_in = 1; |
| 298 | | ti85serial->send_data_counter = 0; |
| 299 | | return 0; |
| 300 | | } |
| 301 | | ti85serial->red_in = ti85serial->white_in = 1; |
| 302 | | return 1; |
| 303 | | } |
| 304 | | |
| 305 | | if (ti85serial->red_in && ti85serial->white_in && !ti85serial->red_out && !ti85serial->white_out) |
| 306 | | { |
| 307 | | ti85serial->red_in = serial_data[ti85serial->send_data_counter] ? 1 : 0; |
| 308 | | ti85serial->white_in = serial_data[ti85serial->send_data_counter] ? 0 : 1; |
| 309 | | return 1; |
| 310 | | } |
| 311 | | |
| 312 | | if ((ti85serial->red_in == ti85serial->red_out) && (ti85serial->white_in == ti85serial->white_out)) |
| 313 | | { |
| 314 | | ti85serial->red_in = ti85serial->white_in = 1; |
| 315 | | ti85serial->send_data_counter++; |
| 316 | | return 1; |
| 317 | | } |
| 318 | | return 1; |
| 319 | | } |
| 320 | | |
| 321 | | |
| 322 | | static void ti85_convert_data_to_stream (const UINT8* file_data, unsigned int size, UINT8* serial_data) |
| 323 | | { |
| 324 | | unsigned int i, bits; |
| 325 | | |
| 326 | | for (i=0; i<size; i++) |
| 327 | | for (bits = 0; bits < 8; bits++) |
| 328 | | serial_data[i*8+bits] = (file_data[i]>>bits) & 0x01; |
| 329 | | } |
| 330 | | |
| 331 | | |
| 332 | | static void ti85_append_head_to_stream (UINT8 transfer_id, UINT8 tranfer_type, UINT8* serial_data) |
| 333 | | { |
| 334 | | UINT8 tmp_data[4]; |
| 335 | | |
| 336 | | tmp_data[0] = transfer_id; |
| 337 | | tmp_data[1] = tranfer_type; |
| 338 | | tmp_data[2] = 0; |
| 339 | | tmp_data[3] = 0; |
| 340 | | |
| 341 | | ti85_convert_data_to_stream(tmp_data, sizeof(tmp_data), serial_data); |
| 342 | | } |
| 343 | | |
| 344 | | |
| 345 | | static void ti85_convert_stream_to_data (const UINT8* serial_data, UINT32 size, UINT8* data) |
| 346 | | { |
| 347 | | UINT32 i; |
| 348 | | UINT8 bits; |
| 349 | | |
| 350 | | size = size/8; |
| 351 | | |
| 352 | | for (i=0; i<size; i++) |
| 353 | | { |
| 354 | | data[i] = 0; |
| 355 | | for (bits = 0; bits < 8; bits++) |
| 356 | | data[i] |= serial_data[i*8+bits]<<bits; |
| 357 | | } |
| 358 | | } |
| 359 | | |
| 360 | | |
| 361 | | static int ti85_convert_file_data_to_serial_stream (device_t *device, const UINT8* file_data, unsigned int file_size, ti85_serial_data* serial_data) |
| 362 | | { |
| 363 | | ti85serial_state *ti85serial = get_token( device ); |
| 364 | | UINT16 i; |
| 365 | | UINT16 number_of_entries; |
| 366 | | UINT8 backup_id = (ti85serial->image_type == TI_FILE_V1) ? TI85_BACKUP_ID : ((device->type() == TI82SERIAL) ? TI82_BACKUP_ID : TI83_BACKUP_ID); |
| 367 | | |
| 368 | | ti85_entry* ti85_entries = NULL; |
| 369 | | |
| 370 | | UINT8* temp_data_to_convert = NULL; |
| 371 | | UINT16 checksum; |
| 372 | | |
| 373 | | //verify that the provided file is compatible with the model |
| 374 | | if (device->type() == TI73SERIAL) |
| 375 | | if (strncmp((char *) file_data, (char *) ti73_file_signature, 11)) |
| 376 | | return 0; |
| 377 | | if (device->type() == TI85SERIAL) |
| 378 | | if (strncmp((char *) file_data, (char *) ti85_file_signature, 11)) |
| 379 | | return 0; |
| 380 | | if (device->type() == TI82SERIAL) |
| 381 | | if (strncmp((char *) file_data, (char *) ti82_file_signature, 11)) |
| 382 | | return 0; |
| 383 | | if (device->type() == TI83PSERIAL) //TI-83+ is compatible with TI-83 and TI-82 file |
| 384 | | if (strncmp((char *) file_data, (char *) ti83p_file_signature, 10) && strncmp((char *) file_data, (char *) ti83_file_signature, 11) |
| 385 | | && strncmp((char *) file_data, (char *) ti82_file_signature, 11)) |
| 386 | | return 0; |
| 387 | | if (device->type() == TI86SERIAL) //TI-86 is compatible with TI-85 file |
| 388 | | if (strncmp((char *) file_data, (char *) ti86_file_signature, 11) && strncmp((char *) file_data, (char *) ti85_file_signature, 11)) |
| 389 | | return 0; |
| 390 | | |
| 391 | | //identify the image |
| 392 | | if (!strncmp((char *) file_data, (char *) ti73_file_signature, 11)) |
| 393 | | { |
| 394 | | ti85serial->send_id = TI_TRANFER_ID_TI73; |
| 395 | | ti85serial->image_type = TI_FILE_V2; |
| 396 | | } |
| 397 | | else if (!strncmp((char *) file_data, (char *) ti85_file_signature, 11)) |
| 398 | | { |
| 399 | | ti85serial->send_id = TI_TRANFER_ID_TI85; |
| 400 | | ti85serial->image_type = TI_FILE_V1; |
| 401 | | } |
| 402 | | else if (!strncmp((char *) file_data, (char *) ti82_file_signature, 11)) |
| 403 | | { |
| 404 | | ti85serial->send_id = TI_TRANFER_ID_TI82; |
| 405 | | ti85serial->image_type = TI_FILE_V2; |
| 406 | | } |
| 407 | | else if (!strncmp((char *) file_data, (char *) ti83_file_signature, 11)) |
| 408 | | { |
| 409 | | ti85serial->send_id = TI_TRANFER_ID_TI83; |
| 410 | | ti85serial->image_type = TI_FILE_V2; |
| 411 | | } |
| 412 | | else if (!strncmp((char *) file_data, (char *) ti83p_file_signature, 11)) |
| 413 | | { |
| 414 | | ti85serial->send_id = TI_TRANFER_ID_TI83P; |
| 415 | | ti85serial->image_type = TI_FILE_V3; |
| 416 | | } |
| 417 | | else if (!strncmp((char *) file_data, (char *) ti86_file_signature, 11)) |
| 418 | | { |
| 419 | | ti85serial->send_id = TI_TRANFER_ID_TI86; |
| 420 | | ti85serial->image_type = TI_FILE_V1; |
| 421 | | } |
| 422 | | |
| 423 | | logerror("Image ID: 0x%02x, version: 0x%02x\n", ti85serial->send_id, ti85serial->image_type); |
| 424 | | |
| 425 | | /*Serial stream preparing*/ |
| 426 | | serial_data->end = NULL; |
| 427 | | |
| 428 | | number_of_entries = (file_data[0x3b]==backup_id) ? 3 : ti85_variables_count(file_data, file_size); |
| 429 | | if (!number_of_entries) return 0; |
| 430 | | |
| 431 | | serial_data->variables = (ti85_serial_variable*)malloc(sizeof(ti85_serial_variable)*number_of_entries); |
| 432 | | if (!serial_data->variables) return 0; |
| 433 | | |
| 434 | | for (i=0; i<number_of_entries; i++) |
| 435 | | { |
| 436 | | serial_data->variables[i].header = NULL; |
| 437 | | serial_data->variables[i].ok = NULL; |
| 438 | | serial_data->variables[i].data = NULL; |
| 439 | | } |
| 440 | | |
| 441 | | serial_data->number_of_variables = number_of_entries; |
| 442 | | |
| 443 | | ti85_entries = (ti85_entry*) malloc (sizeof(ti85_entry)*number_of_entries); |
| 444 | | if (!ti85_entries) return 0; |
| 445 | | |
| 446 | | if (file_data[0x3b]==backup_id) |
| 447 | | { |
| 448 | | ti85serial->transfer_type = TI85_SEND_BACKUP; |
| 449 | | ti85_backup_read (file_data, file_size, ti85_entries); |
| 450 | | } |
| 451 | | else |
| 452 | | { |
| 453 | | ti85serial->transfer_type = TI85_SEND_VARIABLES; |
| 454 | | ti85_variables_read (device, file_data, file_size, ti85_entries); |
| 455 | | } |
| 456 | | for (i=0; i<number_of_entries; i++) |
| 457 | | { |
| 458 | | /*Header packet*/ |
| 459 | | if (file_data[0x3b]==backup_id) |
| 460 | | { |
| 461 | | if (!i) |
| 462 | | { |
| 463 | | temp_data_to_convert = (UINT8*) malloc (0x0f); |
| 464 | | if (!temp_data_to_convert) |
| 465 | | { |
| 466 | | free (ti85_entries); |
| 467 | | return 0; |
| 468 | | } |
| 469 | | serial_data->variables[i].header = (UINT8*) malloc (0x0f*8); |
| 470 | | |
| 471 | | if (!serial_data->variables[i].header) |
| 472 | | { |
| 473 | | free (ti85_entries); |
| 474 | | free (temp_data_to_convert); |
| 475 | | return 0; |
| 476 | | } |
| 477 | | serial_data->variables[i].header_size = 0x0f*8; |
| 478 | | temp_data_to_convert[0] = ti85serial->send_id; //PC sends |
| 479 | | temp_data_to_convert[1] = 0x06; //header |
| 480 | | memcpy( temp_data_to_convert+0x02, file_data+0x37, 0x0b); |
| 481 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4, 0x09); |
| 482 | | temp_data_to_convert[13] = checksum&0x00ff; |
| 483 | | temp_data_to_convert[14] = (checksum&0xff00)>>8; |
| 484 | | ti85_convert_data_to_stream(temp_data_to_convert, 0x0f, serial_data->variables[i].header); |
| 485 | | free(temp_data_to_convert); |
| 486 | | } |
| 487 | | else |
| 488 | | { |
| 489 | | serial_data->variables[i].header = NULL; |
| 490 | | serial_data->variables[i].header_size = 0; |
| 491 | | } |
| 492 | | } |
| 493 | | else |
| 494 | | { |
| 495 | | temp_data_to_convert = (UINT8*) malloc (10+ti85_entries[i].name_size); |
| 496 | | if (!temp_data_to_convert) |
| 497 | | { |
| 498 | | free (ti85_entries); |
| 499 | | return 0; |
| 500 | | } |
| 501 | | serial_data->variables[i].header = (UINT8*) malloc ((10+ti85_entries[i].name_size)*8); |
| 502 | | if (!serial_data->variables[i].header) |
| 503 | | { |
| 504 | | free (temp_data_to_convert); |
| 505 | | free (ti85_entries); |
| 506 | | return 0; |
| 507 | | } |
| 508 | | |
| 509 | | if (ti85serial->image_type == TI_FILE_V1) |
| 510 | | { |
| 511 | | serial_data->variables[i].header_size = (10+ti85_entries[i].name_size)*8; |
| 512 | | |
| 513 | | temp_data_to_convert[0] = ti85serial->send_id; |
| 514 | | temp_data_to_convert[1] = 0x06; //header |
| 515 | | temp_data_to_convert[2] = (4+ti85_entries[i].name_size)&0x00ff; |
| 516 | | temp_data_to_convert[3] = ((4+ti85_entries[i].name_size)&0xff00)>>8; |
| 517 | | temp_data_to_convert[4] = (ti85_entries[i].data_size)&0x00ff; |
| 518 | | temp_data_to_convert[5] = ((ti85_entries[i].data_size)&0xff00)>>8; |
| 519 | | temp_data_to_convert[6] = ti85_entries[i].type; |
| 520 | | temp_data_to_convert[7] = ti85_entries[i].name_size; |
| 521 | | memcpy(temp_data_to_convert+8, file_data+ti85_entries[i].offset+0x06, ti85_entries[i].name_size); |
| 522 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].name_size+4); |
| 523 | | temp_data_to_convert[10+ti85_entries[i].name_size-2] = checksum&0x00ff; |
| 524 | | temp_data_to_convert[10+ti85_entries[i].name_size-1] = (checksum&0xff00)>>8; |
| 525 | | ti85_convert_data_to_stream(temp_data_to_convert, 10+ti85_entries[i].name_size, serial_data->variables[i].header); |
| 526 | | } |
| 527 | | |
| 528 | | if (ti85serial->image_type == TI_FILE_V2 || ti85serial->image_type == TI_FILE_V3) |
| 529 | | { |
| 530 | | serial_data->variables[i].header_size = (9+ti85_entries[i].name_size)*8; |
| 531 | | |
| 532 | | temp_data_to_convert[0] = ti85serial->send_id; |
| 533 | | temp_data_to_convert[1] = 0x06; //header |
| 534 | | temp_data_to_convert[2] = (3+ti85_entries[i].name_size)&0x00ff; |
| 535 | | temp_data_to_convert[3] = ((3+ti85_entries[i].name_size)&0xff00)>>8; |
| 536 | | temp_data_to_convert[4] = (ti85_entries[i].data_size)&0x00ff; |
| 537 | | temp_data_to_convert[5] = ((ti85_entries[i].data_size)&0xff00)>>8; |
| 538 | | temp_data_to_convert[6] = ti85_entries[i].type; |
| 539 | | memcpy(temp_data_to_convert+7, file_data+ti85_entries[i].offset+0x05, ti85_entries[i].name_size); |
| 540 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].name_size+3); |
| 541 | | temp_data_to_convert[9+ti85_entries[i].name_size-2] = checksum&0x00ff; |
| 542 | | temp_data_to_convert[9+ti85_entries[i].name_size-1] = (checksum&0xff00)>>8; |
| 543 | | ti85_convert_data_to_stream(temp_data_to_convert, 9+ti85_entries[i].name_size, serial_data->variables[i].header); |
| 544 | | } |
| 545 | | |
| 546 | | free(temp_data_to_convert); |
| 547 | | } |
| 548 | | |
| 549 | | /*OK packet*/ |
| 550 | | serial_data->variables[i].ok = (UINT8*) malloc (TI85_PC_OK_PACKET_SIZE*8); |
| 551 | | if (!serial_data->variables[i].ok) |
| 552 | | { |
| 553 | | free (ti85_entries); |
| 554 | | return 0; |
| 555 | | } |
| 556 | | ti85_append_head_to_stream(ti85serial->send_id, TI_OK_PACKET, serial_data->variables[i].ok); |
| 557 | | serial_data->variables[i].ok_size = TI85_PC_OK_PACKET_SIZE*8; |
| 558 | | |
| 559 | | /*Data packet*/ |
| 560 | | temp_data_to_convert = (UINT8*) malloc (6+ti85_entries[i].data_size); |
| 561 | | if (!temp_data_to_convert) |
| 562 | | { |
| 563 | | free (ti85_entries); |
| 564 | | return 0; |
| 565 | | } |
| 566 | | serial_data->variables[i].data = (UINT8*) malloc ((6+ti85_entries[i].data_size)*8); |
| 567 | | if (!serial_data->variables[i].data) |
| 568 | | { |
| 569 | | free (temp_data_to_convert); |
| 570 | | free (ti85_entries); |
| 571 | | return 0; |
| 572 | | } |
| 573 | | serial_data->variables[i].data_size = (6+ti85_entries[i].data_size)*8; |
| 574 | | |
| 575 | | temp_data_to_convert[0] = ti85serial->send_id; |
| 576 | | temp_data_to_convert[1] = 0x15; //data |
| 577 | | temp_data_to_convert[2] = (ti85_entries[i].data_size)&0x00ff; |
| 578 | | temp_data_to_convert[3] = ((ti85_entries[i].data_size)&0xff00)>>8; |
| 579 | | |
| 580 | | UINT8 name_start = (ti85serial->image_type != TI_FILE_V1) ? 5 : 6; |
| 581 | | |
| 582 | | //TI-83+ files have two additional byte used for the file's version and flag |
| 583 | | if (ti85serial->image_type == TI_FILE_V3) |
| 584 | | name_start += 2; |
| 585 | | |
| 586 | | if (file_data[0x3b]==backup_id) |
| 587 | | memcpy(temp_data_to_convert+4, file_data+ti85_entries[i].offset, ti85_entries[i].data_size); |
| 588 | | else |
| 589 | | memcpy(temp_data_to_convert+4, file_data+ti85_entries[i].offset+name_start+ti85_entries[i].name_size+0x02, ti85_entries[i].data_size); |
| 590 | | |
| 591 | | checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].data_size); |
| 592 | | temp_data_to_convert[6+ti85_entries[i].data_size-2] = checksum&0x00ff; |
| 593 | | temp_data_to_convert[6+ti85_entries[i].data_size-1] = (checksum&0xff00)>>8; |
| 594 | | ti85_convert_data_to_stream(temp_data_to_convert, 6+ti85_entries[i].data_size, serial_data->variables[i].data); |
| 595 | | free(temp_data_to_convert); |
| 596 | | } |
| 597 | | |
| 598 | | |
| 599 | | /*END packet*/ |
| 600 | | serial_data->end = (UINT8*) malloc (TI85_PC_END_PACKET_SIZE*8); |
| 601 | | if (!serial_data->end) |
| 602 | | { |
| 603 | | free (ti85_entries); |
| 604 | | return 0; |
| 605 | | } |
| 606 | | ti85_append_head_to_stream(ti85serial->send_id, TI_END_PACKET, serial_data->end); |
| 607 | | serial_data->end_size = TI85_PC_END_PACKET_SIZE*8; |
| 608 | | |
| 609 | | free (ti85_entries); |
| 610 | | |
| 611 | | return 1; |
| 612 | | } |
| 613 | | |
| 614 | | |
| 615 | | static void ti85_free_serial_stream (ti85_serial_data* serial_data) |
| 616 | | { |
| 617 | | UINT16 i; |
| 618 | | if (serial_data->variables) |
| 619 | | { |
| 620 | | for (i=0; i<serial_data->number_of_variables; i++) |
| 621 | | { |
| 622 | | if (serial_data->variables[i].header) free (serial_data->variables[i].header); |
| 623 | | if (serial_data->variables[i].ok) free (serial_data->variables[i].ok); |
| 624 | | if (serial_data->variables[i].data) free (serial_data->variables[i].data); |
| 625 | | } |
| 626 | | free (serial_data->variables); |
| 627 | | serial_data->variables = NULL; |
| 628 | | } |
| 629 | | serial_data->number_of_variables = 0; |
| 630 | | if (serial_data->end) |
| 631 | | { |
| 632 | | free (serial_data->end); |
| 633 | | serial_data->end = NULL; |
| 634 | | } |
| 635 | | } |
| 636 | | |
| 637 | | |
| 638 | | static void ti85_send_variables (device_t *device) |
| 639 | | { |
| 640 | | ti85serial_state *ti85serial = get_token( device ); |
| 641 | | |
| 642 | | if (!ti85_alloc_serial_data_memory(device, 7)) |
| 643 | | ti85serial->status = TI85_SEND_STOP; |
| 644 | | |
| 645 | | switch (ti85serial->status) |
| 646 | | { |
| 647 | | case TI85_SEND_HEADER: |
| 648 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].header,ti85serial->stream.variables[ti85serial->variables_variable_number].header_size)) |
| 649 | | { |
| 650 | | ti85serial->status = TI85_RECEIVE_OK_1; |
| 651 | | memset (ti85serial->receive_data, 0, 7); |
| 652 | | logerror ("Header sent\n"); |
| 653 | | } |
| 654 | | break; |
| 655 | | case TI85_RECEIVE_OK_1: |
| 656 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 657 | | { |
| 658 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 659 | | ti85serial->status = TI85_RECEIVE_ANSWER_1; |
| 660 | | logerror ("OK received\n"); |
| 661 | | } |
| 662 | | break; |
| 663 | | case TI85_RECEIVE_ANSWER_1: |
| 664 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 665 | | { |
| 666 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 667 | | switch (ti85serial->receive_data[1]) |
| 668 | | { |
| 669 | | case 0x09: //continue |
| 670 | | ti85serial->status = TI85_SEND_OK; |
| 671 | | logerror ("Continue received\n"); |
| 672 | | break; |
| 673 | | case 0x36: //out of memory, skip or exit |
| 674 | | ti85serial->status = TI85_RECEIVE_ANSWER_2; |
| 675 | | break; |
| 676 | | } |
| 677 | | } |
| 678 | | break; |
| 679 | | case TI85_RECEIVE_ANSWER_2: |
| 680 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer+4*8, 1*8)) |
| 681 | | { |
| 682 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 5*8, ti85serial->receive_data); |
| 683 | | switch (ti85serial->receive_data[4]) |
| 684 | | { |
| 685 | | case 0x01: //exit |
| 686 | | case 0x02: //skip |
| 687 | | ti85serial->status = TI85_RECEIVE_ANSWER_3; |
| 688 | | break; |
| 689 | | case 0x03: //out of memory |
| 690 | | ti85serial->variables_variable_number = 0; |
| 691 | | ti85_free_serial_data_memory(device); |
| 692 | | ti85serial->status = TI85_SEND_STOP; |
| 693 | | break; |
| 694 | | } |
| 695 | | } |
| 696 | | break; |
| 697 | | case TI85_RECEIVE_ANSWER_3: |
| 698 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer+5*8, 2*8)) |
| 699 | | { |
| 700 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 7*8, ti85serial->receive_data); |
| 701 | | switch (ti85serial->receive_data[4]) |
| 702 | | { |
| 703 | | case 0x01: //exit |
| 704 | | ti85serial->variables_variable_number = 0; |
| 705 | | ti85_free_serial_data_memory(device); |
| 706 | | ti85serial->status = TI85_SEND_STOP; |
| 707 | | break; |
| 708 | | case 0x02: //skip |
| 709 | | ti85serial->variables_variable_number++; |
| 710 | | ti85serial->status = TI85_SEND_OK; |
| 711 | | break; |
| 712 | | } |
| 713 | | } |
| 714 | | break; |
| 715 | | case TI85_SEND_OK: |
| 716 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].ok,ti85serial->stream.variables[ti85serial->variables_variable_number].ok_size)) |
| 717 | | { |
| 718 | | ti85serial->status = (ti85serial->receive_data[4]==0x02) ? ((ti85serial->variables_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_HEADER : TI85_SEND_END) : TI85_SEND_DATA; |
| 719 | | memset(ti85serial->receive_data, 0, 7); |
| 720 | | } |
| 721 | | break; |
| 722 | | case TI85_SEND_DATA: |
| 723 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].data,ti85serial->stream.variables[ti85serial->variables_variable_number].data_size)) |
| 724 | | ti85serial->status = TI85_RECEIVE_OK_2; |
| 725 | | break; |
| 726 | | case TI85_RECEIVE_OK_2: |
| 727 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 728 | | { |
| 729 | | ti85serial->variables_variable_number++; |
| 730 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 731 | | ti85serial->status = (ti85serial->variables_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_HEADER : TI85_SEND_END; |
| 732 | | } |
| 733 | | break; |
| 734 | | case TI85_SEND_END: |
| 735 | | if(!ti85_send_serial(device, ti85serial->stream.end,ti85serial->stream.end_size)) |
| 736 | | { |
| 737 | | logerror ("End sent\n"); |
| 738 | | ti85serial->variables_variable_number = 0; |
| 739 | | ti85serial->status = TI85_RECEIVE_OK_3; |
| 740 | | } |
| 741 | | break; |
| 742 | | case TI85_RECEIVE_OK_3: |
| 743 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 744 | | { |
| 745 | | logerror ("OK received\n"); |
| 746 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 747 | | ti85_free_serial_data_memory(device); |
| 748 | | ti85serial->status = TI85_SEND_STOP; |
| 749 | | } |
| 750 | | break; |
| 751 | | } |
| 752 | | } |
| 753 | | |
| 754 | | |
| 755 | | static void ti85_send_backup (device_t *device) |
| 756 | | { |
| 757 | | ti85serial_state *ti85serial = get_token( device ); |
| 758 | | |
| 759 | | if (!ti85_alloc_serial_data_memory(device, 7)) |
| 760 | | ti85serial->status = TI85_SEND_STOP; |
| 761 | | |
| 762 | | switch (ti85serial->status) |
| 763 | | { |
| 764 | | case TI85_SEND_HEADER: |
| 765 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].header,ti85serial->stream.variables[ti85serial->send_backup_variable_number].header_size)) |
| 766 | | ti85serial->status = TI85_RECEIVE_OK_1; |
| 767 | | break; |
| 768 | | case TI85_RECEIVE_OK_1: |
| 769 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 770 | | { |
| 771 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 772 | | ti85serial->status = TI85_RECEIVE_ANSWER_1; |
| 773 | | } |
| 774 | | break; |
| 775 | | case TI85_RECEIVE_ANSWER_1: |
| 776 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 777 | | { |
| 778 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 779 | | switch (ti85serial->receive_data[1]) |
| 780 | | { |
| 781 | | case 0x09: //continue |
| 782 | | ti85serial->status = TI85_SEND_OK; |
| 783 | | break; |
| 784 | | case 0x36: //out of memory, skip or exit |
| 785 | | ti85serial->status = TI85_RECEIVE_ANSWER_2; |
| 786 | | break; |
| 787 | | } |
| 788 | | } |
| 789 | | break; |
| 790 | | case TI85_RECEIVE_ANSWER_2: |
| 791 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer+4*8, 3*8)) |
| 792 | | { |
| 793 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 5*8, ti85serial->receive_data); |
| 794 | | ti85serial->send_backup_variable_number = 0; |
| 795 | | ti85_free_serial_data_memory(device); |
| 796 | | ti85serial->status = TI85_SEND_STOP; |
| 797 | | } |
| 798 | | break; |
| 799 | | case TI85_SEND_OK: |
| 800 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].ok,ti85serial->stream.variables[ti85serial->send_backup_variable_number].ok_size)) |
| 801 | | ti85serial->status = TI85_SEND_DATA; |
| 802 | | break; |
| 803 | | case TI85_SEND_DATA: |
| 804 | | if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].data,ti85serial->stream.variables[ti85serial->send_backup_variable_number].data_size)) |
| 805 | | ti85serial->status = TI85_RECEIVE_OK_2; |
| 806 | | break; |
| 807 | | case TI85_RECEIVE_OK_2: |
| 808 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 809 | | { |
| 810 | | ti85serial->send_backup_variable_number++; |
| 811 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 812 | | ti85serial->status = (ti85serial->send_backup_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_DATA : TI85_SEND_END; |
| 813 | | } |
| 814 | | break; |
| 815 | | case TI85_SEND_END: |
| 816 | | if(!ti85_send_serial(device, ti85serial->stream.end,ti85serial->stream.end_size)) |
| 817 | | { |
| 818 | | ti85serial->send_backup_variable_number = 0; |
| 819 | | ti85_free_serial_data_memory(device); |
| 820 | | ti85serial->status = TI85_SEND_STOP; |
| 821 | | } |
| 822 | | break; |
| 823 | | } |
| 824 | | } |
| 825 | | |
| 826 | | |
| 827 | | static void ti85_receive_variables (device_t *device) |
| 828 | | { |
| 829 | | ti85serial_state *ti85serial = get_token( device ); |
| 830 | | char var_file_name[16]; |
| 831 | | UINT8* temp; |
| 832 | | file_error filerr; |
| 833 | | |
| 834 | | switch (ti85serial->status) |
| 835 | | { |
| 836 | | case TI85_RECEIVE_HEADER_1: |
| 837 | | if(!ti85_receive_serial(device, ti85serial->receive_buffer+4*8, 3*8)) |
| 838 | | { |
| 839 | | ti85_convert_stream_to_data (ti85serial->receive_buffer+4*8, 3*8, ti85serial->receive_data+4); |
| 840 | | ti85serial->status = TI85_PREPARE_VARIABLE_DATA; |
| 841 | | } |
| 842 | | break; |
| 843 | | case TI85_PREPARE_VARIABLE_DATA: |
| 844 | | ti85serial->var_data = (UINT8*) malloc (ti85serial->receive_data[2]+2+ti85serial->receive_data[4]+ti85serial->receive_data[5]*256+2); |
| 845 | | if(!ti85serial->var_data) |
| 846 | | ti85serial->status = TI85_SEND_STOP; |
| 847 | | memcpy (ti85serial->var_data, ti85serial->receive_data+2, 5); |
| 848 | | ti85_free_serial_data_memory(device); |
| 849 | | if (!ti85_alloc_serial_data_memory(device, ti85serial->var_data[0]-1)) |
| 850 | | { |
| 851 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 852 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 853 | | ti85serial->status = TI85_SEND_STOP; |
| 854 | | return; |
| 855 | | } |
| 856 | | ti85serial->status = TI85_RECEIVE_HEADER_2; |
| 857 | | case TI85_RECEIVE_HEADER_2: |
| 858 | | if(!ti85_receive_serial(device, ti85serial->receive_buffer, (ti85serial->var_data[0]-1)*8)) |
| 859 | | { |
| 860 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->var_data[0]-1)*8, ti85serial->receive_data); |
| 861 | | memcpy (ti85serial->var_data+5, ti85serial->receive_data, ti85serial->var_data[0]-3); |
| 862 | | ti85_free_serial_data_memory(device); |
| 863 | | if(!ti85_alloc_serial_data_memory (device, 8)) |
| 864 | | { |
| 865 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 866 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 867 | | ti85serial->status = TI85_SEND_STOP; |
| 868 | | return; |
| 869 | | } |
| 870 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
| 871 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_CONTINUE_PACKET, ti85serial->receive_buffer+4*8); |
| 872 | | ti85serial->status = TI85_SEND_OK_1; |
| 873 | | } |
| 874 | | break; |
| 875 | | case TI85_SEND_OK_1: |
| 876 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
| 877 | | ti85serial->status = TI85_SEND_CONTINUE; |
| 878 | | break; |
| 879 | | case TI85_SEND_CONTINUE: |
| 880 | | if(!ti85_send_serial(device, ti85serial->receive_buffer+4*8, 4*8)) |
| 881 | | { |
| 882 | | ti85_free_serial_data_memory(device); |
| 883 | | if(!ti85_alloc_serial_data_memory(device, 4)) |
| 884 | | { |
| 885 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 886 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 887 | | ti85serial->status = TI85_SEND_STOP; |
| 888 | | return; |
| 889 | | } |
| 890 | | ti85serial->status = TI85_RECEIVE_OK; |
| 891 | | } |
| 892 | | break; |
| 893 | | case TI85_RECEIVE_OK: |
| 894 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 895 | | { |
| 896 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 897 | | ti85_free_serial_data_memory(device); |
| 898 | | if(!ti85_alloc_serial_data_memory(device, ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)) |
| 899 | | { |
| 900 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 901 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 902 | | ti85serial->status = TI85_SEND_STOP; |
| 903 | | return; |
| 904 | | } |
| 905 | | ti85serial->status = TI85_RECEIVE_DATA; |
| 906 | | } |
| 907 | | break; |
| 908 | | case TI85_RECEIVE_DATA: |
| 909 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, (ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)*8)) |
| 910 | | { |
| 911 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)*8, ti85serial->receive_data); |
| 912 | | memcpy (ti85serial->var_data+ti85serial->var_data[0]+2, ti85serial->receive_data+2, ti85serial->var_data[2]+ti85serial->var_data[3]*256+2); |
| 913 | | ti85_free_serial_data_memory(device); |
| 914 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
| 915 | | { |
| 916 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 917 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 918 | | ti85serial->status = TI85_SEND_STOP; |
| 919 | | return; |
| 920 | | } |
| 921 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
| 922 | | ti85serial->status = TI85_SEND_OK_2; |
| 923 | | } |
| 924 | | break; |
| 925 | | case TI85_SEND_OK_2: |
| 926 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
| 927 | | { |
| 928 | | ti85_free_serial_data_memory(device); |
| 929 | | if(!ti85_alloc_serial_data_memory(device, 7)) |
| 930 | | { |
| 931 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 932 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 933 | | ti85serial->status = TI85_SEND_STOP; |
| 934 | | return; |
| 935 | | } |
| 936 | | ti85serial->status = TI85_RECEIVE_END_OR_HEADER_1; |
| 937 | | } |
| 938 | | break; |
| 939 | | case TI85_RECEIVE_END_OR_HEADER_1: |
| 940 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 941 | | { |
| 942 | | if (ti85serial->variable_number == 0) |
| 943 | | { |
| 944 | | ti85serial->var_file_data = (UINT8*) malloc (0x39); |
| 945 | | if (!ti85serial->var_file_data) |
| 946 | | { |
| 947 | | free (ti85serial->var_data); ti85serial->var_data = NULL; |
| 948 | | free (ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 949 | | ti85serial->status = TI85_SEND_STOP; |
| 950 | | } |
| 951 | | else |
| 952 | | { |
| 953 | | memcpy(ti85serial->var_file_data, ti85_file_signature, 0x0b); |
| 954 | | memcpy(ti85serial->var_file_data+0x0b, "File created by MESS", 0x14); |
| 955 | | memset(ti85serial->var_file_data+0x1f, 0, 0x1a); |
| 956 | | ti85serial->var_file_size = 0x39; |
| 957 | | } |
| 958 | | } |
| 959 | | temp = (UINT8*)malloc (ti85serial->var_file_size+ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2); |
| 960 | | if (temp) |
| 961 | | { |
| 962 | | memcpy (temp, ti85serial->var_file_data, ti85serial->var_file_size); |
| 963 | | free (ti85serial->var_file_data); |
| 964 | | ti85serial->var_file_data = temp; |
| 965 | | memcpy (ti85serial->var_file_data + ti85serial->var_file_size -2, ti85serial->var_data, ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2); |
| 966 | | ti85serial->var_file_size += ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2; |
| 967 | | ti85serial->var_file_data[0x35] = (ti85serial->var_file_size-0x39)&0x00ff; |
| 968 | | ti85serial->var_file_data[0x36] = ((ti85serial->var_file_size-0x39)&0xff00)>>8; |
| 969 | | ti85serial->var_file_data[ti85serial->var_file_size-2] = ti85_calculate_checksum(ti85serial->var_file_data+0x37, ti85serial->var_file_size-0x39)&0x00ff; |
| 970 | | ti85serial->var_file_data[ti85serial->var_file_size-1] = (ti85_calculate_checksum(ti85serial->var_file_data+0x37, ti85serial->var_file_size-0x39)&0xff00)>>8; |
| 971 | | } |
| 972 | | free (ti85serial->var_data); |
| 973 | | ti85serial->var_data = NULL; |
| 974 | | ti85serial->variable_number ++; |
| 975 | | |
| 976 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 977 | | if (ti85serial->receive_data[1] == 0x06) |
| 978 | | ti85serial->status = TI85_RECEIVE_HEADER_1; |
| 979 | | else |
| 980 | | { |
| 981 | | ti85_free_serial_data_memory(device); |
| 982 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
| 983 | | { |
| 984 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 985 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 986 | | ti85serial->status = TI85_SEND_STOP; |
| 987 | | return; |
| 988 | | } |
| 989 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
| 990 | | ti85serial->status = TI85_SEND_OK_3; |
| 991 | | } |
| 992 | | } |
| 993 | | break; |
| 994 | | case TI85_SEND_OK_3: |
| 995 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
| 996 | | { |
| 997 | | ti85_free_serial_data_memory(device); |
| 998 | | ti85serial->variable_number = 0; |
| 999 | | ti85serial->status = TI85_SEND_STOP; |
| 1000 | | sprintf (var_file_name, "%08d.85g", ti85serial->var_file_number); |
| 1001 | | emu_file var_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 1002 | | filerr = var_file.open(var_file_name); |
| 1003 | | |
| 1004 | | if (filerr == FILERR_NONE) |
| 1005 | | { |
| 1006 | | var_file.write(ti85serial->var_file_data, ti85serial->var_file_size); |
| 1007 | | free (ti85serial->var_file_data); |
| 1008 | | ti85serial->var_file_data = NULL; |
| 1009 | | ti85serial->var_file_size = 0; |
| 1010 | | ti85serial->var_file_number++; |
| 1011 | | } |
| 1012 | | } |
| 1013 | | break; |
| 1014 | | } |
| 1015 | | } |
| 1016 | | |
| 1017 | | |
| 1018 | | static void ti85_receive_backup (device_t *device) |
| 1019 | | { |
| 1020 | | ti85serial_state *ti85serial = get_token( device ); |
| 1021 | | |
| 1022 | | file_error filerr; |
| 1023 | | char backup_file_name[] = "00000000.85b"; |
| 1024 | | |
| 1025 | | switch (ti85serial->status) |
| 1026 | | { |
| 1027 | | case TI85_RECEIVE_HEADER_2: |
| 1028 | | if(!ti85_receive_serial(device, ti85serial->receive_buffer+7*8, 8*8)) |
| 1029 | | { |
| 1030 | | ti85_convert_stream_to_data (ti85serial->receive_buffer+7*8, 8*8, ti85serial->receive_data+7); |
| 1031 | | ti85serial->backup_data_size[0] = ti85serial->receive_data[4] + ti85serial->receive_data[5]*256; |
| 1032 | | ti85serial->backup_data_size[1] = ti85serial->receive_data[7] + ti85serial->receive_data[8]*256; |
| 1033 | | ti85serial->backup_data_size[2] = ti85serial->receive_data[9] + ti85serial->receive_data[10]*256; |
| 1034 | | ti85serial->backup_file_data = (UINT8*)malloc (0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x02); |
| 1035 | | if(!ti85serial->backup_file_data) |
| 1036 | | { |
| 1037 | | ti85serial->backup_variable_number = 0; |
| 1038 | | ti85serial->status = TI85_SEND_STOP; |
| 1039 | | return; |
| 1040 | | } |
| 1041 | | memcpy(ti85serial->backup_file_data, ti85_file_signature, 0x0b); |
| 1042 | | memcpy(ti85serial->backup_file_data+0x0b, "File created by MESS", 0x14); |
| 1043 | | memset(ti85serial->backup_file_data+0x1f, 0, 0x16); |
| 1044 | | ti85serial->backup_file_data[0x35] = (ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x11)&0x00ff; |
| 1045 | | ti85serial->backup_file_data[0x36] = ((ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x11)&0xff00)>>8; |
| 1046 | | memcpy(ti85serial->backup_file_data+0x37, ti85serial->receive_data+0x02, 0x0b); |
| 1047 | | ti85_free_serial_data_memory(device); |
| 1048 | | if(!ti85_alloc_serial_data_memory (device, 8)) |
| 1049 | | { |
| 1050 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
| 1051 | | ti85serial->backup_variable_number = 0; |
| 1052 | | ti85serial->status = TI85_SEND_STOP; |
| 1053 | | return; |
| 1054 | | } |
| 1055 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
| 1056 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_CONTINUE_PACKET, ti85serial->receive_buffer+4*8); |
| 1057 | | ti85serial->status = TI85_SEND_OK_1; |
| 1058 | | } |
| 1059 | | break; |
| 1060 | | case TI85_SEND_OK_1: |
| 1061 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
| 1062 | | ti85serial->status = TI85_SEND_CONTINUE; |
| 1063 | | break; |
| 1064 | | case TI85_SEND_CONTINUE: |
| 1065 | | if(!ti85_send_serial(device, ti85serial->receive_buffer+4*8, 4*8)) |
| 1066 | | { |
| 1067 | | ti85_free_serial_data_memory(device); |
| 1068 | | if(!ti85_alloc_serial_data_memory(device, 4)) |
| 1069 | | { |
| 1070 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
| 1071 | | ti85serial->backup_variable_number = 0; |
| 1072 | | ti85serial->status = TI85_SEND_STOP; |
| 1073 | | return; |
| 1074 | | } |
| 1075 | | ti85serial->status = TI85_RECEIVE_OK; |
| 1076 | | } |
| 1077 | | break; |
| 1078 | | case TI85_RECEIVE_OK: |
| 1079 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 1080 | | { |
| 1081 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 1082 | | ti85_free_serial_data_memory(device); |
| 1083 | | if(!ti85_alloc_serial_data_memory(device, ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)) |
| 1084 | | { |
| 1085 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
| 1086 | | ti85serial->backup_variable_number = 0; |
| 1087 | | ti85serial->status = TI85_SEND_STOP; |
| 1088 | | return; |
| 1089 | | } |
| 1090 | | ti85serial->status = TI85_RECEIVE_DATA; |
| 1091 | | } |
| 1092 | | break; |
| 1093 | | case TI85_RECEIVE_DATA: |
| 1094 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, (ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)*8)) |
| 1095 | | { |
| 1096 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)*8, ti85serial->receive_data); |
| 1097 | | switch (ti85serial->backup_variable_number) |
| 1098 | | { |
| 1099 | | case 0: |
| 1100 | | memcpy(ti85serial->backup_file_data+0x42, ti85serial->receive_data+0x02, ti85serial->backup_data_size[0]+0x02); |
| 1101 | | break; |
| 1102 | | case 1: |
| 1103 | | memcpy(ti85serial->backup_file_data+0x42+ti85serial->backup_data_size[0]+0x02, ti85serial->receive_data+0x02, ti85serial->backup_data_size[1]+0x02); |
| 1104 | | break; |
| 1105 | | case 2: |
| 1106 | | memcpy(ti85serial->backup_file_data+0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+0x04, ti85serial->receive_data+0x02, ti85serial->backup_data_size[2]+0x02); |
| 1107 | | break; |
| 1108 | | } |
| 1109 | | ti85_free_serial_data_memory(device); |
| 1110 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
| 1111 | | { |
| 1112 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
| 1113 | | ti85serial->backup_variable_number = 0; |
| 1114 | | ti85serial->status = TI85_SEND_STOP; |
| 1115 | | return; |
| 1116 | | } |
| 1117 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
| 1118 | | ti85serial->status = TI85_SEND_OK_2; |
| 1119 | | } |
| 1120 | | break; |
| 1121 | | case TI85_SEND_OK_2: |
| 1122 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
| 1123 | | { |
| 1124 | | ti85_free_serial_data_memory(device); |
| 1125 | | ti85serial->backup_variable_number++; |
| 1126 | | if (ti85serial->backup_variable_number<3) |
| 1127 | | { |
| 1128 | | if(!ti85_alloc_serial_data_memory(device, ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)) |
| 1129 | | { |
| 1130 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
| 1131 | | ti85serial->backup_variable_number = 0; |
| 1132 | | ti85serial->status = TI85_SEND_STOP; |
| 1133 | | return; |
| 1134 | | } |
| 1135 | | ti85serial->status = TI85_RECEIVE_DATA; |
| 1136 | | } |
| 1137 | | else |
| 1138 | | { |
| 1139 | | ti85serial->backup_variable_number = 0; |
| 1140 | | ti85serial->backup_file_data[0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]] = ti85_calculate_checksum(ti85serial->backup_file_data+0x37, 0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x06-0x37)&0x00ff; |
| 1141 | | ti85serial->backup_file_data[0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x01] = (ti85_calculate_checksum(ti85serial->backup_file_data+0x37, 0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x06-0x37)&0xff00)>>8; |
| 1142 | | sprintf (backup_file_name, "%08d.85b", ti85serial->backup_file_number); |
| 1143 | | |
| 1144 | | emu_file backup_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 1145 | | filerr = backup_file.open(backup_file_name); |
| 1146 | | |
| 1147 | | if (filerr == FILERR_NONE) |
| 1148 | | { |
| 1149 | | backup_file.write(ti85serial->backup_file_data, 0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x02); |
| 1150 | | ti85serial->backup_file_number++; |
| 1151 | | } |
| 1152 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
| 1153 | | ti85serial->status = TI85_SEND_STOP; |
| 1154 | | } |
| 1155 | | } |
| 1156 | | break; |
| 1157 | | } |
| 1158 | | } |
| 1159 | | |
| 1160 | | static void ti85_receive_screen (device_t *device) |
| 1161 | | { |
| 1162 | | ti85serial_state *ti85serial = get_token( device ); |
| 1163 | | char image_file_name[] = "00000000.85i"; |
| 1164 | | file_error filerr; |
| 1165 | | UINT8 * image_file_data; |
| 1166 | | |
| 1167 | | switch (ti85serial->status) |
| 1168 | | { |
| 1169 | | case TI85_PREPARE_SCREEN_REQUEST: |
| 1170 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
| 1171 | | { |
| 1172 | | ti85serial->status = TI85_SEND_STOP; |
| 1173 | | return; |
| 1174 | | } |
| 1175 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_SCREEN_REQUEST_PACKET, ti85serial->receive_buffer); |
| 1176 | | ti85serial->status = TI85_SEND_SCREEN_REQUEST; |
| 1177 | | break; |
| 1178 | | case TI85_SEND_SCREEN_REQUEST: |
| 1179 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
| 1180 | | { |
| 1181 | | ti85_free_serial_data_memory(device); |
| 1182 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
| 1183 | | { |
| 1184 | | ti85serial->status = TI85_SEND_STOP; |
| 1185 | | return; |
| 1186 | | } |
| 1187 | | ti85serial->status = TI85_RECEIVE_OK; |
| 1188 | | } |
| 1189 | | break; |
| 1190 | | case TI85_RECEIVE_OK: |
| 1191 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8)) |
| 1192 | | { |
| 1193 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data); |
| 1194 | | ti85_free_serial_data_memory(device); |
| 1195 | | if(!ti85_alloc_serial_data_memory (device, 1030)) |
| 1196 | | { |
| 1197 | | ti85serial->status = TI85_SEND_STOP; |
| 1198 | | return; |
| 1199 | | } |
| 1200 | | ti85serial->status = TI85_RECEIVE_DATA; |
| 1201 | | } |
| 1202 | | break; |
| 1203 | | case TI85_RECEIVE_DATA: |
| 1204 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 1030*8)) |
| 1205 | | { |
| 1206 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 1030*8, ti85serial->receive_data); |
| 1207 | | sprintf (image_file_name, "%08d.85i", ti85serial->image_file_number); |
| 1208 | | |
| 1209 | | emu_file image_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 1210 | | filerr = image_file.open(image_file_name); |
| 1211 | | |
| 1212 | | if (filerr == FILERR_NONE) |
| 1213 | | { |
| 1214 | | image_file_data = (UINT8*)malloc (0x49+1008); |
| 1215 | | if(!image_file_data) |
| 1216 | | { |
| 1217 | | ti85_free_serial_data_memory(device); |
| 1218 | | ti85serial->status = TI85_SEND_OK; |
| 1219 | | return; |
| 1220 | | } |
| 1221 | | memcpy(image_file_data, ti85_file_signature, 0x0b); |
| 1222 | | memcpy(image_file_data+0x0b, "File created by MESS", 0x14); |
| 1223 | | memset(image_file_data+0x1f, 0, 0x16); |
| 1224 | | image_file_data[0x35] = 0x00; |
| 1225 | | image_file_data[0x36] = 0x04; |
| 1226 | | image_file_data[0x37] = 0x0a; //header size |
| 1227 | | image_file_data[0x38] = 0x00; |
| 1228 | | image_file_data[0x39] = 0xf2; //data size |
| 1229 | | image_file_data[0x3a] = 0x03; |
| 1230 | | image_file_data[0x3b] = 0x11; //data type |
| 1231 | | image_file_data[0x3c] = 0x06; //name size |
| 1232 | | memcpy(image_file_data+0x3d, "Screen", 0x06); |
| 1233 | | image_file_data[0x43] = 0xf2; |
| 1234 | | image_file_data[0x44] = 0x03; |
| 1235 | | image_file_data[0x45] = 0xf0; |
| 1236 | | image_file_data[0x46] = 0x03; |
| 1237 | | memcpy(image_file_data+0x47, ti85serial->receive_data+4, 1008); |
| 1238 | | image_file_data[1008+0x49-2] = ti85_calculate_checksum(image_file_data+0x37, 1008+0x10)&0x00ff; |
| 1239 | | image_file_data[1008+0x49-1] = (ti85_calculate_checksum(image_file_data+0x37, 1008+0x10)&0xff00)>>8; |
| 1240 | | image_file.write(image_file_data, 1008+0x49); |
| 1241 | | free(image_file_data); |
| 1242 | | ti85serial->image_file_number++; |
| 1243 | | } |
| 1244 | | ti85_free_serial_data_memory(device); |
| 1245 | | if(!ti85_alloc_serial_data_memory (device, 4)) |
| 1246 | | { |
| 1247 | | ti85serial->status = TI85_SEND_STOP; |
| 1248 | | return; |
| 1249 | | } |
| 1250 | | ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer); |
| 1251 | | ti85serial->status = TI85_SEND_OK; |
| 1252 | | } |
| 1253 | | break; |
| 1254 | | case TI85_SEND_OK: |
| 1255 | | if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8)) |
| 1256 | | { |
| 1257 | | ti85_free_serial_data_memory(device); |
| 1258 | | ti85serial->status = TI85_SEND_STOP; |
| 1259 | | } |
| 1260 | | break; |
| 1261 | | } |
| 1262 | | } |
| 1263 | | |
| 1264 | | |
| 1265 | | void ti85_update_serial (device_t *device) |
| 1266 | | { |
| 1267 | | ti85serial_state *ti85serial = get_token( device ); |
| 1268 | | |
| 1269 | | if (ti85serial->status == TI85_SEND_STOP) |
| 1270 | | { |
| 1271 | | if (input_port_read(*device, "SERIAL") & 0x01) |
| 1272 | | { |
| 1273 | | if(!ti85_alloc_serial_data_memory(device, 15)) return; |
| 1274 | | if(!ti85_receive_serial (device, ti85serial->receive_buffer, 7*8)) |
| 1275 | | { |
| 1276 | | ti85_convert_stream_to_data (ti85serial->receive_buffer, 7*8, ti85serial->receive_data); |
| 1277 | | if (ti85serial->receive_data[0]!=0x85 || ti85serial->receive_data[1]!=0x06) |
| 1278 | | { |
| 1279 | | ti85_receive_serial (device, NULL, 0); |
| 1280 | | return; |
| 1281 | | } |
| 1282 | | ti85serial->transfer_type = (ti85serial->receive_data[6]==0x1d) ? TI85_RECEIVE_BACKUP : TI85_RECEIVE_VARIABLES; |
| 1283 | | ti85serial->status = (ti85serial->receive_data[6]==0x1d) ? TI85_RECEIVE_HEADER_2 : TI85_PREPARE_VARIABLE_DATA; |
| 1284 | | } |
| 1285 | | } |
| 1286 | | else |
| 1287 | | { |
| 1288 | | ti85_receive_serial(device, NULL, 0); |
| 1289 | | ti85_free_serial_data_memory(device); |
| 1290 | | if (input_port_read(*device, "DUMP") & 0x01) |
| 1291 | | { |
| 1292 | | ti85serial->status = TI85_PREPARE_SCREEN_REQUEST; |
| 1293 | | ti85serial->transfer_type = TI85_RECEIVE_SCREEN; |
| 1294 | | } |
| 1295 | | return; |
| 1296 | | } |
| 1297 | | } |
| 1298 | | |
| 1299 | | switch (ti85serial->transfer_type) |
| 1300 | | { |
| 1301 | | case TI85_SEND_VARIABLES: |
| 1302 | | ti85_send_variables(device); |
| 1303 | | break; |
| 1304 | | case TI85_SEND_BACKUP: |
| 1305 | | ti85_send_backup(device); |
| 1306 | | break; |
| 1307 | | case TI85_RECEIVE_BACKUP: |
| 1308 | | ti85_receive_backup(device); |
| 1309 | | break; |
| 1310 | | case TI85_RECEIVE_VARIABLES: |
| 1311 | | ti85_receive_variables(device); |
| 1312 | | break; |
| 1313 | | case TI85_RECEIVE_SCREEN: |
| 1314 | | ti85_receive_screen(device); |
| 1315 | | break; |
| 1316 | | } |
| 1317 | | } |
| 1318 | | |
| 1319 | | |
| 1320 | | WRITE8_DEVICE_HANDLER( ti85serial_red_out ) |
| 1321 | | { |
| 1322 | | ti85serial_state *ti85serial = get_token( device ); |
| 1323 | | |
| 1324 | | ti85serial->red_out = data; |
| 1325 | | } |
| 1326 | | |
| 1327 | | |
| 1328 | | WRITE8_DEVICE_HANDLER( ti85serial_white_out ) |
| 1329 | | { |
| 1330 | | ti85serial_state *ti85serial = get_token( device ); |
| 1331 | | |
| 1332 | | ti85serial->white_out = data; |
| 1333 | | } |
| 1334 | | |
| 1335 | | |
| 1336 | | READ8_DEVICE_HANDLER( ti85serial_red_in ) |
| 1337 | | { |
| 1338 | | ti85serial_state *ti85serial = get_token( device ); |
| 1339 | | |
| 1340 | | return ti85serial->red_in; |
| 1341 | | } |
| 1342 | | |
| 1343 | | |
| 1344 | | READ8_DEVICE_HANDLER( ti85serial_white_in ) |
| 1345 | | { |
| 1346 | | ti85serial_state *ti85serial = get_token( device ); |
| 1347 | | |
| 1348 | | return ti85serial->white_in; |
| 1349 | | } |
| 1350 | | |
| 1351 | | |
| 1352 | | static DEVICE_START( ti85serial ) |
| 1353 | | { |
| 1354 | | ti85serial_state *ti85serial = get_token( device ); |
| 1355 | | |
| 1356 | | ti85serial->transfer_type = TI85_SEND_VARIABLES; |
| 1357 | | ti85serial->receive_buffer = NULL; |
| 1358 | | ti85serial->receive_data = NULL; |
| 1359 | | ti85serial->var_file_number = 0; |
| 1360 | | ti85serial->backup_file_number = 0; |
| 1361 | | ti85serial->image_file_number = 0; |
| 1362 | | } |
| 1363 | | |
| 1364 | | |
| 1365 | | static DEVICE_STOP( ti85serial ) |
| 1366 | | { |
| 1367 | | ti85serial_state *ti85serial = get_token( device ); |
| 1368 | | |
| 1369 | | ti85_free_serial_data_memory(device); |
| 1370 | | if (ti85serial->var_data) |
| 1371 | | { |
| 1372 | | free(ti85serial->var_data); ti85serial->var_data = NULL; |
| 1373 | | } |
| 1374 | | if (ti85serial->var_file_data) |
| 1375 | | { |
| 1376 | | free(ti85serial->var_file_data); ti85serial->var_file_data = NULL; |
| 1377 | | } |
| 1378 | | if (ti85serial->backup_file_data) |
| 1379 | | { |
| 1380 | | free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL; |
| 1381 | | } |
| 1382 | | } |
| 1383 | | |
| 1384 | | |
| 1385 | | static DEVICE_RESET( ti85serial ) |
| 1386 | | { |
| 1387 | | ti85serial_state *ti85serial = get_token( device ); |
| 1388 | | |
| 1389 | | ti85serial->receive_data_counter = 0; |
| 1390 | | ti85serial->send_data_counter = 0; |
| 1391 | | ti85_free_serial_data_memory(device); |
| 1392 | | ti85serial->red_in = 0; |
| 1393 | | ti85serial->white_in = 0; |
| 1394 | | ti85serial->red_out = 1; |
| 1395 | | ti85serial->white_out = 1; |
| 1396 | | ti85serial->variables_variable_number = 0; |
| 1397 | | ti85serial->send_backup_variable_number = 0; |
| 1398 | | ti85serial->var_data = NULL; |
| 1399 | | ti85serial->var_file_data = NULL; |
| 1400 | | ti85serial->var_file_size = 0; |
| 1401 | | ti85serial->variable_number = 0; |
| 1402 | | ti85serial->backup_file_data = NULL; |
| 1403 | | ti85serial->backup_variable_number = 0; |
| 1404 | | ti85serial->status = TI85_SEND_STOP; |
| 1405 | | |
| 1406 | | //initialize the receive_id used for TI to PC transfer |
| 1407 | | if (device->type() == TI73SERIAL) |
| 1408 | | ti85serial->receive_id = TI_TRANFER_ID_TI73; |
| 1409 | | else if (device->type() == TI85SERIAL) |
| 1410 | | ti85serial->receive_id = TI_TRANFER_ID_TI85; |
| 1411 | | else if (device->type() == TI82SERIAL) |
| 1412 | | ti85serial->receive_id = TI_TRANFER_ID_TI82; |
| 1413 | | else if (device->type() == TI83PSERIAL) |
| 1414 | | ti85serial->receive_id = TI_TRANFER_ID_TI83P; |
| 1415 | | else if (device->type() == TI86SERIAL) |
| 1416 | | ti85serial->receive_id = TI_TRANFER_ID_TI86; |
| 1417 | | |
| 1418 | | ti85serial->send_id = ti85serial->receive_id; |
| 1419 | | } |
| 1420 | | |
| 1421 | | |
| 1422 | | static DEVICE_IMAGE_LOAD( ti85serial ) |
| 1423 | | { |
| 1424 | | ti85serial_state *ti85serial = get_token( image ); |
| 1425 | | UINT8* file_data; |
| 1426 | | UINT16 file_size; |
| 1427 | | |
| 1428 | | if (ti85serial->status != TI85_SEND_STOP) return IMAGE_INIT_FAIL; |
| 1429 | | |
| 1430 | | file_size = image.length(); |
| 1431 | | |
| 1432 | | if (file_size != 0) |
| 1433 | | { |
| 1434 | | file_data = auto_alloc_array(image.device().machine(), UINT8, file_size); |
| 1435 | | image.fread( file_data, file_size); |
| 1436 | | |
| 1437 | | if(!ti85_convert_file_data_to_serial_stream(image, file_data, file_size, &ti85serial->stream)) |
| 1438 | | { |
| 1439 | | ti85_free_serial_stream (&ti85serial->stream); |
| 1440 | | return IMAGE_INIT_FAIL; |
| 1441 | | } |
| 1442 | | |
| 1443 | | ti85serial->status = TI85_SEND_HEADER; |
| 1444 | | } |
| 1445 | | else |
| 1446 | | { |
| 1447 | | return IMAGE_INIT_FAIL; |
| 1448 | | } |
| 1449 | | return IMAGE_INIT_PASS; |
| 1450 | | } |
| 1451 | | |
| 1452 | | |
| 1453 | | static DEVICE_IMAGE_UNLOAD( ti85serial ) |
| 1454 | | { |
| 1455 | | ti85serial_state *ti85serial = get_token( image ); |
| 1456 | | |
| 1457 | | ti85_free_serial_data_memory(image); |
| 1458 | | ti85serial->status = TI85_SEND_STOP; |
| 1459 | | ti85_free_serial_stream (&ti85serial->stream); |
| 1460 | | } |
| 1461 | | |
| 1462 | | |
| 1463 | | static INPUT_PORTS_START ( ti85serial ) |
| 1464 | | PORT_START("SERIAL") /* receive data from calculator */ |
| 1465 | | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Receive data") PORT_CODE(KEYCODE_R) |
| 1466 | | PORT_START("DUMP") /* screen dump requesting */ |
| 1467 | | PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Screen dump request") PORT_CODE(KEYCODE_S) |
| 1468 | | INPUT_PORTS_END |
| 1469 | | |
| 1470 | | |
| 1471 | | DEVICE_GET_INFO( ti85serial ) |
| 1472 | | { |
| 1473 | | switch ( state ) |
| 1474 | | { |
| 1475 | | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof( ti85serial_state ); break; |
| 1476 | | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 1477 | | case DEVINFO_INT_IMAGE_TYPE: info->i = IO_SERIAL; break; |
| 1478 | | case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break; |
| 1479 | | case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 0; break; |
| 1480 | | case DEVINFO_INT_IMAGE_CREATABLE: info->i = 0; break; |
| 1481 | | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ti85serial ); break; |
| 1482 | | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ti85serial ); break; |
| 1483 | | case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME( ti85serial ); break; |
| 1484 | | case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( ti85serial ); break; |
| 1485 | | case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME( ti85serial ); break; |
| 1486 | | case DEVINFO_PTR_INPUT_PORTS: info->ipt = INPUT_PORTS_NAME( ti85serial ); break; |
| 1487 | | case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "ser"); break; |
| 1488 | | case DEVINFO_STR_IMAGE_INSTANCE_NAME: strcpy(info->s, "serial"); break; |
| 1489 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI85 Serial"); break; |
| 1490 | | case DEVINFO_STR_FAMILY: strcpy(info->s, "serial protocol"); break; |
| 1491 | | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 1492 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "85p,85s,85i,85n,85c,85l,85k,85m,85v,85d,85e,85r,85g,85b"); break; |
| 1493 | | } |
| 1494 | | } |
| 1495 | | |
| 1496 | | DEVICE_GET_INFO( ti73serial ) |
| 1497 | | { |
| 1498 | | switch ( state ) |
| 1499 | | { |
| 1500 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI73 Serial"); break; |
| 1501 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "73p,73s,73i,73n,73c,73l,73k,73m,73v,73d,73e,73r,73g"); break; |
| 1502 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
| 1503 | | } |
| 1504 | | } |
| 1505 | | |
| 1506 | | DEVICE_GET_INFO( ti82serial ) |
| 1507 | | { |
| 1508 | | switch ( state ) |
| 1509 | | { |
| 1510 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI82 Serial"); break; |
| 1511 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "82p,82s,82i,82n,82c,82l,82k,82m,82v,82d,82e,82r,82g"); break; |
| 1512 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
| 1513 | | } |
| 1514 | | } |
| 1515 | | |
| 1516 | | |
| 1517 | | DEVICE_GET_INFO( ti83pserial ) |
| 1518 | | { |
| 1519 | | switch ( state ) |
| 1520 | | { |
| 1521 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI83 Plus Serial"); break; |
| 1522 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "82p,82s,82i,82n,82c,82l,82k,82m,82v,82d,82e,82r,82g," //for TI-82 compatibility |
| 1523 | | "83p,83s,83i,83n,83c,83l,83k,83m,83v,83d,83e,83r,83g," //for TI-83 compatibility |
| 1524 | | "8xc,8xd,8xg,8xi,8xl,8xm,8xn,8xp,8xs,8xt,8xv,8xw,8xy,8xz"); break; |
| 1525 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
| 1526 | | } |
| 1527 | | } |
| 1528 | | |
| 1529 | | DEVICE_GET_INFO( ti86serial ) |
| 1530 | | { |
| 1531 | | switch ( state ) |
| 1532 | | { |
| 1533 | | case DEVINFO_STR_NAME: strcpy(info->s, "TI86 Serial"); break; |
| 1534 | | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "85p,85s,85i,85n,85c,85l,85k,85m,85v,85d,85e,85r,85g,85b" //for TI-85 compatibility |
| 1535 | | "86p,86s,86i,86n,86c,86l,86k,86m,86v,86d,86e,86r,86g"); break; |
| 1536 | | default: DEVICE_GET_INFO_CALL( ti85serial ); |
| 1537 | | } |
| 1538 | | } |
| 1539 | | |
| 1540 | | DEFINE_LEGACY_IMAGE_DEVICE(TI85SERIAL, ti85serial); |
| 1541 | | DEFINE_LEGACY_IMAGE_DEVICE(TI73SERIAL, ti73serial); |
| 1542 | | DEFINE_LEGACY_IMAGE_DEVICE(TI82SERIAL, ti82serial); |
| 1543 | | DEFINE_LEGACY_IMAGE_DEVICE(TI83PSERIAL, ti83pserial); |
| 1544 | | DEFINE_LEGACY_IMAGE_DEVICE(TI86SERIAL, ti86serial); |
trunk/src/mess/drivers/c16.c
| r17575 | r17576 | |
| 1 | | /*************************************************************************** |
| 2 | | commodore c16 home computer |
| 3 | | |
| 4 | | PeT mess@utanet.at |
| 5 | | |
| 6 | | documentation |
| 7 | | www.funet.fi |
| 8 | | |
| 9 | | ***************************************************************************/ |
| 10 | | |
| 11 | | /* |
| 12 | | |
| 13 | | 2008 - Driver Updates |
| 14 | | --------------------- |
| 15 | | |
| 16 | | (most of the informations are taken from http://www.zimmers.net/cbmpics/ ) |
| 17 | | |
| 18 | | |
| 19 | | [CBM systems which belong to this driver] |
| 20 | | |
| 21 | | * Commodore 116 (1984, Europe only) |
| 22 | | |
| 23 | | Entry level computer of the Commodore 264 family, it was marketed only |
| 24 | | in Europe. It was impressive for the small size of its case, but it didn't |
| 25 | | meet commercial success |
| 26 | | |
| 27 | | CPU: MOS Technology 7501 (variable clock rate, with max 1.76 MHz) |
| 28 | | RAM: 16 kilobytes (expandable to 64k internally) |
| 29 | | ROM: 32 kilobytes |
| 30 | | Video: MOS Technology 7360 "TED" (5 Video modes; Max. Resolution 320x200; |
| 31 | | 40 columns text; Palette of 16 colors in 8 shades, for 128 colors) |
| 32 | | Sound: MOS Technology 7360 "TED" (2 voice tone-generating sound capabilities) |
| 33 | | Ports: MOS 7360 (2 Joystick/Mouse ports; CBM Serial port; 'TED' port; "TV" |
| 34 | | Port and switch; CBM Monitor port; Power and reset switches; Power |
| 35 | | connector) |
| 36 | | Keyboard: QWERTY 62 key "membrane" (8 programmable function keys; 4 direction |
| 37 | | cursor-pad) |
| 38 | | |
| 39 | | |
| 40 | | * Commodore 16 (1984) |
| 41 | | |
| 42 | | Redesigned version of the C116, with a different case and a different |
| 43 | | keyboard. |
| 44 | | |
| 45 | | CPU: MOS Technology 7501 (variable clock rate, with max 1.76 MHz) |
| 46 | | RAM: 16 kilobytes (expandable to 64k internally) |
| 47 | | ROM: 32 kilobytes |
| 48 | | Video: MOS Technology 7360 "TED" (5 Video modes; Max. Resolution 320x200; |
| 49 | | 40 columns text; Palette of 16 colors in 8 shades, for 128 colors) |
| 50 | | Sound: MOS Technology 7360 "TED" (2 voice tone-generating sound capabilities) |
| 51 | | Ports: MOS 7360 (2 Joystick/Mouse ports; CBM Serial port; 'TED' port; "TV" |
| 52 | | Port and switch; CBM Monitor port; Power and reset switches; Power |
| 53 | | connector) |
| 54 | | Keyboard: QWERTY 66 key typewriter style (8 programmable function keys; |
| 55 | | 4 direction cursor-pad) |
| 56 | | |
| 57 | | |
| 58 | | * Commodore Plus/4 (1984) |
| 59 | | |
| 60 | | This system became the middle tier of the Commodore 264 family, replacing |
| 61 | | the original Commodore 264. The Plus/4 is basically the same as the C264, |
| 62 | | but the name refers to the four built-in programs which came with the |
| 63 | | machine: Word Processing, Spreadsheet, Database software, Graphing package. |
| 64 | | |
| 65 | | CPU: MOS Technology 7501 (variable clock rate, with max 1.76 MHz) |
| 66 | | RAM: 64 kilobytes (expandable to 64k internally) |
| 67 | | ROM: 64 kilobytes |
| 68 | | Video: MOS Technology 7360 "TED" (5 Video modes; Max. Resolution 320x200; |
| 69 | | 40 columns text; Palette of 16 colors in 8 shades, for 128 colors) |
| 70 | | Sound: MOS Technology 7360 "TED" (2 voice tone-generating sound capabilities) |
| 71 | | Ports: MOS 7360 (2 Joystick/Mouse ports; CBM Serial port; 'TED' port; "TV" |
| 72 | | Port and switch; CBM Monitor port; Power and reset switches; Power |
| 73 | | connector) |
| 74 | | Keyboard: Full-sized QWERTY 67 key (8 programmable function keys; |
| 75 | | 4 direction cursor-pad) |
| 76 | | |
| 77 | | |
| 78 | | * Commodore 232 (1984, Prototype) |
| 79 | | |
| 80 | | This system never reached the production and only few units exist. It is |
| 81 | | in between the C16 and the C264, with its 32 kilobytes of RAM. |
| 82 | | |
| 83 | | |
| 84 | | * Commodore 264 (1984, Prototype) |
| 85 | | |
| 86 | | Basically the same of a Plus/4 but without the built-in programs. |
| 87 | | |
| 88 | | |
| 89 | | * Commodore V364 (1984, Prototype) |
| 90 | | |
| 91 | | This system was supposed to become the high-end system of the family, |
| 92 | | featuring 64 kilobytes of RAM, the same technology of the Plus/4, a |
| 93 | | keyboard with numeric keypad and built in voice synthesis capabilities. |
| 94 | | |
| 95 | | [TO DO] |
| 96 | | |
| 97 | | * Supported Systems: |
| 98 | | |
| 99 | | - Once we can add / remove devices, we shall only support c16, c116 and plus/4, |
| 100 | | removing the separated drivers for different floppy drives |
| 101 | | |
| 102 | | * Other Peripherals: |
| 103 | | |
| 104 | | - Lightpen support is unfinished |
| 105 | | - Missing support for (it might or might not be added eventually): |
| 106 | | printers and other devices; most expansion modules; userport; rs232/v.24 interface. |
| 107 | | |
| 108 | | * System Specific |
| 109 | | |
| 110 | | - V364 lacks speech hardware emulation |
| 111 | | |
| 112 | | */ |
| 113 | | |
| 114 | | |
| 115 | | #include "emu.h" |
| 116 | | #include "audio/ted7360.h" |
| 117 | | #include "audio/t6721.h" |
| 118 | | #include "cpu/m6502/m6502.h" |
| 119 | | #include "machine/ram.h" |
| 120 | | #include "formats/cbm_snqk.h" |
| 121 | | #include "includes/cbm.h" |
| 122 | | #include "includes/c16.h" |
| 123 | | #include "machine/c1551.h" |
| 124 | | #include "machine/cbmiec.h" |
| 125 | | #include "machine/cbmipt.h" |
| 126 | | #include "sound/sid6581.h" |
| 127 | | #include "machine/plus4exp.h" |
| 128 | | #include "machine/plus4user.h" |
| 129 | | |
| 130 | | |
| 131 | | /************************************* |
| 132 | | * |
| 133 | | * Main CPU memory handlers |
| 134 | | * |
| 135 | | *************************************/ |
| 136 | | |
| 137 | | |
| 138 | | /* |
| 139 | | * commodore c16/c116/plus 4 |
| 140 | | * 16 KByte (C16/C116) or 32 KByte or 64 KByte (plus4) RAM |
| 141 | | * 32 KByte Rom (C16/C116) 64 KByte Rom (plus4) |
| 142 | | * availability to append additional 64 KByte Rom |
| 143 | | * |
| 144 | | * ports 0xfd00 till 0xff3f are always read/writeable for the cpu |
| 145 | | * for the video interface chip it seams to read from |
| 146 | | * ram or from rom in this area |
| 147 | | * |
| 148 | | * writes go always to ram |
| 149 | | * only 16 KByte Ram mapped to 0x4000,0x8000,0xc000 |
| 150 | | * only 32 KByte Ram mapped to 0x8000 |
| 151 | | * |
| 152 | | * rom bank at 0x8000: 16K Byte(low bank) |
| 153 | | * first: basic |
| 154 | | * second(plus 4 only): plus4 rom low |
| 155 | | * third: expansion slot |
| 156 | | * fourth: expansion slot |
| 157 | | * rom bank at 0xc000: 16K Byte(high bank) |
| 158 | | * first: kernal |
| 159 | | * second(plus 4 only): plus4 rom high |
| 160 | | * third: expansion slot |
| 161 | | * fourth: expansion slot |
| 162 | | * writes to 0xfddx select rom banks: |
| 163 | | * address line 0 and 1: rom bank low |
| 164 | | * address line 2 and 3: rom bank high |
| 165 | | * |
| 166 | | * writes to 0xff3e switches to roms (0x8000 till 0xfd00, 0xff40 till 0xffff) |
| 167 | | * writes to 0xff3f switches to rams |
| 168 | | * |
| 169 | | * at 0xfc00 till 0xfcff is ram or rom kernal readable |
| 170 | | */ |
| 171 | | |
| 172 | | static ADDRESS_MAP_START(c16_map, AS_PROGRAM, 8, c16_state ) |
| 173 | | AM_RANGE(0x0000, 0x3fff) AM_RAMBANK("bank9") |
| 174 | | AM_RANGE(0x4000, 0x7fff) AM_READ_BANK("bank1") AM_WRITE_BANK("bank5") /* only ram memory configuration */ |
| 175 | | AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank2") AM_WRITE_BANK("bank6") |
| 176 | | AM_RANGE(0xc000, 0xfbff) AM_READ_BANK("bank3") |
| 177 | | AM_RANGE(0xfc00, 0xfcff) AM_READ_BANK("bank4") |
| 178 | | AM_RANGE(0xc000, 0xfcff) AM_WRITE_BANK("bank7") |
| 179 | | AM_RANGE(0xfd10, 0xfd1f) AM_READ_LEGACY(c16_fd1x_r) |
| 180 | | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE_LEGACY(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
| 181 | | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE_LEGACY(c16_select_roms) /* rom chips selection */ |
| 182 | | AM_RANGE(0xff00, 0xff1f) AM_DEVREADWRITE_LEGACY("ted7360", ted7360_port_r, ted7360_port_w) |
| 183 | | AM_RANGE(0xff20, 0xffff) AM_READ_BANK("bank8") |
| 184 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE_LEGACY(c16_switch_to_rom) |
| 185 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE_LEGACY(c16_switch_to_ram) |
| 186 | | ADDRESS_MAP_END |
| 187 | | |
| 188 | | static ADDRESS_MAP_START(plus4_map, AS_PROGRAM, 8, c16_state ) |
| 189 | | AM_RANGE(0x0000, 0x7fff) AM_READ_BANK("bank9") |
| 190 | | AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank2") |
| 191 | | AM_RANGE(0xc000, 0xfbff) AM_READ_BANK("bank3") |
| 192 | | AM_RANGE(0xfc00, 0xfcff) AM_READ_BANK("bank4") |
| 193 | | AM_RANGE(0x0000, 0xfcff) AM_WRITE_BANK("bank9") |
| 194 | | AM_RANGE(0xfd00, 0xfd0f) AM_READWRITE_LEGACY(c16_6551_port_r, c16_6551_port_w) |
| 195 | | AM_RANGE(0xfd10, 0xfd1f) AM_READWRITE_LEGACY(plus4_6529_port_r, plus4_6529_port_w) |
| 196 | | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE_LEGACY(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
| 197 | | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE_LEGACY(c16_select_roms) /* rom chips selection */ |
| 198 | | AM_RANGE(0xff00, 0xff1f) AM_DEVREADWRITE_LEGACY("ted7360", ted7360_port_r, ted7360_port_w) |
| 199 | | AM_RANGE(0xff20, 0xffff) AM_READ_BANK("bank8") |
| 200 | | AM_RANGE(0xff20, 0xff3d) AM_WRITEONLY |
| 201 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE_LEGACY(c16_switch_to_rom) |
| 202 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE_LEGACY(c16_switch_to_ram) |
| 203 | | AM_RANGE(0xff40, 0xffff) AM_WRITEONLY |
| 204 | | ADDRESS_MAP_END |
| 205 | | |
| 206 | | static ADDRESS_MAP_START(c364_map , AS_PROGRAM, 8, c16_state ) |
| 207 | | AM_RANGE(0x0000, 0x7fff) AM_READ_BANK("bank9") |
| 208 | | AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank2") |
| 209 | | AM_RANGE(0xc000, 0xfbff) AM_READ_BANK("bank3") |
| 210 | | AM_RANGE(0xfc00, 0xfcff) AM_READ_BANK("bank4") |
| 211 | | AM_RANGE(0x0000, 0xfcff) AM_WRITE_BANK("bank9") |
| 212 | | AM_RANGE(0xfd00, 0xfd0f) AM_READWRITE_LEGACY(c16_6551_port_r, c16_6551_port_w) |
| 213 | | AM_RANGE(0xfd10, 0xfd1f) AM_READWRITE_LEGACY(plus4_6529_port_r, plus4_6529_port_w) |
| 214 | | AM_RANGE(0xfd20, 0xfd2f) AM_DEVREADWRITE_LEGACY("t6721", t6721_speech_r, t6721_speech_w) |
| 215 | | AM_RANGE(0xfd30, 0xfd3f) AM_READWRITE_LEGACY(c16_6529_port_r, c16_6529_port_w) /* 6529 keyboard matrix */ |
| 216 | | AM_RANGE(0xfdd0, 0xfddf) AM_WRITE_LEGACY(c16_select_roms) /* rom chips selection */ |
| 217 | | AM_RANGE(0xff00, 0xff1f) AM_DEVREADWRITE_LEGACY("ted7360", ted7360_port_r, ted7360_port_w) |
| 218 | | AM_RANGE(0xff20, 0xffff) AM_READ_BANK("bank8") |
| 219 | | AM_RANGE(0xff20, 0xff3d) AM_WRITEONLY |
| 220 | | AM_RANGE(0xff3e, 0xff3e) AM_WRITE_LEGACY(c16_switch_to_rom) |
| 221 | | AM_RANGE(0xff3f, 0xff3f) AM_WRITE_LEGACY(c16_switch_to_ram) |
| 222 | | AM_RANGE(0xff40, 0xffff) AM_WRITEONLY |
| 223 | | ADDRESS_MAP_END |
| 224 | | |
| 225 | | |
| 226 | | /************************************* |
| 227 | | * |
| 228 | | * Input Ports |
| 229 | | * |
| 230 | | *************************************/ |
| 231 | | |
| 232 | | static INPUT_PORTS_START( c16 ) |
| 233 | | PORT_INCLUDE( common_cbm_keyboard ) /* ROW0 -> ROW7 */ |
| 234 | | |
| 235 | | PORT_MODIFY("ROW0") |
| 236 | | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("@") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') |
| 237 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F6)) |
| 238 | | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F5)) |
| 239 | | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F4)) |
| 240 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("HELP f7") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_CHAR(UCHAR_MAMEKEY(F7)) |
| 241 | | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(0xA3) |
| 242 | | |
| 243 | | PORT_MODIFY("ROW1") |
| 244 | | /* Both Shift keys were mapped to the same bit */ |
| 245 | | PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift (Left & Right)") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) |
| 246 | | |
| 247 | | PORT_MODIFY("ROW4") |
| 248 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0 \xE2\x86\x91") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(0x2191) |
| 249 | | |
| 250 | | PORT_MODIFY("ROW5") |
| 251 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') |
| 252 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR(UCHAR_MAMEKEY(UP)) |
| 253 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) |
| 254 | | |
| 255 | | PORT_MODIFY("ROW6") |
| 256 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('+') |
| 257 | | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("= Pi \xE2\x86\x90") PORT_CODE(KEYCODE_PGDN) PORT_CHAR('=') PORT_CHAR(0x03C0) PORT_CHAR(0x2190) |
| 258 | | PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) |
| 259 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) |
| 260 | | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*') |
| 261 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) |
| 262 | | |
| 263 | | PORT_MODIFY("ROW7") |
| 264 | | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home Clear") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(HOME)) |
| 265 | | |
| 266 | | PORT_INCLUDE( c16_special ) /* SPECIAL */ |
| 267 | | |
| 268 | | PORT_INCLUDE( c16_controls ) /* CTRLSEL, JOY0, JOY1 */ |
| 269 | | INPUT_PORTS_END |
| 270 | | |
| 271 | | |
| 272 | | static INPUT_PORTS_START( plus4 ) |
| 273 | | PORT_INCLUDE( c16 ) |
| 274 | | |
| 275 | | PORT_MODIFY( "ROW0" ) |
| 276 | | PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(0xA3) |
| 277 | | PORT_MODIFY( "ROW5" ) |
| 278 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') |
| 279 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) |
| 280 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) |
| 281 | | PORT_MODIFY( "ROW6" ) |
| 282 | | PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+') |
| 283 | | PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("= Pi \xE2\x86\x90") PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('=') PORT_CHAR(0x03C0) PORT_CHAR(0x2190) |
| 284 | | PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) |
| 285 | | PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_INSERT) PORT_CHAR('*') |
| 286 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) |
| 287 | | INPUT_PORTS_END |
| 288 | | |
| 289 | | static INPUT_PORTS_START( c16sid ) |
| 290 | | PORT_INCLUDE( c16 ) |
| 291 | | |
| 292 | | PORT_START("SID") |
| 293 | | PORT_CONFNAME( 0x01, 0x00, "SID Card Address") |
| 294 | | PORT_CONFSETTING( 0x00, "0xfd40" ) |
| 295 | | PORT_CONFSETTING( 0x01, "0xfe80" ) |
| 296 | | #if 0 |
| 297 | | PORT_CONFNAME( 0x02, 0x00, "Enable SID writes to 0xd400") |
| 298 | | PORT_CONFSETTING( 0x00, DEF_STR( No ) ) |
| 299 | | PORT_CONFSETTING( 0x02, DEF_STR( Yes ) ) |
| 300 | | #endif |
| 301 | | INPUT_PORTS_END |
| 302 | | |
| 303 | | |
| 304 | | static INPUT_PORTS_START( plus4sid ) |
| 305 | | PORT_INCLUDE( plus4 ) |
| 306 | | |
| 307 | | PORT_START("SID") |
| 308 | | PORT_CONFNAME( 0x01, 0x00, "SID Card Address") |
| 309 | | PORT_CONFSETTING( 0x00, "0xfd40" ) |
| 310 | | PORT_CONFSETTING( 0x01, "0xfe80" ) |
| 311 | | #if 0 |
| 312 | | PORT_CONFNAME( 0x02, 0x00, "Enable SID writes to 0xd400") |
| 313 | | PORT_CONFSETTING( 0x00, DEF_STR( No ) ) |
| 314 | | PORT_CONFSETTING( 0x02, DEF_STR( Yes ) ) |
| 315 | | #endif |
| 316 | | INPUT_PORTS_END |
| 317 | | |
| 318 | | |
| 319 | | /************************************* |
| 320 | | * |
| 321 | | * Graphics definitions |
| 322 | | * |
| 323 | | *************************************/ |
| 324 | | |
| 325 | | static const unsigned char ted7360_palette[] = |
| 326 | | { |
| 327 | | /* black, white, red, cyan */ |
| 328 | | /* purple, green, blue, yellow */ |
| 329 | | /* orange, light orange, pink, light cyan, */ |
| 330 | | /* light violett, light green, light blue, light yellow */ |
| 331 | | /* these 16 colors are 8 times here in different luminance (dark..light) */ |
| 332 | | /* taken from digitized tv screenshot */ |
| 333 | | 0x06, 0x01, 0x03, 0x2b, 0x2b, 0x2b, 0x67, 0x0e, 0x0f, 0x00, 0x3f, 0x42, |
| 334 | | 0x57, 0x00, 0x6d, 0x00, 0x4e, 0x00, 0x19, 0x1c, 0x94, 0x38, 0x38, 0x00, |
| 335 | | 0x56, 0x20, 0x00, 0x4b, 0x28, 0x00, 0x16, 0x48, 0x00, 0x69, 0x07, 0x2f, |
| 336 | | 0x00, 0x46, 0x26, 0x06, 0x2a, 0x80, 0x2a, 0x14, 0x9b, 0x0b, 0x49, 0x00, |
| 337 | | |
| 338 | | 0x00, 0x03, 0x02, 0x3d, 0x3d, 0x3d, 0x75, 0x1e, 0x20, 0x00, 0x50, 0x4f, |
| 339 | | 0x6a, 0x10, 0x78, 0x04, 0x5c, 0x00, 0x2a, 0x2a, 0xa3, 0x4c, 0x47, 0x00, |
| 340 | | 0x69, 0x2f, 0x00, 0x59, 0x38, 0x00, 0x26, 0x56, 0x00, 0x75, 0x15, 0x41, |
| 341 | | 0x00, 0x58, 0x3d, 0x15, 0x3d, 0x8f, 0x39, 0x22, 0xae, 0x19, 0x59, 0x00, |
| 342 | | |
| 343 | | 0x00, 0x03, 0x04, 0x42, 0x42, 0x42, 0x7b, 0x28, 0x20, 0x02, 0x56, 0x59, |
| 344 | | 0x6f, 0x1a, 0x82, 0x0a, 0x65, 0x09, 0x30, 0x34, 0xa7, 0x50, 0x51, 0x00, |
| 345 | | 0x6e, 0x36, 0x00, 0x65, 0x40, 0x00, 0x2c, 0x5c, 0x00, 0x7d, 0x1e, 0x45, |
| 346 | | 0x01, 0x61, 0x45, 0x1c, 0x45, 0x99, 0x42, 0x2d, 0xad, 0x1d, 0x62, 0x00, |
| 347 | | |
| 348 | | 0x05, 0x00, 0x02, 0x56, 0x55, 0x5a, 0x90, 0x3c, 0x3b, 0x17, 0x6d, 0x72, |
| 349 | | 0x87, 0x2d, 0x99, 0x1f, 0x7b, 0x15, 0x46, 0x49, 0xc1, 0x66, 0x63, 0x00, |
| 350 | | 0x84, 0x4c, 0x0d, 0x73, 0x55, 0x00, 0x40, 0x72, 0x00, 0x91, 0x33, 0x5e, |
| 351 | | 0x19, 0x74, 0x5c, 0x32, 0x59, 0xae, 0x59, 0x3f, 0xc3, 0x32, 0x76, 0x00, |
| 352 | | |
| 353 | | 0x02, 0x01, 0x06, 0x84, 0x7e, 0x85, 0xbb, 0x67, 0x68, 0x45, 0x96, 0x96, |
| 354 | | 0xaf, 0x58, 0xc3, 0x4a, 0xa7, 0x3e, 0x73, 0x73, 0xec, 0x92, 0x8d, 0x11, |
| 355 | | 0xaf, 0x78, 0x32, 0xa1, 0x80, 0x20, 0x6c, 0x9e, 0x12, 0xba, 0x5f, 0x89, |
| 356 | | 0x46, 0x9f, 0x83, 0x61, 0x85, 0xdd, 0x84, 0x6c, 0xef, 0x5d, 0xa3, 0x29, |
| 357 | | |
| 358 | | 0x02, 0x00, 0x0a, 0xb2, 0xac, 0xb3, 0xe9, 0x92, 0x92, 0x6c, 0xc3, 0xc1, |
| 359 | | 0xd9, 0x86, 0xf0, 0x79, 0xd1, 0x76, 0x9d, 0xa1, 0xff, 0xbd, 0xbe, 0x40, |
| 360 | | 0xdc, 0xa2, 0x61, 0xd1, 0xa9, 0x4c, 0x93, 0xc8, 0x3d, 0xe9, 0x8a, 0xb1, |
| 361 | | 0x6f, 0xcd, 0xab, 0x8a, 0xb4, 0xff, 0xb2, 0x9a, 0xff, 0x88, 0xcb, 0x59, |
| 362 | | |
| 363 | | 0x02, 0x00, 0x0a, 0xc7, 0xca, 0xc9, 0xff, 0xac, 0xac, 0x85, 0xd8, 0xe0, |
| 364 | | 0xf3, 0x9c, 0xff, 0x92, 0xea, 0x8a, 0xb7, 0xba, 0xff, 0xd6, 0xd3, 0x5b, |
| 365 | | 0xf3, 0xbe, 0x79, 0xe6, 0xc5, 0x65, 0xb0, 0xe0, 0x57, 0xff, 0xa4, 0xcf, |
| 366 | | 0x89, 0xe5, 0xc8, 0xa4, 0xca, 0xff, 0xca, 0xb3, 0xff, 0xa2, 0xe5, 0x7a, |
| 367 | | |
| 368 | | 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xf2, 0xd1, 0xff, 0xff, |
| 369 | | 0xff, 0xe9, 0xff, 0xdb, 0xff, 0xd3, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xa3, |
| 370 | | 0xff, 0xff, 0xc1, 0xff, 0xff, 0xb2, 0xfc, 0xff, 0xa2, 0xff, 0xee, 0xff, |
| 371 | | 0xd1, 0xff, 0xff, 0xeb, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xed, 0xff, 0xbc |
| 372 | | }; |
| 373 | | |
| 374 | | static PALETTE_INIT( c16 ) |
| 375 | | { |
| 376 | | int i; |
| 377 | | |
| 378 | | for (i = 0; i < sizeof(ted7360_palette) / 3; i++) |
| 379 | | palette_set_color_rgb(machine, i, ted7360_palette[i * 3], ted7360_palette[i * 3 + 1], ted7360_palette[i * 3 + 2]); |
| 380 | | } |
| 381 | | |
| 382 | | /************************************* |
| 383 | | * |
| 384 | | * TED7360 interfaces |
| 385 | | * |
| 386 | | *************************************/ |
| 387 | | |
| 388 | | static const ted7360_interface c16_ted7360_intf = { |
| 389 | | "screen", |
| 390 | | TED7360_PAL, |
| 391 | | c16_dma_read, |
| 392 | | c16_dma_read_rom, |
| 393 | | c16_interrupt, |
| 394 | | c16_read_keyboard |
| 395 | | }; |
| 396 | | |
| 397 | | static const ted7360_interface plus4_ted7360_intf = { |
| 398 | | "screen", |
| 399 | | TED7360_NTSC, |
| 400 | | c16_dma_read, |
| 401 | | c16_dma_read_rom, |
| 402 | | c16_interrupt, |
| 403 | | c16_read_keyboard |
| 404 | | }; |
| 405 | | |
| 406 | | |
| 407 | | /************************************* |
| 408 | | * |
| 409 | | * Machine driver |
| 410 | | * |
| 411 | | *************************************/ |
| 412 | | |
| 413 | | static const m6502_interface c16_m7501_interface = |
| 414 | | { |
| 415 | | NULL, /* read_indexed_func */ |
| 416 | | NULL, /* write_indexed_func */ |
| 417 | | DEVCB_HANDLER(c16_m7501_port_read), /* port_read_func */ |
| 418 | | DEVCB_HANDLER(c16_m7501_port_write) /* port_write_func */ |
| 419 | | }; |
| 420 | | |
| 421 | | static CBM_IEC_INTERFACE( cbm_iec_intf ) |
| 422 | | { |
| 423 | | DEVCB_NULL, |
| 424 | | DEVCB_NULL, |
| 425 | | DEVCB_NULL, |
| 426 | | DEVCB_NULL, |
| 427 | | DEVCB_NULL |
| 428 | | }; |
| 429 | | |
| 430 | | static PLUS4_EXPANSION_INTERFACE( expansion_intf ) |
| 431 | | { |
| 432 | | DEVCB_NULL, |
| 433 | | DEVCB_NULL, |
| 434 | | DEVCB_NULL, |
| 435 | | DEVCB_NULL, |
| 436 | | DEVCB_NULL |
| 437 | | }; |
| 438 | | |
| 439 | | static PLUS4_USER_PORT_INTERFACE( user_intf ) |
| 440 | | { |
| 441 | | DEVCB_NULL |
| 442 | | }; |
| 443 | | |
| 444 | | static SCREEN_UPDATE_IND16( c16 ) |
| 445 | | { |
| 446 | | c16_state *state = screen.machine().driver_data<c16_state>(); |
| 447 | | ted7360_video_update(state->m_ted7360, bitmap, cliprect); |
| 448 | | return 0; |
| 449 | | } |
| 450 | | |
| 451 | | static INTERRUPT_GEN( c16_raster_interrupt ) |
| 452 | | { |
| 453 | | c16_state *state = device->machine().driver_data<c16_state>(); |
| 454 | | ted7360_raster_interrupt_gen(state->m_ted7360); |
| 455 | | } |
| 456 | | |
| 457 | | |
| 458 | | static MACHINE_START( c16 ) |
| 459 | | { |
| 460 | | c16_state *state = machine.driver_data<c16_state>(); |
| 461 | | |
| 462 | | state->m_maincpu = machine.device<legacy_cpu_device>("maincpu"); |
| 463 | | state->m_ted7360 = machine.device("ted7360"); |
| 464 | | state->m_cassette = machine.device<cassette_image_device>(CASSETTE_TAG); |
| 465 | | state->m_messram = machine.device<ram_device>(RAM_TAG); |
| 466 | | state->m_sid = machine.device("sid"); |
| 467 | | |
| 468 | | state->save_item(NAME(state->m_old_level)); |
| 469 | | state->save_item(NAME(state->m_lowrom)); |
| 470 | | state->save_item(NAME(state->m_highrom)); |
| 471 | | state->save_item(NAME(state->m_port6529)); |
| 472 | | state->save_item(NAME(state->m_keyline)); |
| 473 | | } |
| 474 | | |
| 475 | | static MACHINE_CONFIG_START( c16, c16_state ) |
| 476 | | /* basic machine hardware */ |
| 477 | | MCFG_CPU_ADD("maincpu", M7501, XTAL_17_73447MHz/20) |
| 478 | | MCFG_CPU_PROGRAM_MAP(c16_map) |
| 479 | | MCFG_CPU_CONFIG( c16_m7501_interface ) |
| 480 | | MCFG_CPU_VBLANK_INT("screen", c16_frame_interrupt) |
| 481 | | MCFG_CPU_PERIODIC_INT(c16_raster_interrupt, TED7360_HRETRACERATE) |
| 482 | | MCFG_QUANTUM_TIME(attotime::from_hz(60)) |
| 483 | | |
| 484 | | MCFG_MACHINE_START( c16 ) |
| 485 | | MCFG_MACHINE_RESET( c16 ) |
| 486 | | |
| 487 | | /* video hardware */ |
| 488 | | MCFG_SCREEN_ADD("screen", RASTER) |
| 489 | | MCFG_SCREEN_REFRESH_RATE(TED7360PAL_VRETRACERATE) |
| 490 | | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ |
| 491 | | MCFG_SCREEN_SIZE(336, 216) |
| 492 | | MCFG_SCREEN_VISIBLE_AREA(0, 336 - 1, 0, 216 - 1) |
| 493 | | MCFG_SCREEN_UPDATE_STATIC( c16 ) |
| 494 | | |
| 495 | | MCFG_PALETTE_LENGTH(ARRAY_LENGTH(ted7360_palette) / 3) |
| 496 | | MCFG_PALETTE_INIT(c16) |
| 497 | | |
| 498 | | /* sound hardware */ |
| 499 | | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 500 | | MCFG_TED7360_ADD("ted7360", c16_ted7360_intf) |
| 501 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 502 | | |
| 503 | | /* devices */ |
| 504 | | MCFG_QUICKLOAD_ADD("quickload", cbm_c16, "p00,prg", CBM_QUICKLOAD_DELAY_SECONDS) |
| 505 | | |
| 506 | | /* cassette */ |
| 507 | | MCFG_CASSETTE_ADD( CASSETTE_TAG, cbm_cassette_interface ) |
| 508 | | |
| 509 | | MCFG_FRAGMENT_ADD(c16_cartslot) |
| 510 | | |
| 511 | | MCFG_C1551_ADD(C1551_TAG, 8) |
| 512 | | MCFG_SOFTWARE_LIST_ADD("disk_list", "plus4_flop") |
| 513 | | |
| 514 | | /* IEC serial bus */ |
| 515 | | MCFG_CBM_IEC_ADD(cbm_iec_intf, NULL) |
| 516 | | |
| 517 | | MCFG_PLUS4_EXPANSION_SLOT_ADD(PLUS4_EXPANSION_SLOT_TAG, XTAL_17_73447MHz/20, expansion_intf, plus4_expansion_cards, NULL, NULL) |
| 518 | | MCFG_PLUS4_USER_PORT_ADD(PLUS4_USER_PORT_TAG, user_intf, plus4_user_port_cards, NULL, NULL) |
| 519 | | |
| 520 | | /* internal ram */ |
| 521 | | MCFG_RAM_ADD(RAM_TAG) |
| 522 | | MCFG_RAM_DEFAULT_SIZE("64K") |
| 523 | | MCFG_RAM_EXTRA_OPTIONS("16K,32K") |
| 524 | | MACHINE_CONFIG_END |
| 525 | | |
| 526 | | static MACHINE_CONFIG_DERIVED( plus4, c16 ) |
| 527 | | MCFG_CPU_MODIFY( "maincpu" ) |
| 528 | | MCFG_CPU_CLOCK( XTAL_14_31818MHz/16 ) |
| 529 | | MCFG_CPU_PROGRAM_MAP(plus4_map) |
| 530 | | MCFG_CPU_CONFIG( c16_m7501_interface ) |
| 531 | | |
| 532 | | MCFG_SCREEN_MODIFY("screen") |
| 533 | | MCFG_SCREEN_REFRESH_RATE(TED7360NTSC_VRETRACERATE) |
| 534 | | |
| 535 | | MCFG_DEVICE_REMOVE("ted7360") |
| 536 | | MCFG_TED7360_ADD("ted7360", plus4_ted7360_intf) |
| 537 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 538 | | |
| 539 | | /* internal ram */ |
| 540 | | MCFG_RAM_MODIFY(RAM_TAG) |
| 541 | | MCFG_RAM_DEFAULT_SIZE("64K") |
| 542 | | MACHINE_CONFIG_END |
| 543 | | |
| 544 | | static MACHINE_CONFIG_DERIVED( c364, plus4 ) |
| 545 | | MCFG_SCREEN_MODIFY("screen") |
| 546 | | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ |
| 547 | | MCFG_CPU_MODIFY( "maincpu" ) |
| 548 | | MCFG_CPU_PROGRAM_MAP(c364_map) |
| 549 | | |
| 550 | | MCFG_T6721_ADD("t6721") |
| 551 | | MACHINE_CONFIG_END |
| 552 | | |
| 553 | | static MACHINE_CONFIG_DERIVED( c264, c16 ) |
| 554 | | /* internal ram */ |
| 555 | | MCFG_RAM_MODIFY(RAM_TAG) |
| 556 | | MCFG_RAM_DEFAULT_SIZE("64K") |
| 557 | | MACHINE_CONFIG_END |
| 558 | | |
| 559 | | static MACHINE_CONFIG_DERIVED( c16sid, c16 ) |
| 560 | | |
| 561 | | MCFG_SOUND_ADD("sid", SID8580, TED7360PAL_CLOCK/4) |
| 562 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 563 | | MACHINE_CONFIG_END |
| 564 | | |
| 565 | | static MACHINE_CONFIG_DERIVED( plus4sid, plus4 ) |
| 566 | | |
| 567 | | MCFG_SOUND_ADD("sid", SID8580, TED7360NTSC_CLOCK/4) |
| 568 | | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 569 | | MACHINE_CONFIG_END |
| 570 | | |
| 571 | | |
| 572 | | /************************************* |
| 573 | | * |
| 574 | | * ROM definition(s) |
| 575 | | * |
| 576 | | *************************************/ |
| 577 | | ROM_START( c232 ) |
| 578 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
| 579 | | ROM_LOAD( "318006-01.bin", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
| 580 | | ROM_LOAD( "318004-01.bin", 0x14000, 0x4000, CRC(dbdc3319) SHA1(3c77caf72914c1c0a0875b3a7f6935cd30c54201) ) |
| 581 | | ROM_END |
| 582 | | |
| 583 | | ROM_START( c264 ) |
| 584 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
| 585 | | ROM_LOAD( "basic-264.bin", 0x10000, 0x4000, CRC(6a2fc8e3) SHA1(473fce23afa07000cdca899fbcffd6961b36a8a0) ) |
| 586 | | ROM_LOAD( "kernal-264.bin", 0x14000, 0x4000, CRC(8f32abe7) SHA1(d481faf5fcbb331878dc7851c642d04f26a32873) ) |
| 587 | | ROM_END |
| 588 | | |
| 589 | | ROM_START( c364 ) |
| 590 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
| 591 | | ROM_LOAD( "318006.01", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
| 592 | | ROM_LOAD( "kern364p.bin", 0x14000, 0x4000, CRC(84fd4f7a) SHA1(b9a5b5dacd57ca117ef0b3af29e91998bf4d7e5f) ) |
| 593 | | ROM_LOAD( "317053-01.bin", 0x18000, 0x4000, CRC(4fd1d8cb) SHA1(3b69f6e7cb4c18bb08e203fb18b7dabfa853390f) ) |
| 594 | | ROM_LOAD( "317054-01.bin", 0x1c000, 0x4000, CRC(109de2fc) SHA1(0ad7ac2db7da692d972e586ca0dfd747d82c7693) ) |
| 595 | | /* at address 0x20000 not so good */ |
| 596 | | ROM_LOAD( "spk3cc4.bin", 0x28000, 0x4000, CRC(5227c2ee) SHA1(59af401cbb2194f689898271c6e8aafa28a7af11) ) |
| 597 | | ROM_END |
| 598 | | |
| 599 | | |
| 600 | | ROM_START( c16 ) |
| 601 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
| 602 | | ROM_DEFAULT_BIOS("r5") |
| 603 | | ROM_LOAD( "318006-01.u3", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
| 604 | | |
| 605 | | ROM_SYSTEM_BIOS( 0, "r3", "rev. 3" ) |
| 606 | | ROMX_LOAD( "318004-03.u4", 0x14000, 0x4000, CRC(77bab934) SHA1(97814dab9d757fe5a3a61d357a9a81da588a9783), ROM_BIOS(1) ) |
| 607 | | ROM_SYSTEM_BIOS( 1, "r4", "rev. 4" ) |
| 608 | | ROMX_LOAD( "318004-04.u4", 0x14000, 0x4000, CRC(be54ed79) SHA1(514ad3c29d01a2c0a3b143d9c1d4143b1912b793), ROM_BIOS(2) ) |
| 609 | | ROM_SYSTEM_BIOS( 2, "r5", "rev. 5" ) |
| 610 | | ROMX_LOAD( "318004-05.u4", 0x14000, 0x4000, CRC(71c07bd4) SHA1(7c7e07f016391174a557e790c4ef1cbe33512cdb), ROM_BIOS(3) ) |
| 611 | | ROM_END |
| 612 | | |
| 613 | | #define rom_c16c rom_c16 |
| 614 | | #define rom_c16v rom_c16 |
| 615 | | |
| 616 | | #define rom_c116 rom_c16 |
| 617 | | #define rom_c116c rom_c16c |
| 618 | | #define rom_c116v rom_c16v |
| 619 | | |
| 620 | | ROM_START( c16hun ) |
| 621 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
| 622 | | ROM_LOAD( "318006-01.u3", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
| 623 | | ROM_LOAD( "hungary.u4", 0x14000, 0x4000, CRC(775f60c5) SHA1(20cf3c4bf6c54ef09799af41887218933f2e27ee) ) |
| 624 | | ROM_END |
| 625 | | |
| 626 | | ROM_START( plus4 ) |
| 627 | | ROM_REGION( 0x40000, "maincpu", 0 ) |
| 628 | | ROM_DEFAULT_BIOS("r5") |
| 629 | | ROM_SYSTEM_BIOS( 0, "r4", "rev. 4" ) |
| 630 | | ROMX_LOAD( "318005-04.u24", 0x14000, 0x4000, CRC(799a633d) SHA1(5df52c693387c0e2b5d682613a3b5a65477311cf), ROM_BIOS(1) ) |
| 631 | | ROM_SYSTEM_BIOS( 1, "r5", "rev. 5" ) |
| 632 | | ROMX_LOAD( "318005-05.u24", 0x14000, 0x4000, CRC(70295038) SHA1(a3d9e5be091b98de39a046ab167fb7632d053682), ROM_BIOS(2) ) |
| 633 | | ROM_SYSTEM_BIOS( 2, "jiffydos", "JiffyDOS v6.01" ) |
| 634 | | ROMX_LOAD( "jiffydos plus4.u24", 0x10000, 0x8000, CRC(818d3f45) SHA1(9bc1b1c3da9ca642deae717905f990d8e36e6c3b), ROM_BIOS(3) ) |
| 635 | | |
| 636 | | ROM_LOAD( "318006-01.u23", 0x10000, 0x4000, CRC(74eaae87) SHA1(161c96b4ad20f3a4f2321808e37a5ded26a135dd) ) |
| 637 | | |
| 638 | | ROM_LOAD( "317053-01.u25", 0x18000, 0x4000, CRC(4fd1d8cb) SHA1(3b69f6e7cb4c18bb08e203fb18b7dabfa853390f) ) |
| 639 | | ROM_LOAD( "317054-01.26", 0x1c000, 0x4000, CRC(109de2fc) SHA1(0ad7ac2db7da692d972e586ca0dfd747d82c7693) ) |
| 640 | | ROM_END |
| 641 | | |
| 642 | | #define rom_plus4c rom_plus4 |
| 643 | | #define rom_plus4v rom_plus4 |
| 644 | | |
| 645 | | #define rom_c16sid rom_c16 |
| 646 | | #define rom_plus4sid rom_plus4 |
| 647 | | |
| 648 | | /*************************************************************************** |
| 649 | | |
| 650 | | Game driver(s) |
| 651 | | |
| 652 | | ***************************************************************************/ |
| 653 | | |
| 654 | | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ |
| 655 | | |
| 656 | | COMP( 1984, c16, 0, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 16 (PAL)", 0) |
| 657 | | COMP( 1984, c16hun, c16, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 16 Novotrade (PAL, Hungary)", 0) |
| 658 | | |
| 659 | | COMP( 1984, c116, c16, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 116 (PAL)", 0) |
| 660 | | |
| 661 | | COMP( 1984, plus4, c16, 0, plus4, plus4, c16_state, plus4, "Commodore Business Machines", "Commodore Plus/4 (NTSC)", 0) |
| 662 | | |
| 663 | | COMP( 1984, c232, c16, 0, c16, c16, c16_state, c16, "Commodore Business Machines", "Commodore 232 (Prototype)", 0) |
| 664 | | COMP( 1984, c264, c16, 0, c264, plus4, c16_state, plus4, "Commodore Business Machines", "Commodore 264 (Prototype)", 0) |
| 665 | | COMP( 1984, c364, c16, 0, c364, plus4, c16_state, plus4, "Commodore Business Machines", "Commodore V364 (Prototype)", GAME_IMPERFECT_SOUND) |
| 666 | | |
| 667 | | COMP( 1984, c16sid, c16, 0, c16sid, c16sid, c16_state, c16sid, "Commodore Business Machines", "Commodore 16 (PAL, SID Card)", GAME_UNOFFICIAL | GAME_IMPERFECT_SOUND) |
| 668 | | COMP( 1984, plus4sid, c16, 0, plus4sid, plus4sid, c16_state, plus4sid, "Commodore Business Machines", "Commodore Plus/4 (NTSC, SID Card)", GAME_UNOFFICIAL | GAME_IMPERFECT_SOUND) |