src/mess/machine/vc1541.c
| r3251 | r3252 | |
| 96 | 96 | 2 heads |
| 97 | 97 | |
| 98 | 98 | */ |
| 99 | /* 2008-09 FP |
| 100 | started some work on the floppy emulation code: |
| 101 | + made the functions / structs less vc1541-centric |
| 102 | + unified config & reset functions, using type variable |
| 103 | to choose the actions to be done |
| 104 | |
| 105 | a limitation is clear: only a single occurrence of emulated drive |
| 106 | is expected. |
| 107 | at a later stage, at least drive_config & drive_reset will need |
| 108 | an index to choose between the drives |
| 99 | 109 | |
| 110 | current status: |
| 111 | + preliminary vc1541 & c1551 implementation (I still have to |
| 112 | investigate how good) |
| 113 | + no support for other drive types (even if now I list all |
| 114 | the variants supported by Vice in the enum) |
| 115 | */ |
| 116 | |
| 117 | |
| 100 | 118 | #include <assert.h> |
| 101 | 119 | #include <stdio.h> |
| 102 | 120 | |
| r3251 | r3252 | |
| 140 | 158 | /* G64 or D64 image |
| 141 | 159 | implementation as writeback system |
| 142 | 160 | */ |
| 143 | | typedef enum { TypeVC1541, TypeC1551, Type2031 } CBM_Drive_Emu_type; |
| 144 | 161 | |
| 145 | 162 | typedef struct |
| 146 | 163 | { |
| 147 | 164 | int cpunumber; |
| 148 | | CBM_Drive_Emu_type type; |
| 165 | int type; |
| 149 | 166 | union { |
| 150 | 167 | struct { |
| 151 | 168 | int deviceid; |
| r3251 | r3252 | |
| 157 | 174 | } ieee488; |
| 158 | 175 | struct { |
| 159 | 176 | UINT8 cpu_ddr, cpu_port; |
| 160 | | void *timer; |
| 177 | void *irq_timer; |
| 161 | 178 | } c1551; |
| 162 | 179 | } drive; |
| 163 | 180 | |
| r3251 | r3252 | |
| 184 | 201 | } d64; |
| 185 | 202 | } CBM_Drive_Emu; |
| 186 | 203 | |
| 187 | | static CBM_Drive_Emu vc1541_static= { 0 }, *vc1541 = &vc1541_static; |
| 204 | static CBM_Drive_Emu drive_static= { 0 }, *drive = &drive_static; |
| 188 | 205 | |
| 206 | |
| 207 | /************************************** |
| 208 | |
| 209 | Generic image handling |
| 210 | |
| 211 | **************************************/ |
| 212 | |
| 213 | |
| 189 | 214 | /* four different frequencies for the 4 different zones on the disk */ |
| 190 | | static const double vc1541_times[4]= { |
| 215 | static const double drive_times[4]= { |
| 191 | 216 | 13/16e6, 14/16e6, 15/16e6, 16/16e6 |
| 192 | 217 | }; |
| 193 | 218 | |
| r3251 | r3252 | |
| 258 | 283 | int data[4]; |
| 259 | 284 | } gcr_helper; |
| 260 | 285 | |
| 261 | | static void vc1541_sector_start(void) |
| 286 | static void drive_sector_start(void) |
| 262 | 287 | { |
| 263 | 288 | gcr_helper.count=0; |
| 264 | 289 | } |
| 265 | 290 | |
| 266 | | static void vc1541_sector_data(UINT8 data, int *pos) |
| 291 | static void drive_sector_data(UINT8 data, int *pos) |
| 267 | 292 | { |
| 268 | 293 | gcr_helper.data[gcr_helper.count++]=data; |
| 269 | 294 | if (gcr_helper.count==4) { |
| 270 | 295 | gcr_double_2_gcr(gcr_helper.data[0], gcr_helper.data[1], |
| 271 | 296 | gcr_helper.data[2], gcr_helper.data[3], |
| 272 | | vc1541->head.data+*pos); |
| 297 | drive->head.data+*pos); |
| 273 | 298 | *pos=*pos+5; |
| 274 | 299 | gcr_helper.count=0; |
| 275 | 300 | } |
| 276 | 301 | } |
| 277 | 302 | |
| 278 | | static void vc1541_sector_end(int *pos) |
| 303 | static void drive_sector_end(int *pos) |
| 279 | 304 | { |
| 280 | 305 | assert(gcr_helper.count==0); |
| 281 | 306 | } |
| 282 | 307 | |
| 283 | | static void vc1541_sector_to_gcr(int track, int sector) |
| 308 | static void drive_sector_to_gcr(int track, int sector) |
| 284 | 309 | { |
| 285 | 310 | int i=0, j, offset, chksum=0; |
| 286 | 311 | |
| 287 | | if (vc1541->d64.data==NULL) return; |
| 288 | | vc1541->head.data[i++]=0xff; |
| 289 | | vc1541->head.data[i++]=0xff; |
| 290 | | vc1541->head.data[i++]=0xff; |
| 291 | | vc1541->head.data[i++]=0xff; |
| 292 | | vc1541->head.data[i++]=0xff; |
| 293 | | vc1541_sector_start(); |
| 312 | if (drive->d64.data==NULL) return; |
| 313 | drive->head.data[i++]=0xff; |
| 314 | drive->head.data[i++]=0xff; |
| 315 | drive->head.data[i++]=0xff; |
| 316 | drive->head.data[i++]=0xff; |
| 317 | drive->head.data[i++]=0xff; |
| 318 | drive_sector_start(); |
| 294 | 319 | |
| 295 | | vc1541_sector_data(8, &i); |
| 320 | drive_sector_data(8, &i); |
| 296 | 321 | chksum= sector^track |
| 297 | | ^vc1541->d64.data[D64_TRACK_ID1]^vc1541->d64.data[D64_TRACK_ID2]; |
| 298 | | vc1541_sector_data(chksum, &i); |
| 299 | | vc1541_sector_data(sector, &i); |
| 300 | | vc1541_sector_data(track, &i); |
| 301 | | vc1541_sector_data(vc1541->d64.data[D64_TRACK_ID1], &i); |
| 302 | | vc1541_sector_data(vc1541->d64.data[D64_TRACK_ID2], &i); |
| 303 | | vc1541_sector_data(0xf, &i); |
| 304 | | vc1541_sector_data(0xf, &i); |
| 305 | | vc1541_sector_end(&i); |
| 322 | ^drive->d64.data[D64_TRACK_ID1]^drive->d64.data[D64_TRACK_ID2]; |
| 323 | drive_sector_data(chksum, &i); |
| 324 | drive_sector_data(sector, &i); |
| 325 | drive_sector_data(track, &i); |
| 326 | drive_sector_data(drive->d64.data[D64_TRACK_ID1], &i); |
| 327 | drive_sector_data(drive->d64.data[D64_TRACK_ID2], &i); |
| 328 | drive_sector_data(0xf, &i); |
| 329 | drive_sector_data(0xf, &i); |
| 330 | drive_sector_end(&i); |
| 306 | 331 | |
| 307 | 332 | /* 5 - 10 gcr bytes cap */ |
| 308 | | gcr_double_2_gcr(0, 0, 0, 0, vc1541->head.data+i);i+=5; |
| 309 | | gcr_double_2_gcr(0, 0, 0, 0, vc1541->head.data+i);i+=5; |
| 310 | | vc1541->head.data[i++]=0xff; |
| 311 | | vc1541->head.data[i++]=0xff; |
| 312 | | vc1541->head.data[i++]=0xff; |
| 313 | | vc1541->head.data[i++]=0xff; |
| 314 | | vc1541->head.data[i++]=0xff; |
| 315 | | vc1541_sector_data(0x7, &i); |
| 333 | gcr_double_2_gcr(0, 0, 0, 0, drive->head.data+i);i+=5; |
| 334 | gcr_double_2_gcr(0, 0, 0, 0, drive->head.data+i);i+=5; |
| 335 | drive->head.data[i++]=0xff; |
| 336 | drive->head.data[i++]=0xff; |
| 337 | drive->head.data[i++]=0xff; |
| 338 | drive->head.data[i++]=0xff; |
| 339 | drive->head.data[i++]=0xff; |
| 340 | drive_sector_data(0x7, &i); |
| 316 | 341 | |
| 317 | 342 | chksum=0; |
| 318 | 343 | for (offset=d64_tracksector2offset(track,sector), j=0; j<256; j++) { |
| 319 | | chksum^=vc1541->d64.data[offset]; |
| 320 | | vc1541_sector_data(vc1541->d64.data[offset++], &i); |
| 344 | chksum^=drive->d64.data[offset]; |
| 345 | drive_sector_data(drive->d64.data[offset++], &i); |
| 321 | 346 | } |
| 322 | | vc1541_sector_data(chksum, &i); |
| 323 | | vc1541_sector_data(0, &i); /* padding up */ |
| 324 | | vc1541_sector_data(0, &i); |
| 325 | | vc1541_sector_end(&i); |
| 326 | | gcr_double_2_gcr(0, 0, 0, 0, vc1541->head.data+i);i+=5; |
| 327 | | gcr_double_2_gcr(0, 0, 0, 0, vc1541->head.data+i);i+=5; |
| 347 | drive_sector_data(chksum, &i); |
| 348 | drive_sector_data(0, &i); /* padding up */ |
| 349 | drive_sector_data(0, &i); |
| 350 | drive_sector_end(&i); |
| 351 | gcr_double_2_gcr(0, 0, 0, 0, drive->head.data+i);i+=5; |
| 352 | gcr_double_2_gcr(0, 0, 0, 0, drive->head.data+i);i+=5; |
| 328 | 353 | } |
| 329 | 354 | |
| 330 | 355 | |
| 356 | /************************************** |
| 357 | |
| 358 | VC1541 |
| 359 | |
| 360 | **************************************/ |
| 361 | |
| 362 | |
| 331 | 363 | static ADDRESS_MAP_START( vc1541_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 332 | 364 | AM_RANGE(0x0000, 0x07ff) AM_RAM |
| 333 | 365 | AM_RANGE(0x1800, 0x180f) AM_READWRITE(via_2_r, via_2_w) /* 0 and 1 used in vc20 */ |
| 334 | | AM_RANGE(0x1810, 0x189f) AM_READ( SMH_NOP) /* for debugger */ |
| 366 | AM_RANGE(0x1810, 0x189f) AM_READ(SMH_NOP) /* for debugger */ |
| 335 | 367 | AM_RANGE(0x1c00, 0x1c0f) AM_READWRITE(via_3_r, via_3_w) |
| 336 | | AM_RANGE(0x1c10, 0x1c9f) AM_READ( SMH_NOP) /* for debugger */ |
| 368 | AM_RANGE(0x1c10, 0x1c9f) AM_READ(SMH_NOP) /* for debugger */ |
| 337 | 369 | AM_RANGE(0xc000, 0xffff) AM_ROM |
| 338 | 370 | ADDRESS_MAP_END |
| 339 | 371 | |
| r3251 | r3252 | |
| 358 | 390 | INPUT_PORTS_END |
| 359 | 391 | #endif |
| 360 | 392 | |
| 361 | | static TIMER_CALLBACK(vc1541_timer) |
| 393 | static TIMER_CALLBACK(drive_timer) |
| 362 | 394 | { |
| 363 | | if (vc1541->clock==0) { |
| 364 | | vc1541->clock=1; |
| 365 | | vc1541->head.ready=0; |
| 366 | | vc1541->head.sync=0; |
| 367 | | if (vc1541->type==TypeVC1541) { |
| 368 | | cpunum_set_input_line(machine, vc1541->cpunumber, M6502_SET_OVERFLOW, 1); |
| 395 | if (drive->clock==0) { |
| 396 | drive->clock=1; |
| 397 | drive->head.ready=0; |
| 398 | drive->head.sync=0; |
| 399 | if (drive->type==type_1541) { |
| 400 | cpunum_set_input_line(machine, drive->cpunumber, M6502_SET_OVERFLOW, 1); |
| 369 | 401 | via_3_ca1_w(machine, 0,1); |
| 370 | 402 | } |
| 371 | 403 | return; |
| 372 | 404 | } |
| 373 | | if (++(vc1541->d64.pos)>=sizeof(vc1541->head.data)) { |
| 374 | | if (++(vc1541->d64.sector)>= |
| 375 | | d64_sectors_per_track[(int)vc1541->track-1]) { |
| 376 | | vc1541->d64.sector=0; |
| 405 | if (++(drive->d64.pos)>=sizeof(drive->head.data)) { |
| 406 | if (++(drive->d64.sector)>= |
| 407 | d64_sectors_per_track[(int)drive->track-1]) { |
| 408 | drive->d64.sector=0; |
| 377 | 409 | } |
| 378 | | vc1541_sector_to_gcr((int)vc1541->track,vc1541->d64.sector); |
| 379 | | vc1541->d64.pos=0; |
| 410 | drive_sector_to_gcr((int)drive->track,drive->d64.sector); |
| 411 | drive->d64.pos=0; |
| 380 | 412 | } |
| 381 | | vc1541->head.ready=1; |
| 382 | | if (vc1541->head.data[vc1541->d64.pos]==0xff) { |
| 383 | | vc1541->head.ffcount++; |
| 384 | | if (vc1541->head.ffcount==5) { |
| 385 | | vc1541->head.sync=1; |
| 413 | drive->head.ready=1; |
| 414 | if (drive->head.data[drive->d64.pos]==0xff) { |
| 415 | drive->head.ffcount++; |
| 416 | if (drive->head.ffcount==5) { |
| 417 | drive->head.sync=1; |
| 386 | 418 | } |
| 387 | 419 | } else { |
| 388 | | vc1541->head.ffcount=0; |
| 389 | | vc1541->head.sync=0; |
| 420 | drive->head.ffcount=0; |
| 421 | drive->head.sync=0; |
| 390 | 422 | } |
| 391 | | if (vc1541->type==TypeVC1541) { |
| 392 | | cpunum_set_input_line(machine, vc1541->cpunumber, M6502_SET_OVERFLOW, 0); |
| 423 | if (drive->type==type_1541) { |
| 424 | cpunum_set_input_line(machine, drive->cpunumber, M6502_SET_OVERFLOW, 0); |
| 393 | 425 | via_3_ca1_w(machine, 0,0); |
| 394 | 426 | } |
| 395 | | vc1541->clock=0; |
| 427 | drive->clock=0; |
| 396 | 428 | } |
| 397 | 429 | |
| 398 | 430 | /* |
| r3251 | r3252 | |
| 412 | 444 | */ |
| 413 | 445 | static void vc1541_via0_irq (running_machine *machine, int level) |
| 414 | 446 | { |
| 415 | | vc1541->via0irq = level; |
| 416 | | DBG_LOG(2, "vc1541 via0 irq",("level %d %d\n",vc1541->via0irq,vc1541->via1irq)); |
| 417 | | cpunum_set_input_line (machine, vc1541->cpunumber, |
| 418 | | M6502_IRQ_LINE, vc1541->via1irq || vc1541->via0irq); |
| 447 | drive->via0irq = level; |
| 448 | DBG_LOG(2, "vc1541 via0 irq",("level %d %d\n",drive->via0irq,drive->via1irq)); |
| 449 | cpunum_set_input_line (machine, drive->cpunumber, |
| 450 | M6502_IRQ_LINE, drive->via1irq || drive->via0irq); |
| 419 | 451 | } |
| 420 | 452 | |
| 421 | 453 | static READ8_HANDLER( vc1541_via0_read_portb ) |
| r3251 | r3252 | |
| 423 | 455 | static int old=-1; |
| 424 | 456 | int value = 0x7a; |
| 425 | 457 | |
| 426 | | if (!vc1541->drive.serial.serial_data || !serial.data[0]) |
| 458 | if (!drive->drive.serial.serial_data || !serial.data[0]) |
| 427 | 459 | value |= 1; |
| 428 | | if (!vc1541->drive.serial.serial_clock || !serial.clock[0]) |
| 460 | if (!drive->drive.serial.serial_clock || !serial.clock[0]) |
| 429 | 461 | value |= 4; |
| 430 | 462 | if (!serial.atn[0]) value |= 0x80; |
| 431 | 463 | |
| 432 | | switch (vc1541->drive.serial.deviceid) |
| 464 | switch (drive->drive.serial.deviceid) |
| 433 | 465 | { |
| 434 | 466 | case 8: |
| 435 | 467 | value &= ~0x60; |
| r3251 | r3252 | |
| 467 | 499 | data&8?"CLOCK":"clock", |
| 468 | 500 | data&2?"DATA":"data")); |
| 469 | 501 | |
| 470 | | vc1541->drive.serial.data=data&2?0:1; |
| 471 | | vc1541->drive.serial.acka=(data&0x10)?1:0; |
| 502 | drive->drive.serial.data=data&2?0:1; |
| 503 | drive->drive.serial.acka=(data&0x10)?1:0; |
| 472 | 504 | |
| 473 | | if ((!(data & 2)) != vc1541->drive.serial.serial_data) |
| 505 | if ((!(data & 2)) != drive->drive.serial.serial_data) |
| 474 | 506 | { |
| 475 | | vc1541_serial_data_write (1, vc1541->drive.serial.serial_data = !(data & 2)); |
| 507 | vc1541_serial_data_write (1, drive->drive.serial.serial_data = !(data & 2)); |
| 476 | 508 | } |
| 477 | 509 | |
| 478 | | if ((!(data & 8)) != vc1541->drive.serial.serial_clock) |
| 510 | if ((!(data & 8)) != drive->drive.serial.serial_clock) |
| 479 | 511 | { |
| 480 | | vc1541_serial_clock_write (1, vc1541->drive.serial.serial_clock = !(data & 8)); |
| 512 | vc1541_serial_clock_write (1, drive->drive.serial.serial_clock = !(data & 8)); |
| 481 | 513 | } |
| 482 | | vc1541_serial_atn_write (machine, 1, vc1541->drive.serial.serial_atn = 1); |
| 514 | vc1541_serial_atn_write (machine, 1, drive->drive.serial.serial_atn = 1); |
| 483 | 515 | } |
| 484 | 516 | |
| 485 | 517 | /* |
| r3251 | r3252 | |
| 511 | 543 | */ |
| 512 | 544 | static void vc1541_via1_irq (running_machine *machine, int level) |
| 513 | 545 | { |
| 514 | | vc1541->via1irq = level; |
| 515 | | DBG_LOG(2, "vc1541 via1 irq",("level %d %d\n",vc1541->via0irq,vc1541->via1irq)); |
| 516 | | cpunum_set_input_line (machine, vc1541->cpunumber, |
| 517 | | M6502_IRQ_LINE, vc1541->via1irq || vc1541->via0irq); |
| 546 | drive->via1irq = level; |
| 547 | DBG_LOG(2, "vc1541 via1 irq",("level %d %d\n",drive->via0irq,drive->via1irq)); |
| 548 | cpunum_set_input_line (machine, drive->cpunumber, |
| 549 | M6502_IRQ_LINE, drive->via1irq || drive->via0irq); |
| 518 | 550 | } |
| 519 | 551 | |
| 520 | 552 | static READ8_HANDLER( vc1541_via1_read_porta ) |
| 521 | 553 | { |
| 522 | | int data=vc1541->head.data[vc1541->d64.pos]; |
| 554 | int data=drive->head.data[drive->d64.pos]; |
| 523 | 555 | DBG_LOG(2, "vc1541 drive",("port a read %.2x\n", data)); |
| 524 | 556 | return data; |
| 525 | 557 | } |
| r3251 | r3252 | |
| 537 | 569 | if (WRITEPROTECTED) |
| 538 | 570 | value &= ~0x10; |
| 539 | 571 | #endif |
| 540 | | if (vc1541->head.sync) { |
| 572 | if (drive->head.sync) { |
| 541 | 573 | value&=~0x80; |
| 542 | 574 | } |
| 543 | 575 | |
| r3251 | r3252 | |
| 552 | 584 | if ((old&3)!=(data&3)) { |
| 553 | 585 | switch (old&3) { |
| 554 | 586 | case 0: |
| 555 | | if ((data&3)==1) vc1541->track+=0.5; |
| 556 | | else if ((data&3)==3) vc1541->track-=0.5; |
| 587 | if ((data&3)==1) drive->track+=0.5; |
| 588 | else if ((data&3)==3) drive->track-=0.5; |
| 557 | 589 | break; |
| 558 | 590 | case 1: |
| 559 | | if ((data&3)==2) vc1541->track+=0.5; |
| 560 | | else if ((data&3)==0) vc1541->track-=0.5; |
| 591 | if ((data&3)==2) drive->track+=0.5; |
| 592 | else if ((data&3)==0) drive->track-=0.5; |
| 561 | 593 | break; |
| 562 | 594 | case 2: |
| 563 | | if ((data&3)==3) vc1541->track+=0.5; |
| 564 | | else if ((data&3)==1) vc1541->track-=0.5; |
| 595 | if ((data&3)==3) drive->track+=0.5; |
| 596 | else if ((data&3)==1) drive->track-=0.5; |
| 565 | 597 | break; |
| 566 | 598 | case 3: |
| 567 | | if ((data&3)==0) vc1541->track+=0.5; |
| 568 | | else if ((data&3)==2) vc1541->track-=0.5; |
| 599 | if ((data&3)==0) drive->track+=0.5; |
| 600 | else if ((data&3)==2) drive->track-=0.5; |
| 569 | 601 | break; |
| 570 | 602 | } |
| 571 | | if (vc1541->track<1) vc1541->track=1.0; |
| 572 | | if (vc1541->track>35) vc1541->track=35; |
| 603 | if (drive->track<1) drive->track=1.0; |
| 604 | if (drive->track>35) drive->track=35; |
| 573 | 605 | } |
| 574 | | if ( (vc1541->motor!=(data&4))||(vc1541->frequency!=(data&0x60)) ) |
| 606 | if ( (drive->motor!=(data&4))||(drive->frequency!=(data&0x60)) ) |
| 575 | 607 | { |
| 576 | 608 | double tme; |
| 577 | | vc1541->motor = data & 4; |
| 578 | | vc1541->frequency = data & 0x60; |
| 579 | | tme=vc1541_times[vc1541->frequency>>5]*8*2; |
| 580 | | if (vc1541->motor) |
| 609 | drive->motor = data & 4; |
| 610 | drive->frequency = data & 0x60; |
| 611 | tme=drive_times[drive->frequency>>5]*8*2; |
| 612 | if (drive->motor) |
| 581 | 613 | { |
| 582 | | if (attotime_to_double(timer_timeelapsed(vc1541->timer)) > 1.0e29) |
| 583 | | timer_reset(vc1541->timer, attotime_never); |
| 614 | if (attotime_to_double(timer_timeelapsed(drive->timer)) > 1.0e29) |
| 615 | timer_reset(drive->timer, attotime_never); |
| 584 | 616 | else |
| 585 | | timer_adjust_periodic(vc1541->timer, attotime_zero, 0, double_to_attotime(tme)); |
| 617 | timer_adjust_periodic(drive->timer, attotime_zero, 0, double_to_attotime(tme)); |
| 586 | 618 | } |
| 587 | 619 | else |
| 588 | 620 | { |
| 589 | | timer_reset(vc1541->timer, attotime_never); |
| 621 | timer_reset(drive->timer, attotime_never); |
| 590 | 622 | } |
| 591 | 623 | } |
| 592 | 624 | old=data; |
| 593 | 625 | } |
| 594 | | vc1541->led = data & 8; |
| 626 | drive->led = data & 8; |
| 595 | 627 | } |
| 596 | 628 | |
| 597 | 629 | static const struct via6522_interface via2 = |
| r3251 | r3252 | |
| 626 | 658 | vc1541_via1_irq |
| 627 | 659 | }; |
| 628 | 660 | |
| 629 | | DEVICE_IMAGE_LOAD(vc1541) |
| 630 | | { |
| 631 | | vc1541->d64.data = image_ptr(image); |
| 632 | | if (!vc1541->d64.data) |
| 633 | | return INIT_FAIL; |
| 634 | 661 | |
| 635 | | logerror("floppy image %s loaded\n", image_filename(image)); |
| 636 | | |
| 637 | | return INIT_PASS; |
| 638 | | } |
| 639 | | |
| 640 | | DEVICE_IMAGE_UNLOAD(vc1541) |
| 641 | | { |
| 642 | | /* writeback of image data */ |
| 643 | | vc1541->d64.data = NULL; |
| 644 | | } |
| 645 | | |
| 646 | | int vc1541_config (int id, int mode, VC1541_CONFIG *config) |
| 647 | | { |
| 648 | | via_config (2, &via2); |
| 649 | | via_config (3, &via3); |
| 650 | | vc1541->type=TypeVC1541; |
| 651 | | vc1541->cpunumber = config->cpunr; |
| 652 | | vc1541->drive.serial.deviceid = config->devicenr; |
| 653 | | vc1541->timer = timer_alloc(vc1541_timer, NULL); |
| 654 | | return 0; |
| 655 | | } |
| 656 | | |
| 657 | | void vc1541_reset (void) |
| 658 | | { |
| 659 | | int i; |
| 660 | | |
| 661 | | if (vc1541->type==TypeVC1541) { |
| 662 | | for (i = 0; i < sizeof (serial.atn) / sizeof (serial.atn[0]); i++) |
| 663 | | { |
| 664 | | serial.atn[i] = serial.data[i] = serial.clock[i] = 1; |
| 665 | | } |
| 666 | | } |
| 667 | | vc1541->track=1.0; |
| 668 | | if ((vc1541->type==TypeVC1541)||(vc1541->type==Type2031)) { |
| 669 | | via_reset (); |
| 670 | | } |
| 671 | | if ((vc1541->type==TypeC1551)) { |
| 672 | | tpi6525_0_reset(); |
| 673 | | } |
| 674 | | } |
| 675 | | |
| 676 | | /* delivers status for displaying */ |
| 677 | | void vc1541_drive_status (char *text, int size) |
| 678 | | { |
| 679 | | #if 0 |
| 680 | | if (vc1541->type==TypeVC1541) { |
| 681 | | snprintf (text, size, "%s %4.1f %s %.2x %s %s %s", |
| 682 | | vc1541->led ? "LED" : "led", |
| 683 | | vc1541->track, |
| 684 | | vc1541->motor ? "MOTOR" : "motor", |
| 685 | | vc1541->frequency, |
| 686 | | serial.atn[0]?"ATN":"atn", |
| 687 | | serial.clock[0]?"CLOCK":"clock", |
| 688 | | serial.data[0]?"DATA":"data"); |
| 689 | | } else if (vc1541->type==TypeC1551) { |
| 690 | | snprintf (text, size, "%s %4.1f %s %.2x", |
| 691 | | vc1541->led ? "LED" : "led", |
| 692 | | vc1541->track, |
| 693 | | vc1541->motor ? "MOTOR" : "motor", |
| 694 | | vc1541->frequency); |
| 695 | | } |
| 696 | | #else |
| 697 | | text[0] = 0; |
| 698 | | #endif |
| 699 | | return; |
| 700 | | } |
| 701 | | |
| 702 | 662 | void vc1541_serial_reset_write (int which, int level) |
| 703 | 663 | { |
| 704 | 664 | } |
| r3251 | r3252 | |
| 733 | 693 | serial.atn[0]?"ATN":"atn")); |
| 734 | 694 | via_set_input_ca1 (machine, 2, !level); |
| 735 | 695 | #if 0 |
| 736 | | value=vc1541->drive.serial.data; |
| 737 | | if (vc1541->drive.serial.acka!=!level) value=0; |
| 696 | value=drive->drive.serial.data; |
| 697 | if (drive->drive.serial.acka!=!level) value=0; |
| 738 | 698 | if (value!=serial.data[2]) { |
| 739 | 699 | serial.data[2]=value; |
| 740 | 700 | if (serial.data[0]!=value) { |
| r3251 | r3252 | |
| 816 | 776 | { |
| 817 | 777 | } |
| 818 | 778 | |
| 779 | |
| 780 | /************************************** |
| 781 | |
| 782 | C1551 |
| 783 | |
| 784 | **************************************/ |
| 785 | |
| 819 | 786 | /* |
| 820 | 787 | c1551 irq line |
| 821 | 788 | only timing related??? (60 hz?), delivered from c16? |
| 822 | 789 | */ |
| 823 | | static TIMER_CALLBACK(c1551_timer) |
| 790 | static TIMER_CALLBACK(c1551_irq_timer) |
| 824 | 791 | { |
| 825 | | cpunum_set_input_line(machine, vc1541->cpunumber, M6502_IRQ_LINE, PULSE_LINE); |
| 792 | cpunum_set_input_line(machine, drive->cpunumber, M6502_IRQ_LINE, PULSE_LINE); |
| 826 | 793 | } |
| 827 | 794 | |
| 828 | 795 | /* |
| r3251 | r3252 | |
| 839 | 806 | static int old=0; |
| 840 | 807 | if (offset) { |
| 841 | 808 | DBG_LOG(1, "c1551 port",("write %.2x\n",data)); |
| 842 | | vc1541->drive.c1551.cpu_port=data; |
| 809 | drive->drive.c1551.cpu_port=data; |
| 843 | 810 | |
| 844 | 811 | if (data!=old) { |
| 845 | 812 | DBG_LOG(1, "vc1541 drive",("%.2x\n", data)); |
| 846 | 813 | if ((old&3)!=(data&3)) { |
| 847 | 814 | switch (old&3) { |
| 848 | 815 | case 0: |
| 849 | | if ((data&3)==1) vc1541->track+=0.5; |
| 850 | | else if ((data&3)==3) vc1541->track-=0.5; |
| 816 | if ((data&3)==1) drive->track+=0.5; |
| 817 | else if ((data&3)==3) drive->track-=0.5; |
| 851 | 818 | break; |
| 852 | 819 | case 1: |
| 853 | | if ((data&3)==2) vc1541->track+=0.5; |
| 854 | | else if ((data&3)==0) vc1541->track-=0.5; |
| 820 | if ((data&3)==2) drive->track+=0.5; |
| 821 | else if ((data&3)==0) drive->track-=0.5; |
| 855 | 822 | break; |
| 856 | 823 | case 2: |
| 857 | | if ((data&3)==3) vc1541->track+=0.5; |
| 858 | | else if ((data&3)==1) vc1541->track-=0.5; |
| 824 | if ((data&3)==3) drive->track+=0.5; |
| 825 | else if ((data&3)==1) drive->track-=0.5; |
| 859 | 826 | break; |
| 860 | 827 | case 3: |
| 861 | | if ((data&3)==0) vc1541->track+=0.5; |
| 862 | | else if ((data&3)==2) vc1541->track-=0.5; |
| 828 | if ((data&3)==0) drive->track+=0.5; |
| 829 | else if ((data&3)==2) drive->track-=0.5; |
| 863 | 830 | break; |
| 864 | 831 | } |
| 865 | | if (vc1541->track<1) vc1541->track=1.0; |
| 866 | | if (vc1541->track>35) vc1541->track=35; |
| 832 | if (drive->track<1) drive->track=1.0; |
| 833 | if (drive->track>35) drive->track=35; |
| 867 | 834 | } |
| 868 | | if ( (vc1541->motor!=(data&4))||(vc1541->frequency!=(data&0x60)) ) { |
| 835 | if ( (drive->motor!=(data&4))||(drive->frequency!=(data&0x60)) ) { |
| 869 | 836 | double tme; |
| 870 | | vc1541->motor = data & 4; |
| 871 | | vc1541->frequency = data & 0x60; |
| 872 | | tme=vc1541_times[vc1541->frequency>>5]*8*2; |
| 873 | | if (vc1541->motor) |
| 837 | drive->motor = data & 4; |
| 838 | drive->frequency = data & 0x60; |
| 839 | tme=drive_times[drive->frequency>>5]*8*2; |
| 840 | if (drive->motor) |
| 874 | 841 | { |
| 875 | | if (attotime_to_double(timer_timeelapsed(vc1541->timer)) > 1.0e29) |
| 876 | | timer_reset(vc1541->timer, attotime_never); |
| 842 | if (attotime_to_double(timer_timeelapsed(drive->timer)) > 1.0e29) |
| 843 | timer_reset(drive->timer, attotime_never); |
| 877 | 844 | else |
| 878 | | timer_adjust_periodic(vc1541->timer, attotime_zero, 0, double_to_attotime(tme)); |
| 845 | timer_adjust_periodic(drive->timer, attotime_zero, 0, double_to_attotime(tme)); |
| 879 | 846 | } |
| 880 | 847 | else |
| 881 | 848 | { |
| 882 | | timer_reset(vc1541->timer, attotime_never); |
| 849 | timer_reset(drive->timer, attotime_never); |
| 883 | 850 | } |
| 884 | 851 | } |
| 885 | 852 | old=data; |
| 886 | 853 | } |
| 887 | | vc1541->led = data & 8; |
| 854 | drive->led = data & 8; |
| 888 | 855 | } else { |
| 889 | | vc1541->drive.c1551.cpu_ddr=data; |
| 856 | drive->drive.c1551.cpu_ddr=data; |
| 890 | 857 | DBG_LOG(1, "c1551 ddr",("write %.2x\n",data)); |
| 891 | 858 | } |
| 892 | 859 | } |
| r3251 | r3252 | |
| 901 | 868 | if (WRITEPROTECTED) |
| 902 | 869 | data &= ~0x10; |
| 903 | 870 | #endif |
| 904 | | if (vc1541->head.ready) { |
| 871 | if (drive->head.ready) { |
| 905 | 872 | data|=0x80; |
| 906 | | vc1541->head.ready=0; |
| 873 | drive->head.ready=0; |
| 907 | 874 | } |
| 908 | | data&=~vc1541->drive.c1551.cpu_ddr; |
| 909 | | data|=vc1541->drive.c1551.cpu_ddr&vc1541->drive.c1551.cpu_port; |
| 875 | data&=~drive->drive.c1551.cpu_ddr; |
| 876 | data|=drive->drive.c1551.cpu_ddr&drive->drive.c1551.cpu_port; |
| 910 | 877 | DBG_LOG(3, "c1551 port",("read %.2x\n", data)); |
| 911 | 878 | } else { |
| 912 | | data=vc1541->drive.c1551.cpu_ddr; |
| 879 | data=drive->drive.c1551.cpu_ddr; |
| 913 | 880 | DBG_LOG(3, "c1551 ddr",("read %.2x\n", data)); |
| 914 | 881 | } |
| 915 | 882 | return data; |
| r3251 | r3252 | |
| 935 | 902 | { |
| 936 | 903 | int data=0xff; |
| 937 | 904 | data&=~0x20; |
| 938 | | if (vc1541->head.sync) data&=~0x40; |
| 905 | if (drive->head.sync) data&=~0x40; |
| 939 | 906 | return data; |
| 940 | 907 | } |
| 941 | 908 | |
| 942 | 909 | static int c1551_port_b_r (void) |
| 943 | 910 | { |
| 944 | | int data=vc1541->head.data[vc1541->d64.pos]; |
| 911 | int data=drive->head.data[drive->d64.pos]; |
| 945 | 912 | DBG_LOG(2, "c1551 drive",("port a read %.2x\n", data)); |
| 946 | 913 | return data; |
| 947 | 914 | } |
| 948 | 915 | |
| 949 | | int c1551_config (int id, int mode, C1551_CONFIG *config) |
| 950 | | { |
| 951 | | vc1541->cpunumber = config->cpunr; |
| 952 | | vc1541->type=TypeC1551; |
| 953 | | vc1541->timer = timer_alloc(vc1541_timer, NULL); |
| 954 | | tpi6525[0].c.read=c1551_port_c_r; |
| 955 | | tpi6525[0].b.read=c1551_port_b_r; |
| 956 | 916 | |
| 957 | | /* time should be small enough to allow quitting of the irq |
| 958 | | line before the next interrupt is triggered */ |
| 959 | | vc1541->drive.c1551.timer = timer_alloc(c1551_timer, NULL); |
| 960 | | timer_adjust_periodic(vc1541->drive.c1551.timer, attotime_zero, 0, ATTOTIME_IN_HZ(60)); |
| 961 | | return 0; |
| 962 | | } |
| 963 | | |
| 964 | | |
| 965 | 917 | static ADDRESS_MAP_START( c1551_map, ADDRESS_SPACE_PROGRAM, 8 ) |
| 966 | 918 | AM_RANGE(0x0000, 0x0001) AM_READWRITE(c1551_port_r, c1551_port_w) |
| 967 | 919 | AM_RANGE(0x0002, 0x07ff) AM_RAM |
| r3251 | r3252 | |
| 1051 | 1003 | return c1551x_read_status(Machine, tpi6525); |
| 1052 | 1004 | } |
| 1053 | 1005 | |
| 1006 | /************************************** |
| 1007 | |
| 1008 | Drive init & reset |
| 1009 | |
| 1010 | **************************************/ |
| 1011 | |
| 1012 | |
| 1013 | int drive_config (int type, int id, int mode, int cpunr, int devicenr) |
| 1014 | { |
| 1015 | drive->type = type; |
| 1016 | drive->cpunumber = cpunr; |
| 1017 | drive->drive.serial.deviceid = devicenr; |
| 1018 | drive->timer = timer_alloc(drive_timer, NULL); |
| 1019 | |
| 1020 | if ((drive->type == type_1541) || (drive->type == type_2031)) |
| 1021 | { |
| 1022 | via_config (2, &via2); |
| 1023 | via_config (3, &via3); |
| 1024 | } |
| 1025 | |
| 1026 | if (type == type_1551) |
| 1027 | { |
| 1028 | tpi6525[0].c.read=c1551_port_c_r; |
| 1029 | tpi6525[0].b.read=c1551_port_b_r; |
| 1030 | |
| 1031 | /* time should be small enough to allow quitting of the irq |
| 1032 | line before the next interrupt is triggered */ |
| 1033 | drive->drive.c1551.irq_timer = timer_alloc(c1551_irq_timer, NULL); |
| 1034 | timer_adjust_periodic(drive->drive.c1551.irq_timer, attotime_zero, 0, ATTOTIME_IN_HZ(60)); |
| 1035 | } |
| 1036 | |
| 1037 | return 0; |
| 1038 | } |
| 1039 | |
| 1040 | void drive_reset (void) |
| 1041 | { |
| 1042 | int i; |
| 1043 | |
| 1044 | if (drive->type == type_1541) |
| 1045 | { |
| 1046 | for (i = 0; i < sizeof (serial.atn) / sizeof (serial.atn[0]); i++) |
| 1047 | { |
| 1048 | serial.atn[i] = serial.data[i] = serial.clock[i] = 1; |
| 1049 | } |
| 1050 | } |
| 1051 | |
| 1052 | drive->track = 1.0; |
| 1053 | |
| 1054 | if ((drive->type == type_1541) || (drive->type == type_2031)) |
| 1055 | { |
| 1056 | via_reset (); |
| 1057 | } |
| 1058 | |
| 1059 | if ((drive->type == type_1551)) |
| 1060 | { |
| 1061 | tpi6525_0_reset(); |
| 1062 | } |
| 1063 | } |
| 1064 | |
| 1065 | /************************************** |
| 1066 | |
| 1067 | Machine drivers |
| 1068 | |
| 1069 | **************************************/ |
| 1070 | |
| 1054 | 1071 | MACHINE_DRIVER_START( cpu_vc1540 ) |
| 1055 | 1072 | MDRV_CPU_ADD("cpu_vc1540", M6502, 1000000) |
| 1056 | 1073 | MDRV_CPU_PROGRAM_MAP(vc1541_map, 0) |
| r3251 | r3252 | |
| 1078 | 1095 | MDRV_IMPORT_FROM(cpu_vc1541) |
| 1079 | 1096 | MACHINE_DRIVER_END |
| 1080 | 1097 | |
| 1098 | /************************************** |
| 1081 | 1099 | |
| 1100 | Device configurations |
| 1101 | |
| 1102 | **************************************/ |
| 1103 | |
| 1104 | DEVICE_IMAGE_LOAD(vc1541) |
| 1105 | { |
| 1106 | drive->d64.data = image_ptr(image); |
| 1107 | if (!drive->d64.data) |
| 1108 | return INIT_FAIL; |
| 1109 | |
| 1110 | logerror("floppy image %s loaded\n", image_filename(image)); |
| 1111 | |
| 1112 | return INIT_PASS; |
| 1113 | } |
| 1114 | |
| 1115 | DEVICE_IMAGE_UNLOAD(vc1541) |
| 1116 | { |
| 1117 | /* writeback of image data */ |
| 1118 | drive->d64.data = NULL; |
| 1119 | } |
| 1120 | |
| 1082 | 1121 | void vc1541_device_getinfo(const mess_device_class *devclass, UINT32 state, union devinfo *info) |
| 1083 | 1122 | { |
| 1084 | 1123 | switch(state) |
| 1085 | 1124 | { |
| 1086 | 1125 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 1087 | 1126 | case MESS_DEVINFO_INT_TYPE: info->i = IO_FLOPPY; break; |
| 1088 | | case MESS_DEVINFO_INT_COUNT: info->i = 1; break; |
| 1127 | case MESS_DEVINFO_INT_COUNT: info->i = 1; break; |
| 1089 | 1128 | case MESS_DEVINFO_INT_READABLE: info->i = 1; break; |
| 1090 | | case MESS_DEVINFO_INT_WRITEABLE: info->i = 0; break; |
| 1091 | | case MESS_DEVINFO_INT_CREATABLE: info->i = 0; break; |
| 1092 | | case MESS_DEVINFO_INT_RESET_ON_LOAD: info->i = 1; break; |
| 1129 | case MESS_DEVINFO_INT_WRITEABLE: info->i = 0; break; |
| 1130 | case MESS_DEVINFO_INT_CREATABLE: info->i = 0; break; |
| 1131 | case MESS_DEVINFO_INT_RESET_ON_LOAD: info->i = 1; break; |
| 1093 | 1132 | |
| 1094 | 1133 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 1095 | 1134 | case MESS_DEVINFO_PTR_LOAD: info->load = DEVICE_IMAGE_LOAD_NAME(vc1541); break; |
| 1096 | 1135 | case MESS_DEVINFO_PTR_UNLOAD: info->unload = DEVICE_IMAGE_UNLOAD_NAME(vc1541); break; |
| 1097 | | case DEVINFO_PTR_VC1541_CONFIG: info->f = (genf *) vc1541_config; break; |
| 1136 | case MESS_DEVINFO_PTR_DEV_SPECIFIC: info->f = (genf *) drive_config; break; |
| 1098 | 1137 | |
| 1099 | 1138 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1100 | 1139 | case MESS_DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "d64"); break; |
| r3251 | r3252 | |
| 1115 | 1154 | switch(state) |
| 1116 | 1155 | { |
| 1117 | 1156 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 1118 | | case DEVINFO_PTR_VC1541_CONFIG: info->f = (genf *) c1551_config; break; |
| 1157 | case MESS_DEVINFO_PTR_DEV_SPECIFIC: info->f = (genf *) drive_config; break; |
| 1119 | 1158 | |
| 1120 | 1159 | default: vc1541_device_getinfo(devclass, state, info); break; |
| 1121 | 1160 | } |