/* Attach routine */ t_stat mfdc_attach(UNIT *uptr, char *cptr) { t_stat r; unsigned int i = 0; r = attach_unit(uptr, cptr); /* attach unit */ if ( r != SCPE_OK) /* error? */ return r; /* Determine length of this disk */ if(sim_fsize(uptr->fileref) != 0) { uptr->capac = sim_fsize(uptr->fileref); } else { uptr->capac = MFDC_CAPACITY; } i = find_unit_index(uptr); /* Default for new file is DSK */ uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { r = assignDiskType(uptr); if (r != SCPE_OK) { mfdc_detach(uptr); return r; } } if (uptr->flags & UNIT_MFDC_VERBOSE) printf("MDSK%d, attached to '%s', type=%s, len=%d\n", i, cptr, uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); if(uptr->u3 == IMAGE_TYPE_IMD) { if(uptr->capac < 318000) { printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); mfdc_detach(uptr); return SCPE_OPENERR; } if (uptr->flags & UNIT_MFDC_VERBOSE) printf("--------------------------------------------------------\n"); mfdc_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_MFDC_VERBOSE)); if (uptr->flags & UNIT_MFDC_VERBOSE) printf("\n"); } else { mfdc_info->drive[i].imd = NULL; } return SCPE_OK; }
/* Attach routine */ static t_stat mdsad_attach(UNIT *uptr, CONST char *cptr) { char header[4]; t_stat r; unsigned int i = 0; r = attach_unit(uptr, cptr); /* attach unit */ if(r != SCPE_OK) /* error? */ return r; /* Determine length of this disk */ if(sim_fsize(uptr->fileref) != 0) { uptr->capac = sim_fsize(uptr->fileref); } else { uptr->capac = MDSAD_CAPACITY; } for(i = 0; i < MDSAD_MAX_DRIVES; i++) { mdsad_info->drive[i].uptr = &mdsad_dev.units[i]; } for(i = 0; i < MDSAD_MAX_DRIVES; i++) { if(mdsad_dev.units[i].fileref == uptr->fileref) { break; } mdsad_info->orders.st = 0; /* ensure valid state */ } /* Default for new file is DSK */ uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { char *rtn = fgets(header, 4, uptr->fileref); if((rtn != NULL) && (strncmp(header, "CPT", 3) == 0)) { sim_printf("CPT images not yet supported\n"); uptr->u3 = IMAGE_TYPE_CPT; mdsad_detach(uptr); return SCPE_OPENERR; } else { uptr->u3 = IMAGE_TYPE_DSK; } } if (uptr->flags & UNIT_MDSAD_VERBOSE) sim_printf("MDSAD%d, attached to '%s', type=%s, len=%d\n", i, cptr, uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); return SCPE_OK; }
uint32 sim_fsize_name (char *fname) { FILE *fp; uint32 sz; if ((fp = sim_fopen (fname, "rb")) == NULL) return 0; sz = sim_fsize (fp); fclose (fp); return sz; }
/* Attach routine */ static t_stat disk3_attach(UNIT *uptr, char *cptr) { t_stat r = SCPE_OK; DISK3_DRIVE_INFO *pDrive; int i = 0; i = find_unit_index(uptr); if (i == -1) { return (SCPE_IERR); } pDrive = &disk3_info->drive[i]; pDrive->ready = 1; pDrive->track = 5; pDrive->ntracks = C20MB_NTRACKS; pDrive->nheads = C20MB_NHEADS; pDrive->nsectors = C20MB_NSECTORS; pDrive->sectsize = C20MB_SECTSIZE; r = attach_unit(uptr, cptr); /* attach unit */ if ( r != SCPE_OK) /* error? */ return r; /* Determine length of this disk */ if(sim_fsize(uptr->fileref) != 0) { uptr->capac = sim_fsize(uptr->fileref); } else { uptr->capac = (pDrive->ntracks * pDrive->nsectors * pDrive->nheads * pDrive->sectsize); } pDrive->uptr = uptr; /* Default for new file is DSK */ uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { r = assignDiskType(uptr); if (r != SCPE_OK) { disk3_detach(uptr); return r; } } if (uptr->flags & UNIT_DISK3_VERBOSE) printf("DISK3%d, attached to '%s', type=%s, len=%d\n", i, cptr, uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); if(uptr->u3 == IMAGE_TYPE_IMD) { if(uptr->capac < 318000) { printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); disk3_detach(uptr); return SCPE_OPENERR; } if (uptr->flags & UNIT_DISK3_VERBOSE) printf("--------------------------------------------------------\n"); disk3_info->drive[i].imd = diskOpenEx((uptr->fileref), (uptr->flags & UNIT_DISK3_VERBOSE), &disk3_dev, VERBOSE_MSG, VERBOSE_MSG); if (uptr->flags & UNIT_DISK3_VERBOSE) printf("\n"); } else { disk3_info->drive[i].imd = NULL; } return SCPE_OK; }
/* Attach routine */ static t_stat hdc1001_attach(UNIT *uptr, char *cptr) { t_stat r = SCPE_OK; HDC1001_DRIVE_INFO *pDrive; char header[4]; unsigned int i = 0; i = find_unit_index(uptr); if (i == -1) { return (SCPE_IERR); } pDrive = &hdc1001_info->drive[i]; pDrive->ready = 1; pDrive->track = 5; pDrive->ntracks = 243; pDrive->nheads = 8; pDrive->nsectors = 11; pDrive->sectsize = 1024; r = attach_unit(uptr, cptr); /* attach unit */ if ( r != SCPE_OK) /* error? */ return r; /* Determine length of this disk */ if(sim_fsize(uptr->fileref) != 0) { uptr->capac = sim_fsize(uptr->fileref); } else { uptr->capac = (pDrive->ntracks * pDrive->nsectors * pDrive->nheads * pDrive->sectsize); } pDrive->uptr = uptr; /* Default for new file is DSK */ uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { fgets(header, 4, uptr->fileref); if(!strcmp(header, "IMD")) { uptr->u3 = IMAGE_TYPE_IMD; } else if(!strcmp(header, "CPT")) { printf("CPT images not yet supported\n"); uptr->u3 = IMAGE_TYPE_CPT; hdc1001_detach(uptr); return SCPE_OPENERR; } else { uptr->u3 = IMAGE_TYPE_DSK; } } if (uptr->flags & UNIT_HDC1001_VERBOSE) printf("HDC1001%d, attached to '%s', type=%s, len=%d\n", i, cptr, uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); if(uptr->u3 == IMAGE_TYPE_IMD) { if(uptr->capac < 318000) { printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); hdc1001_detach(uptr); return SCPE_OPENERR; } if (uptr->flags & UNIT_HDC1001_VERBOSE) printf("--------------------------------------------------------\n"); hdc1001_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_HDC1001_VERBOSE)); if (uptr->flags & UNIT_HDC1001_VERBOSE) printf("\n"); } else { hdc1001_info->drive[i].imd = NULL; } return SCPE_OK; }
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); }
/* Attach routine */ t_stat i8272_attach(UNIT *uptr, char *cptr) { char header[4]; t_stat r; int32 i = 0; r = attach_unit(uptr, cptr); /* attach unit */ if ( r != SCPE_OK) /* error? */ return r; /* Determine length of this disk */ uptr->capac = sim_fsize(uptr->fileref); i = find_unit_index(uptr); if (i == -1) { return (SCPE_IERR); } DBG_PRINT(("Attach I8272%d\n", i)); i8272_info->drive[i].uptr = uptr; /* Default to drive not ready */ i8272_info->drive[i].ready = 0; if(uptr->capac > 0) { char *rtn = fgets(header, 4, uptr->fileref); if((rtn != NULL) && strncmp(header, "IMD", 3)) { printf("I8272: Only IMD disk images are supported\n"); i8272_info->drive[i].uptr = NULL; return SCPE_OPENERR; } } else { /* create a disk image file in IMD format. */ if (diskCreate(uptr->fileref, "$Id: i8272.c 1999 2008-07-22 04:25:28Z hharte $") != SCPE_OK) { printf("I8272: Failed to create IMD disk.\n"); i8272_info->drive[i].uptr = NULL; return SCPE_OPENERR; } uptr->capac = sim_fsize(uptr->fileref); } uptr->u3 = IMAGE_TYPE_IMD; if (uptr->flags & UNIT_I8272_VERBOSE) { printf("I8272%d: attached to '%s', type=%s, len=%d\n", i, cptr, uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); } if(uptr->u3 == IMAGE_TYPE_IMD) { if (uptr->flags & UNIT_I8272_VERBOSE) printf("--------------------------------------------------------\n"); i8272_info->drive[i].imd = diskOpen(uptr->fileref, uptr->flags & UNIT_I8272_VERBOSE); if (uptr->flags & UNIT_I8272_VERBOSE) printf("\n"); if (i8272_info->drive[i].imd == NULL) { printf("I8272: IMD disk corrupt.\n"); i8272_info->drive[i].uptr = NULL; return SCPE_OPENERR; } i8272_info->drive[i].ready = 1; } else { i8272_info->drive[i].imd = NULL; } return SCPE_OK; }
/* Attach routine */ static t_stat vfdhd_attach(UNIT *uptr, char *cptr) { char header[4]; t_stat r; unsigned int i = 0; r = attach_unit(uptr, cptr); /* attach unit */ if ( r != SCPE_OK) /* error? */ return r; /* Determine length of this disk */ uptr->capac = sim_fsize(uptr->fileref); for(i = 0; i < VFDHD_MAX_DRIVES; i++) { vfdhd_info->drive[i].uptr = &vfdhd_dev.units[i]; } for(i = 0; i < VFDHD_MAX_DRIVES; i++) { if(vfdhd_dev.units[i].fileref == uptr->fileref) { break; } } if(uptr->capac > 0) { fgets(header, 4, uptr->fileref); if(!strcmp(header, "IMD")) { uptr->u3 = IMAGE_TYPE_IMD; } else if(!strcmp(header, "CPT")) { printf("CPT images not yet supported\n"); uptr->u3 = IMAGE_TYPE_CPT; vfdhd_detach(uptr); return SCPE_OPENERR; } else { uptr->u3 = IMAGE_TYPE_DSK; } } else { /* creating file, must be DSK format. */ uptr->u3 = IMAGE_TYPE_DSK; } if (uptr->flags & UNIT_VFDHD_VERBOSE) printf("VFDHD%d: attached to '%s', type=%s, len=%d\n", i, cptr, uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); if(uptr->u3 == IMAGE_TYPE_IMD) { if(uptr->capac < 318000) { printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); vfdhd_detach(uptr); return SCPE_OPENERR; } if (uptr->flags & UNIT_VFDHD_VERBOSE) printf("--------------------------------------------------------\n"); vfdhd_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_VFDHD_VERBOSE)); if (uptr->flags & UNIT_VFDHD_VERBOSE) printf("\n"); } else { vfdhd_info->drive[i].imd = NULL; } if(i>0) { /* Floppy Disk, Unit 1-3 */ vfdhd_info->drive[i].ntracks = 77; /* number of tracks */ vfdhd_info->drive[i].nheads = 2; /* number of heads */ vfdhd_info->drive[i].nspt = 16; /* number of sectors per track */ vfdhd_info->drive[i].npre_len = 40; /* preamble length */ vfdhd_info->drive[i].sectsize = VFDHD_SECTOR_LEN; /* sector size, not including pre/postamble */ } else { /* Hard Disk, Unit 0 */ if(hdSize == 10) { vfdhd_info->drive[i].ntracks = 153; /* number of tracks */ vfdhd_info->drive[i].nheads = 6; /* number of heads */ vfdhd_info->hdsk_type = 1; printf("10MB\n"); } else if (hdSize == 5) { vfdhd_info->drive[i].ntracks = 153; /* number of tracks */ vfdhd_info->drive[i].nheads = 4; /* number of heads */ vfdhd_info->hdsk_type = 0; printf("5MB\n"); } else { vfdhd_info->drive[i].ntracks = 512; /* number of tracks */ vfdhd_info->drive[i].nheads = 8; /* number of heads */ vfdhd_info->hdsk_type = 1; printf("32MB\n"); } vfdhd_info->drive[i].nheads = 4; /* number of heads */ vfdhd_info->drive[i].nspt = 32; /* number of sectors per track */ vfdhd_info->drive[i].npre_len = 30; /* preamble length */ vfdhd_info->drive[i].sectsize = VFDHD_SECTOR_LEN; /* sector size, not including pre/postamble */ vfdhd_info->drive[i].ready = 1; vfdhd_info->drive[i].seek_complete = 1; vfdhd_info->drive[i].sync_lost = 1; /* Active LOW */ } vfdhd_info->motor_on = 1; return SCPE_OK; }
/* * Create an ImageDisk (IMD) file. This function just creates the comment header, and allows * the user to enter a comment. After the IMD is created, it must be formatted with a format * program on the simulated operating system, ie CP/M, CDOS, 86-DOS. * * If the IMD file already exists, the user will be given the option of overwriting it. */ t_stat diskCreate(FILE *fileref, const char *ctlr_comment) { DISK_INFO *myDisk = NULL; char *comment; char *curptr; char *result; uint8 answer; int32 len, remaining; if(fileref == NULL) { return (SCPE_OPENERR); } if(sim_fsize(fileref) != 0) { sim_printf("SIM_IMD: Disk image already has data, do you want to overwrite it? "); answer = getchar(); if((answer != 'y') && (answer != 'Y')) { return (SCPE_OPENERR); } } if((curptr = comment = (char *)calloc(1, MAX_COMMENT_LEN)) == 0) { sim_printf("Memory allocation failure.\n"); return (SCPE_MEM); } sim_printf("SIM_IMD: Enter a comment for this disk.\n" "SIM_IMD: Terminate with a '.' on an otherwise blank line.\n"); remaining = MAX_COMMENT_LEN; do { sim_printf("IMD> "); result = fgets(curptr, remaining - 3, stdin); if ((result == NULL) || (strcmp(curptr, ".\n") == 0)) { remaining = 0; } else { len = strlen(curptr) - 1; if (curptr[len] != '\n') len++; remaining -= len; curptr += len; *curptr++ = 0x0d; *curptr++ = 0x0a; } } while (remaining > 4); *curptr = 0x00; /* rewind to the beginning of the file. */ rewind(fileref); /* Erase the contents of the IMD file in case we are overwriting an existing image. */ if (sim_set_fsize(fileref, (t_addr)ftell (fileref)) == -1) { sim_printf("SIM_IMD: Error overwriting disk image.\n"); return(SCPE_OPENERR); } fprintf(fileref, "IMD SIMH %s %s\n", __DATE__, __TIME__); fputs(comment, fileref); free(comment); fprintf(fileref, "\n\n$Id: sim_imd.c 1999 2008-07-22 04:25:28Z hharte $\n"); fprintf(fileref, "%s\n", ctlr_comment); fputc(0x1A, fileref); /* EOF marker for IMD comment. */ fflush(fileref); if((myDisk = diskOpen(fileref, 0)) == NULL) { sim_printf("SIM_IMD: Error opening disk for format.\n"); return(SCPE_OPENERR); } if(diskFormat(myDisk) != SCPE_OK) { sim_printf("SIM_IMD: error formatting disk.\n"); } return diskClose(&myDisk); }
/* Attach routine */ static t_stat hdsk_attach(UNIT *uptr, char *cptr) { t_stat r; uint32 i; char unitChar; r = attach_unit(uptr, cptr); /* attach unit */ if ( r != SCPE_OK) /* error? */ return r; /* Step 1: Determine capacity of this disk */ uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good candidate */ if (uptr -> capac == 0) { /* file does not exist or has length 0 */ uptr -> capac = uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE; if (uptr -> capac == 0) uptr -> capac = HDSK_CAPACITY; } /* post condition: uptr -> capac > 0 */ assert(uptr -> capac); /* Step 2: Determine format based on disk capacity */ uptr -> HDSK_FORMAT_TYPE = -1; /* default to unknown format type */ for (i = 0; dpb[i].capac != 0; i++) { /* find disk parameter block */ if (dpb[i].capac == uptr -> capac) { /* found if correct capacity */ uptr -> HDSK_FORMAT_TYPE = i; break; } } /* Step 3: Set number of sectors per track and sector size */ if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found*/ for (i = 0; i < hdsk_dev.numunits; i++) /* find affected unit number */ if (&hdsk_unit[i] == uptr) break; /* found */ unitChar = '0' + i; uptr -> HDSK_FORMAT_TYPE = 0; printf("HDSK%c: WARNING: Unsupported disk capacity, assuming HDSK type with capacity %iKB.\n", unitChar, uptr -> capac / 1000); uptr -> flags |= UNIT_HDSK_WLK; printf("HDSK%c: WARNING: Forcing WRTLCK.\n", unitChar); /* check whether capacity corresponds to setting of tracks, sectors per track and sector size */ if (uptr -> capac != (uint32)(uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE)) { printf("HDSK%c: WARNING: Fixing geometry.\n", unitChar); if (uptr -> HDSK_SECTORS_PER_TRACK == 0) uptr -> HDSK_SECTORS_PER_TRACK = 32; if (uptr -> HDSK_SECTOR_SIZE == 0) uptr -> HDSK_SECTOR_SIZE = 128; } } else { /* Case 2: disk parameter block found */ uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); } assert(uptr -> HDSK_SECTORS_PER_TRACK && uptr -> HDSK_SECTOR_SIZE); /* Step 4: Number of tracks is smallest number to accomodate capacity */ uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE - 1) / (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); assert( ( (t_addr) ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) && (uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) ); return SCPE_OK; }
/* Attach routine */ static t_stat hdsk_attach(UNIT *uptr, char *cptr) { int32 thisUnitIndex; char unitChar; const t_stat r = attach_unit(uptr, cptr); /* attach unit */ if (r != SCPE_OK) /* error? */ return r; assert(uptr != NULL); thisUnitIndex = find_unit_index(uptr); unitChar = '0' + thisUnitIndex; assert((0 <= thisUnitIndex) && (thisUnitIndex < HDSK_NUMBER)); if (is_imd(uptr)) { if ((sim_fsize(uptr -> fileref) == 0) && (diskCreate(uptr -> fileref, "$Id: SIMH hdsk.c $") != SCPE_OK)) { printf("HDSK%c (IMD): Failed to create IMD disk.\n", unitChar); detach_unit(uptr); return SCPE_OPENERR; } hdsk_imd[thisUnitIndex] = diskOpen(uptr -> fileref, sim_deb && (hdsk_dev.dctrl & VERBOSE_MSG)); if (hdsk_imd[thisUnitIndex] == NULL) return SCPE_IOERR; verifyDiskInfo(*hdsk_imd[thisUnitIndex], '0' + thisUnitIndex); uptr -> HDSK_NUMBER_OF_TRACKS = hdsk_imd[thisUnitIndex] -> ntracks; uptr -> HDSK_SECTORS_PER_TRACK = hdsk_imd[thisUnitIndex] -> track[1][0].nsects; uptr -> HDSK_SECTOR_SIZE = hdsk_imd[thisUnitIndex] -> track[1][0].sectsize; uptr -> capac = ((uptr -> HDSK_NUMBER_OF_TRACKS) * (uptr -> HDSK_SECTORS_PER_TRACK) * (uptr -> HDSK_SECTOR_SIZE)); assignFormat(uptr); if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found*/ uptr -> HDSK_FORMAT_TYPE = 0; printf("HDSK%c (IMD): WARNING: Unsupported disk capacity, assuming HDSK type " "with capacity %iKB.\n", unitChar, uptr -> capac / 1000); uptr -> flags |= UNIT_HDSK_WLK; printf("HDSK%c (IMD): WARNING: Forcing WRTLCK.\n", unitChar); } return SCPE_OK; } /* Step 1: Determine capacity of this disk */ uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good indication */ if (uptr -> capac == 0) { /* file does not exist or has length 0 */ uptr -> capac = (uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); if (uptr -> capac == 0) uptr -> capac = HDSK_CAPACITY; } /* post condition: uptr -> capac > 0 */ assert(uptr -> capac); /* Step 2: Determine format based on disk capacity */ assignFormat(uptr); /* Step 3: Set number of sectors per track and sector size */ if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found */ uptr -> HDSK_FORMAT_TYPE = 0; printf("HDSK%c: WARNING: Unsupported disk capacity, assuming HDSK type with capacity %iKB.\n", unitChar, uptr -> capac / 1000); uptr -> flags |= UNIT_HDSK_WLK; printf("HDSK%c: WARNING: Forcing WRTLCK.\n", unitChar); /* check whether capacity corresponds to setting of tracks, sectors per track and sector size */ if (uptr -> capac != (uint32)(uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE)) { printf("HDSK%c: WARNING: Fixing geometry.\n", unitChar); if (uptr -> HDSK_SECTORS_PER_TRACK == 0) uptr -> HDSK_SECTORS_PER_TRACK = 32; if (uptr -> HDSK_SECTOR_SIZE == 0) uptr -> HDSK_SECTOR_SIZE = 128; } } else { /* Case 2: disk parameter block found */ uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); } assert((uptr -> HDSK_SECTORS_PER_TRACK) && (uptr -> HDSK_SECTOR_SIZE) && (uptr -> HDSK_FORMAT_TYPE >= 0)); /* Step 4: Number of tracks is smallest number to accomodate capacity */ uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE - 1) / (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); assert( ( (t_addr) ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) && (uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) ); return SCPE_OK; }
/* Attach routine */ t_stat wd179x_attach(UNIT *uptr, char *cptr) { char header[4]; t_stat r; int32 i = 0; r = attach_unit(uptr, cptr); /* attach unit */ if ( r != SCPE_OK) /* error? */ return r; /* Determine length of this disk */ uptr->capac = sim_fsize(uptr->fileref); i = find_unit_index(uptr); if (i == -1) { return (SCPE_IERR); } DBG_PRINT(("Attach WD179X%d\n", i)); wd179x_info->drive[i].uptr = uptr; /* Default to drive not ready */ wd179x_info->drive[i].ready = 0; if(uptr->capac > 0) { char *rtn = fgets(header, 4, uptr->fileref); if ((rtn != NULL) && strncmp(header, "IMD", 3)) { printf("WD179X: Only IMD disk images are supported\n"); wd179x_info->drive[i].uptr = NULL; return SCPE_OPENERR; } } else { /* create a disk image file in IMD format. */ if (diskCreate(uptr->fileref, "$Id: wd179x.c 1999 2008-07-22 04:25:28Z hharte $") != SCPE_OK) { printf("WD179X: Failed to create IMD disk.\n"); wd179x_info->drive[i].uptr = NULL; return SCPE_OPENERR; } uptr->capac = sim_fsize(uptr->fileref); } uptr->u3 = IMAGE_TYPE_IMD; if (uptr->flags & UNIT_WD179X_VERBOSE) printf("WD179X%d: attached to '%s', type=%s, len=%d\n", i, cptr, uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); if(uptr->u3 == IMAGE_TYPE_IMD) { if (uptr->flags & UNIT_WD179X_VERBOSE) printf("--------------------------------------------------------\n"); wd179x_info->drive[i].imd = diskOpen(uptr->fileref, uptr->flags & UNIT_WD179X_VERBOSE); if (uptr->flags & UNIT_WD179X_VERBOSE) printf("\n"); if (wd179x_info->drive[i].imd == NULL) { printf("WD179X: IMD disk corrupt.\n"); wd179x_info->drive[i].uptr = NULL; return SCPE_OPENERR; } /* Write-protect the unit if IMD think's it's writelocked. */ if(imdIsWriteLocked(wd179x_info->drive[i].imd)) { uptr->flags |= UNIT_WD179X_WLK; } wd179x_info->drive[i].ready = 1; } else { wd179x_info->drive[i].imd = NULL; } wd179x_info->fdc_sec_len = 0; /* 128 byte sectors, fixme */ wd179x_info->sel_drive = 0; return SCPE_OK; }
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; }