📄 fdc.c
字号:
static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value){ fdctrl_t *fdctrl = opaque; FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value); switch (reg & 0x07) { case 0x02: fdctrl_write_dor(fdctrl, value); break; case 0x03: fdctrl_write_tape(fdctrl, value); break; case 0x04: fdctrl_write_rate(fdctrl, value); break; case 0x05: fdctrl_write_data(fdctrl, value); break; default: break; }}static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg){ return fdctrl_read(opaque, reg);}static void fdctrl_write_mem (void *opaque, target_phys_addr_t reg, uint32_t value){ fdctrl_write(opaque, reg, value);}static CPUReadMemoryFunc *fdctrl_mem_read[3] = { fdctrl_read_mem, fdctrl_read_mem, fdctrl_read_mem,};static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { fdctrl_write_mem, fdctrl_write_mem, fdctrl_write_mem,};fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t io_base, BlockDriverState **fds){ fdctrl_t *fdctrl; int io_mem; int i; FLOPPY_DPRINTF("init controller\n"); fdctrl = qemu_mallocz(sizeof(fdctrl_t)); if (!fdctrl) return NULL; fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN); if (fdctrl->fifo == NULL) { qemu_free(fdctrl); return NULL; } fdctrl->result_timer = qemu_new_timer(vm_clock, fdctrl_result_timer, fdctrl); fdctrl->version = 0x90; /* Intel 82078 controller */ fdctrl->irq_lvl = irq_lvl; fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ if (fdctrl->dma_chann != -1) { fdctrl->dma_en = 1; DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); } else { fdctrl->dma_en = 0; } for (i = 0; i < 2; i++) { fd_init(&fdctrl->drives[i], fds[i]); } fdctrl_reset(fdctrl, 0); fdctrl->state = FD_CTRL_ACTIVE; if (mem_mapped) { io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); cpu_register_physical_memory(io_base, 0x08, io_mem); } else { register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl); register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl); register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); } for (i = 0; i < 2; i++) { fd_revalidate(&fdctrl->drives[i]); } return fdctrl;}/* XXX: may change if moved to bdrv */int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num){ return fdctrl->drives[drive_num].drive;}/* Change IRQ state */static void fdctrl_reset_irq (fdctrl_t *fdctrl){ FLOPPY_DPRINTF("Reset interrupt\n"); pic_set_irq(fdctrl->irq_lvl, 0); fdctrl->state &= ~FD_CTRL_INTR;}static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status){#ifdef TARGET_SPARC // Sparc mutation if (!fdctrl->dma_en) { fdctrl->state &= ~FD_CTRL_BUSY; fdctrl->int_status = status; return; }#endif if (~(fdctrl->state & FD_CTRL_INTR)) { pic_set_irq(fdctrl->irq_lvl, 1); fdctrl->state |= FD_CTRL_INTR; } FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status); fdctrl->int_status = status;}/* Reset controller */static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq){ int i; FLOPPY_DPRINTF("reset controller\n"); fdctrl_reset_irq(fdctrl); /* Initialise controller */ fdctrl->cur_drv = 0; /* FIFO state */ fdctrl->data_pos = 0; fdctrl->data_len = 0; fdctrl->data_state = FD_STATE_CMD; fdctrl->data_dir = FD_DIR_WRITE; for (i = 0; i < MAX_FD; i++) fd_reset(&fdctrl->drives[i]); fdctrl_reset_fifo(fdctrl); if (do_irq) fdctrl_raise_irq(fdctrl, 0xc0);}static inline fdrive_t *drv0 (fdctrl_t *fdctrl){ return &fdctrl->drives[fdctrl->bootsel];}static inline fdrive_t *drv1 (fdctrl_t *fdctrl){ return &fdctrl->drives[1 - fdctrl->bootsel];}static fdrive_t *get_cur_drv (fdctrl_t *fdctrl){ return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);}/* Status B register : 0x01 (read-only) */static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl){ FLOPPY_DPRINTF("status register: 0x00\n"); return 0;}/* Digital output register : 0x02 */static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl){ uint32_t retval = 0; /* Drive motors state indicators */ if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON) retval |= 1 << 5; if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON) retval |= 1 << 4; /* DMA enable */ retval |= fdctrl->dma_en << 3; /* Reset indicator */ retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0; /* Selected drive */ retval |= fdctrl->cur_drv; FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval); return retval;}static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value){ /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { if (!(value & 0x04)) { FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } } FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value); /* Drive motors state indicators */ if (value & 0x20) fd_start(drv1(fdctrl)); else fd_stop(drv1(fdctrl)); if (value & 0x10) fd_start(drv0(fdctrl)); else fd_stop(drv0(fdctrl)); /* DMA enable */#if 0 if (fdctrl->dma_chann != -1) fdctrl->dma_en = 1 - ((value >> 3) & 1);#endif /* Reset */ if (!(value & 0x04)) { if (!(fdctrl->state & FD_CTRL_RESET)) { FLOPPY_DPRINTF("controller enter RESET state\n"); fdctrl->state |= FD_CTRL_RESET; } } else { if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("controller out of RESET state\n"); fdctrl_reset(fdctrl, 1); fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); } } /* Selected drive */ fdctrl->cur_drv = value & 1;}/* Tape drive register : 0x03 */static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl){ uint32_t retval = 0; /* Disk boot selection indicator */ retval |= fdctrl->bootsel << 2; /* Tape indicators: never allowed */ FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval); return retval;}static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value){ /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value); /* Disk boot selection indicator */ fdctrl->bootsel = (value >> 2) & 1; /* Tape indicators: never allow */}/* Main status register : 0x04 (read) */static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl){ uint32_t retval = 0; fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); if (!(fdctrl->state & FD_CTRL_BUSY)) { /* Data transfer allowed */ retval |= 0x80; /* Data transfer direction indicator */ if (fdctrl->data_dir == FD_DIR_READ) retval |= 0x40; } /* Should handle 0x20 for SPECIFY command */ /* Command busy indicator */ if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA || FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) retval |= 0x10; FLOPPY_DPRINTF("main status register: 0x%02x\n", retval); return retval;}/* Data select rate register : 0x04 (write) */static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value){ /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); /* Reset: autoclear */ if (value & 0x80) { fdctrl->state |= FD_CTRL_RESET; fdctrl_reset(fdctrl, 1); fdctrl->state &= ~FD_CTRL_RESET; } if (value & 0x40) { fdctrl->state |= FD_CTRL_SLEEP; fdctrl_reset(fdctrl, 1); }// fdctrl.precomp = (value >> 2) & 0x07;}static int fdctrl_media_changed(fdrive_t *drv){ int ret; if (!drv->bs) return 0; ret = bdrv_media_changed(drv->bs); if (ret) { fd_revalidate(drv); } return ret;}/* Digital input register : 0x07 (read-only) */static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl){ uint32_t retval = 0; if (fdctrl_media_changed(drv0(fdctrl)) || fdctrl_media_changed(drv1(fdctrl))) retval |= 0x80; if (retval != 0) FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval); return retval;}/* FIFO state control */static void fdctrl_reset_fifo (fdctrl_t *fdctrl){ fdctrl->data_dir = FD_DIR_WRITE; fdctrl->data_pos = 0; FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);}/* Set FIFO status for the host to read */static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq){ fdctrl->data_dir = FD_DIR_READ; fdctrl->data_len = fifo_len; fdctrl->data_pos = 0; FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS); if (do_irq) fdctrl_raise_irq(fdctrl, 0x00);}/* Set an error: unimplemented/unknown command */static void fdctrl_unimplemented (fdctrl_t *fdctrl){#if 0 fdrive_t *cur_drv; cur_drv = get_cur_drv(fdctrl); fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv; fdctrl->fifo[1] = 0x00; fdctrl->fifo[2] = 0x00; fdctrl_set_fifo(fdctrl, 3, 1);#else // fdctrl_reset_fifo(fdctrl); fdctrl->fifo[0] = 0x80; fdctrl_set_fifo(fdctrl, 1, 0);#endif}/* Callback for transfer end (stop or abort) */static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, uint8_t status1, uint8_t status2){ fdrive_t *cur_drv; cur_drv = get_cur_drv(fdctrl); FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", status0, status1, status2, status0 | (cur_drv->head << 2) | fdctrl->cur_drv); fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv; fdctrl->fifo[1] = status1; fdctrl->fifo[2] = status2; fdctrl->fifo[3] = cur_drv->track; fdctrl->fifo[4] = cur_drv->head; fdctrl->fifo[5] = cur_drv->sect; fdctrl->fifo[6] = FD_SECTOR_SC; fdctrl->data_dir = FD_DIR_READ; if (fdctrl->state & FD_CTRL_BUSY) { DMA_release_DREQ(fdctrl->dma_chann); fdctrl->state &= ~FD_CTRL_BUSY; } fdctrl_set_fifo(fdctrl, 7, 1);}/* Prepare a data transfer (either DMA or FIFO) */static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction){ fdrive_t *cur_drv; uint8_t kh, kt, ks; int did_seek; fdctrl->cur_drv = fdctrl->fifo[1] & 1; cur_drv = get_cur_drv(fdctrl); kt = fdctrl->fifo[2]; kh = fdctrl->fifo[3]; ks = fdctrl->fifo[4]; FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n", fdctrl->cur_drv, kh, kt, ks, _fd_sector(kh, kt, ks, cur_drv->last_sect)); did_seek = 0; switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) { case 2: /* sect too big */ fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 3: /* track too big */ fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 4: /* No seek enabled */ fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; case 1: did_seek = 1; break; default: break; } /* Set the FIFO state */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -