static uint8 DISK3_Write(const uint32 Addr, uint8 cData) { uint32 next_link; uint8 result = DISK3_STATUS_COMPLETE; uint8 i; uint8 cmd; DISK3_DRIVE_INFO *pDrive; for(i = 0; i < DISK3_IOPB_LEN; i++) { disk3_info->iopb[i] = GetByteDMA(disk3_info->link_addr + i); } cmd = disk3_info->iopb[DISK3_IOPB_CMD]; disk3_info->sel_drive = disk3_info->iopb[DISK3_IOPB_DRIVE] & 0x03; disk3_info->dma_addr = disk3_info->iopb[0x0A]; disk3_info->dma_addr |= disk3_info->iopb[0x0B] << 8; disk3_info->dma_addr |= disk3_info->iopb[0x0C] << 16; next_link = disk3_info->iopb[DISK3_IOPB_LINK+0]; next_link |= disk3_info->iopb[DISK3_IOPB_LINK+1] << 8; next_link |= disk3_info->iopb[DISK3_IOPB_LINK+2] << 16; sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, %s DMA@0x%05x\n", disk3_info->sel_drive, disk3_info->link_addr, next_link, disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_CMD_MASK, (disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_REQUEST_IRQ) ? "IRQ" : "POLL", disk3_info->dma_addr); pDrive = &disk3_info->drive[disk3_info->sel_drive]; if(pDrive->ready) { /* Perform command */ switch(cmd & DISK3_CMD_MASK) { case DISK3_CODE_NOOP: sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " NOOP\n", disk3_info->sel_drive, PCX); break; case DISK3_CODE_VERSION: break; case DISK3_CODE_GLOBAL: sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " GLOBAL\n", disk3_info->sel_drive, PCX); disk3_info->mode = disk3_info->iopb[DISK3_IOPB_ARG1]; disk3_info->retries = disk3_info->iopb[DISK3_IOPB_ARG2]; disk3_info->ndrives = disk3_info->iopb[DISK3_IOPB_ARG3]; sim_debug(SPECIFY_MSG, &disk3_dev, " Mode: 0x%02x\n", disk3_info->mode); sim_debug(SPECIFY_MSG, &disk3_dev, " # Retries: 0x%02x\n", disk3_info->retries); sim_debug(SPECIFY_MSG, &disk3_dev, " # Drives: 0x%02x\n", disk3_info->ndrives); if(disk3_info->mode == DISK3_MODE_ABS) { sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n"); } break; case DISK3_CODE_SPECIFY: { uint8 specify_data[22]; sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " SPECIFY\n", disk3_info->sel_drive, PCX); for(i = 0; i < 22; i++) { specify_data[i] = GetByteDMA(disk3_info->dma_addr + i); } pDrive->sectsize = specify_data[4] | (specify_data[5] << 8); pDrive->nsectors = specify_data[6] | (specify_data[7] << 8); pDrive->nheads = specify_data[8] | (specify_data[9] << 8); pDrive->ntracks = specify_data[10] | (specify_data[11] << 8); pDrive->res_tracks = specify_data[18] | (specify_data[19] << 8); sim_debug(SPECIFY_MSG, &disk3_dev, " Sectsize: %d\n", pDrive->sectsize); sim_debug(SPECIFY_MSG, &disk3_dev, " Sectors: %d\n", pDrive->nsectors); sim_debug(SPECIFY_MSG, &disk3_dev, " Heads: %d\n", pDrive->nheads); sim_debug(SPECIFY_MSG, &disk3_dev, " Tracks: %d\n", pDrive->ntracks); sim_debug(SPECIFY_MSG, &disk3_dev, " Reserved: %d\n", pDrive->res_tracks); break; } case DISK3_CODE_HOME: pDrive->track = 0; sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " HOME\n", disk3_info->sel_drive, PCX); break; case DISK3_CODE_SEEK: pDrive->track = disk3_info->iopb[DISK3_IOPB_ARG1]; pDrive->track |= (disk3_info->iopb[DISK3_IOPB_ARG2] << 8); if(pDrive->track > pDrive->ntracks) { sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found\n", disk3_info->sel_drive, PCX, pDrive->track); pDrive->track = pDrive->ntracks - 1; result = DISK3_STATUS_TIMEOUT; } else { sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " SEEK %d\n", disk3_info->sel_drive, PCX, pDrive->track); } break; case DISK3_CODE_READ_HDR: { sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " READ HEADER: %d\n", pDrive->track, PCX, pDrive->track >> 8); PutByteDMA(disk3_info->dma_addr + 0, pDrive->track & 0xFF); PutByteDMA(disk3_info->dma_addr + 1, (pDrive->track >> 8) & 0xFF); PutByteDMA(disk3_info->dma_addr + 2, 0); PutByteDMA(disk3_info->dma_addr + 3, 1); break; } case DISK3_CODE_READWRITE: { uint32 track_len; uint32 xfr_len; uint32 file_offset; uint32 xfr_count = 0; uint8 *dataBuffer; size_t rtn; if(disk3_info->mode == DISK3_MODE_ABS) { sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n"); break; } pDrive->cur_sect = disk3_info->iopb[DISK3_IOPB_ARG2] | (disk3_info->iopb[DISK3_IOPB_ARG3] << 8); pDrive->cur_track = disk3_info->iopb[DISK3_IOPB_ARG4] | (disk3_info->iopb[DISK3_IOPB_ARG5] << 8); pDrive->xfr_nsects = disk3_info->iopb[DISK3_IOPB_ARG6] | (disk3_info->iopb[DISK3_IOPB_ARG7] << 8); track_len = pDrive->nsectors * pDrive->sectsize; file_offset = (pDrive->cur_track * track_len); /* Calculate offset based on current track */ file_offset += pDrive->cur_sect * pDrive->sectsize; xfr_len = pDrive->xfr_nsects * pDrive->sectsize; dataBuffer = malloc(xfr_len); sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET); if(disk3_info->iopb[DISK3_IOPB_ARG1] == 1) { /* Read */ rtn = sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); sim_debug(RD_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d %s\n", disk3_info->sel_drive, PCX, disk3_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects, rtn == (size_t)xfr_len ? "OK" : "NOK" ); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { PutByteDMA(disk3_info->dma_addr + xfr_count, dataBuffer[xfr_count]); } } else { /* Write */ sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d\n", disk3_info->sel_drive, PCX, disk3_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects ); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { dataBuffer[xfr_count] = GetByteDMA(disk3_info->dma_addr + xfr_count); } sim_fwrite(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); } free(dataBuffer); /* Update Track/Sector in IOPB */ pDrive->cur_sect += pDrive->xfr_nsects; if(pDrive->cur_sect >= pDrive->nsectors) { pDrive->cur_sect = pDrive->cur_sect % pDrive->nsectors; pDrive->cur_track++; } disk3_info->iopb[DISK3_IOPB_ARG2] = pDrive->cur_sect & 0xFF; disk3_info->iopb[DISK3_IOPB_ARG3] = (pDrive->cur_sect >> 8) & 0xFF; disk3_info->iopb[DISK3_IOPB_ARG4] = pDrive->cur_track & 0xFF; disk3_info->iopb[DISK3_IOPB_ARG5] = (pDrive->cur_track >> 8) & 0xFF; disk3_info->iopb[DISK3_IOPB_ARG6] = 0; disk3_info->iopb[DISK3_IOPB_ARG7] = 0; /* Update the DATA field in the IOPB */ disk3_info->dma_addr += xfr_len; disk3_info->iopb[DISK3_IOPB_DATA+0] = disk3_info->dma_addr & 0xFF; disk3_info->iopb[DISK3_IOPB_DATA+1] = (disk3_info->dma_addr >> 8) & 0xFF; disk3_info->iopb[DISK3_IOPB_DATA+2] = (disk3_info->dma_addr >> 16) & 0xFF; break; } case DISK3_CODE_FORMAT: { uint32 data_len; uint32 file_offset; uint8 *fmtBuffer; data_len = pDrive->nsectors * pDrive->sectsize; sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d\n", disk3_info->sel_drive, PCX, pDrive->track, disk3_info->iopb[DISK3_IOPB_ARG3], disk3_info->iopb[DISK3_IOPB_ARG2], data_len); file_offset = (pDrive->track * (pDrive->nheads) * data_len); /* Calculate offset based on current track */ file_offset += (disk3_info->iopb[DISK3_IOPB_ARG3] * data_len); fmtBuffer = malloc(data_len); memset(fmtBuffer, disk3_info->iopb[DISK3_IOPB_ARG2], data_len); sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET); sim_fwrite(fmtBuffer, 1, data_len, (pDrive->uptr)->fileref); free(fmtBuffer); break; } case DISK3_CODE_SET_MAP: break; case DISK3_CODE_RELOCATE: case DISK3_CODE_FORMAT_BAD: case DISK3_CODE_STATUS: case DISK3_CODE_SELECT: case DISK3_CODE_EXAMINE: case DISK3_CODE_MODIFY: default: sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported\n", disk3_info->sel_drive, PCX, cmd & DISK3_CMD_MASK); break; } } else { /* Drive not ready */
uint8 I8272_Write(const uint32 Addr, uint8 cData) { I8272_DRIVE_INFO *pDrive; uint32 flags = 0; uint32 readlen; uint8 disk_read = 0; int32 i; pDrive = &i8272_info->drive[i8272_info->sel_drive]; if(pDrive->uptr == NULL) { return 0xFF; } switch(Addr & 0x3) { case I8272_FDC_MSR: sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " WR Drive Select Reg=%02x\n", PCX, cData); break; case I8272_FDC_DATA: i8272_info->fdc_msr &= 0xF0; sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " WR Data, phase=%d, index=%d\n", PCX, i8272_info->fdc_phase, i8272_info->cmd_index); if(i8272_info->fdc_phase == CMD_PHASE) { i8272_info->cmd[i8272_info->cmd_index] = cData; if(i8272_info->cmd_index == 0) { sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " CMD=0x%02x[%s]\n", PCX, cData & 0x1F, messages[cData & 0x1F]); I8272_Setup_Cmd(cData & 0x1F); } i8272_info->cmd_index ++; if(i8272_info->cmd_len == i8272_info->cmd_index) { i8272_info->cmd_index = 0; i8272_info->fdc_phase = EXEC_PHASE; } } if(i8272_info->fdc_phase == EXEC_PHASE) { switch(i8272_info->cmd[0] & 0x1F) { case I8272_READ_DATA: case I8272_WRITE_DATA: case I8272_READ_DELETED_DATA: case I8272_WRITE_DELETED_DATA: case I8272_READ_TRACK: case I8272_SCAN_LOW_EQUAL: case I8272_SCAN_HIGH_EQUAL: case I8272_SCAN_EQUAL: i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7; i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; i8272_info->fdc_sk = (i8272_info->cmd[0] & 0x20) >> 5; i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); pDrive = &i8272_info->drive[i8272_info->sel_drive]; if(pDrive->uptr == NULL) { return 0xFF; } if(pDrive->track != i8272_info->cmd[2]) { i8272_info->fdc_seek_end = 1; } else { i8272_info->fdc_seek_end = 0; } if(pDrive->track != i8272_info->cmd[2]) { sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, " "but positioner is on track %d.\n", PCX, i8272_info->cmd[0] & 0x1F, messages[i8272_info->cmd[0] & 0x1F], i8272_info->sel_drive, i8272_info->cmd[2], pDrive->track); } pDrive->track = i8272_info->cmd[2]; i8272_info->fdc_head = i8272_info->cmd[3] & 1; /* AGN mask to head 0 or 1 */ i8272_info->fdc_sector = i8272_info->cmd[4]; i8272_info->fdc_sec_len = i8272_info->cmd[5]; if(i8272_info->fdc_sec_len > I8272_MAX_N) { sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n", PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N); i8272_info->fdc_sec_len = I8272_MAX_N; } i8272_info->fdc_eot = i8272_info->cmd[6]; i8272_info->fdc_gpl = i8272_info->cmd[7]; i8272_info->fdc_dtl = i8272_info->cmd[8]; sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, " "EOT=%02x, GPL=%02x, DTL=%02x\n", PCX, i8272_info->cmd[0] & 0x1F, messages[i8272_info->cmd[0] & 0x1F], i8272_info->sel_drive, i8272_info->fdc_mt ? "Multi" : "Single", i8272_info->fdc_mfm ? "MFM" : "FM", pDrive->track, i8272_info->fdc_head, i8272_info->fdc_sector, i8272_info->fdc_sec_len, i8272_info->fdc_eot, i8272_info->fdc_gpl, i8272_info->fdc_dtl); i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03); i8272_info->fdc_status[0] |= 0x40; i8272_info->fdc_status[1] = 0; i8272_info->fdc_status[2] = 0; i8272_info->result[0] = i8272_info->fdc_status[0]; i8272_info->result[1] = i8272_info->fdc_status[1]; i8272_info->result[2] = i8272_info->fdc_status[2]; i8272_info->result[3] = pDrive->imd->track[pDrive->track][i8272_info->fdc_head].logicalCyl[i8272_info->fdc_sector]; /* AGN logicalCyl */ i8272_info->result[4] = pDrive->imd->track[pDrive->track][i8272_info->fdc_head].logicalHead[i8272_info->fdc_sector]; /* AGN logicalHead */ i8272_info->result[5] = i8272_info->fdc_sector; i8272_info->result[6] = i8272_info->fdc_sec_len; break; case I8272_READ_ID: /* READ ID */ i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); pDrive = &i8272_info->drive[i8272_info->sel_drive]; if(pDrive->uptr == NULL) { return 0xFF; } /* Compute the i8272 "N" value from the sectorsize of this */ /* disk's current track - i.e. N = log2(sectsize) - log2(128) */ /* The calculation also works for non-standard format disk images with */ /* sectorsizes of 2048, 4096 and 8192 bytes */ i8272_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][i8272_info->fdc_hds].sectsize) - 7; /* AGN fix to use fdc_hds (was fdc_head)*/ /* For now always return the starting sector number */ /* but could return (say) a valid sector number based */ /* on elapsed time for a more "realistic" simulation. */ /* This would allow disk analysis programs that use */ /* READID to detect non-standard disk formats. */ i8272_info->fdc_sector = pDrive->imd->track[pDrive->track][i8272_info->fdc_hds].start_sector; if((i8272_info->fdc_sec_len == 0xF8) || (i8272_info->fdc_sec_len > I8272_MAX_N)) { /* Error calculating N or N too large */ sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Illegal sector size N=%d. Reset to 0.\n", PCX, i8272_info->fdc_sec_len); i8272_info->fdc_sec_len = 0; return 0xFF; } i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03); i8272_info->fdc_status[1] = 0; i8272_info->fdc_status[2] = 0; i8272_info->result[0] = i8272_info->fdc_status[0]; i8272_info->result[1] = i8272_info->fdc_status[1]; i8272_info->result[2] = i8272_info->fdc_status[2]; i8272_info->result[3] = pDrive->imd->track[pDrive->track][i8272_info->fdc_hds].logicalCyl[i8272_info->fdc_sector]; /* AGN logicalCyl */ i8272_info->result[4] = pDrive->imd->track[pDrive->track][i8272_info->fdc_hds].logicalHead[i8272_info->fdc_sector]; /* AGN logicalHead */ i8272_info->result[5] = i8272_info->fdc_sector; i8272_info->result[6] = i8272_info->fdc_sec_len; break; case I8272_RECALIBRATE: /* RECALIBRATE */ i8272_info->sel_drive = i8272_info->cmd[1] & 0x03; pDrive = &i8272_info->drive[i8272_info->sel_drive]; if(pDrive->uptr == NULL) { return 0xFF; } pDrive->track = 0; i8272_info->fdc_phase = CMD_PHASE; /* No result phase */ i8272_info->fdc_seek_end = 1; sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Recalibrate: Drive 0x%02x\n", PCX, i8272_info->sel_drive); break; case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; i8272_info->fdc_head = i8272_info->fdc_hds; i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); pDrive = &i8272_info->drive[i8272_info->sel_drive]; if(pDrive->uptr == NULL) { return 0xFF; } if(pDrive->track != i8272_info->cmd[2]) { i8272_info->fdc_seek_end = 1; } else { i8272_info->fdc_seek_end = 0; } i8272_info->fdc_sec_len = i8272_info->cmd[2]; if(i8272_info->fdc_sec_len > I8272_MAX_N) { sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n", PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N); i8272_info->fdc_sec_len = I8272_MAX_N; } i8272_info->fdc_sc = i8272_info->cmd[3]; i8272_info->fdc_gpl = i8272_info->cmd[4]; i8272_info->fdc_fillbyte = i8272_info->cmd[5]; sim_debug(FMT_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x\n", PCX, i8272_info->sel_drive, i8272_info->fdc_mfm ? "MFM" : "FM", pDrive->track, i8272_info->fdc_head, i8272_info->fdc_sec_len, i8272_info->fdc_sc, i8272_info->fdc_gpl, i8272_info->fdc_fillbyte); i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03); i8272_info->fdc_status[1] = 0; i8272_info->fdc_status[2] = 0; i8272_info->fdc_sectorcount = 0; i8272_info->result[0] = i8272_info->fdc_status[0]; i8272_info->result[1] = i8272_info->fdc_status[1]; i8272_info->result[2] = i8272_info->fdc_status[2]; i8272_info->result[3] = pDrive->track; i8272_info->result[4] = i8272_info->fdc_head; /* AGN for now we cannot format with logicalHead */ i8272_info->result[5] = i8272_info->fdc_sector; /* AGN ditto for logicalCyl */ i8272_info->result[6] = i8272_info->fdc_sec_len; break; case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */ sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Sense Interrupt Status\n", PCX); i8272_info->result[0] = i8272_info->fdc_seek_end ? 0x20 : 0x00; /* SEEK_END */ i8272_info->result[0] |= i8272_info->sel_drive; i8272_info->result[1] = pDrive->track; i8272_irq = 0; break; case I8272_SPECIFY: /* SPECIFY */ i8272_info->fdc_srt = 16 - ((i8272_info->cmd[1] & 0xF0) >> 4); i8272_info->fdc_hut = (i8272_info->cmd[1] & 0x0F) * 16; i8272_info->fdc_hlt = ((i8272_info->cmd[2] & 0xFE) >> 1) * 2; i8272_info->fdc_nd = (i8272_info->cmd[2] & 0x01); i8272_info->fdc_phase = CMD_PHASE; /* No result phase */ sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s\n", PCX, i8272_info->fdc_srt, i8272_info->fdc_hut, i8272_info->fdc_hlt, i8272_info->fdc_nd ? "NON-DMA" : "DMA"); break; case I8272_SENSE_DRIVE_STATUS: /* Setup Status3 Byte */ i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); pDrive = &i8272_info->drive[i8272_info->sel_drive]; if(pDrive->uptr == NULL) { return 0xFF; } i8272_info->result[0] = (pDrive->ready) ? DRIVE_STATUS_READY : 0; /* Drive Ready */ if(imdGetSides(pDrive->imd) == 2) { i8272_info->result[0] |= DRIVE_STATUS_TWO_SIDED; /* Two-sided? */ } if(imdIsWriteLocked(pDrive->imd)) { i8272_info->result[0] |= DRIVE_STATUS_WP; /* Write Protected? */ } i8272_info->result[0] |= (i8272_info->fdc_hds & 1) << 2; i8272_info->result[0] |= (i8272_info->sel_drive & 0x03); i8272_info->result[0] |= (pDrive->track == 0) ? DRIVE_STATUS_TRACK0 : 0x00; /* Track 0 */ sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Sense Drive Status = 0x%02x\n", PCX, i8272_info->result[0]); break; case I8272_SEEK: /* SEEK */ i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7; i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; i8272_info->fdc_sk = (i8272_info->cmd[0] & 0x20) >> 5; i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); pDrive = &i8272_info->drive[i8272_info->sel_drive]; if(pDrive->uptr == NULL) { return 0xFF; } pDrive->track = i8272_info->cmd[2]; i8272_info->fdc_head = i8272_info->fdc_hds; /*AGN seek should save the head */ i8272_info->fdc_seek_end = 1; sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s\n", PCX, i8272_info->sel_drive, i8272_info->fdc_mt ? "Multi" : "Single", i8272_info->fdc_mfm ? "MFM" : "FM", i8272_info->cmd[2], i8272_info->fdc_sk ? "True" : "False", i8272_info->fdc_hds ? "True" : "False"); break; default: /* INVALID */ break; } if(i8272_info->fdc_phase == EXEC_PHASE) { switch(i8272_info->cmd[0] & 0x1F) { case I8272_READ_TRACK: printf("I8272: " ADDRESS_FORMAT " Read a track (untested.)" NLP, PCX); i8272_info->fdc_sector = 1; /* Read entire track from sector 1...eot */ case I8272_READ_DATA: case I8272_READ_DELETED_DATA: disk_read = 1; case I8272_WRITE_DATA: case I8272_WRITE_DELETED_DATA: for(;i8272_info->fdc_sector<=i8272_info->fdc_eot;i8272_info->fdc_sector++) { sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " %s Data, sector: %d sector len=%d\n", PCX, disk_read ? "RD" : "WR", i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len); if(pDrive->imd == NULL) { printf(".imd is NULL!" NLP); } if(disk_read) { /* Read sector */ sectRead(pDrive->imd, pDrive->track, i8272_info->fdc_head, i8272_info->fdc_sector, sdata.raw, 128 << i8272_info->fdc_sec_len, &flags, &readlen); for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) { PutByteDMA(i8272_info->fdc_dma_addr, sdata.raw[i]); i8272_info->fdc_dma_addr++; } sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " T:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x\n", PCX, pDrive->track, i8272_info->fdc_head, i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_dma_addr - i); } else { /* Write */ for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) { sdata.raw[i] = GetByteDMA(i8272_info->fdc_dma_addr); i8272_info->fdc_dma_addr++; } sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Data transferred from RAM at 0x%06x\n", PCX, i8272_info->fdc_dma_addr); sectWrite(pDrive->imd, pDrive->track, i8272_info->fdc_head, i8272_info->fdc_sector, sdata.raw, 128 << i8272_info->fdc_sec_len, &flags, &readlen); } i8272_info->result[5] = i8272_info->fdc_sector; i8272_info->result[1] = 0x80; } break; case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ for(i8272_info->fdc_sector = 1;i8272_info->fdc_sector<=i8272_info->fdc_sc;i8272_info->fdc_sector++) { sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Format Track %d, Sector=%d, len=%d\n", PCX, pDrive->track, i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len); if(i8272_info->fdc_sectorcount >= I8272_MAX_SECTOR) { sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Illegal sector count\n", PCX); i8272_info->fdc_sectorcount = 0; } i8272_info->fdc_sectormap[i8272_info->fdc_sectorcount] = i8272_info->fdc_sector; i8272_info->fdc_sectorcount++; if(i8272_info->fdc_sectorcount == i8272_info->fdc_sc) { trackWrite(pDrive->imd, pDrive->track, i8272_info->fdc_head, i8272_info->fdc_sc, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sectormap, i8272_info->fdc_mfm ? 3 : 0, i8272_info->fdc_fillbyte, &flags); /* Recalculate disk size */ pDrive->uptr->capac = sim_fsize(pDrive->uptr->fileref); } } break; case I8272_SCAN_LOW_EQUAL: /* SCAN LOW OR EQUAL */ case I8272_SCAN_HIGH_EQUAL: /* SCAN HIGH OR EQUAL */ case I8272_SCAN_EQUAL: /* SCAN EQUAL */ sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " Scan Data\n", PCX); sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " ERROR: Scan not implemented.\n", PCX); break; case I8272_READ_ID: /* READ ID */ sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x " "C=%d H=%d R=%02x N=%d\n", PCX, i8272_info->sel_drive, i8272_info->result[0], i8272_info->result[1], i8272_info->result[2], i8272_info->result[3], i8272_info->result[4], i8272_info->result[5], i8272_info->result[6]); break; default: break; } } if(i8272_info->result_len != 0) { i8272_info->fdc_phase ++; } else { i8272_info->fdc_phase = CMD_PHASE; } i8272_info->result_index = 0; if((i8272_info->cmd[0] & 0x1F) != I8272_SENSE_INTR_STATUS) { raise_i8272_interrupt(); } } break; } cData = 0x00; return (cData); }