t_stat ssem_dump (FILE *fi) { if (sim_fwrite(A, sizeof(int32), 1, fi) != 1 || sim_fwrite(C, sizeof(uint32), 1, fi) != 1 || sim_fwrite(S, sizeof(uint32), MEMSIZE, fi) != MEMSIZE) { return SCPE_IOERR; } return SCPE_OK; }
/* * Initiate a write operation on a disk. */ static enum dpio_status DPDiskIOWrite(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); t_bool fill = FALSE; int i; if (iou->cylinder >= numcy) return DPIO_ADDRERR; for (i = 0; i < DP_NUMWD; i++) { if (!fill) { iou->buf[i] = LoadFromMem(iou->CWA); iou->CWA++; if (iou->CWA == iou->LWA) fill = TRUE; } else iou->buf[i] = 0; } /* * Report any error in the underlying container infrastructure as an * address error. */ if (sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET) || (sim_fwrite(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD)) return DPIO_ADDRERR; DPDiskIOIncSector(iou); return fill ? DPIO_DONE : DPIO_MORE; }
t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc) { uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; MT_CLR_PNU (uptr); sbc = MTR_L (bc); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; if (sbc == 0) /* nothing to do? */ return MTSE_OK; sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ switch (f) { /* case on format */ case MTUF_F_STD: /* standard */ sbc = MTR_L ((bc + 1) & ~1); /* pad odd length */ case MTUF_F_E11: /* E11 */ sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref); sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); return sim_tape_ioerr (uptr); } uptr->pos = uptr->pos + sbc + (2 * sizeof (t_mtrlnt)); /* move tape */ break; case MTUF_F_P7B: /* Pierce 7B */ buf[0] = buf[0] | P7B_SOR; /* mark start of rec */ sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref); sim_fwrite (buf, sizeof (uint8), 1, uptr->fileref); /* delimit rec */ if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); return sim_tape_ioerr (uptr); } uptr->pos = uptr->pos + sbc; /* move tape */ break; } return MTSE_OK; }
t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat) { MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return MTSE_UNATT; if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ sim_fwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); return sim_tape_ioerr (uptr); } uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* move tape */ return MTSE_OK; }
int32 fdcdata(int32 io, int32 data) { int32 i; if (io) { /* write byte to fdc */ fdcbyte = data; /* save for seek */ if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes to buffer */ #if DEBUG > 3 printf("Writing byte %d of %02X\n\r", cur_byt[cur_dsk], data); #endif cur_byt[cur_dsk]++; /* step counter */ dskbuf[i] = data; /* byte into buffer */ if (cur_byt[cur_dsk] == SECT_SIZE) { cur_flg[cur_dsk] &= ~(BUSY | DRQ); if (dptr) { /* if initiated by FDC write command */ sim_fwrite(dskbuf, 256, 1, dptr -> fileref); /* write it */ dptr = NULL; } #if DEBUG > 0 printf("Sector write complete\n\r"); #endif } } return 0; } else { /* read byte from fdc */ if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes from buffer */ #if DEBUG > 1 printf("Reading byte %d\n\r", cur_byt[cur_dsk]); #endif cur_byt[cur_dsk]++; /* step counter */ if (cur_byt[cur_dsk] == SECT_SIZE) { /* done? */ cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ #if DEBUG > 0 printf("Sector read complete\n\r"); #endif } return (dskbuf[i] & 0xFF); } else return 0; } }
uint32 lp_print (UNIT *uptr) { uint32 i, bp, c; uint32 max = (lp_model == LP_7440)? BUF_LNT4: BUF_LNT5; uint32 st; if (lp_pass == 0) { /* pass 1? clr buf */ for (i = 0; i < BUF_LNT4; i++) lp_buf[i] = ' '; } for (bp = 0, st = 0; (bp < max) && !st; bp++) { /* fill buffer */ st = chan_RdMemB (lp_dib.dva, &c); /* get char */ if (CHS_IFERR (st)) /* channel error? */ return st; /* caller handles */ if ((lp_model == LP_7440) || /* 7440 or */ ((bp & 1) == lp_pass)) /* correct pass? */ lp_buf[bp] = lp_to_ascii[c & 0x3F]; } if ((lp_model == LP_7440) || lp_pass) { /* ready to print? */ lp_pass = 0; for (i = BUF_LNT4; (i > 0) && (lp_buf[i - 1] == ' '); i--) ; /* trim */ if (i) /* write line */ sim_fwrite (lp_buf, 1, i, uptr->fileref); fputc (lp_inh? '\r': '\n', uptr->fileref); /* cr or nl */ uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ sim_perror ("Line printer I/O error"); clearerr (uptr->fileref); chan_set_chf (lp_dib.dva, CHF_XMDE); return SCPE_IOERR; } if ((lp_model == LP_7440) && /* 7440? */ ((bp != BUF_LNT4) || (st != CHS_ZBC)) && /* check lnt err */ chan_set_chf (lp_dib.dva, CHF_LNTE)) return CHS_INACTV; /* stop if asked */ } else lp_pass = 1; /* 7450 pass 2 */ lp_cmd = LPS_END; /* end state */ return 0; }
int32 fdcdata(int32 io, int32 data) { int32 val; if (io) { /* write byte to fdc */ fdcbyte = data; /* save for seek */ if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes to buffer */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdata: Writing byte %d of %02X", dsk_unit[cur_dsk].pos, data); *(uint8 *)(dsk_unit[cur_dsk].filebuf + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ dsk_unit[cur_dsk].pos++; /* step counter */ if (dsk_unit[cur_dsk].pos == SECSIZ) { dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); if (wrt_flag) { /* if initiated by FDC write command */ sim_fwrite(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* write it */ wrt_flag = 0; /* clear write flag */ } if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdata: Sector write complete"); } } return 0; } else { /* read byte from fdc */ if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes from buffer */ if (dsk_dev.dctrl & DEBUG_read) printf("\nfdcdata: Reading byte %d u3=%02X", dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); val = *(uint8 *)(dsk_unit[cur_dsk].filebuf + dsk_unit[cur_dsk].pos) & 0xFF; dsk_unit[cur_dsk].pos++; /* step counter */ if (dsk_unit[cur_dsk].pos == SECSIZ) { /* done? */ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdata: Sector read complete"); } return val; } else return 0; } }
/* precondition: current_disk < NUM_OF_DSK */ static void writebuf(void) { int32 i, rtn; UNIT *uptr; i = current_byte[current_disk]; /* null-fill rest of sector if any */ while (i < DSK_SECTSIZE) dskbuf[i++] = 0; uptr = dsk_dev.units + current_disk; if (((uptr -> flags) & UNIT_DSK_WLK) == 0) { /* write enabled */ sim_debug(WRITE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d\n", current_disk, PCX, current_disk, current_track[current_disk], current_sector[current_disk]); if (dskseek(uptr)) { sim_debug(VERBOSE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d\n", current_disk, PCX, current_disk, current_track[current_disk], current_sector[current_disk]); } rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); if (rtn != DSK_SECTSIZE) { sim_debug(VERBOSE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d\n", current_disk, PCX, current_track[current_disk], current_sector[current_disk], rtn); } } else if ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnLock[current_disk] < warnLevelDSK) ) { /* write locked - print warning message if required */ warnLock[current_disk]++; sim_debug(VERBOSE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " Attempt to write to locked DSK%d - ignored.\n", current_disk, PCX, current_disk); } current_flag[current_disk] &= 0xfe; /* ENWD off */ current_byte[current_disk] = 0xff; dirty = FALSE; }
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 */
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); }
/* Format an entire track. The new track to be formatted must be after any existing tracks on * the disk. * * This routine should be enhanced to re-format an existing track to the same format (this * does not involve changing the disk image size.) * * Any existing data on the disk image will be destroyed when Track 0, Head 0 is formatted. * At that time, the IMD file is truncated. So for the trackWrite to be used to sucessfully * format a disk image, then format program must format tracks starting with Cyl 0, Head 0, * and proceed sequentially through all tracks/heads on the disk. * * Format programs that are known to work include: * Cromemco CDOS "INIT.COM" * ADC Super-Six (CP/M-80) "FMT8.COM" * 86-DOS "INIT.COM" * */ t_stat trackWrite(DISK_INFO *myDisk, uint32 Cyl, uint32 Head, uint32 numSectors, uint32 sectorLen, uint8 *sectorMap, uint8 mode, uint8 fillbyte, uint32 *flags) { FILE *fileref; IMD_HEADER track_header; uint8 *sectorData; unsigned long i; unsigned long dataLen; *flags = 0; /* Check parameters */ if(myDisk == NULL) { *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } if(myDisk->flags & FD_FLAG_WRITELOCK) { sim_printf("Disk write-protected, cannot format tracks.\n"); *flags |= IMD_DISK_IO_ERROR_WPROT; return(SCPE_IOERR); } fileref = myDisk->file; sim_debug(myDisk->debugmask, myDisk->device, "Formatting C:%d/H:%d/N:%d, len=%d, Fill=0x%02x\n", Cyl, Head, numSectors, sectorLen, fillbyte); /* Truncate the IMD file when formatting Cyl 0, Head 0 */ if((Cyl == 0) && (Head == 0)) { /* Skip over IMD comment field. */ commentParse(myDisk, NULL, 0); /* Truncate the IMD file after the comment field. */ if (sim_set_fsize(fileref, (t_addr)ftell (fileref)) == -1) { sim_printf("Disk truncation failed.\n"); *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } /* Flush and re-parse the IMD file. */ fflush(fileref); diskParse(myDisk, 0); } /* Check to make sure the Cyl / Head is not already formatted. */ if(sectSeek(myDisk, Cyl, Head) == 0) { sim_printf("SIM_IMD: ERROR: Not Formatting C:%d/H:%d, track already exists.\n", Cyl, Head); *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } track_header.mode = mode; track_header.cyl = Cyl; track_header.head = Head; track_header.nsects = numSectors; track_header.sectsize = sectorLen; /* Forward to end of the file, write track header and sector map. */ sim_fseek(myDisk->file, 0, SEEK_END); sim_fwrite(&track_header, 1, sizeof(IMD_HEADER), fileref); sim_fwrite(sectorMap, 1, numSectors, fileref); /* Compute data length, and fill a sector buffer with the * sector record type as the first byte, and fill the sector * data with the fillbyte. */ dataLen = sectorLen + 1; sectorData = (uint8 *)malloc(dataLen); memset(sectorData, fillbyte, dataLen); sectorData[0] = SECT_RECORD_NORM; /* For each sector on the track, write the record type and sector data. */ for(i=0;i<numSectors;i++) { sim_fwrite(sectorData, 1, dataLen, fileref); } /* Flush the file, and free the sector buffer. */ fflush(fileref); free(sectorData); /* Now that the disk track/sector layout has been modified, re-parse the disk image. */ diskParse(myDisk, 0); return(SCPE_OK); }
/* Write a sector to an IMD image. */ t_stat sectWrite(DISK_INFO *myDisk, uint32 Cyl, uint32 Head, uint32 Sector, uint8 *buf, uint32 buflen, uint32 *flags, uint32 *writelen) { uint32 sectorFileOffset; uint8 sectRecordType; uint8 start_sect; *writelen = 0; sim_debug(myDisk->debugmask, myDisk->device, "Writing C:%d/H:%d/S:%d, len=%d\n", Cyl, Head, Sector, buflen); /* Check parameters */ if(myDisk == NULL) { *flags = IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); } if(sectSeek(myDisk, Cyl, Head) != 0) { *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(myDisk->flags & FD_FLAG_WRITELOCK) { sim_printf("Disk write-protected because the image contains compressed sectors. Use IMDU to uncompress.\n"); *flags = IMD_DISK_IO_ERROR_WPROT; return(SCPE_IOERR); } if(buflen < myDisk->track[Cyl][Head].sectsize) { sim_printf("%s: user buffer too short [buflen %i < sectsize %i]\n", __FUNCTION__, 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_fseek(myDisk->file, sectorFileOffset-1, SEEK_SET); if (*flags & IMD_DISK_IO_ERROR_GENERAL) { sectRecordType = SECT_RECORD_UNAVAILABLE; } else if (*flags & IMD_DISK_IO_ERROR_CRC) { if (*flags & IMD_DISK_IO_DELETED_ADDR_MARK) sectRecordType = SECT_RECORD_NORM_DAM_ERR; else sectRecordType = SECT_RECORD_NORM_ERR; } else { if (*flags & IMD_DISK_IO_DELETED_ADDR_MARK) sectRecordType = SECT_RECORD_NORM_DAM; else sectRecordType = SECT_RECORD_NORM; } fputc(sectRecordType, myDisk->file); sim_fwrite(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file); *writelen = myDisk->track[Cyl][Head].sectsize; return(SCPE_OK); }
static uint8 MFDC_Write(const uint32 Addr, uint8 cData) { unsigned int sec_offset; uint32 flags = 0; uint32 writelen; MFDC_DRIVE_INFO *pDrive; pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; switch(Addr & 0x3) { case 0: case 1: MFDC_Command(cData); break; case 2: case 3: /* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " WR Data" NLP, PCX)); */ if(mfdc_info->wr_latch == 0) { printf("MFDC: " ADDRESS_FORMAT " Error, attempt to write data when write latch is not set." NLP, PCX); } else { #ifdef USE_VGI sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \ (pDrive->sector * MFDC_SECTOR_LEN); sdata.raw[mfdc_info->datacount] = cData; #else int data_index = mfdc_info->datacount - 13; sec_offset = (pDrive->track * 4096) + \ (pDrive->sector * 256); if((data_index >= 0) && (data_index < 256)) { DBG_PRINT(("writing data [%03d]=%02x" NLP, data_index, cData)); sdata.u.data[data_index] = cData; } #endif /* USE_VGI */ mfdc_info->datacount ++; if(mfdc_info->datacount == 270) { sim_debug(WR_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector); 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); } sectWrite(pDrive->imd, pDrive->track, mfdc_info->head, pDrive->sector, sdata.u.data, 256, &flags, &writelen); 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 sim_fwrite(sdata.raw, 1, MFDC_SECTOR_LEN, (pDrive->uptr)->fileref); #else sim_fwrite(sdata.u.data, 1, 256, (pDrive->uptr)->fileref); #endif /* USE_VGI */ } break; case IMAGE_TYPE_CPT: printf("%s: CPT Format not supported" NLP, __FUNCTION__); break; default: printf("%s: Unknown image Format" NLP, __FUNCTION__); break; } } } break; } cData = 0x00; return (cData); }