Esempio n. 1
0
File: fdc.c Progetto: AreaScout/vice
static BYTE fdc_do_job_(unsigned int fnum, int buf,
                        unsigned int drv, BYTE job, BYTE *header)
{
#endif
    unsigned int dnr;
    BYTE rc;
    int ret;
    int i;
    disk_addr_t dadr;
    BYTE *base;
    BYTE sector_data[256];
    BYTE disk_id[2];
    drive_t *drive;

    dadr.track = header[2];
    dadr.sector = header[3];

    /* determine drive/disk image to use */
    if (drv < fdc[fnum].num_drives) {
        dnr = fnum + drv;
    } else {
        /* drive 1 on a single disk drive */
        return FDC_ERR_SYNC;
    }

    rc = 0;
    base = &(fdc[fnum].buffer[(buf + 1) << 8]);

#ifdef FDC_DEBUG
    log_message(fdc_log, "do job %02x, buffer %d ($%04x): d%d t%d s%d, "
                "image=%p, type=%04d",
                job, buf, (buf + 1) << 8, dnr, dadr.track, dadr.sector,
                fdc[dnr].image,
                fdc[dnr].image ? fdc[dnr].image->type : 0);
#endif

    if (fdc[dnr].image == NULL && job != 0xd0) {
#ifdef FDC_DEBUG
        log_message(fdc_log, "dnr=%d, image=NULL -> no disk!", dnr);
#endif
        return FDC_ERR_SYNC;
    }

    file_system_bam_get_disk_id(dnr + 8, disk_id);

    switch (job) {
        case 0x80:        /* read */
            if (header[0] != disk_id[0] || header[1] != disk_id[1]) {
                rc = FDC_ERR_ID;
                break;
            }
            ret = disk_image_read_sector(fdc[dnr].image, sector_data, &dadr);
            if (ret < 0) {
                log_error(LOG_DEFAULT,
                          "Cannot read T:%d S:%d from disk image.",
                          dadr.track, dadr.sector);
                rc = FDC_ERR_DRIVE;
            } else {
                memcpy(base, sector_data, 256);
                rc = FDC_ERR_OK;
            }
            break;
        case 0x90:        /* write */
            if (header[0] != disk_id[0] || header[1] != disk_id[1]) {
                rc = FDC_ERR_ID;
                break;
            }
            if (fdc[dnr].image->read_only) {
                rc = FDC_ERR_WPROT;
                break;
            }
            memcpy(sector_data, base, 256);
            ret = disk_image_write_sector(fdc[dnr].image, sector_data, &dadr);
            if (ret < 0) {
                log_error(LOG_DEFAULT,
                          "Could not update T:%d S:%d on disk image.",
                          dadr.track, dadr.sector);
                rc = FDC_ERR_DRIVE;
            } else {
                rc = FDC_ERR_OK;
            }
            break;
        case 0xA0:        /* verify */
            if (header[0] != disk_id[0] || header[1] != disk_id[1]) {
                rc = FDC_ERR_ID;
                break;
            }
            ret = disk_image_read_sector(fdc[dnr].image, sector_data, &dadr);
            if (ret < 0) {
                log_error(LOG_DEFAULT,
                          "Cannot read T:%d S:%d from disk image.",
                          dadr.track, dadr.sector);
                rc = FDC_ERR_DRIVE;
            } else {
                rc = FDC_ERR_OK;
                for (i = 0; i < 256; i++) {
                    if (fnum) {
                        if (sector_data[i] != base[i]) {
                            rc = FDC_ERR_VERIFY;
                        }
                    } else {
                        if (sector_data[i] != base[i]) {
                            rc = FDC_ERR_VERIFY;
                        }
                    }
                }
            }
            break;
        case 0xB0:        /* seek - move to track and read ID(?) */
            header[0] = disk_id[0];
            header[1] = disk_id[1];
            /* header[2] = fdc[dnr].last_track; */
            dadr.track = header[2];
            header[3] = 1;
            rc = FDC_ERR_OK;
            break;
        case 0xC0:        /* bump (to track 0 and back to 18?) */
            dadr.track = 1;
            if (DOS_IS_20(fdc[fnum].drive_type)) {
                header[2] = 18;
            }
            rc = FDC_ERR_OK;
            break;
        case 0xD0:        /* jump to buffer - but we do not emulate FDC CPU */
#ifdef FDC_DEBUG
            log_message(fdc_log, "exec buffer %d ($%04x): %02x %02x %02x %02x %02x",
                        buf, (buf + 1) << 8,
                        base[0], base[1], base[2], base[3]
                        );
#endif
            if (DOS_IS_40(fdc[fnum].drive_type)
                || DOS_IS_30(fdc[fnum].drive_type)) {
                if (!memcmp(fdc[fnum].iprom + 0x12f8, &fdc[fnum].buffer[0x100],
                            0x100)) {
                    fdc[fnum].fdc_state = FDC_RESET2;
                    return 0;
                }
            }
            if (DOS_IS_80(fdc[fnum].drive_type)) {
                static const BYTE jumpseq[] = {
                    0x78, 0x6c, 0xfc, 0xff
                };
                if (!memcmp(jumpseq, &fdc[fnum].buffer[0x100], 4)) {
                    fdc[fnum].fdc_state = FDC_RESET0;
                    return 0;
                }
            }
            rc = FDC_ERR_DRIVE;
            break;
        case 0xE0:        /* execute when drive/head ready. We do not emulate
                             FDC CPU, but we handle the case when a disk is
                             formatted */
            /* we have to check for standard format code that is copied
               to buffers 0-3 */
            if (DOS_IS_80(fdc[fnum].drive_type)) {
                rc = fdc_do_format_D80(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header);
            } else
            if (DOS_IS_40(fdc[fnum].drive_type)
                || DOS_IS_30(fdc[fnum].drive_type)) {
                rc = fdc_do_format_D40(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header);
            } else
            if (DOS_IS_20(fdc[fnum].drive_type)) {
                rc = fdc_do_format_D20(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header);
            } else {
                rc = FDC_ERR_DRIVE;
            }
            break;
        case 0xF0:
            if (header[0] != disk_id[0] || header[1] != disk_id[1]) {
                rc = FDC_ERR_ID;
                break;
            }
            /* try to read block header from disk */
            rc = FDC_ERR_OK;
            break;
    }

    drive = drive_context[dnr]->drive;
    drive->current_half_track = 2 * dadr.track;
    fdc[dnr].last_track = dadr.track;
    fdc[dnr].last_sector = dadr.sector;

    return rc;
}
Esempio n. 2
0
static void int_fdc(CLOCK offset, void *data)
{
    CLOCK rclk;
    int i, j;
    drive_t *drive;
    unsigned int fnum;
    drive_context_t *drv = (drive_context_t *)data;

    fnum = drv->mynumber;
    rclk = drive_clk[fnum] - offset;

#ifdef FDC_DEBUG
    if (fdc[fnum].fdc_state < FDC_RUN) {
        static int old_state[NUM_FDC] = { -1, -1 };
        if (fdc[fnum].fdc_state != old_state[fnum])
            log_message(fdc_log, "int_fdc%d %d: state=%d\n",
                                        fnum, rclk, fdc[fnum].fdc_state);
        old_state[fnum] = fdc[fnum].fdc_state;
    }
#endif

    switch(fdc[fnum].fdc_state) {
      case FDC_RESET0:
        drive = drive_context[fnum]->drive;
        if (DOS_IS_80(fdc[fnum].drive_type)) {
            drive->current_half_track = 2 * 38;
            fdc[fnum].buffer[0] = 2;
        } else {
            drive->current_half_track = 2 * 18;
            fdc[fnum].buffer[0] = 0x3f;
        }

        if (DOS_IS_20(fdc[fnum].drive_type)) {
            fdc[fnum].fdc_state = FDC_RUN;
        } else {
            fdc[fnum].fdc_state++;
        }
        fdc[fnum].alarm_clk = rclk + 2000;
        alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk);
        break;
      case FDC_RESET1:
        if (DOS_IS_80(fdc[fnum].drive_type)) {
            if (fdc[fnum].buffer[0] == 0) {
                fdc[fnum].buffer[0] = 1;
                fdc[fnum].fdc_state++;
            }
        } else {
            if (fdc[fnum].buffer[3] == 0xd0) {
                fdc[fnum].buffer[3] = 0;
                fdc[fnum].fdc_state++;
            }
        }
        fdc[fnum].alarm_clk = rclk + 2000;
        alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk);
        break;
      case FDC_RESET2:
        if (DOS_IS_80(fdc[fnum].drive_type)) {
            if (fdc[fnum].buffer[0] == 0) {
                /* emulate routine written to buffer RAM */
                fdc[fnum].buffer[1] = 0x0e;
                fdc[fnum].buffer[2] = 0x2d;
                /* number of sides on disk drive */
                fdc[fnum].buffer[0xac] =
                    (fdc[fnum].drive_type == DRIVE_TYPE_8050) ? 1 : 2;
                /* 0 = 4040 (2A), 1 = 8x80 (2C) drive type */
                fdc[fnum].buffer[0xea] = 1;
                fdc[fnum].buffer[0xee] = 5;     /* 3 for 4040, 5 for 8x50 */
                fdc[fnum].buffer[0] = 3;        /* 5 for 4040, 3 for 8x50 */

                fdc[fnum].fdc_state = FDC_RUN;
                fdc[fnum].alarm_clk = rclk + 10000;
            } else {
                fdc[fnum].alarm_clk = rclk + 2000;
            }
        } else
        if (DOS_IS_40(fdc[fnum].drive_type)
            || DOS_IS_30(fdc[fnum].drive_type)
            ) {
            if (fdc[fnum].buffer[0] == 0) {
                fdc[fnum].buffer[0] = 0x0f;
                fdc[fnum].fdc_state = FDC_RUN;
                fdc[fnum].alarm_clk = rclk + 10000;
            } else {
                fdc[fnum].alarm_clk = rclk + 2000;
            }
        }
        alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk);
        break;
    case FDC_RUN:
        /* check write protect switch */
        if (fdc[fnum].wps_change) {
            fdc[fnum].buffer[0xA6] = 1;
            fdc[fnum].wps_change--;
#ifdef FDC_DEBUG
            log_message(fdc_log, "Detect Unit %d Drive %d wps change",
                        fnum + 8, fnum);
#endif
        }
        if (fdc[fnum].num_drives == 2) {
            if (fdc[mk_drive1(fnum)].wps_change) {
                fdc[fnum].buffer[0xA6 + 1] = 1;
                fdc[mk_drive1(fnum)].wps_change--;
#ifdef FDC_DEBUG
                log_message(fdc_log, "Detect Unit %d Drive 1 wps change",
                            fnum + 8);
#endif
            }
        }

        /* check buffers */
        for (i=14; i >= 0; i--) {
            /* job there? */
            if (fdc[fnum].buffer[i + 3] > 127) {
                /* pointer to buffer/block header:
                    +0 = ID1
                    +1 = ID2
                    +2 = Track
                    +3 = Sector
                */
                j = 0x21 + (i << 3);
#ifdef FDC_DEBUG
                log_message(fdc_log, "D/Buf %d/%x: Job code %02x t:%02d s:%02d",                        fnum, i, fdc[fnum].buffer[i+3],
                        fdc[fnum].buffer[j+2],fdc[fnum].buffer[j+3]);
#endif
                fdc[fnum].buffer[i + 3] =
                        fdc_do_job(fnum,                        /* FDC# */
                                i,                              /* buffer# */
                                (unsigned int)fdc[fnum].buffer[i+3] & 1,
                                /* drive */
                                (BYTE)(fdc[fnum].buffer[i+3] & 0xfe),
                                                                /* job code */
                                &(fdc[fnum].buffer[j])          /* header */
                        );
            }
        }
        /* check "move head", by half tracks I guess... */
        for (i = 0; i < 2; i++) {
            if (fdc[fnum].buffer[i + 0xa1]) {
#ifdef FDC_DEBUG
                log_message(fdc_log, "D %d: move head %d",
                            fnum, fdc[fnum].buffer[i + 0xa1]);
#endif
                fdc[fnum].buffer[i + 0xa1] = 0;
            }
        }
        fdc[fnum].alarm_clk = rclk + 30000;
        alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk);
        /* job loop */
        break;
    }
}