t_stat ssem_load_dmp (FILE *fi) { C[1] = 0; if (sim_fread(A, sizeof(int32), 1, fi) != 1 || sim_fread(C, sizeof(uint32), 1, fi) != 1 || sim_fread(S, sizeof(uint32), MEMSIZE, fi) != MEMSIZE) { return SCPE_IOERR; } return SCPE_OK; }
int32 dsk12(const int32 port, const int32 io, const int32 data) { int32 i, rtn; UNIT *uptr; if (current_disk >= NUM_OF_DSK) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; sim_debug(VERBOSE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " Attempt of %s 0x0a on unattached disk - ignored.\n", current_disk, PCX, selectInOut(io)); } return 0; } /* now current_disk < NUM_OF_DSK */ in9_count = 0; uptr = dsk_dev.units + current_disk; if (io == 0) { if (current_byte[current_disk] >= DSK_SECTSIZE) { /* physically read the sector */ sim_debug(READ_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " IN 0x0a (READ) D%d T%d S%d\n", current_disk, PCX, current_disk, current_track[current_disk], current_sector[current_disk]); for (i = 0; i < DSK_SECTSIZE; i++) dskbuf[i] = 0; if (dskseek(uptr)) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; sim_debug(VERBOSE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d\n", current_disk, PCX, current_disk, current_track[current_disk], current_sector[current_disk]); } } rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); if (rtn != DSK_SECTSIZE) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; sim_debug(VERBOSE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d\n", current_disk, PCX, current_disk, current_track[current_disk], current_sector[current_disk]); } } current_byte[current_disk] = 0; } return dskbuf[current_byte[current_disk]++] & 0xff; } else { if (current_byte[current_disk] >= DSK_SECTSIZE) writebuf(); /* from above we have that current_disk < NUM_OF_DSK */ else { dirty = TRUE; /* this guarantees for the next call to writebuf that current_disk < NUM_OF_DSK */ dskbuf[current_byte[current_disk]++] = data & 0xff; } return 0; /* ignored since OUT */ } }
/* * Initiate a compare operation on a disk. */ static enum dpio_status DPDiskIOCompare(UNIT *uptr) { struct dpio_unit *iou = (struct dpio_unit *)uptr->up7; uint16 numcy = ((uptr->flags & UNIT_854) != 0) ? DP_854CY : DP_853CY; uint32 lba = DPLBA(iou); int i; if (iou->cylinder >= numcy) return DPIO_ADDRERR; /* * Report any error in the underlying container infrastructure as an * address error. */ if (sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET) || (sim_fread(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD)) return DPIO_ADDRERR; for (i = 0; i < DP_NUMWD; i++) { if (iou->buf[i] != LoadFromMem(iou->CWA)) return DPIO_MISMATCH; iou->CWA++; if (iou->CWA == iou->LWA) { DPDiskIOIncSector(iou); return DPIO_DONE; } } DPDiskIOIncSector(iou); return DPIO_MORE; }
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max) { uint32 f = MT_GET_FMT (uptr); t_mtrlnt i, tbc, rbc; t_addr opos; t_stat st; opos = uptr->pos; /* old position */ if (st = sim_tape_rdlntf (uptr, &tbc)) /* read rec lnt */ return st; *bc = rbc = MTR_L (tbc); /* strip error flag */ if (rbc > max) { /* rec out of range? */ MT_SET_PNU (uptr); uptr->pos = opos; return MTSE_INVRL; } i = sim_fread (buf, sizeof (uint8), rbc, uptr->fileref);/* read record */ if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); uptr->pos = opos; return sim_tape_ioerr (uptr); } for ( ; i < rbc; i++) /* fill with 0's */ buf[i] = 0; if (f == MTUF_F_P7B) /* p7b? strip SOR */ buf[0] = buf[0] & P7B_DPAR; return (MTR_F (tbc)? MTSE_RECE: MTSE_OK); }
int32 fdcdrv(int32 io, int32 data) { static long pos; char buf[128]; if (io) { /* write to DC-4 drive register */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdrv: Drive selected %d cur_dsk=%d", data & 0x03, cur_dsk); if (cur_dsk == (data & 0x03)) return 0; /* already selected */ cur_dsk = data & 0x03; /* only 2 drive select bits */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdrv: Drive set to %d", cur_dsk); if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) { dsk_unit[cur_dsk].u3 |= WRPROT; /* set 1797 WPROT */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdrv: Drive write protected"); } else { dsk_unit[cur_dsk].u3 &= ~WRPROT; /* set 1797 not WPROT */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdrv: Drive NOT write protected"); } pos = 0x200; /* Read in SIR */ if (dsk_dev.dctrl & DEBUG_read) printf("\nfdcdrv: Read pos = %ld ($%04X)", pos, (unsigned int) pos); sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ sim_fread(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ spt = *(uint8 *)(dsk_unit[cur_dsk].filebuf + MAXSEC) & 0xFF; heds = 0; cpd = *(uint8 *)(dsk_unit[cur_dsk].filebuf + MAXCYL) & 0xFF; trksiz = spt * SECSIZ; dsksiz = trksiz * cpd; if (dsk_dev.dctrl & DEBUG_read) printf("\nfdcdrv: spt=%d heds=%d cpd=%d trksiz=%d dsksiz=%d flags=%08X u3=%08X", spt, heds, cpd, trksiz, dsksiz, dsk_unit[cur_dsk].flags, dsk_unit[cur_dsk].u3); return 0; } else { /* read from DC-4 drive register */ if (dsk_dev.dctrl & DEBUG_read) printf("\nfdcdrv: Drive read as %02X", intrq); return intrq; } }
uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map) { t_addr tpos; t_tpclnt bc; uint32 i, objc; if ((uptr == NULL) || (uptr->fileref == NULL)) return 0; for (objc = 0, tpos = 0;; ) { sim_fseek (uptr->fileref, tpos, SEEK_SET); i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref); if (i == 0) break; if (map) map[objc] = tpos; objc++; tpos = tpos + ((bc + 1) & ~1) + sizeof (t_tpclnt); } if (map) map[objc] = tpos; return objc; }
/* Read a sector from an IMD image. */ t_stat sectRead(DISK_INFO *myDisk, uint32 Cyl, uint32 Head, uint32 Sector, uint8 *buf, uint32 buflen, uint32 *flags, uint32 *readlen) { uint32 sectorFileOffset; uint8 sectRecordType; uint8 start_sect; *readlen = 0; *flags = 0; /* Check parameters */ if(myDisk == NULL) { *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } if(sectSeek(myDisk, Cyl, Head) != SCPE_OK) { *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } if(Sector > myDisk->track[Cyl][Head].nsects) { sim_debug(myDisk->debugmask, myDisk->device, "%s: invalid sector\n", __FUNCTION__); *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } if(buflen < myDisk->track[Cyl][Head].sectsize) { sim_printf("%s: Reading C:%d/H:%d/S:%d, len=%d: user buffer too short, need %d\n", __FUNCTION__, Cyl, Head, Sector, buflen, myDisk->track[Cyl][Head].sectsize); *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } start_sect = myDisk->track[Cyl][Head].start_sector; sectorFileOffset = myDisk->track[Cyl][Head].sectorOffsetMap[Sector-start_sect]; sim_debug(myDisk->debugmask, myDisk->device, "Reading C:%d/H:%d/S:%d, len=%d, offset=0x%08x\n", Cyl, Head, Sector, buflen, sectorFileOffset); sim_fseek(myDisk->file, sectorFileOffset-1, SEEK_SET); sectRecordType = fgetc(myDisk->file); switch(sectRecordType) { case SECT_RECORD_UNAVAILABLE: /* Data could not be read from the original media */ *flags |= IMD_DISK_IO_ERROR_GENERAL; break; case SECT_RECORD_NORM_ERR: /* Normal Data with read error */ case SECT_RECORD_NORM_DAM_ERR: /* Normal Data with deleted address mark with read error */ *flags |= IMD_DISK_IO_ERROR_CRC; case SECT_RECORD_NORM: /* Normal Data */ case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */ /* sim_debug(myDisk->debugmask, myDisk->device, "Uncompressed Data\n"); */ if (sim_fread(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file) != myDisk->track[Cyl][Head].sectsize) { sim_printf("SIM_IMD[%s]: sim_fread error for SECT_RECORD_NORM_DAM.\n", __FUNCTION__); } *readlen = myDisk->track[Cyl][Head].sectsize; break; case SECT_RECORD_NORM_COMP_ERR: /* Compressed Normal Data */ case SECT_RECORD_NORM_DAM_COMP_ERR: /* Compressed Normal Data with deleted address mark */ *flags |= IMD_DISK_IO_ERROR_CRC; case SECT_RECORD_NORM_COMP: /* Compressed Normal Data */ case SECT_RECORD_NORM_DAM_COMP: /* Compressed Normal Data with deleted address mark */ /* sim_debug(myDisk->debugmask, myDisk->device, "Compressed Data\n"); */ memset(buf, fgetc(myDisk->file), myDisk->track[Cyl][Head].sectsize); *readlen = myDisk->track[Cyl][Head].sectsize; *flags |= IMD_DISK_IO_COMPRESSED; break; default: sim_printf("ERROR: unrecognized sector record type %d\n", sectRecordType); break; } /* Set flags for deleted address mark. */ switch(sectRecordType) { case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */ case SECT_RECORD_NORM_DAM_ERR: /* Normal Data with deleted address mark with read error */ case SECT_RECORD_NORM_DAM_COMP: /* Compressed Normal Data with deleted address mark */ case SECT_RECORD_NORM_DAM_COMP_ERR: /* Compressed Normal Data with deleted address mark */ *flags |= IMD_DISK_IO_DELETED_ADDR_MARK; default: break; } return(SCPE_OK); }
/* Parse an IMD image. This sets up sim_imd to be able to do sector read/write and * track write. */ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose) { uint8 comment[256]; uint8 sectorMap[256]; uint8 sectorHeadMap[256]; uint8 sectorCylMap[256]; uint32 sectorSize, sectorHeadwithFlags, sectRecordType; uint32 i; uint8 start_sect; uint32 TotalSectorCount = 0; IMD_HEADER imd; if(myDisk == NULL) { return (SCPE_OPENERR); } memset(myDisk->track, 0, (sizeof(TRACK_INFO)*MAX_CYL*MAX_HEAD)); if (commentParse(myDisk, comment, sizeof(comment)) != SCPE_OK) { return (SCPE_OPENERR); } if(isVerbose) sim_printf("%s\n", comment); myDisk->nsides = 1; myDisk->ntracks = 0; myDisk->flags = 0; /* Make sure all flags are clear. */ if(feof(myDisk->file)) { sim_printf("SIM_IMD: Disk image is blank, it must be formatted.\n"); return (SCPE_OPENERR); } do { sim_debug(myDisk->debugmask, myDisk->device, "start of track %d at file offset %ld\n", myDisk->ntracks, ftell(myDisk->file)); sim_fread(&imd, 1, 5, myDisk->file); if (feof(myDisk->file)) break; sectorSize = 128 << imd.sectsize; sectorHeadwithFlags = imd.head; /*AGN save the head and flags */ imd.head &= 1 ; /*AGN mask out flag bits to head 0 or 1 */ sim_debug(myDisk->debugmask, myDisk->device, "Track %d:\n", myDisk->ntracks); sim_debug(myDisk->debugmask, myDisk->device, "\tMode=%d, Cyl=%d, Head=%d(%d), #sectors=%d, sectsize=%d (%d bytes)\n", imd.mode, imd.cyl, sectorHeadwithFlags, imd.head, imd.nsects, imd.sectsize, sectorSize); if (!headerOk(imd)) { sim_printf("SIM_IMD: Corrupt header.\n"); return (SCPE_OPENERR); } if((imd.head + 1) > myDisk->nsides) { myDisk->nsides = imd.head + 1; } myDisk->track[imd.cyl][imd.head].mode = imd.mode; myDisk->track[imd.cyl][imd.head].nsects = imd.nsects; myDisk->track[imd.cyl][imd.head].sectsize = sectorSize; if (sim_fread(sectorMap, 1, imd.nsects, myDisk->file) != imd.nsects) { sim_printf("SIM_IMD: Corrupt file [Sector Map].\n"); return (SCPE_OPENERR); } myDisk->track[imd.cyl][imd.head].start_sector = imd.nsects; sim_debug(myDisk->debugmask, myDisk->device, "\tSector Map: "); for(i=0;i<imd.nsects;i++) { sim_debug(myDisk->debugmask, myDisk->device, "%d ", sectorMap[i]); if(sectorMap[i] < myDisk->track[imd.cyl][imd.head].start_sector) { myDisk->track[imd.cyl][imd.head].start_sector = sectorMap[i]; } } sim_debug(myDisk->debugmask, myDisk->device, ", Start Sector=%d", myDisk->track[imd.cyl][imd.head].start_sector); if(sectorHeadwithFlags & IMD_FLAG_SECT_HEAD_MAP) { if (sim_fread(sectorHeadMap, 1, imd.nsects, myDisk->file) != imd.nsects) { sim_printf("SIM_IMD: Corrupt file [Sector Head Map].\n"); return (SCPE_OPENERR); } sim_debug(myDisk->debugmask, myDisk->device, "\tSector Head Map: "); for(i=0;i<imd.nsects;i++) { sim_debug(myDisk->debugmask, myDisk->device, "%d ", sectorHeadMap[i]); } sim_debug(myDisk->debugmask, myDisk->device, "\n"); } else { /* Default Head is physical head for each sector */ for(i=0;i<imd.nsects;i++) { sectorHeadMap[i] = imd.head; }; } if(sectorHeadwithFlags & IMD_FLAG_SECT_CYL_MAP) { if (sim_fread(sectorCylMap, 1, imd.nsects, myDisk->file) != imd.nsects) { sim_printf("SIM_IMD: Corrupt file [Sector Cyl Map].\n"); return (SCPE_OPENERR); } sim_debug(myDisk->debugmask, myDisk->device, "\tSector Cyl Map: "); for(i=0;i<imd.nsects;i++) { sim_debug(myDisk->debugmask, myDisk->device, "%d ", sectorCylMap[i]); } sim_debug(myDisk->debugmask, myDisk->device, "\n"); } else { /* Default Cyl Map is physical cylinder for each sector */ for(i=0;i<imd.nsects;i++) { sectorCylMap[i] = imd.cyl; } } sim_debug(myDisk->debugmask, myDisk->device, "\nSector data at offset 0x%08lx\n", ftell(myDisk->file)); /* Build the table with location 0 being the start sector. */ start_sect = myDisk->track[imd.cyl][imd.head].start_sector; /* Now read each sector */ for(i=0;i<imd.nsects;i++) { TotalSectorCount++; sim_debug(myDisk->debugmask, myDisk->device, "Sector Phys: %d/Logical: %d: %d bytes: ", i, sectorMap[i], sectorSize); sectRecordType = fgetc(myDisk->file); /* AGN Logical head mapping */ myDisk->track[imd.cyl][imd.head].logicalHead[i] = sectorHeadMap[i]; /* AGN Logical cylinder mapping */ myDisk->track[imd.cyl][imd.head].logicalCyl[i] = sectorCylMap[i]; switch(sectRecordType) { case SECT_RECORD_UNAVAILABLE: /* Data could not be read from the original media */ if (sectorMap[i]-start_sect < MAX_SPT) myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = 0xBADBAD; else { sim_printf("SIM_IMD: ERROR: Illegal sector offset %d\n", sectorMap[i]-start_sect); return (SCPE_OPENERR); } break; case SECT_RECORD_NORM: /* Normal Data */ case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */ case SECT_RECORD_NORM_ERR: /* Normal Data with read error */ case SECT_RECORD_NORM_DAM_ERR: /* Normal Data with deleted address mark with read error */ /* sim_debug(myDisk->debugmask, myDisk->device, "Uncompressed Data\n"); */ if (sectorMap[i]-start_sect < MAX_SPT) { myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = ftell(myDisk->file); sim_fseek(myDisk->file, sectorSize, SEEK_CUR); } else { sim_printf("SIM_IMD: ERROR: Illegal sector offset %d\n", sectorMap[i]-start_sect); return (SCPE_OPENERR); } break; case SECT_RECORD_NORM_COMP: /* Compressed Normal Data */ case SECT_RECORD_NORM_DAM_COMP: /* Compressed Normal Data with deleted address mark */ case SECT_RECORD_NORM_COMP_ERR: /* Compressed Normal Data */ case SECT_RECORD_NORM_DAM_COMP_ERR: /* Compressed Normal Data with deleted address mark */ if (sectorMap[i]-start_sect < MAX_SPT) { myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = ftell(myDisk->file); myDisk->flags |= FD_FLAG_WRITELOCK; /* Write-protect the disk if any sectors are compressed. */ if (1) { uint8 cdata = fgetc(myDisk->file); sim_debug(myDisk->debugmask, myDisk->device, "Compressed Data = 0x%02x\n", cdata); } } else { sim_printf("SIM_IMD: ERROR: Illegal sector offset %d\n", sectorMap[i]-start_sect); return (SCPE_OPENERR); } break; default: sim_printf("SIM_IMD: ERROR: unrecognized sector record type %d\n", sectRecordType); return (SCPE_OPENERR); break; } sim_debug(myDisk->debugmask, myDisk->device, "\n"); } myDisk->ntracks++; } while (!feof(myDisk->file)); sim_debug(myDisk->debugmask, myDisk->device, "Processed %d sectors\n", TotalSectorCount); for(i=0;i<myDisk->ntracks;i++) { uint8 j; sim_debug(myDisk->verbosedebugmask, myDisk->device, "Track %02d: ", i); for(j=0;j<imd.nsects;j++) { sim_debug(myDisk->verbosedebugmask, myDisk->device, "0x%06x ", myDisk->track[i][0].sectorOffsetMap[j]); } sim_debug(myDisk->verbosedebugmask, myDisk->device, "\n"); } if(myDisk->flags & FD_FLAG_WRITELOCK) { sim_printf("Disk write-protected because the image contains compressed sectors. Use IMDU to uncompress.\n"); } return SCPE_OK; }
int32 fdccmd(int32 io, int32 data) { static int32 val = 0, val1 = NOTRDY, i; static long pos; UNIT *uptr; if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ cur_flg[cur_dsk] |= NOTRDY; /* set not ready flag */ printf("Drive %d is not attached\n\r", cur_dsk); return 0; } else { cur_flg[cur_dsk] &= ~NOTRDY; /* clear not ready flag */ } uptr = dsk_dev.units + cur_dsk; /* get virtual drive address */ if (io) { /* write command to fdc */ switch(data) { case 0x8C: /* read command */ case 0x9C: #if DEBUG > 0 printf("Read of disk %d, track %d, sector %d\n\r", cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); #endif pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); #if DEBUG > 0 printf("Read pos = %ld ($%04X)\n\r", pos, pos); #endif sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ sim_fread(dskbuf, 256, 1, uptr -> fileref); /* read in buffer */ cur_flg[cur_dsk] |= BUSY | DRQ; /* set DRQ & BUSY */ i = cur_byt[cur_dsk] = 0; /* clear counter */ break; case 0xAC: /* write command */ #if DEBUG > 0 printf("Write of disk %d, track %d, sector %d\n\r", cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); #endif if (cur_flg[cur_dsk] & WRPROT) { printf("Drive %d is write-protected\n\r", cur_dsk); } else { pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); #if DEBUG > 1 printf("Write pos = %ld ($%04X)\n\r", pos, pos); #endif sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ dptr = uptr; /* save pointer for actual write */ cur_flg[cur_dsk] |= BUSY | DRQ;/* set DRQ & BUSY */ i = cur_byt[cur_dsk] = 0; /* clear counter */ } break; case 0x18: /* seek command */ case 0x1B: cur_trk[cur_dsk] = fdcbyte; /* set track */ cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ #if DEBUG > 0 printf("Seek of disk %d, track %d\n\r", cur_dsk, fdcbyte); #endif break; case 0x0B: /* restore command */ cur_trk[cur_dsk] = 0; /* home the drive */ cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ #if DEBUG > 0 printf("Drive %d homed\n\r", cur_dsk); #endif break; default: printf("Unknown FDC command %02XH\n\r", data); } } else { /* read status from fdc */ val = cur_flg[cur_dsk]; /* set return value */ if (val1 == 0 && val == 0x03) /* delay BUSY going high */ val = 0x02; /* set DRQ first */ if (val != val1) { /* now allow BUSY after on read */ val1 = val; #if DEBUG > 0 printf("Drive %d status=%02X\n\r", cur_dsk, cur_flg[cur_dsk]); #endif } } return val; }
#ifdef USE_VGI if (rtn != MFDC_SECTOR_LEN) #else rtn = sim_fread(sdata.u.data, 1, 256, (pDrive->uptr)->fileref);
t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc) { uint8 c; t_bool all_eof; uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; t_tpclnt tpcbc; MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ switch (f) { /* switch on fmt */ case MTUF_F_STD: case MTUF_F_E11: do { sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ sbc = MTR_L (*bc); /* save rec lnt */ if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); /* pos not upd */ return sim_tape_ioerr (uptr); } if (feof (uptr->fileref) || (*bc == MTR_EOM)) { /* eof or eom? */ MT_SET_PNU (uptr); /* pos not upd */ return MTSE_EOM; } uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over rec lnt */ if (*bc == MTR_TMK) /* tape mark? */ return MTSE_TMK; if (*bc == MTR_FHGAP) { /* half gap? */ uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2; /* half space fwd */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* resync */ } else if (*bc != MTR_GAP) uptr->pos = uptr->pos + sizeof (t_mtrlnt) + /* spc over record */ ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); } while ((*bc == MTR_GAP) || (*bc == MTR_FHGAP)); break; case MTUF_F_TPC: sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref); *bc = tpcbc; /* save rec lnt */ if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); /* pos not upd */ return sim_tape_ioerr (uptr); } if (feof (uptr->fileref)) { /* eof? */ MT_SET_PNU (uptr); /* pos not upd */ return MTSE_EOM; } uptr->pos = uptr->pos + sizeof (t_tpclnt); /* spc over reclnt */ if (tpcbc == TPC_TMK) /* tape mark? */ return MTSE_TMK; uptr->pos = uptr->pos + ((tpcbc + 1) & ~1); /* spc over record */ break; case MTUF_F_P7B: for (sbc = 0, all_eof = 1; ; sbc++) { /* loop thru record */ sim_fread (&c, sizeof (uint8), 1, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); /* pos not upd */ return sim_tape_ioerr (uptr); } if (feof (uptr->fileref)) { /* eof? */ if (sbc == 0) /* no data? eom */ return MTSE_EOM; break; /* treat like eor */ } if ((sbc != 0) && (c & P7B_SOR)) /* next record? */ break; if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0; } *bc = sbc; /* save rec lnt */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ uptr->pos = uptr->pos + sbc; /* spc over record */ if (all_eof) /* tape mark? */ return MTSE_TMK; break; default: return MTSE_FMT; } return MTSE_OK; }
static uint8 MFDC_Read(const uint32 Addr) { uint8 cData; MFDC_DRIVE_INFO *pDrive; int32 rtn; cData = 0x00; pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; switch(Addr & 0x3) { case 0: if(mfdc_info->read_in_progress == FALSE) { pDrive->sector_wait_count++; if(pDrive->sector_wait_count > 10) { pDrive->sector++; pDrive->sector &= 0x0F; /* Max of 16 sectors */ mfdc_info->wr_latch = 0; /* on new sector, disable the write latch */ DBG_PRINT(("Head over sector %d" NLP, pDrive->sector)); pDrive->sector_wait_count = 0; } } cData = (pDrive->sector) & 0xF; /* [3:0] current sector */ cData |= (JUMPER_W10 << 4); cData |= ((~JUMPER_W9) & 1) << 5; cData |= (0 << 6); /* Sector Interrupt Flag, reset by RESET command or Interrupt Disable */ cData |= (1 << 7); /* Sector Flag */ mfdc_info->xfr_flag = 1; /* Drive has data */ mfdc_info->datacount = 0; sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x\n", PCX, cData); break; case 1: cData = (mfdc_info->sel_drive & 0x3); /* [1:0] selected drive */ cData |= (!mfdc_info->selected << 2); /* [2] drive is selected */ cData |= (pDrive->track == 0) ? 0x08 : 0; /* [3] TK0 */ pDrive->wp = ((pDrive->uptr)->flags & UNIT_MFDC_WLK) ? 1 : 0; cData |= (pDrive->wp << 4); /* [4] Write Protect */ cData |= (pDrive->ready << 5); /* [5] Drive Ready */ cData |= (0 << 6); /* [6] PINTE from S-100 Bus */ cData |= (mfdc_info->xfr_flag << 7); /* [7] Transfer Flag */ sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x\n", PCX, cData); break; case 2: case 3: if(mfdc_info->datacount == 0) { unsigned int i, checksum; unsigned long sec_offset; uint32 flags; uint32 readlen; /* Clear out unused portion of sector. */ memset(&sdata.u.unused[0], 0x00, 10); sdata.u.sync = 0xFF; sdata.u.header[0] = pDrive->track; sdata.u.header[1] = pDrive->sector; sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector); #ifdef USE_VGI sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \ (pDrive->sector * MFDC_SECTOR_LEN); #else sec_offset = (pDrive->track * 4096) + \ (pDrive->sector * 256); #endif /* USE_VGI */ if (!(pDrive->uptr->flags & UNIT_ATT)) { if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE) printf("MFDC: " ADDRESS_FORMAT " MDSK%i not attached." NLP, PCX, mfdc_info->sel_drive); return 0x00; } switch((pDrive->uptr)->u3) { case IMAGE_TYPE_IMD: if(pDrive->imd == NULL) { printf(".imd is NULL!" NLP); } /* printf("%s: Read: imd=%p" NLP, __FUNCTION__, pDrive->imd); */ sectRead(pDrive->imd, pDrive->track, mfdc_info->head, pDrive->sector, sdata.u.data, 256, &flags, &readlen); break; case IMAGE_TYPE_DSK: if(pDrive->uptr->fileref == NULL) { printf(".fileref is NULL!" NLP); } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); #ifdef USE_VGI rtn = sim_fread(sdata.raw, 1, MFDC_SECTOR_LEN, (pDrive->uptr)->fileref); if (rtn != MFDC_SECTOR_LEN) #else rtn = sim_fread(sdata.u.data, 1, 256, (pDrive->uptr)->fileref); if (rtn != 256) #endif /* USE_VGI */ printf("%s: sim_fread error. Result = %d." NLP, __FUNCTION__, rtn); } break; case IMAGE_TYPE_CPT: printf("%s: CPT Format not supported" NLP, __FUNCTION__); break; default: printf("%s: Unknown image Format" NLP, __FUNCTION__); break; } /* printf("%d/%d @%04x Len=%04x" NLP, sdata.u.header[0], sdata.u.header[1], sdata.u.header[9]<<8|sdata.u.header[8], sdata.u.header[11]<<8|sdata.u.header[10]); */ adc(0,0); /* clear Carry bit */ checksum = 0; /* Checksum everything except the sync byte */ for(i=1;i<269;i++) { checksum = adc(checksum, sdata.raw[i]); } sdata.u.checksum = checksum & 0xFF; /* DBG_PRINT(("Checksum=%x" NLP, sdata.u.checksum)); */ mfdc_info->read_in_progress = TRUE; } cData = sdata.raw[mfdc_info->datacount]; mfdc_info->datacount++; if(mfdc_info->datacount == 270) { sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Read sector [%d] complete\n", PCX, pDrive->sector); mfdc_info->read_in_progress = FALSE; } /* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, mfdc_info->datacount, cData)); */ break; } return (cData); }
t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi) { t_stat st; t_mtrlnt meta, sbc, new_len, rec_size; t_addr gap_pos = uptr->pos; uint32 file_size, marker_count; uint32 format = MT_GET_FMT (uptr); uint32 gap_alloc = 0; /* gap allocated from tape */ int32 gap_needed = (gaplen * bpi) / 10; /* gap remainder still needed */ const uint32 meta_size = sizeof (t_mtrlnt); /* bytes per metadatum */ const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2; /* smallest data record size */ MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; if (format != MTUF_F_STD) /* not SIMH fmt? */ return MTSE_FMT; if (sim_tape_wrp (uptr)) /* write protected? */ return MTSE_WRP; file_size = sim_fsize (uptr->fileref); /* get file size */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */ /* Read tape records and allocate to gap until amount required is consumed. Read next metadatum from tape: - EOF or EOM: allocate remainder of bytes needed. - TMK or GAP: allocate sizeof(metadatum) bytes. - Reverse GAP: allocate sizeof(metadatum) / 2 bytes. - Data record: see below. Loop until bytes needed = 0. */ do { sim_fread (&meta, meta_size, 1, uptr->fileref); /* read metadatum */ if (ferror (uptr->fileref)) { /* read error? */ uptr->pos = gap_pos; /* restore original position */ MT_SET_PNU (uptr); /* position not updated */ return sim_tape_ioerr (uptr); /* translate error */ } else uptr->pos = uptr->pos + meta_size; /* move tape over datum */ if (feof (uptr->fileref) || (meta == MTR_EOM)) { /* at eof or eom? */ gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ gap_needed = 0; } else if ((meta == MTR_GAP) || (meta == MTR_TMK)) { /* gap or tape mark? */ gap_alloc = gap_alloc + meta_size; /* allocate marker space */ gap_needed = gap_needed - meta_size; /* reduce requirement */ } else if (meta == MTR_FHGAP) { /* half gap? */ uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */ gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */ gap_needed = gap_needed - meta_size / 2; /* reduce requirement */ } else if (uptr->pos + MTR_L (meta) + meta_size > file_size) { /* rec len out of range? */ gap_alloc = gap_alloc + gap_needed; /* presume overwritten tape */ gap_needed = 0; /* allocate remainder */ } /* Allocate a data record: - Determine record size in bytes (including metadata) - If record size - bytes needed < smallest allowed record size, allocate entire record to gap, else allocate needed amount and truncate data record to reflect remainder. */ else { /* data record */ sbc = MTR_L (meta); /* get record data length */ rec_size = ((sbc + 1) & ~1) + meta_size * 2; /* overall size in bytes */ if (rec_size < gap_needed + min_rec_size) { /* rec too small? */ uptr->pos = uptr->pos - meta_size + rec_size; /* position past record */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* move tape */ gap_alloc = gap_alloc + rec_size; /* allocate record */ gap_needed = gap_needed - rec_size; /* reduce requirement */ } else { /* record size OK */ uptr->pos = uptr->pos - meta_size + gap_needed; /* position to end of gap */ new_len = MTR_F (meta) | (sbc - gap_needed); /* truncate to new len */ st = sim_tape_wrdata (uptr, new_len); /* write new rec len */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } uptr->pos = uptr->pos + sbc - gap_needed; /* position to end of data */ st = sim_tape_wrdata (uptr, new_len); /* write new rec len */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ gap_needed = 0; } } } while (gap_needed > 0); uptr->pos = gap_pos; /* reposition to gap start */ if (gap_alloc & (meta_size - 1)) { /* gap size "odd?" */ st = sim_tape_wrdata (uptr, MTR_FHGAP); /* write half gap marker */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } uptr->pos = uptr->pos - meta_size / 2; /* realign position */ gap_alloc = gap_alloc - 2; /* decrease gap to write */ } marker_count = gap_alloc / meta_size; /* count of gap markers */ do { st = sim_tape_wrdata (uptr, MTR_GAP); /* write gap markers */ if (st != MTSE_OK) { /* write OK? */ uptr->pos = gap_pos; /* restore orig pos */ return st; /* PNU was set by wrdata */ } } while (--marker_count > 0); return MTSE_OK; }
t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc) { uint8 c; t_bool all_eof; uint32 f = MT_GET_FMT (uptr); t_addr ppos; t_mtrlnt sbc; t_tpclnt tpcbc; MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; if (sim_tape_bot (uptr)) /* at BOT? */ return MTSE_BOT; switch (f) { /* switch on fmt */ case MTUF_F_STD: case MTUF_F_E11: do { sim_fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ sbc = MTR_L (*bc); if (ferror (uptr->fileref)) /* error? */ return sim_tape_ioerr (uptr); if (feof (uptr->fileref)) /* eof? */ return MTSE_EOM; uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over rec lnt */ if (*bc == MTR_EOM) /* eom? */ return MTSE_EOM; if (*bc == MTR_TMK) /* tape mark? */ return MTSE_TMK; if ((*bc & MTR_M_RHGAP) == MTR_RHGAP) { /* half gap? */ uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2; /* half space rev */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* resync */ } else if (*bc != MTR_GAP) { uptr->pos = uptr->pos - sizeof (t_mtrlnt) - /* spc over record */ ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); sim_fseek (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET); } else if (sim_tape_bot (uptr)) /* backed into BOT? */ return MTSE_BOT; } while ((*bc == MTR_GAP) || (*bc == MTR_RHGAP)); break; case MTUF_F_TPC: ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf); /* find prev rec */ sim_fseek (uptr->fileref, ppos, SEEK_SET); /* position */ sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref); *bc = tpcbc; /* save rec lnt */ if (ferror (uptr->fileref)) /* error? */ return sim_tape_ioerr (uptr); if (feof (uptr->fileref)) /* eof? */ return MTSE_EOM; uptr->pos = ppos; /* spc over record */ if (*bc == MTR_TMK) /* tape mark? */ return MTSE_TMK; sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET); break; case MTUF_F_P7B: for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) { sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET); sim_fread (&c, sizeof (uint8), 1, uptr->fileref); if (ferror (uptr->fileref)) /* error? */ return sim_tape_ioerr (uptr); if (feof (uptr->fileref)) /* eof? */ return MTSE_EOM; if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0; if (c & P7B_SOR) /* start of record? */ break; } uptr->pos = uptr->pos - sbc; /* update position */ *bc = sbc; /* save rec lnt */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ if (all_eof) /* tape mark? */ return MTSE_TMK; break; default: return MTSE_FMT; } return MTSE_OK; }
static uint8 MDSAD_Read(const uint32 Addr) { uint8 cData; uint8 ds; MDSAD_DRIVE_INFO *pDrive; int32 rtn; cData = 0x00; pDrive = &mdsad_info->drive[mdsad_info->orders.ds]; switch( (Addr & 0x300) >> 8 ) { case MDSAD_READ_ROM: cData = mdsad_rom[Addr & 0xFF]; break; case MDSAD_WRITE_DATA: { if(mdsad_info->datacount == 0) { sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n", PCX, mdsad_info->orders.ds, pDrive->track, mdsad_info->orders.ss, pDrive->sector); sec_offset = calculate_mdsad_sec_offset(pDrive->track, mdsad_info->orders.ss, pDrive->sector); } DBG_PRINT(("MDSAD: " ADDRESS_FORMAT " WRITE-DATA[offset:%06x+%03x]=%02x" NLP, PCX, sec_offset, mdsad_info->datacount, Addr & 0xFF)); mdsad_info->datacount++; if(mdsad_info->datacount < MDSAD_RAW_LEN) sdata.raw[mdsad_info->datacount] = Addr & 0xFF; if(mdsad_info->datacount == (MDSAD_RAW_LEN - 1)) { sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Write Complete\n", PCX); if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) { sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Drive: %d not attached - write ignored.\n", PCX, mdsad_info->orders.ds); return 0x00; } if(mdsad_dev.dctrl & WR_DATA_DETAIL_MSG) showdata(FALSE); switch((pDrive->uptr)->u3) { case IMAGE_TYPE_DSK: if(pDrive->uptr->fileref == NULL) { printf(".fileref is NULL!" NLP); } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); sim_fwrite(sdata.u.data, 1, MDSAD_SECTOR_LEN, (pDrive->uptr)->fileref); } break; case IMAGE_TYPE_CPT: printf("%s: CPT Format not supported" NLP, __FUNCTION__); break; default: printf("%s: Unknown image Format" NLP, __FUNCTION__); break; } } break; } case MDSAD_CTLR_ORDERS: mdsad_info->orders.dd = (Addr & 0x80) >> 7; mdsad_info->orders.ss = (Addr & 0x40) >> 6; mdsad_info->orders.dp = (Addr & 0x20) >> 5; mdsad_info->orders.st = (Addr & 0x10) >> 4; mdsad_info->orders.ds = (Addr & 0x0F); ds = mdsad_info->orders.ds; switch(mdsad_info->orders.ds) { case 0: case 1: mdsad_info->orders.ds = 0; break; case 2: mdsad_info->orders.ds = 1; break; case 4: mdsad_info->orders.ds = 2; break; case 8: mdsad_info->orders.ds = 3; break; } if(mdsad_info->orders.ds != (mdsad_info->orders.ds & 0x03)) { sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Controller Orders update drive %x\n", PCX, mdsad_info->orders.ds); mdsad_info->orders.ds &= 0x03; } sim_debug(ORDERS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d\n", PCX, mdsad_info->orders.ds, ds, mdsad_info->orders.dd, mdsad_info->orders.ss, mdsad_info->orders.dp, mdsad_info->orders.st); /* use latest selected drive */ pDrive = &mdsad_info->drive[mdsad_info->orders.ds]; if(mdsad_info->orders.st == 1) { if(mdsad_info->orders.dp == 0) { sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Step out: Track=%d%s\n", PCX, pDrive->track, pDrive->track == 0 ? "[Warn: already at 0]" : ""); if(pDrive->track > 0) /* anything to do? */ pDrive->track--; } else { sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Step in: Track=%d%s\n", PCX, pDrive->track, pDrive->track == (MDSAD_TRACKS - 1) ? "[Warn: already at highest track]" : ""); if(pDrive->track < (MDSAD_TRACKS - 1)) /* anything to do? */ pDrive->track++; } } /* always update t0 */ mdsad_info->b_status.t0 = (pDrive->track == 0); break; case MDSAD_CTLR_COMMAND: /* sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " DM=%x\n", PCX, (Addr & 0xF0) >> 4); */ switch(Addr & 0x0F) { case MDSAD_CMD_MOTORS_ON: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " CMD=Motors On\n", PCX); mdsad_info->com_status.mo = 1; /* Turn motors on */ break; case MDSAD_CMD_NOP: pDrive->sector_wait_count++; switch(pDrive->sector_wait_count) { case 10: { mdsad_info->com_status.sf = 1; mdsad_info->a_status.wi = 0; mdsad_info->a_status.re = 0; mdsad_info->a_status.bd = 0; pDrive->sector_wait_count = 0; pDrive->sector++; if(pDrive->sector >= MDSAD_SECTORS_PER_TRACK) { pDrive->sector = 0; mdsad_info->com_status.ix = 1; } else { mdsad_info->com_status.ix = 0; } break; } case 2: mdsad_info->a_status.wi = 1; break; case 3: mdsad_info->a_status.re = 1; mdsad_info->a_status.bd = 1; break; default: break; } break; case MDSAD_CMD_RESET_SF: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " CMD=Reset Sector Flag\n", PCX); mdsad_info->com_status.sf = 0; mdsad_info->datacount = 0; break; case MDSAD_CMD_INTR_DIS: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " CMD=Disarm Interrupt\n", PCX); mdsad_info->int_enable = 0; break; case MDSAD_CMD_INTR_ARM: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " CMD=Arm Interrupt\n", PCX); mdsad_info->int_enable = 1; break; case MDSAD_CMD_SET_BODY: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " CMD=Set Body (Diagnostic)\n", PCX); break; case MDSAD_CMD_BEGIN_WR: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " CMD=Begin Write\n", PCX); break; case MDSAD_CMD_RESET: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " CMD=Reset Controller\n", PCX); mdsad_info->com_status.mo = 0; /* Turn motors off */ break; default: sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Unsupported CMD=0x%x\n", PCX, Addr & 0x0F); break; } /* Always Double-Density for now... */ mdsad_info->com_status.dd = 1; cData = (mdsad_info->com_status.sf & 1) << 7; cData |= (mdsad_info->com_status.ix & 1) << 6; cData |= (mdsad_info->com_status.dd & 1) << 5; cData |= (mdsad_info->com_status.mo & 1) << 4; mdsad_info->c_status.sc = pDrive->sector; switch( (Addr & 0xF0) >> 4) { case MDSAD_A_STATUS: /* A-STATUS */ cData |= (mdsad_info->a_status.wi & 1) << 3; cData |= (mdsad_info->a_status.re & 1) << 2; cData |= (mdsad_info->a_status.sp & 1) << 1; cData |= (mdsad_info->a_status.bd & 1); sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " A-Status = <%s %s %s %s %s %s %s %s>\n", PCX, cData & MDSAD_A_SF ? "SF" : " ", cData & MDSAD_A_IX ? "IX" : " ", cData & MDSAD_A_DD ? "DD" : " ", cData & MDSAD_A_MO ? "MO" : " ", cData & MDSAD_A_WI ? "WI" : " ", cData & MDSAD_A_RE ? "RE" : " ", cData & MDSAD_A_SP ? "SP" : " ", cData & MDSAD_A_BD ? "BD" : " "); break; case MDSAD_B_STATUS: /* B-STATUS */ cData |= (mdsad_info->b_status.wr & 1) << 3; cData |= (mdsad_info->b_status.sp & 1) << 2; cData |= (mdsad_info->b_status.wp & 1) << 1; cData |= (mdsad_info->b_status.t0 & 1); sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " B-Status = <%s %s %s %s %s %s %s %s>\n", PCX, cData & MDSAD_B_SF ? "SF" : " ", cData & MDSAD_B_IX ? "IX" : " ", cData & MDSAD_B_DD ? "DD" : " ", cData & MDSAD_B_MO ? "MO" : " ", cData & MDSAD_B_WR ? "WR" : " ", cData & MDSAD_B_SP ? "SP" : " ", cData & MDSAD_B_WP ? "WP" : " ", cData & MDSAD_B_T0 ? "T0" : " "); break; case MDSAD_C_STATUS: /* C-STATUS */ cData |= (mdsad_info->c_status.sc & 0xF); sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " C-Status = <%s %s %s %s %i>\n", PCX, cData & MDSAD_C_SF ? "SF" : " ", cData & MDSAD_C_IX ? "IX" : " ", cData & MDSAD_C_DD ? "DD" : " ", cData & MDSAD_C_MO ? "MO" : " ", cData & MDSAD_C_SC); break; case MDSAD_READ_DATA: /* READ DATA */ { if(mdsad_info->datacount == 0) { sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n", PCX, mdsad_info->orders.ds, pDrive->track, mdsad_info->orders.ss, pDrive->sector); checksum = 0; sec_offset = calculate_mdsad_sec_offset(pDrive->track, mdsad_info->orders.ss, pDrive->sector); if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) { sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " Drive: %d not attached - read ignored.\n", PCX, mdsad_info->orders.ds); return 0xe5; } switch((pDrive->uptr)->u3) { case IMAGE_TYPE_DSK: if(pDrive->uptr->fileref == NULL) { printf(".fileref is NULL!" NLP); } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); rtn = sim_fread(&sdata.u.data[0], 1, MDSAD_SECTOR_LEN, (pDrive->uptr)->fileref); if (rtn != MDSAD_SECTOR_LEN) { sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " READ: sim_fread error.\n", PCX); } } break; case IMAGE_TYPE_CPT: printf("%s: CPT Format not supported" NLP, __FUNCTION__); break; default: printf("%s: Unknown image Format" NLP, __FUNCTION__); break; } if(mdsad_dev.dctrl & RD_DATA_DETAIL_MSG) showdata(TRUE); } if(mdsad_info->datacount < MDSAD_SECTOR_LEN) { cData = sdata.u.data[mdsad_info->datacount]; /* Exclusive OR */ checksum ^= cData; /* Rotate Left Circular */ checksum = ((checksum << 1) | ((checksum & 0x80) != 0)) & 0xff; DBG_PRINT(("MDSAD: " ADDRESS_FORMAT " READ-DATA[offset:%06x+%03x]=%02x" NLP, PCX, sec_offset, mdsad_info->datacount, cData)); } else { /* checksum */ cData = checksum; sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " READ-DATA: Checksum is: 0x%02x\n", PCX, cData); } mdsad_info->datacount++; break; } default: DBG_PRINT(("MDSAD: " ADDRESS_FORMAT " Invalid DM=%x" NLP, PCX, Addr & 0xF)); break; } break; } return (cData); }
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 */
int32 fdccmd(int32 io, int32 data) { static int32 val = 0, val1 = NOTRDY; static long pos; if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ dsk_unit[cur_dsk].u3 |= NOTRDY; /* set not ready flag */ if (dsk_dev.dctrl & DEBUG_flow) printf("\nfdccmd: Drive %d is not attached", cur_dsk); return 0; } else { dsk_unit[cur_dsk].u3 &= ~NOTRDY; /* clear not ready flag */ } if (io) { /* write command to fdc */ switch(data) { case 0x8C: /* read command */ case 0x9C: if (dsk_dev.dctrl & DEBUG_read) printf("\nfdccmd: Read of disk %d, track %d, sector %d", cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ pos += SECSIZ * (dsk_unit[cur_dsk].u5 - 1); if (dsk_dev.dctrl & DEBUG_read) printf("\nfdccmd: Read pos = %ld ($%08X)", pos, (unsigned int) pos); sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ sim_fread(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ break; case 0xAC: /* write command */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdccmd: Write of disk %d, track %d, sector %d", cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); if (dsk_unit[cur_dsk].u3 & WRPROT) { printf("\nfdccmd: Drive %d is write-protected", cur_dsk); } else { pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ pos += SECSIZ * (dsk_unit[cur_dsk].u5 - 1); if (dsk_dev.dctrl & DEBUG_write) printf("\nfdccmd: Write pos = %ld ($%08X)", pos, (unsigned int) pos); sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ wrt_flag = 1; /* set write flag */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ;/* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ } break; case 0x18: /* seek command */ case 0x1B: dsk_unit[cur_dsk].u4 = fdcbyte; /* set track */ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ if (dsk_dev.dctrl & DEBUG_flow) printf("\nfdccmd: Seek of disk %d, track %d", cur_dsk, fdcbyte); break; case 0x0B: /* restore command */ dsk_unit[cur_dsk].u4 = 0; /* home the drive */ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ if (dsk_dev.dctrl & DEBUG_flow) printf("\nfdccmd: Drive %d homed", cur_dsk); break; case 0xF0: /* write track command */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdccmd: Write track command for drive %d", cur_dsk); break; default: printf("Unknown FDC command %02XH\n\r", data); } } else { /* read status from fdc */ val = dsk_unit[cur_dsk].u3; /* set return value */ /* either print below will force the val to 0x43 forever. timing problem in the 6800 disk driver software? */ // if (dsk_dev.dctrl & DEBUG_flow) // printf("\nfdccmd: Exit Drive %d status=%02X", cur_dsk, val); // printf("\n%02X", val); //even this short fails it! if (val1 == 0 && ((val & (BUSY + DRQ)) == (BUSY + DRQ))) /* delay BUSY going high */ val &= ~BUSY; if (val != val1) /* now allow BUSY after one read */ val1 = val; if (dsk_dev.dctrl & DEBUG_flow) printf("\nfdccmd: Exit Drive %d status=%02X", cur_dsk, val); } return val; }