src/lib/formats/ap2_dsk.c
| r14973 | r14974 | |
| 1 | 1 | /********************************************************************* |
| 2 | 2 | |
| 3 | | ap2_dsk.c |
| 3 | ap2_dsk.c |
| 4 | 4 | |
| 5 | | Apple II disk images |
| 5 | Apple II disk images |
| 6 | 6 | |
| 7 | 7 | *********************************************************************/ |
| 8 | 8 | |
| r14973 | r14974 | |
| 511 | 511 | SECTOR_LENGTH([256]) |
| 512 | 512 | FIRST_SECTOR_ID([0])) |
| 513 | 513 | LEGACY_FLOPPY_OPTIONS_END |
| 514 | |
| 515 | /*************************************************************************** |
| 516 | |
| 517 | New implementation |
| 518 | |
| 519 | **************************************************************************** |
| 520 | |
| 521 | Copyright Olivier Galibert, Lord Nightmare and Balrog |
| 522 | All rights reserved. |
| 523 | |
| 524 | Redistribution and use in source and binary forms, with or without |
| 525 | modification, are permitted provided that the following conditions are |
| 526 | met: |
| 527 | |
| 528 | * Redistributions of source code must retain the above copyright |
| 529 | notice, this list of conditions and the following disclaimer. |
| 530 | * Redistributions in binary form must reproduce the above copyright |
| 531 | notice, this list of conditions and the following disclaimer in |
| 532 | the documentation and/or other materials provided with the |
| 533 | distribution. |
| 534 | * Neither the name 'MAME' nor the names of its contributors may be |
| 535 | used to endorse or promote products derived from this software |
| 536 | without specific prior written permission. |
| 537 | |
| 538 | THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR |
| 539 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 540 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 541 | DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, |
| 542 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 543 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 544 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 545 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 546 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| 547 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 548 | POSSIBILITY OF SUCH DAMAGE. |
| 549 | |
| 550 | ****************************************************************************/ |
| 551 | |
| 552 | |
| 553 | a2_16sect_format::a2_16sect_format() : floppy_image_format_t() |
| 554 | { |
| 555 | } |
| 556 | |
| 557 | const char *a2_16sect_format::name() const |
| 558 | { |
| 559 | return "a2_16sect"; |
| 560 | } |
| 561 | |
| 562 | const char *a2_16sect_format::description() const |
| 563 | { |
| 564 | return "Apple II 16-sector dsk image"; |
| 565 | } |
| 566 | |
| 567 | const char *a2_16sect_format::extensions() const |
| 568 | { |
| 569 | return "dsk"; |
| 570 | } |
| 571 | |
| 572 | bool a2_16sect_format::supports_save() const |
| 573 | { |
| 574 | return true; |
| 575 | } |
| 576 | |
| 577 | int a2_16sect_format::identify(io_generic *io, UINT32 form_factor) |
| 578 | { |
| 579 | int size = io_generic_size(io); |
| 580 | int expected_size = 35 * 16 * 256; |
| 581 | return size == expected_size; |
| 582 | } |
| 583 | |
| 584 | const floppy_image_format_t::desc_e a2_16sect_format::mac_gcr[] = { |
| 585 | { SECTOR_LOOP_START, 0, -1 }, |
| 586 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 587 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 588 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 589 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 590 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 591 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 592 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 593 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 594 | { RAWBITS, 0xd5aa96, 24 }, |
| 595 | { CRC_MACHEAD_START, 0 }, |
| 596 | { TRACK_ID_GCR6 }, |
| 597 | { SECTOR_ID_GCR6 }, |
| 598 | { TRACK_HEAD_ID_GCR6 }, |
| 599 | { SECTOR_INFO_GCR6 }, |
| 600 | { CRC_END, 0 }, |
| 601 | { CRC, 0 }, |
| 602 | { RAWBITS, 0xdeaaff, 24 }, |
| 603 | { RAWBITS, 0xff3fcf, 24 }, { RAWBITS, 0xf3fcff, 24 }, |
| 604 | { RAWBITS, 0xd5aaad, 24 }, |
| 605 | { SECTOR_ID_GCR6 }, |
| 606 | { SECTOR_DATA_MAC, -1 }, |
| 607 | { RAWBITS, 0xdeaaff, 24 }, |
| 608 | { RAWBITS, 0xff, 8 }, |
| 609 | { SECTOR_LOOP_END }, |
| 610 | { END }, |
| 611 | }; |
| 612 | |
| 613 | |
| 614 | bool a2_16sect_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 615 | { |
| 616 | |
| 617 | UINT8 sector_data[(256)*16]; |
| 618 | memset(sector_data, 0, sizeof(sector_data)); |
| 619 | |
| 620 | desc_s sectors[16]; |
| 621 | int format = 0; |
| 622 | int pos_data = 0; |
| 623 | |
| 624 | int head_count = 1; |
| 625 | |
| 626 | for(int track=0; track < 35; track++) { |
| 627 | for(int head=0; head < head_count; head++) { |
| 628 | for(int si=0; si<16; si++) { |
| 629 | UINT8 *data = sector_data + (256)*si; |
| 630 | sectors[si].data = data; |
| 631 | sectors[si].size = 256; |
| 632 | sectors[si].sector_id = si; |
| 633 | sectors[si].sector_info = format; |
| 634 | io_generic_read(io, data, pos_data, 256); |
| 635 | pos_data += 256; |
| 636 | } |
| 637 | generate_track(mac_gcr, track, head, sectors, 16, 3104*16, image); |
| 638 | } |
| 639 | } |
| 640 | return true; |
| 641 | } |
| 642 | |
| 643 | UINT8 a2_16sect_format::gb(const UINT8 *buf, int ts, int &pos, int &wrap) |
| 644 | { |
| 645 | UINT8 v = 0; |
| 646 | int w1 = wrap; |
| 647 | while(wrap != w1+2 && !(v & 0x80)) { |
| 648 | v = v << 1 | ((buf[pos >> 3] >> (7-(pos & 7))) & 1); |
| 649 | pos++; |
| 650 | if(pos == ts) { |
| 651 | pos = 0; |
| 652 | wrap++; |
| 653 | } |
| 654 | } |
| 655 | return v; |
| 656 | } |
| 657 | |
| 658 | void a2_16sect_format::update_chk(const UINT8 *data, int size, UINT32 &chk) |
| 659 | { |
| 660 | } |
| 661 | |
| 662 | bool a2_16sect_format::save(io_generic *io, floppy_image *image) |
| 663 | { |
| 664 | int g_tracks, g_heads; |
| 665 | int visualgrid[16][35]; // visualizer grid, cleared/initialized below |
| 666 | #define NOTFOUND 0 |
| 667 | #define ADDRFOUND 1 |
| 668 | #define ADDRGOOD 2 |
| 669 | #define DATAFOUND 4 |
| 670 | #define DATAGOOD 8 |
| 671 | #define DATAPOST 16 |
| 672 | for (int i = 0; i < 16; i++) { |
| 673 | for (int j = 0; j < 35; j++) { |
| 674 | visualgrid[i][j] = 0; |
| 675 | } |
| 676 | } |
| 677 | image->get_actual_geometry(g_tracks, g_heads); |
| 678 | |
| 679 | int head = 0; |
| 680 | |
| 681 | int pos_data = 0; |
| 682 | |
| 683 | for(int track=0; track < 70; track+=2) { |
| 684 | UINT8 sectdata[(256)*16]; |
| 685 | memset(sectdata, 0, sizeof(sectdata)); |
| 686 | int nsect = 16; |
| 687 | UINT8 buf[130000]; // originally 13000, multiread dfi disks need larger |
| 688 | int ts; |
| 689 | fprintf(stderr,"DEBUG: a2_16sect_format::save() about to generate bitstream from physical track %d (logical %d)...", track, track/2); |
| 690 | generate_bitstream_from_track(track, head, 200000000/(1552*nsect*6), buf, ts, image); // 3104 needs tweaking, *3 is 3x multiread from a dfi disk |
| 691 | fprintf(stderr,"done.\n"); |
| 692 | int pos = 0; |
| 693 | int wrap = 0; |
| 694 | int hb = 0; |
| 695 | for(;;) { |
| 696 | UINT8 v = gb(buf, ts, pos, wrap); |
| 697 | if(v == 0xff) |
| 698 | hb = 1; |
| 699 | else if(hb == 1 && v == 0xd5) |
| 700 | hb = 2; |
| 701 | else if(hb == 2 && v == 0xaa) |
| 702 | hb = 3; |
| 703 | else if(hb == 3 && v == 0x96) |
| 704 | hb = 4; |
| 705 | else |
| 706 | hb = 0; |
| 707 | |
| 708 | if(hb == 4) { |
| 709 | UINT8 h[11]; |
| 710 | for(int i=0; i<11; i++) |
| 711 | h[i] = gb(buf, ts, pos, wrap); |
| 712 | //UINT8 v2 = gcr6bw_tb[h[2]]; |
| 713 | UINT8 vl = gcr4_decode(h[0],h[1]); |
| 714 | UINT8 tr = gcr4_decode(h[2],h[3]); |
| 715 | UINT8 se = gcr4_decode(h[4],h[5]); |
| 716 | UINT8 chk = gcr4_decode(h[6],h[7]); |
| 717 | UINT32 post = (h[8]<<16)|(h[9]<<8)|h[10]; |
| 718 | printf("Address Mark:\tVolume %d, Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s\n", vl, tr, se, chk, (chk ^ vl ^ tr ^ se)==0?"OK":"BAD", post, (post&0xFFFF00)==0xDEAA00?"OK":"BAD"); |
| 719 | if (tr == track/2 && se < nsect) { |
| 720 | visualgrid[se][track/2] |= ADDRFOUND; |
| 721 | visualgrid[se][track/2] |= (chk ^ vl ^ tr ^ se)==0?ADDRGOOD:0; |
| 722 | int opos = pos; |
| 723 | int owrap = wrap; |
| 724 | hb = 0; |
| 725 | for(int i=0; i<20 && hb != 4; i++) { |
| 726 | v = gb(buf, ts, pos, wrap); |
| 727 | if(v == 0xff) |
| 728 | hb = 1; |
| 729 | else if(hb == 1 && v == 0xd5) |
| 730 | hb = 2; |
| 731 | else if(hb == 2 && v == 0xaa) |
| 732 | hb = 3; |
| 733 | else if(hb == 3 && v == 0xad) |
| 734 | hb = 4; |
| 735 | else |
| 736 | hb = 0; |
| 737 | } |
| 738 | if(hb == 4) { |
| 739 | visualgrid[se][track/2] |= DATAFOUND; |
| 740 | UINT8 *dest = sectdata+(256)*se; |
| 741 | UINT8 data[0x157]; |
| 742 | UINT32 dpost = 0; |
| 743 | UINT8 c = 0; |
| 744 | // first read in sector and decode to 6bit form |
| 745 | for(int i=0; i<0x156; i++) { |
| 746 | data[i] = gcr6bw_tb[gb(buf, ts, pos, wrap)] ^ c; |
| 747 | c = data[i]; |
| 748 | // printf("%02x ", c); |
| 749 | // if (((i&0xf)+1)==0x10) printf("\n"); |
| 750 | } |
| 751 | // read the checksum byte |
| 752 | data[0x156] = gcr6bw_tb[gb(buf,ts,pos,wrap)]; |
| 753 | // now read the postamble bytes |
| 754 | for(int i=0; i<3; i++) { |
| 755 | dpost <<= 8; |
| 756 | dpost |= gb(buf, ts, pos, wrap); |
| 757 | } |
| 758 | // next combine in the upper 2 bits of each byte |
| 759 | UINT8 bit_swap[4] = { 0, 2, 1, 3 }; |
| 760 | for(int i=0; i<0x56; i++) |
| 761 | data[i+0x056] = data[i+0x056]<<2 | bit_swap[data[i]&3]; |
| 762 | for(int i=0; i<0x56; i++) |
| 763 | data[i+0x0ac] = data[i+0x0ac]<<2 | bit_swap[(data[i]>>2)&3]; |
| 764 | for(int i=0; i<0x54; i++) |
| 765 | data[i+0x102] = data[i+0x102]<<2 | bit_swap[(data[i]>>4)&3]; |
| 766 | // now decode it into 256 bytes |
| 767 | // but only write it if the bitfield of the track shows datagood is NOT set. |
| 768 | // if it is set we don't want to overwrite a guaranteed good read with a bad one |
| 769 | if ((visualgrid[se][track/2]&DATAGOOD)==0) { |
| 770 | // TODO: |
| 771 | // if the current read is good but the postamble isn't, write it in. |
| 772 | // if the current read isn't good but the postamble is, its better than nothing. |
| 773 | // if the current read isn't good and neither is the postamble but nothing better |
| 774 | // has been written before, write it anyway. |
| 775 | for(int i=0x56; i<0x156; i++) { |
| 776 | UINT8 dv = data[i]; |
| 777 | *dest++ = dv; |
| 778 | } |
| 779 | } |
| 780 | // do some checking |
| 781 | if ((data[0x156] != c) || (dpost&0xFFFF00)!=0xDEAA00) { |
| 782 | printf("Data Mark:\tChecksum xpctd %d found %d: %s, Postamble %03X: %s\n", data[0x156], c, (data[0x156]==c)?"OK":"BAD", dpost, (dpost&0xFFFF00)==0xDEAA00?"OK":"BAD"); |
| 783 | } |
| 784 | else visualgrid[se][track/2] |= DATAGOOD; |
| 785 | } else { |
| 786 | pos = opos; |
| 787 | wrap = owrap; |
| 788 | } |
| 789 | } |
| 790 | hb = 0; |
| 791 | } |
| 792 | if(wrap) |
| 793 | break; |
| 794 | } |
| 795 | for(int i=0; i<nsect; i++) { |
| 796 | //if(nsect>0) printf("t%d,", track); |
| 797 | UINT8 *data = sectdata + (256)*i; |
| 798 | io_generic_write(io, data, pos_data, 256); |
| 799 | pos_data += 256; |
| 800 | } |
| 801 | //printf("\n"); |
| 802 | } |
| 803 | // display a little table of which sectors decoded ok |
| 804 | for (int j = 0; j < 35; j++) { |
| 805 | printf("T%2d: ",j); |
| 806 | for (int i = 0; i < 16; i++) { |
| 807 | if (visualgrid[i][j] == NOTFOUND) printf("-NF-"); |
| 808 | else { |
| 809 | if (visualgrid[i][j] & ADDRFOUND) printf("a"); else printf(" "); |
| 810 | if (visualgrid[i][j] & ADDRGOOD) printf("A"); else printf(" "); |
| 811 | if (visualgrid[i][j] & DATAFOUND) printf("d"); else printf(" "); |
| 812 | if (visualgrid[i][j] & DATAGOOD) printf("D"); else printf(" "); |
| 813 | } |
| 814 | printf(" "); |
| 815 | } |
| 816 | printf("\n"); |
| 817 | } |
| 818 | |
| 819 | return true; |
| 820 | } |
| 821 | |
| 822 | const floppy_format_type FLOPPY_A216S_FORMAT = &floppy_image_format_creator<a2_16sect_format>; |
| | No newline at end of file |