ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/IEC.cpp
(Generate patch)

Comparing Frodo4/Src/IEC.cpp (file contents):
Revision 1.1 by cebix, 2003-07-01T17:09:43Z vs.
Revision 1.4 by cebix, 2004-01-11T14:03:29Z

# Line 1 | Line 1
1   /*
2   *  IEC.cpp - IEC bus routines, 1541 emulation (DOS level)
3   *
4 < *  Frodo (C) 1994-1997,2002 Christian Bauer
4 > *  Frodo (C) 1994-1997,2002-2003 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 210 | Line 210 | uint8 IEC::OutSec(uint8 byte)
210   *  Read one byte
211   */
212  
213 < uint8 IEC::In(uint8 *byte)
213 > uint8 IEC::In(uint8 &byte)
214   {
215          if (talker_active && (received_cmd == CMD_DATA))
216                  return data_in(byte);
217  
218 <        *byte = 0;
218 >        byte = 0;
219          return ST_TIMEOUT;
220   }
221  
# Line 367 | Line 367 | uint8 IEC::open_out(uint8 byte, bool eoi
367                  *name_ptr = 0;                          // End string
368                  listener->LED = DRVLED_ON;      // Turn on drive LED
369                  UpdateLEDs();
370 <                return listener->Open(sec_addr, name_buf);
370 >                return listener->Open(sec_addr, name_buf, name_len);
371          }
372  
373          return ST_OK;
# Line 388 | Line 388 | uint8 IEC::data_out(uint8 byte, bool eoi
388   *  Read byte from channel
389   */
390  
391 < uint8 IEC::data_in(uint8 *byte)
391 > uint8 IEC::data_in(uint8 &byte)
392   {
393          return talker->Read(sec_addr, byte);
394   }
# Line 412 | Line 412 | Drive::Drive(IEC *iec)
412   */
413  
414   // 1541 error messages
415 < char *Errors_1541[] = {
416 <        "00, OK,00,00\r",
417 <        "25,WRITE ERROR,00,00\r",
418 <        "26,WRITE PROTECT ON,00,00\r",
419 <        "30,SYNTAX ERROR,00,00\r",
420 <        "33,SYNTAX ERROR,00,00\r",
421 <        "60,WRITE FILE OPEN,00,00\r",
422 <        "61,FILE NOT OPEN,00,00\r",
423 <        "62,FILE NOT FOUND,00,00\r",
424 <        "67,ILLEGAL TRACK OR SECTOR,00,00\r",
425 <        "70,NO CHANNEL,00,00\r",
426 <        "73,CBM DOS V2.6 1541,00,00\r",
427 <        "74,DRIVE NOT READY,00,00\r"
415 > static const char *Errors_1541[] = {
416 >        "00, OK,%02d,%02d\x0d",
417 >        "01, FILES SCRATCHED,%02d,%02d\x0d",
418 >        "03, UNIMPLEMENTED,%02d,%02d\x0d",
419 >        "20, READ ERROR,%02d,%02d\x0d",
420 >        "21, READ ERROR,%02d,%02d\x0d",
421 >        "22, READ ERROR,%02d,%02d\x0d",
422 >        "23, READ ERROR,%02d,%02d\x0d",
423 >        "24, READ ERROR,%02d,%02d\x0d",
424 >        "25, WRITE ERROR,%02d,%02d\x0d",
425 >        "26, WRITE PROTECT ON,%02d,%02d\x0d",
426 >        "27, READ ERROR,%02d,%02d\x0d",
427 >        "28, WRITE ERROR,%02d,%02d\x0d",
428 >        "29, DISK ID MISMATCH,%02d,%02d\x0d",
429 >        "30, SYNTAX ERROR,%02d,%02d\x0d",
430 >        "31, SYNTAX ERROR,%02d,%02d\x0d",
431 >        "32, SYNTAX ERROR,%02d,%02d\x0d",
432 >        "33, SYNTAX ERROR,%02d,%02d\x0d",
433 >        "34, SYNTAX ERROR,%02d,%02d\x0d",
434 >        "60, WRITE FILE OPEN,%02d,%02d\x0d",
435 >        "61, FILE NOT OPEN,%02d,%02d\x0d",
436 >        "62, FILE NOT FOUND,%02d,%02d\x0d",
437 >        "63, FILE EXISTS,%02d,%02d\x0d",
438 >        "64, FILE TYPE MISMATCH,%02d,%02d\x0d",
439 >        "65, NO BLOCK,%02d,%02d\x0d",
440 >        "66, ILLEGAL TRACK OR SECTOR,%02d,%02d\x0d",
441 >        "70, NO CHANNEL,%02d,%02d\x0d",
442 >        "71, DIR ERROR,%02d,%02d\x0d",
443 >        "72, DISK FULL,%02d,%02d\x0d",
444 >        "73, CBM DOS V2.6 1541,%02d,%02d\x0d",
445 >        "74, DRIVE NOT READY,%02d,%02d\x0d"
446   };
447  
448 < void Drive::set_error(int error)
448 > void Drive::set_error(int error, int track, int sector)
449   {
450 <        error_ptr = Errors_1541[error];
451 <        error_len = strlen(error_ptr);
450 >        // Write error message to buffer
451 >        sprintf(error_buf, Errors_1541[error], track, sector);
452 >        error_ptr = error_buf;
453 >        error_len = strlen(error_buf);
454 >        current_error = error;
455  
456          // Set drive condition
457 <        if (error != ERR_OK)
457 >        if (error != ERR_OK && error != ERR_SCRATCHED)
458                  if (error == ERR_STARTUP)
459                          LED = DRVLED_OFF;
460                  else
# Line 442 | Line 463 | void Drive::set_error(int error)
463                  LED = DRVLED_OFF;
464          the_iec->UpdateLEDs();
465   }
466 +
467 +
468 + /*
469 + *  Parse file name, determine access mode and file type
470 + */
471 +
472 + void Drive::parse_file_name(const uint8 *src, int src_len, uint8 *dest, int &dest_len, int &mode, int &type, int &rec_len, bool convert_charset)
473 + {
474 +        // If the string contains a ':', the file name starts after that
475 +        const uint8 *p = (const uint8 *)memchr(src, ':', src_len);
476 +        if (p) {
477 +                p++;
478 +                src_len -= p - src;
479 +        } else
480 +                p = src;
481 +
482 +        // Transfer file name upto ','
483 +        dest_len = 0;
484 +        uint8 *q = dest;
485 +        while (*p != ',' && src_len-- > 0) {
486 +                if (convert_charset)
487 +                        *q++ = petscii2ascii(*p++);
488 +                else
489 +                        *q++ = *p++;
490 +                dest_len++;
491 +        }
492 +        *q++ = 0;
493 +
494 +        // Strip trailing CRs
495 +        while (dest_len > 0 && dest[dest_len - 1] == 0x0d)
496 +                dest[--dest_len] = 0;
497 +
498 +        // Look for mode and type parameters separated by ','
499 +        p++; src_len--;
500 +        while (src_len > 0) {
501 +                switch (*p) {
502 +                        case 'D':
503 +                                type = FTYPE_DEL;
504 +                                break;
505 +                        case 'S':
506 +                                type = FTYPE_SEQ;
507 +                                break;
508 +                        case 'P':
509 +                                type = FTYPE_PRG;
510 +                                break;
511 +                        case 'U':
512 +                                type = FTYPE_USR;
513 +                                break;
514 +                        case 'L':
515 +                                type = FTYPE_REL;
516 +                                while (*p != ',' && src_len-- > 0) p++;
517 +                                p++; src_len--;
518 +                                rec_len = *p++; src_len--;
519 +                                if (src_len < 0)
520 +                                        rec_len = 0;
521 +                                break;
522 +                        case 'R':
523 +                                mode = FMODE_READ;
524 +                                break;
525 +                        case 'W':
526 +                                mode = FMODE_WRITE;
527 +                                break;
528 +                        case 'A':
529 +                                mode = FMODE_APPEND;
530 +                                break;
531 +                        case 'M':
532 +                                mode = FMODE_M;
533 +                                break;
534 +                }
535 +
536 +                // Skip to ','
537 +                while (*p != ',' && src_len-- > 0) p++;
538 +                p++; src_len--;
539 +        }
540 + }
541 +
542 +
543 + /*
544 + *  Execute DOS command (parse command and call appropriate routine)
545 + */
546 +
547 + static void parse_block_cmd_args(const uint8 *p, int &arg1, int &arg2, int &arg3, int &arg4)
548 + {
549 +        arg1 = arg2 = arg3 = arg4 = 0;
550 +
551 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
552 +        while (*p >= '0' && *p < '@')
553 +                arg1 = arg1 * 10 + (*p++ & 0x0f);
554 +
555 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
556 +        while (*p >= '0' && *p < '@')
557 +                arg2 = arg2 * 10 + (*p++ & 0x0f);
558 +
559 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
560 +        while (*p >= '0' && *p < '@')
561 +                arg3 = arg3 * 10 + (*p++ & 0x0f);
562 +
563 +        while (*p == ' ' || *p == 0x1d || *p == ',') p++;
564 +        while (*p >= '0' && *p < '@')
565 +                arg4 = arg4 * 10 + (*p++ & 0x0f);
566 + }
567 +
568 + void Drive::execute_cmd(const uint8 *cmd, int cmd_len)
569 + {
570 +        // Strip trailing CRs
571 +        while (cmd_len > 0 && cmd[cmd_len - 1] == 0x0d)
572 +                cmd_len--;
573 +
574 +        // Find token delimiters
575 +        const uint8 *colon = (const uint8 *)memchr(cmd, ':', cmd_len);
576 +        const uint8 *equal = colon ? (const uint8 *)memchr(colon, '=', cmd_len - (colon - cmd)) : NULL;
577 +        const uint8 *comma = (const uint8 *)memchr(cmd, ',', cmd_len);
578 +        const uint8 *minus = (const uint8 *)memchr(cmd, '-', cmd_len);
579 +
580 +        // Parse command name
581 +        set_error(ERR_OK);
582 +        switch (cmd[0]) {
583 +                case 'B':       // Block/buffer
584 +                        if (!minus)
585 +                                set_error(ERR_SYNTAX31);
586 +                        else {
587 +                                // Parse arguments (up to 4 decimal numbers separated by
588 +                                // space, cursor right or comma)
589 +                                const uint8 *p = colon ? colon + 1 : cmd + 3;
590 +                                int arg1, arg2, arg3, arg4;
591 +                                parse_block_cmd_args(p, arg1, arg2, arg3, arg4);
592 +
593 +                                // Switch on command
594 +                                switch (minus[1]) {
595 +                                        case 'R':
596 +                                                block_read_cmd(arg1, arg3, arg4);
597 +                                                break;
598 +                                        case 'W':
599 +                                                block_write_cmd(arg1, arg3, arg4);
600 +                                                break;
601 +                                        case 'E':
602 +                                                block_execute_cmd(arg1, arg3, arg4);
603 +                                                break;
604 +                                        case 'A':
605 +                                                block_allocate_cmd(arg2, arg3);
606 +                                                break;
607 +                                        case 'F':
608 +                                                block_free_cmd(arg2, arg3);
609 +                                                break;
610 +                                        case 'P':
611 +                                                buffer_pointer_cmd(arg1, arg2);
612 +                                                break;
613 +                                        default:
614 +                                                set_error(ERR_SYNTAX31);
615 +                                                break;
616 +                                }
617 +                        }
618 +                        break;
619 +
620 +                case 'M':       // Memory
621 +                        if (cmd[1] != '-')
622 +                                set_error(ERR_SYNTAX31);
623 +                        else {
624 +                                // Read parameters
625 +                                uint16 adr = uint8(cmd[3]) | (uint8(cmd[4]) << 8);
626 +                                uint8 len = uint8(cmd[5]);
627 +
628 +                                // Switch on command
629 +                                switch (cmd[2]) {
630 +                                        case 'R':
631 +                                                mem_read_cmd(adr, (cmd_len < 6) ? 1 : len);
632 +                                                break;
633 +                                        case 'W':
634 +                                                mem_write_cmd(adr, len, (uint8 *)cmd + 6);
635 +                                                break;
636 +                                        case 'E':
637 +                                                mem_execute_cmd(adr);
638 +                                                break;
639 +                                        default:
640 +                                                set_error(ERR_SYNTAX31);
641 +                                                break;
642 +                                }
643 +                        }
644 +                        break;
645 +
646 +                case 'C':       // Copy
647 +                        if (!colon)
648 +                                set_error(ERR_SYNTAX31);
649 +                        else if (!equal || memchr(cmd, '*', cmd_len) || memchr(cmd, '?', cmd_len) || (comma && comma < equal))
650 +                                set_error(ERR_SYNTAX30);
651 +                        else
652 +                                copy_cmd(colon + 1, equal - colon - 1, equal + 1, cmd_len - (equal + 1 - cmd));
653 +                        break;
654 +
655 +                case 'R':       // Rename
656 +                        if (!colon)
657 +                                set_error(ERR_SYNTAX34);
658 +                        else if (!equal || comma || memchr(cmd, '*', cmd_len) || memchr(cmd, '?', cmd_len))
659 +                                set_error(ERR_SYNTAX30);
660 +                        else
661 +                                rename_cmd(colon + 1, equal - colon - 1, equal + 1, cmd_len - (equal + 1 - cmd));
662 +                        break;
663 +
664 +                case 'S':       // Scratch
665 +                        if (!colon)
666 +                                set_error(ERR_SYNTAX34);
667 +                        else
668 +                                scratch_cmd(colon + 1, cmd_len - (colon + 1 - cmd));
669 +                        break;
670 +
671 +                case 'P':       // Position
672 +                        position_cmd(cmd + 1, cmd_len - 1);
673 +                        break;
674 +
675 +                case 'I':       // Initialize
676 +                        initialize_cmd();
677 +                        break;
678 +
679 +                case 'N':       // New (format)
680 +                        if (!colon)
681 +                                set_error(ERR_SYNTAX34);
682 +                        else
683 +                                new_cmd(colon + 1, comma ? (comma - colon - 1) : cmd_len - (colon + 1 - cmd), comma);
684 +                        break;
685 +
686 +                case 'V':       // Validate
687 +                        validate_cmd();
688 +                        break;
689 +
690 +                case 'U':       // User
691 +                        if (cmd[1] == '0')
692 +                                break;
693 +                        switch (cmd[1] & 0x0f) {
694 +                                case 1: {       // U1/UA: Read block
695 +                                        const uint8 *p = colon ? colon + 1 : cmd + 2;
696 +                                        int arg1, arg2, arg3, arg4;
697 +                                        parse_block_cmd_args(p, arg1, arg2, arg3, arg4);
698 +                                        block_read_cmd(arg1, arg3, arg4, true);
699 +                                        break;
700 +                                }
701 +                                case 2: {       // U2/UB: Write block
702 +                                        const uint8 *p = colon ? colon + 1 : cmd + 2;
703 +                                        int arg1, arg2, arg3, arg4;
704 +                                        parse_block_cmd_args(p, arg1, arg2, arg3, arg4);
705 +                                        block_write_cmd(arg1, arg3, arg4, true);
706 +                                        break;
707 +                                }
708 +                                case 9:         // U9/UI: C64/VC20 mode switch
709 +                                        if (cmd[2] != '+' && cmd[2] != '-')
710 +                                                Reset();
711 +                                        break;
712 +                                case 10:        // U:/UJ: Reset
713 +                                        Reset();
714 +                                        break;
715 +                                default:
716 +                                        set_error(ERR_UNIMPLEMENTED);
717 +                                        break;
718 +                        }
719 +                        break;
720 +
721 +                default:
722 +                        set_error(ERR_SYNTAX31);
723 +                        break;
724 +        }
725 + }
726 +
727 + // BLOCK-READ:channel,0,track,sector
728 + void Drive::block_read_cmd(int channel, int track, int sector, bool user_cmd)
729 + {
730 +        set_error(ERR_UNIMPLEMENTED);
731 + }
732 +
733 + // BLOCK-WRITE:channel,0,track,sector
734 + void Drive::block_write_cmd(int channel, int track, int sector, bool user_cmd)
735 + {
736 +        set_error(ERR_UNIMPLEMENTED);
737 + }
738 +
739 + // BLOCK-EXECUTE:channel,0,track,sector
740 + void Drive::block_execute_cmd(int channel, int track, int sector)
741 + {
742 +        set_error(ERR_UNIMPLEMENTED);
743 + }
744 +
745 + // BLOCK-ALLOCATE:0,track,sector
746 + void Drive::block_allocate_cmd(int track, int sector)
747 + {
748 +        set_error(ERR_UNIMPLEMENTED);
749 + }
750 +
751 + // BLOCK-FREE:0,track,sector
752 + void Drive::block_free_cmd(int track, int sector)
753 + {
754 +        set_error(ERR_UNIMPLEMENTED);
755 + }
756 +
757 + // BUFFER-POINTER:channel,pos
758 + void Drive::buffer_pointer_cmd(int channel, int pos)
759 + {
760 +        set_error(ERR_UNIMPLEMENTED);
761 + }
762 +
763 + // M-R<adr low><adr high>[<number>]
764 + void Drive::mem_read_cmd(uint16 adr, uint8 len)
765 + {
766 +        unsupp_cmd();
767 +        error_ptr = error_buf;
768 +        error_buf[0] = 0;
769 +        error_len = 0;
770 +        set_error(ERR_OK);
771 + }
772 +
773 + // M-W<adr low><adr high><number><data...>
774 + void Drive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p)
775 + {
776 +        set_error(ERR_UNIMPLEMENTED);
777 + }
778 +
779 + // M-E<adr low><adr high>
780 + void Drive::mem_execute_cmd(uint16 adr)
781 + {
782 +        set_error(ERR_UNIMPLEMENTED);
783 + }
784 +
785 + //   COPY:new=file1,file2,...
786 + //        ^   ^
787 + // new_file   old_files
788 + void Drive::copy_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_files, int old_files_len)
789 + {
790 +        set_error(ERR_UNIMPLEMENTED);
791 + }
792 +
793 + // RENAME:new=old
794 + //        ^   ^
795 + // new_file   old_file
796 + void Drive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len)
797 + {
798 +        set_error(ERR_UNIMPLEMENTED);
799 + }
800 +
801 + // SCRATCH:file1,file2,...
802 + //         ^
803 + //         files
804 + void Drive::scratch_cmd(const uint8 *files, int files_len)
805 + {
806 +        set_error(ERR_UNIMPLEMENTED);
807 + }
808 +
809 + // P<channel><record low><record high><byte>
810 + //  ^
811 + //  cmd
812 + void Drive::position_cmd(const uint8 *cmd, int cmd_len)
813 + {
814 +        set_error(ERR_UNIMPLEMENTED);
815 + }
816 +
817 + // INITIALIZE
818 + void Drive::initialize_cmd(void)
819 + {
820 +        set_error(ERR_UNIMPLEMENTED);
821 + }
822 +
823 + // NEW:name,id
824 + //     ^   ^
825 + //  name   comma (or NULL)
826 + void Drive::new_cmd(const uint8 *name, int name_len, const uint8 *comma)
827 + {
828 +        set_error(ERR_UNIMPLEMENTED);
829 + }
830 +
831 + // VALIDATE
832 + void Drive::validate_cmd(void)
833 + {
834 +        set_error(ERR_UNIMPLEMENTED);
835 + }
836 +
837 +
838 + /*
839 + *  Notice user of unsupported drive command
840 + */
841 +
842 + void Drive::unsupp_cmd(void)
843 + {
844 + }
845 +
846 +
847 + /*
848 + *  Convert PETSCII<->ASCII
849 + */
850 +
851 + char ascii2petscii(char c)
852 + {
853 +        if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
854 +                return c ^ 0x20;
855 +        return c;
856 + }
857 +
858 + void ascii2petscii(char *dest, const char *src, int n)
859 + {
860 +        while (n-- && (*dest++ = ascii2petscii(*src++))) ;
861 + }
862 +
863 + char petscii2ascii(uint8 c)
864 + {
865 +        if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
866 +                return c ^ 0x20;
867 +        if ((c >= 0xc1) && (c <= 0xda))
868 +                return c ^ 0x80;
869 +        return c;
870 + }
871 +
872 + void petscii2ascii(char *dest, const char *src, int n)
873 + {
874 +        while (n-- && (*dest++ = petscii2ascii(*src++))) ;
875 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines