Commit 890fa6bebbb540b9761aafc3fe37b87e26578346
1 parent
a4c4785b
floppy fixes (initial patch by Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1101 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
32 additions
and
23 deletions
hw/fdc.c
| 1 | /* | 1 | /* |
| 2 | - * QEMU Floppy disk emulator | 2 | + * QEMU Floppy disk emulator (Intel 82078) |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2003 Jocelyn Mayer | 4 | * Copyright (c) 2003 Jocelyn Mayer |
| 5 | * | 5 | * |
| @@ -382,6 +382,7 @@ struct fdctrl_t { | @@ -382,6 +382,7 @@ struct fdctrl_t { | ||
| 382 | uint8_t data_state; | 382 | uint8_t data_state; |
| 383 | uint8_t data_dir; | 383 | uint8_t data_dir; |
| 384 | uint8_t int_status; | 384 | uint8_t int_status; |
| 385 | + uint8_t eot; /* last wanted sector */ | ||
| 385 | /* States kept only to be returned back */ | 386 | /* States kept only to be returned back */ |
| 386 | /* Timers state */ | 387 | /* Timers state */ |
| 387 | uint8_t timer0; | 388 | uint8_t timer0; |
| @@ -762,7 +763,7 @@ static void fdctrl_unimplemented (fdctrl_t *fdctrl) | @@ -762,7 +763,7 @@ static void fdctrl_unimplemented (fdctrl_t *fdctrl) | ||
| 762 | fdrive_t *cur_drv; | 763 | fdrive_t *cur_drv; |
| 763 | 764 | ||
| 764 | cur_drv = get_cur_drv(fdctrl); | 765 | cur_drv = get_cur_drv(fdctrl); |
| 765 | - fdctrl->fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl->cur_drv; | 766 | + fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv; |
| 766 | fdctrl->fifo[1] = 0x00; | 767 | fdctrl->fifo[1] = 0x00; |
| 767 | fdctrl->fifo[2] = 0x00; | 768 | fdctrl->fifo[2] = 0x00; |
| 768 | fdctrl_set_fifo(fdctrl, 3, 1); | 769 | fdctrl_set_fifo(fdctrl, 3, 1); |
| @@ -782,8 +783,8 @@ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, | @@ -782,8 +783,8 @@ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, | ||
| 782 | cur_drv = get_cur_drv(fdctrl); | 783 | cur_drv = get_cur_drv(fdctrl); |
| 783 | FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", | 784 | FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", |
| 784 | status0, status1, status2, | 785 | status0, status1, status2, |
| 785 | - status0 | (cur_drv->head << 1) | fdctrl->cur_drv); | ||
| 786 | - fdctrl->fifo[0] = status0 | (cur_drv->head << 1) | fdctrl->cur_drv; | 786 | + status0 | (cur_drv->head << 2) | fdctrl->cur_drv); |
| 787 | + fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv; | ||
| 787 | fdctrl->fifo[1] = status1; | 788 | fdctrl->fifo[1] = status1; |
| 788 | fdctrl->fifo[2] = status2; | 789 | fdctrl->fifo[2] = status2; |
| 789 | fdctrl->fifo[3] = cur_drv->track; | 790 | fdctrl->fifo[3] = cur_drv->track; |
| @@ -810,7 +811,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) | @@ -810,7 +811,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) | ||
| 810 | kt = fdctrl->fifo[2]; | 811 | kt = fdctrl->fifo[2]; |
| 811 | kh = fdctrl->fifo[3]; | 812 | kh = fdctrl->fifo[3]; |
| 812 | ks = fdctrl->fifo[4]; | 813 | ks = fdctrl->fifo[4]; |
| 813 | - FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n", | 814 | + FLOPPY_DPRINTF("Start tranfer at %d %d %02x %02x (%d)\n", |
| 814 | fdctrl->cur_drv, kh, kt, ks, | 815 | fdctrl->cur_drv, kh, kt, ks, |
| 815 | _fd_sector(kh, kt, ks, cur_drv->last_sect)); | 816 | _fd_sector(kh, kt, ks, cur_drv->last_sect)); |
| 816 | did_seek = 0; | 817 | did_seek = 0; |
| @@ -864,6 +865,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) | @@ -864,6 +865,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) | ||
| 864 | tmp += cur_drv->last_sect; | 865 | tmp += cur_drv->last_sect; |
| 865 | fdctrl->data_len *= tmp; | 866 | fdctrl->data_len *= tmp; |
| 866 | } | 867 | } |
| 868 | + fdctrl->eot = fdctrl->fifo[6]; | ||
| 867 | if (fdctrl->dma_en) { | 869 | if (fdctrl->dma_en) { |
| 868 | int dma_mode; | 870 | int dma_mode; |
| 869 | /* DMA transfer are enabled. Check if DMA channel is well programmed */ | 871 | /* DMA transfer are enabled. Check if DMA channel is well programmed */ |
| @@ -924,14 +926,14 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | @@ -924,14 +926,14 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | ||
| 924 | status2 = 0x04; | 926 | status2 = 0x04; |
| 925 | if (size > fdctrl->data_len) | 927 | if (size > fdctrl->data_len) |
| 926 | size = fdctrl->data_len; | 928 | size = fdctrl->data_len; |
| 927 | - if (cur_drv->bs == NULL) { | 929 | + if (cur_drv->bs == NULL) { |
| 928 | if (fdctrl->data_dir == FD_DIR_WRITE) | 930 | if (fdctrl->data_dir == FD_DIR_WRITE) |
| 929 | fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); | 931 | fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); |
| 930 | else | 932 | else |
| 931 | fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); | 933 | fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); |
| 932 | len = 0; | 934 | len = 0; |
| 933 | - goto transfer_error; | ||
| 934 | - } | 935 | + goto transfer_error; |
| 936 | + } | ||
| 935 | rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; | 937 | rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; |
| 936 | for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) { | 938 | for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) { |
| 937 | len = size - fdctrl->data_pos; | 939 | len = size - fdctrl->data_pos; |
| @@ -952,7 +954,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | @@ -952,7 +954,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | ||
| 952 | /* Sure, image size is too small... */ | 954 | /* Sure, image size is too small... */ |
| 953 | memset(fdctrl->fifo, 0, FD_SECTOR_LEN); | 955 | memset(fdctrl->fifo, 0, FD_SECTOR_LEN); |
| 954 | } | 956 | } |
| 955 | - } | 957 | + } |
| 956 | switch (fdctrl->data_dir) { | 958 | switch (fdctrl->data_dir) { |
| 957 | case FD_DIR_READ: | 959 | case FD_DIR_READ: |
| 958 | /* READ commands */ | 960 | /* READ commands */ |
| @@ -968,7 +970,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | @@ -968,7 +970,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | ||
| 968 | FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); | 970 | FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); |
| 969 | fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); | 971 | fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); |
| 970 | goto transfer_error; | 972 | goto transfer_error; |
| 971 | - } | 973 | + } |
| 972 | break; | 974 | break; |
| 973 | default: | 975 | default: |
| 974 | /* SCAN commands */ | 976 | /* SCAN commands */ |
| @@ -994,30 +996,34 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | @@ -994,30 +996,34 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) | ||
| 994 | rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; | 996 | rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; |
| 995 | if (rel_pos == 0) { | 997 | if (rel_pos == 0) { |
| 996 | /* Seek to next sector */ | 998 | /* Seek to next sector */ |
| 997 | - cur_drv->sect++; | ||
| 998 | FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", | 999 | FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", |
| 999 | cur_drv->head, cur_drv->track, cur_drv->sect, | 1000 | cur_drv->head, cur_drv->track, cur_drv->sect, |
| 1000 | fd_sector(cur_drv), | 1001 | fd_sector(cur_drv), |
| 1001 | fdctrl->data_pos - size); | 1002 | fdctrl->data_pos - size); |
| 1002 | - if (cur_drv->sect > cur_drv->last_sect) { | 1003 | + /* XXX: cur_drv->sect >= cur_drv->last_sect should be an |
| 1004 | + error in fact */ | ||
| 1005 | + if (cur_drv->sect >= cur_drv->last_sect || | ||
| 1006 | + cur_drv->sect == fdctrl->eot) { | ||
| 1003 | cur_drv->sect = 1; | 1007 | cur_drv->sect = 1; |
| 1004 | if (FD_MULTI_TRACK(fdctrl->data_state)) { | 1008 | if (FD_MULTI_TRACK(fdctrl->data_state)) { |
| 1005 | if (cur_drv->head == 0 && | 1009 | if (cur_drv->head == 0 && |
| 1006 | (cur_drv->flags & FDISK_DBL_SIDES) != 0) { | 1010 | (cur_drv->flags & FDISK_DBL_SIDES) != 0) { |
| 1007 | - cur_drv->head = 1; | ||
| 1008 | - } else { | ||
| 1009 | - cur_drv->head = 0; | 1011 | + cur_drv->head = 1; |
| 1012 | + } else { | ||
| 1013 | + cur_drv->head = 0; | ||
| 1010 | cur_drv->track++; | 1014 | cur_drv->track++; |
| 1011 | if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) | 1015 | if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) |
| 1012 | break; | 1016 | break; |
| 1017 | + } | ||
| 1018 | + } else { | ||
| 1019 | + cur_drv->track++; | ||
| 1020 | + break; | ||
| 1013 | } | 1021 | } |
| 1014 | - } else { | ||
| 1015 | - cur_drv->track++; | ||
| 1016 | - break; | ||
| 1017 | - } | ||
| 1018 | FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", | 1022 | FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", |
| 1019 | cur_drv->head, cur_drv->track, | 1023 | cur_drv->head, cur_drv->track, |
| 1020 | cur_drv->sect, fd_sector(cur_drv)); | 1024 | cur_drv->sect, fd_sector(cur_drv)); |
| 1025 | + } else { | ||
| 1026 | + cur_drv->sect++; | ||
| 1021 | } | 1027 | } |
| 1022 | } | 1028 | } |
| 1023 | } | 1029 | } |
| @@ -1033,7 +1039,7 @@ end_transfer: | @@ -1033,7 +1039,7 @@ end_transfer: | ||
| 1033 | status0 |= 0x20; | 1039 | status0 |= 0x20; |
| 1034 | fdctrl->data_len -= len; | 1040 | fdctrl->data_len -= len; |
| 1035 | // if (fdctrl->data_len == 0) | 1041 | // if (fdctrl->data_len == 0) |
| 1036 | - fdctrl_stop_transfer(fdctrl, status0, status1, status2); | 1042 | + fdctrl_stop_transfer(fdctrl, status0, status1, status2); |
| 1037 | transfer_error: | 1043 | transfer_error: |
| 1038 | 1044 | ||
| 1039 | return len; | 1045 | return len; |
| @@ -1066,7 +1072,7 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) | @@ -1066,7 +1072,7 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) | ||
| 1066 | retval = fdctrl->fifo[pos]; | 1072 | retval = fdctrl->fifo[pos]; |
| 1067 | if (++fdctrl->data_pos == fdctrl->data_len) { | 1073 | if (++fdctrl->data_pos == fdctrl->data_len) { |
| 1068 | fdctrl->data_pos = 0; | 1074 | fdctrl->data_pos = 0; |
| 1069 | - /* Switch from transfert mode to status mode | 1075 | + /* Switch from transfer mode to status mode |
| 1070 | * then from status mode to command mode | 1076 | * then from status mode to command mode |
| 1071 | */ | 1077 | */ |
| 1072 | if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { | 1078 | if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { |
| @@ -1170,7 +1176,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) | @@ -1170,7 +1176,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) | ||
| 1170 | bdrv_write(cur_drv->bs, fd_sector(cur_drv), | 1176 | bdrv_write(cur_drv->bs, fd_sector(cur_drv), |
| 1171 | fdctrl->fifo, FD_SECTOR_LEN); | 1177 | fdctrl->fifo, FD_SECTOR_LEN); |
| 1172 | } | 1178 | } |
| 1173 | - /* Switch from transfert mode to status mode | 1179 | + /* Switch from transfer mode to status mode |
| 1174 | * then from status mode to command mode | 1180 | * then from status mode to command mode |
| 1175 | */ | 1181 | */ |
| 1176 | if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) | 1182 | if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) |
| @@ -1510,7 +1516,9 @@ enqueue: | @@ -1510,7 +1516,9 @@ enqueue: | ||
| 1510 | /* 1 Byte status back */ | 1516 | /* 1 Byte status back */ |
| 1511 | fdctrl->fifo[0] = (cur_drv->ro << 6) | | 1517 | fdctrl->fifo[0] = (cur_drv->ro << 6) | |
| 1512 | (cur_drv->track == 0 ? 0x10 : 0x00) | | 1518 | (cur_drv->track == 0 ? 0x10 : 0x00) | |
| 1513 | - fdctrl->cur_drv; | 1519 | + (cur_drv->head << 2) | |
| 1520 | + fdctrl->cur_drv | | ||
| 1521 | + 0x28; | ||
| 1514 | fdctrl_set_fifo(fdctrl, 1, 0); | 1522 | fdctrl_set_fifo(fdctrl, 1, 0); |
| 1515 | break; | 1523 | break; |
| 1516 | case 0x07: | 1524 | case 0x07: |
| @@ -1581,6 +1589,7 @@ enqueue: | @@ -1581,6 +1589,7 @@ enqueue: | ||
| 1581 | /* READ_ID */ | 1589 | /* READ_ID */ |
| 1582 | FLOPPY_DPRINTF("treat READ_ID command\n"); | 1590 | FLOPPY_DPRINTF("treat READ_ID command\n"); |
| 1583 | /* XXX: should set main status register to busy */ | 1591 | /* XXX: should set main status register to busy */ |
| 1592 | + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; | ||
| 1584 | qemu_mod_timer(fdctrl->result_timer, | 1593 | qemu_mod_timer(fdctrl->result_timer, |
| 1585 | qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); | 1594 | qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); |
| 1586 | break; | 1595 | break; |