Revision 1c346df2 hw/fdc.c
b/hw/fdc.c | ||
---|---|---|
69 | 69 |
FDRIVE_DRV_NONE = 0x03, /* No drive connected */ |
70 | 70 |
} fdrive_type_t; |
71 | 71 |
|
72 |
typedef enum fdrive_flags_t { |
|
73 |
FDRIVE_MOTOR_ON = 0x01, /* motor on/off */ |
|
74 |
} fdrive_flags_t; |
|
75 |
|
|
76 | 72 |
typedef enum fdisk_flags_t { |
77 | 73 |
FDISK_DBL_SIDES = 0x01, |
78 | 74 |
} fdisk_flags_t; |
... | ... | |
81 | 77 |
BlockDriverState *bs; |
82 | 78 |
/* Drive status */ |
83 | 79 |
fdrive_type_t drive; |
84 |
fdrive_flags_t drflags; |
|
85 | 80 |
uint8_t perpendicular; /* 2.88 MB access mode */ |
86 | 81 |
/* Position */ |
87 | 82 |
uint8_t head; |
... | ... | |
103 | 98 |
/* Drive */ |
104 | 99 |
drv->bs = bs; |
105 | 100 |
drv->drive = FDRIVE_DRV_NONE; |
106 |
drv->drflags = 0; |
|
107 | 101 |
drv->perpendicular = 0; |
108 | 102 |
/* Disk */ |
109 | 103 |
drv->last_sect = 0; |
... | ... | |
296 | 290 |
} |
297 | 291 |
} |
298 | 292 |
|
299 |
/* Motor control */ |
|
300 |
static void fd_start (fdrive_t *drv) |
|
301 |
{ |
|
302 |
drv->drflags |= FDRIVE_MOTOR_ON; |
|
303 |
} |
|
304 |
|
|
305 |
static void fd_stop (fdrive_t *drv) |
|
306 |
{ |
|
307 |
drv->drflags &= ~FDRIVE_MOTOR_ON; |
|
308 |
} |
|
309 |
|
|
310 |
/* Re-initialise a drives (motor off, repositioned) */ |
|
311 |
static void fd_reset (fdrive_t *drv) |
|
312 |
{ |
|
313 |
fd_stop(drv); |
|
314 |
fd_recalibrate(drv); |
|
315 |
} |
|
316 |
|
|
317 | 293 |
/********************************************************/ |
318 | 294 |
/* Intel 82078 floppy disk controller emulation */ |
319 | 295 |
|
... | ... | |
337 | 313 |
|
338 | 314 |
enum { |
339 | 315 |
FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */ |
340 |
FD_CTRL_RESET = 0x02, |
|
341 | 316 |
FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */ |
342 | 317 |
FD_CTRL_BUSY = 0x08, /* dma transfer in progress */ |
343 | 318 |
}; |
... | ... | |
621 | 596 |
|
622 | 597 |
static void fd_save (QEMUFile *f, fdrive_t *fd) |
623 | 598 |
{ |
624 |
uint8_t tmp; |
|
625 |
|
|
626 |
tmp = fd->drflags; |
|
627 |
qemu_put_8s(f, &tmp); |
|
628 | 599 |
qemu_put_8s(f, &fd->head); |
629 | 600 |
qemu_put_8s(f, &fd->track); |
630 | 601 |
qemu_put_8s(f, &fd->sect); |
... | ... | |
662 | 633 |
|
663 | 634 |
static int fd_load (QEMUFile *f, fdrive_t *fd) |
664 | 635 |
{ |
665 |
uint8_t tmp; |
|
666 |
|
|
667 |
qemu_get_8s(f, &tmp); |
|
668 |
fd->drflags = tmp; |
|
669 | 636 |
qemu_get_8s(f, &fd->head); |
670 | 637 |
qemu_get_8s(f, &fd->track); |
671 | 638 |
qemu_get_8s(f, &fd->sect); |
... | ... | |
773 | 740 |
if (!fdctrl->drives[1].bs) |
774 | 741 |
fdctrl->sra |= FD_SRA_nDRV2; |
775 | 742 |
fdctrl->cur_drv = 0; |
776 |
fdctrl->dor = 0;
|
|
743 |
fdctrl->dor = FD_DOR_nRESET;
|
|
777 | 744 |
fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0; |
778 | 745 |
fdctrl->msr = 0; |
779 | 746 |
/* FIFO state */ |
... | ... | |
782 | 749 |
fdctrl->data_state = FD_STATE_CMD; |
783 | 750 |
fdctrl->data_dir = FD_DIR_WRITE; |
784 | 751 |
for (i = 0; i < MAX_FD; i++) |
785 |
fd_reset(&fdctrl->drives[i]);
|
|
752 |
fd_recalibrate(&fdctrl->drives[i]);
|
|
786 | 753 |
fdctrl_reset_fifo(fdctrl); |
787 | 754 |
if (do_irq) |
788 | 755 |
fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG); |
... | ... | |
826 | 793 |
/* Digital output register : 0x02 */ |
827 | 794 |
static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl) |
828 | 795 |
{ |
829 |
uint32_t retval = 0;
|
|
796 |
uint32_t retval = fdctrl->dor;
|
|
830 | 797 |
|
831 |
/* Drive motors state indicators */ |
|
832 |
if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON) |
|
833 |
retval |= FD_DOR_MOTEN0; |
|
834 |
if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON) |
|
835 |
retval |= FD_DOR_MOTEN1; |
|
836 |
/* DMA enable */ |
|
837 |
if (fdctrl->dor & FD_DOR_DMAEN) |
|
838 |
retval |= FD_DOR_DMAEN; |
|
839 |
/* Reset indicator */ |
|
840 |
if (!(fdctrl->state & FD_CTRL_RESET)) |
|
841 |
retval |= FD_DOR_nRESET; |
|
842 | 798 |
/* Selected drive */ |
843 | 799 |
retval |= fdctrl->cur_drv; |
844 | 800 |
FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval); |
... | ... | |
848 | 804 |
|
849 | 805 |
static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) |
850 | 806 |
{ |
851 |
/* Reset mode */ |
|
852 |
if (fdctrl->state & FD_CTRL_RESET) { |
|
853 |
if (!(value & FD_DOR_nRESET)) { |
|
854 |
FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); |
|
855 |
return; |
|
856 |
} |
|
857 |
} |
|
858 | 807 |
FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value); |
859 | 808 |
|
860 | 809 |
/* Motors */ |
... | ... | |
873 | 822 |
else |
874 | 823 |
fdctrl->srb &= ~FD_SRB_DR0; |
875 | 824 |
|
876 |
/* Drive motors state indicators */ |
|
877 |
if (value & FD_DOR_MOTEN1) |
|
878 |
fd_start(drv1(fdctrl)); |
|
879 |
else |
|
880 |
fd_stop(drv1(fdctrl)); |
|
881 |
if (value & FD_DOR_MOTEN0) |
|
882 |
fd_start(drv0(fdctrl)); |
|
883 |
else |
|
884 |
fd_stop(drv0(fdctrl)); |
|
885 |
/* DMA enable */ |
|
886 |
#if 0 |
|
887 |
if (fdctrl->dma_chann != -1) |
|
888 |
fdctrl->dma_en = value & FD_DOR_DMAEN ? 1 : 0; |
|
889 |
#endif |
|
890 | 825 |
/* Reset */ |
891 | 826 |
if (!(value & FD_DOR_nRESET)) { |
892 |
if (!(fdctrl->state & FD_CTRL_RESET)) {
|
|
827 |
if (fdctrl->dor & FD_DOR_nRESET) {
|
|
893 | 828 |
FLOPPY_DPRINTF("controller enter RESET state\n"); |
894 |
fdctrl->state |= FD_CTRL_RESET; |
|
895 | 829 |
} |
896 | 830 |
} else { |
897 |
if (fdctrl->state & FD_CTRL_RESET) {
|
|
831 |
if (!(fdctrl->dor & FD_DOR_nRESET)) {
|
|
898 | 832 |
FLOPPY_DPRINTF("controller out of RESET state\n"); |
899 | 833 |
fdctrl_reset(fdctrl, 1); |
900 |
fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
|
|
834 |
fdctrl->state &= ~FD_CTRL_SLEEP;
|
|
901 | 835 |
} |
902 | 836 |
} |
903 | 837 |
/* Selected drive */ |
... | ... | |
922 | 856 |
static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value) |
923 | 857 |
{ |
924 | 858 |
/* Reset mode */ |
925 |
if (fdctrl->state & FD_CTRL_RESET) {
|
|
859 |
if (!(fdctrl->dor & FD_DOR_nRESET)) {
|
|
926 | 860 |
FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); |
927 | 861 |
return; |
928 | 862 |
} |
... | ... | |
937 | 871 |
{ |
938 | 872 |
uint32_t retval = 0; |
939 | 873 |
|
940 |
fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); |
|
874 |
fdctrl->dor |= FD_DOR_nRESET; |
|
875 |
fdctrl->state &= ~FD_CTRL_SLEEP; |
|
941 | 876 |
if (!(fdctrl->state & FD_CTRL_BUSY)) { |
942 | 877 |
/* Data transfer allowed */ |
943 | 878 |
retval |= FD_MSR_RQM; |
... | ... | |
959 | 894 |
static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) |
960 | 895 |
{ |
961 | 896 |
/* Reset mode */ |
962 |
if (fdctrl->state & FD_CTRL_RESET) {
|
|
897 |
if (!(fdctrl->dor & FD_DOR_nRESET)) {
|
|
963 | 898 |
FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); |
964 | 899 |
return; |
965 | 900 |
} |
966 | 901 |
FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); |
967 | 902 |
/* Reset: autoclear */ |
968 | 903 |
if (value & FD_DSR_SWRESET) { |
969 |
fdctrl->state |= FD_CTRL_RESET;
|
|
904 |
fdctrl->dor &= ~FD_DOR_nRESET;
|
|
970 | 905 |
fdctrl_reset(fdctrl, 1); |
971 |
fdctrl->state &= ~FD_CTRL_RESET;
|
|
906 |
fdctrl->dor |= FD_DOR_nRESET;
|
|
972 | 907 |
} |
973 | 908 |
if (value & FD_DSR_PWRDOWN) { |
974 | 909 |
fdctrl->state |= FD_CTRL_SLEEP; |
... | ... | |
1618 | 1553 |
|
1619 | 1554 |
fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK; |
1620 | 1555 |
cur_drv = get_cur_drv(fdctrl); |
1621 |
fd_start(cur_drv); |
|
1622 | 1556 |
if (fdctrl->fifo[2] <= cur_drv->track) |
1623 | 1557 |
cur_drv->dir = 1; |
1624 | 1558 |
else |
... | ... | |
1640 | 1574 |
if (fdctrl->fifo[1] & 0x80) |
1641 | 1575 |
cur_drv->perpendicular = fdctrl->fifo[1] & 0x7; |
1642 | 1576 |
/* No result back */ |
1643 |
fdctrl_reset_fifo(fdctrl);
|
|
1577 |
fdctrl_reset_fifo(fdctrl); |
|
1644 | 1578 |
} |
1645 | 1579 |
|
1646 | 1580 |
static void fdctrl_handle_configure (fdctrl_t *fdctrl, int direction) |
... | ... | |
1692 | 1626 |
|
1693 | 1627 |
fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK; |
1694 | 1628 |
cur_drv = get_cur_drv(fdctrl); |
1695 |
fd_start(cur_drv); |
|
1696 | 1629 |
cur_drv->dir = 0; |
1697 | 1630 |
if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { |
1698 | 1631 |
cur_drv->track = cur_drv->max_track - 1; |
... | ... | |
1709 | 1642 |
|
1710 | 1643 |
fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK; |
1711 | 1644 |
cur_drv = get_cur_drv(fdctrl); |
1712 |
fd_start(cur_drv); |
|
1713 | 1645 |
cur_drv->dir = 1; |
1714 | 1646 |
if (fdctrl->fifo[2] > cur_drv->track) { |
1715 | 1647 |
cur_drv->track = 0; |
... | ... | |
1772 | 1704 |
|
1773 | 1705 |
cur_drv = get_cur_drv(fdctrl); |
1774 | 1706 |
/* Reset mode */ |
1775 |
if (fdctrl->state & FD_CTRL_RESET) {
|
|
1707 |
if (!(fdctrl->dor & FD_DOR_nRESET)) {
|
|
1776 | 1708 |
FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); |
1777 | 1709 |
return; |
1778 | 1710 |
} |
Also available in: Unified diff