Example #1
0
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 */
Example #2
0
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);
}