t_stat ptp_svc (UNIT *uptr) { dev_done = dev_done | INT_PTP; /* set done */ int_req = INT_UPDATE; /* update interrupts */ if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptp_stopioe, SCPE_UNATT); if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { perror ("PTP I/O error"); clearerr (ptp_unit.fileref); return SCPE_IOERR; } ptp_unit.pos = ptp_unit.pos + 1; return SCPE_OK; }
t_stat lpt_svc (UNIT *uptr) { DEV_CLR_BUSY( INT_LPT ) ; DEV_SET_DONE( INT_LPT ) ; DEV_UPDATE_INTR ; if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); pdflpt_putc (uptr, uptr->buf); uptr->pos = pdflpt_where (uptr, NULL); if (pdflpt_error (uptr)) { pdflpt_perror (uptr, "LPT I/O error"); pdflpt_clearerr (uptr); return SCPE_IOERR; } return SCPE_OK; }
t_stat lpt_svc (UNIT *uptr) { DEV_CLR_BUSY( INT_LPT ) ; DEV_SET_DONE( INT_LPT ) ; DEV_UPDATE_INTR ; if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); fputc (uptr->buf, uptr->fileref); uptr->pos = ftell (uptr->fileref); if (ferror (uptr->fileref)) { sim_perror ("LPT I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; }
t_stat ptp_svc (UNIT *uptr) { ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; if (ptp_csr & CSR_IE) SET_INT (PTP); if ((ptp_unit.flags & UNIT_ATT) == 0) return IORETURN (ptp_stopioe, SCPE_UNATT); if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { perror ("PTP I/O error"); clearerr (ptp_unit.fileref); return SCPE_IOERR; } ptp_csr = ptp_csr & ~CSR_ERR; ptp_unit.pos = ptp_unit.pos + 1; return SCPE_OK; }
t_stat lpt_svc (UNIT *uptr) { dev_done = dev_done | INT_LPT; /* set done */ int_req = INT_UPDATE; /* update interrupts */ if ((uptr->flags & UNIT_ATT) == 0) { lpt_err = 1; return IORETURN (lpt_stopioe, SCPE_UNATT); } pdflpt_putc (uptr, uptr->buf); /* print char */ uptr->pos = pdflpt_where (uptr, NULL); if (pdflpt_error (uptr)) { /* error? */ pdflpt_perror (uptr, "LPT I/O error"); pdflpt_clearerr (uptr); return SCPE_IOERR; } return SCPE_OK; }
t_stat lpt_svc (UNIT *uptr) { int32 t; t_stat r = SCPE_OK; lpt_sta = 0; /* clear busy */ if (lpt_arm) /* armed? intr */ SET_INT (v_LPT); if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); t = uptr->buf; /* get character */ if (lpt_spnd || ((t >= LF) && (t < CR))) { /* spc pend or spc op? */ lpt_spnd = 0; if (lpt_bufout (uptr) != SCPE_OK) /* print */ return SCPE_IOERR; if ((t == 1) || (t == LF)) /* single space */ lpt_spc (uptr, 1); else if (t == VT) /* VT->VFU */ r = lpt_vfu (uptr, VT_VFU - 1); else if (t == 0xC) /* FF->VFU */ r = lpt_vfu (uptr, FF_VFU - 1); else if ((t >= SPC_BASE) && (t < VFU_BASE)) lpt_spc (uptr, t - SPC_BASE); /* space */ else if ((t >= VFU_BASE) && (t < VFU_BASE + VFU_WIDTH)) r = lpt_vfu (uptr, t - VFU_BASE); /* VFU */ else fputs ("\r", uptr->fileref); /* overprint */ uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (lpt_unit.fileref)) { sim_perror ("LPT I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } } else if (t == CR) { /* CR? */ lpt_spnd = 1; /* set spc pend */ return lpt_bufout (uptr); /* print line */ } else if (t >= 0x20) { /* printable? */ if ((uptr->flags & UNIT_UC) && islower (t)) /* UC only? */ t = toupper (t); if (lpt_bptr < LPT_WIDTH) lpxb[lpt_bptr++] = t; } return r; }
t_stat ptp_svc (UNIT *uptr) { if (cpls & CPLS_PTP) { /* completion pulse? */ ios = 1; /* restart */ cpls = cpls & ~CPLS_PTP; } iosta = iosta | IOS_PTP; /* set flag */ dev_req_int (ptp_sbs); /* req interrupt */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return IORETURN (ptp_stopioe, SCPE_UNATT); if (putc (uptr->buf, uptr->fileref) == EOF) { /* I/O error? */ perror ("PTP I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } uptr->pos = uptr->pos + 1; return SCPE_OK; }
t_stat lpt_svc(UNIT * uptr) { lpt_csr = lpt_csr | CSR_ERR | CSR_DONE; if (lpt_csr & CSR_IE) SET_INT(LPT); if ((uptr->flags & UNIT_ATT) == 0) return IORETURN(lpt_stopioe, SCPE_UNATT); fputc(uptr->buf & 0177, uptr->fileref); uptr->pos = ftell(uptr->fileref); if (ferror(uptr->fileref)) { perror("LPT I/O error"); clearerr(uptr->fileref); return SCPE_IOERR; } lpt_csr = lpt_csr & ~CSR_ERR; return SCPE_OK; }
t_stat ptr_svc (UNIT *uptr) { int32 temp; ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; if (ptr_csr & CSR_IE) int_req = int_req | INT_PTR; if ((ptr_unit.flags & UNIT_ATT) == 0) return IORETURN (ptr_stopioe, SCPE_UNATT); if ((temp = getc (ptr_unit.fileref)) == EOF) { if (feof (ptr_unit.fileref)) { if (ptr_stopioe) printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); clearerr (ptr_unit.fileref); return SCPE_IOERR; } ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR; ptr_unit.buf = temp & 0377; ptr_unit.pos = ptr_unit.pos + 1; return SCPE_OK; }
t_stat ptp_svc (UNIT *uptr) { int32 c; if (cpls & CPLS_PTP) { /* completion pulse? */ ios = 1; /* restart */ cpls = cpls & ~CPLS_PTP; } iosta = iosta | IOS_PTP; /* set flag */ dev_req_int (ptp_sbs); /* req interrupt */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return IORETURN (ptp_stopioe, SCPE_UNATT); if ((uptr->flags & UNIT_ASCII) != 0) { /* ASCII mode? */ int32 c1 = uptr->buf & 077; if (uptr->buf == 0) /* ignore nulls */ return SCPE_OK; if (c1 == FIODEC_UC) { /* UC? absorb */ ptp_uc = UC; return SCPE_OK; } else if (c1 == FIODEC_LC) { /* LC? absorb */ ptp_uc = 0; return SCPE_OK; } else c = fiodec_to_ascii[c1 | ptp_uc]; if (c == 0) return SCPE_OK; if (c == '\n') { /* new line? */ putc ('\r', uptr->fileref); /* cr first */ uptr->pos = uptr->pos + 1; } } else c = uptr->buf; if (putc (c, uptr->fileref) == EOF) { /* I/O error? */ sim_perror ("PTP I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } uptr->pos = uptr->pos + 1; return SCPE_OK; }
t_stat hsr_svc (UNIT *uptr) { int32 temp; if ((hsr_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (hsr_stopioe, SCPE_UNATT); if ((temp = getc (hsr_unit.fileref)) == EOF) { /* read char */ if (feof (hsr_unit.fileref)) { /* err or eof? */ if (hsr_stopioe) printf ("HSR end of file\n"); else return SCPE_OK; } else perror ("HSR I/O error"); clearerr (hsr_unit.fileref); return SCPE_IOERR; } dev_done = dev_done | INT_HSR; /* set ready */ hsr_unit.buf = temp & 0377; /* save char */ hsr_unit.pos = hsr_unit.pos + 1; return SCPE_OK; }
t_stat ptr_svc (UNIT *uptr) { int32 temp; if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptr_stopioe, SCPE_UNATT); if ((temp = getc (ptr_unit.fileref)) == EOF) { if (feof (ptr_unit.fileref)) { if (ptr_stopioe) printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); clearerr (ptr_unit.fileref); return SCPE_IOERR; } dev_done = dev_done | INT_PTR; /* set done */ int_req = INT_UPDATE; /* update interrupts */ ptr_unit.buf = temp & 0377; ptr_unit.pos = ptr_unit.pos + 1; return SCPE_OK; }
uint32 clkio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ while (working_set) { signal = IONEXT (working_set); /* isolate next signal */ switch (signal) { /* dispatch I/O signal */ case ioCLF: /* clear flag flip-flop */ clk.flag = clk.flagbuf = CLEAR; break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ clk.flag = clk.flagbuf = SET; break; case ioSFC: /* skip if flag is clear */ setstdSKF (clk); break; case ioSFS: /* skip if flag is set */ setstdSKF (clk); break; case ioIOI: /* I/O data input */ stat_data = IORETURN (SCPE_OK, clk_error); /* merge in return status */ break; case ioIOO: /* I/O data output */ clk_select = IODATA (stat_data) & 07; /* save select */ sim_cancel (&clk_unit); /* stop the clock */ clk.control = CLEAR; /* clear control */ working_set = working_set | ioSIR; /* set interrupt request (IOO normally doesn't) */ break; case ioPOPIO: /* power-on preset to I/O */ clk.flag = clk.flagbuf = SET; /* set flag and flag buffer */ break; case ioCRS: /* control reset */ case ioCLC: /* clear control flip-flop */ clk.control = CLEAR; sim_cancel (&clk_unit); /* deactivate unit */ break; case ioSTC: /* set control flip-flop */ clk.control = SET; if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ else clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ if (!sim_is_active (&clk_unit)) { /* clock running? */ clk_tick = clk_delay (0); /* get tick count */ if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ if (clk_select == 2) /* 10 msec. interval? */ clk_tick = sync_poll (INITIAL); /* sync poll */ else sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ sim_activate (&clk_unit, clk_tick); /* start clock */ clk_ctr = clk_delay (1); /* set repeat ctr */ } clk_error = 0; /* clear error */ break; case ioSIR: /* set interrupt request */ setstdPRL (clk); /* set standard PRL signal */ setstdIRQ (clk); /* set standard IRQ signal */ setstdSRQ (clk); /* set standard SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ clk.flagbuf = CLEAR; break; default: /* all other signals */ break; /* are ignored */ } working_set = working_set & ~signal; /* remove current signal from set */ } return stat_data; }
t_stat dp_svc (UNIT *uptr) { int32 dcyl = 0; /* assume recalibrate */ int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */ uint32 h = CW1_GETHEAD (dp_cw1); /* head */ int32 st; uint32 i, offs, lnt, ming, tpos; t_stat r; if (!(uptr->flags & UNIT_ATT)) { /* not attached? */ dp_done (1, STA_OFLER); /* offline */ return IORETURN (dp_stopioe, SCPE_UNATT); } switch (uptr->FNC) { /* case on function */ case FNC_SEEK: /* seek, need cyl */ offs = CW1_GETOFFS (dp_cw1); /* get offset */ if (dp_cw1 & CW1_DIR) /* get desired cyl */ dcyl = uptr->CYL - offs; else dcyl = uptr->CYL + offs; if ((offs == 0) || (dcyl < 0) || (dcyl >= (int32) dp_tab[dp_ctype].cyl)) return dp_done (1, STA_SEKER); /* bad seek? */ case FNC_SK0: /* recalibrate */ dp_sta = dp_sta & ~STA_BUSY; /* clear busy */ uptr->FNC = FNC_SEEK | FNC_2ND; /* next state */ st = (abs (dcyl - uptr->CYL)) * dp_stime; /* schedule seek */ if (st == 0) st = dp_stime; uptr->CYL = dcyl; /* put on cylinder */ sim_activate (uptr, st); return SCPE_OK; case FNC_SEEK | FNC_2ND: /* seek, 2nd state */ if (dp_sta & STA_BUSY) /* busy? queue intr */ dp_defint = 1; else SET_INT (INT_DP); /* no, req intr */ return SCPE_OK; case FNC_UNL: /* unload */ detach_unit (uptr); /* detach unit */ return dp_done (0, 0); /* clear busy, no intr */ case FNC_RCA: /* read current addr */ if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ return dp_done (1, STA_ADRER); /* error */ if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */ return r; dp_rptr = 0; /* init rec ptr */ if (dpxb[dp_rptr + REC_LNT] == 0) /* unformated? */ return dp_done (1, STA_ADRER); /* error */ tpos = (uint32) (fmod (sim_gtime () / (double) dp_xtime, DP_TRKLEN)); do { /* scan down track */ dp_buf = dpxb[dp_rptr + REC_ADDR]; /* get rec addr */ dp_rptr = dp_rptr + dpxb[dp_rptr + REC_LNT] + REC_OVHD; } while ((dp_rptr < tpos) && (dpxb[dp_rptr + REC_LNT] != 0)); if (dp_dma) { /* DMA/DMC? */ if (Q_DMA (ch)) /* DMA? */ dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */ SET_CH_REQ (ch); /* request chan */ } return dp_done (1, STA_RDY); /* clr busy, set rdy */ /* Formating takes place in five states: init - clear track buffer, start at first record address - store address word data - store data word(s) until end of range pause - wait for gap word or stop command gap - validate gap word, advance to next record Note that formating is stopped externally by an OCP command; the track buffer is flushed at that point. If the stop does not occur in the proper state (gap word received), a format error occurs. */ case FNC_FMT: /* format */ for (i = 0; i < DP_TRKLEN; i++) /* clear track */ dpxb[i] = 0; dp_xip = dp_xip | XIP_FMT; /* format in progress */ dp_rptr = 0; /* init record ptr */ dp_gap = 0; /* no gap before first */ dp_bctr = (uint32) (16.0 * dp_tab[dp_ctype].wrds); /* init bit cntr */ uptr->FNC = uptr->FNC | FNC_2ND; /* address state */ break; /* set up next word */ case FNC_FMT | FNC_2ND: /* format, address word */ dp_wptr = 0; /* clear word ptr */ if (dp_bctr < (dp_gap + REC_OVHD_BITS + 16)) /* room for gap, record? */ return dp_wrdone (uptr, STA_FMTER); /* no, format error */ dp_bctr = dp_bctr - dp_gap - REC_OVHD_BITS; /* charge for gap, ovhd */ dpxb[dp_rptr + REC_ADDR] = dp_buf; /* store address */ uptr->FNC = FNC_FMT | FNC_3RD; /* data state */ if (dp_eor) { /* record done? */ dp_eor = 0; /* clear for restart */ if (dp_dma) /* DMA/DMC? intr */ SET_INT (INT_DP); } break; /* set up next word */ case FNC_FMT | FNC_3RD: /* format, data word */ if (dp_sta & STA_RDY) /* timing failure? */ return dp_wrdone (uptr, STA_DTRER); /* write trk, err */ else { /* no, have word */ if (dp_bctr < 16) /* room for it? */ return dp_wrdone (uptr, STA_FMTER); /* no, error */ dp_bctr = dp_bctr - 16; /* charge for word */ dp_csum = dp_csum ^ dp_buf; /* update checksum */ dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_buf;/* store word */ dpxb[dp_rptr + REC_LNT]++; /* incr rec lnt */ dp_wptr++; /* incr word ptr */ } if (dp_eor) { /* record done? */ dp_eor = 0; /* clear for restart */ if (dp_dma) /* DMA/DMC? intr */ SET_INT (INT_DP); dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; /* store checksum */ uptr->FNC = uptr->FNC | FNC_4TH; /* pause state */ sim_activate (uptr, 5 * dp_xtime); /* schedule pause */ return SCPE_OK; /* don't request word */ } break; /* set up next word */ case FNC_FMT | FNC_4TH: /* format, pause */ uptr->FNC = FNC_FMT | FNC_5TH; /* gap state */ break; /* request word */ case FNC_FMT | FNC_5TH: /* format, gap word */ ming = ((16 * dp_wptr) + REC_OVHD_BITS) / 20; /* min 5% gap */ if (dp_buf < ming) /* too small? */ return dp_wrdone (uptr, STA_FMTER); /* yes, format error */ dp_rptr = dp_rptr + dp_wptr + REC_OVHD; /* next record */ uptr->FNC = FNC_FMT | FNC_2ND; /* address state */ if (dp_eor) { /* record done? */ dp_eor = 0; /* clear for restart */ if (dp_dma) SET_INT (INT_DP); /* DMA/DMC? intr */ } dp_gap = dp_buf; /* save gap */ dp_csum = 0; /* clear checksum */ break; /* set up next word */ /* Read and write take place in two states: init - read track into buffer, find record, validate parameters data - (read) fetch data from buffer, stop on end of range - (write) write data into buffer, flush on end of range */ case FNC_RW: /* read/write */ if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ return dp_done (1, STA_ADRER); /* error */ if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */ return r; if (!dp_findrec (dp_cw2)) /* find rec; error? */ return dp_done (1, STA_ADRER); /* address error */ if ((dpxb[dp_rptr + REC_LNT] >= (DP_TRKLEN - dp_rptr - REC_OVHD)) || (dpxb[dp_rptr + REC_EXT] >= REC_MAXEXT)) { /* bad lnt or ext? */ dp_done (1, STA_UNSER); /* stop simulation */ return STOP_DPFMT; /* bad format */ } uptr->FNC = uptr->FNC | FNC_2ND; /* next state */ if (dp_cw1 & CW1_RW) { /* write? */ if (uptr->flags & UNIT_WPRT) /* write protect? */ return dp_done (1, STA_WPRER); /* error */ dp_xip = dp_xip | XIP_WRT; /* write in progress */ dp_sta = dp_sta | STA_RDY; /* set ready */ if (dp_dma) /* if DMA/DMC, req chan */ SET_CH_REQ (ch); } else if (Q_DMA (ch)) /* read; DMA? */ dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */ sim_activate (uptr, dp_xtime); /* schedule word */ dp_wptr = 0; /* init word pointer */ return SCPE_OK; case FNC_RW | FNC_2ND: /* read/write, word */ if (dp_cw1 & CW1_RW) { /* write? */ if (dp_sta & STA_RDY) /* timing failure? */ return dp_wrdone (uptr, STA_DTRER); /* yes, error */ if (r = dp_wrwd (uptr, dp_buf)) /* wr word, error? */ return r; if (dp_eor) { /* transfer done? */ dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; return dp_wrdone (uptr, 0); /* clear busy, intr req */ } } else { /* read? */ lnt = dpxb[dp_rptr + REC_LNT] + dpxb[dp_rptr + REC_EXT]; dp_buf = dpxb[dp_rptr + REC_DATA + dp_wptr];/* current word */ dp_csum = dp_csum ^ dp_buf; /* xor to csum */ if ((dp_wptr > lnt) || dp_eor) /* transfer done? */ return dp_done (1, (dp_csum? STA_CSMER: 0) | ((dp_wptr >= lnt)? STA_EOR: 0)); if (dp_sta & STA_RDY) /* data buf full? */ return dp_done (1, STA_DTRER); /* no, underrun */ dp_wptr++; /* next word */ } break; default: return SCPE_IERR; } /* end case */ dp_sta = dp_sta | STA_RDY; /* set ready */ if (dp_dma) /* if DMA/DMC, req chan */ SET_CH_REQ (ch); sim_activate (uptr, dp_xtime); /* schedule word */ return SCPE_OK; }
static SIGNALS_DATA clk_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; dprintf (clk_dev, DEB_IOB, "Received data %06o with signals %s\n", inbound_value, fmt_bitset (inbound_signals, inbound_format)); while (working_set) { signal = IONEXTSIG (working_set); /* isolate the next signal */ switch (signal) { /* dispatch an I/O signal */ case DCONTSTB: control_word = inbound_value; /* save the control word */ if (control_word & CN_RESET_LOAD_SEL) { /* if the reset/load selector is set */ rate = CN_RATE (control_word); /* then load the clock rate */ if (clk_unit [0].flags & UNIT_CALTIME) /* if in calibrated timing mode */ prescaler = scale [rate]; /* then set the prescaler */ else /* otherwise */ prescaler = 1; /* the prescaler isn't used */ sim_cancel (&clk_unit [0]); /* changing the rate restarts the timing divider */ if (rate > 0) { /* if the rate is valid */ clk_unit [0].wait = delay [rate]; /* then set the initial service delay */ sim_rtcn_init (clk_unit [0].wait, TMR_CLK); /* initialize the clock */ resync_clock (); /* and reschedule the service */ } } else if (control_word & CN_MR) { /* otherwise, if the master reset bit is set */ clk_reset (&clk_dev); /* then reset the interface */ control_word = 0; /* (which clears the other settings) */ } if (control_word & CN_IRQ_RESET_ALL) { /* if a reset of all interrupts is requested */ limit_irq = CLEAR; /* then clear the limit = count, */ lost_tick_irq = CLEAR; /* limit = count overflow, */ system_irq = CLEAR; /* and system flip-flops */ } else if (control_word & CN_IRQ_RESET_MASK) /* otherwise if any single resets are requested */ switch (CN_RESET (control_word)) { /* then reset the specified flip-flop */ case 1: limit_irq = CLEAR; /* clear the limit = count interrupt request */ break; case 2: lost_tick_irq = CLEAR; /* clear the limit = count overflow interrupt request */ break; case 3: system_irq = CLEAR; /* clear the system interrupt request */ break; default: /* the rest of the values do nothing */ break; } if (dibptr->interrupt_active == CLEAR) /* if no interrupt is active */ working_set |= DRESETINT; /* then recalculate interrupt requests */ dprintf (clk_dev, DEB_CSRW, (inbound_value & CN_RESET_LOAD_SEL ? "Control is %s | %s rate%s\n" : "Control is %s%.0s%s\n"), fmt_bitset (inbound_value, control_format), rate_name [CN_RATE (inbound_value)], irq_reset_name [CN_RESET (inbound_value)]); break; case DSTATSTB: status_word = ST_DIO_OK | ST_RATE (rate); /* set the clock rate */ if (limit_irq) /* if the limit = count flip-flop is set */ status_word |= ST_LR_EQ_CR; /* set the corresponding status bit */ if (lost_tick_irq) /* if the limit = count overflow flip-flop is set */ status_word |= ST_LR_EQ_CR_OVFL; /* set the corresponding status bit */ if (system_irq) /* if the system interrupt request flip-flop is set */ status_word |= ST_SYSTEM_IRQ; /* set the corresponding status bit */ if (control_word & CN_LIMIT_COUNT_SEL) /* if the limit/count selector is set */ status_word |= ST_LIMIT_COUNT_SEL; /* set the corresponding status bit */ if (control_word & CN_COUNT_RESET) /* if the reset-after-interrupt selector is set */ status_word |= ST_COUNT_RESET; /* set the corresponding status bit */ outbound_value = status_word; /* return the status word */ dprintf (clk_dev, DEB_CSRW, "Status is %s%s rate\n", fmt_bitset (outbound_value, status_format), rate_name [ST_TO_RATE (outbound_value)]); break; case DREADSTB: clk_update_counter (); /* update the clock counter register */ outbound_value = LOWER_WORD (count_register); /* and then read it */ dprintf (clk_dev, DEB_CSRW, "Count register value %u returned\n", count_register); break; case DWRITESTB: if (control_word & CN_LIMIT_COUNT_SEL) { /* if the limit/count selector is set */ clk_update_counter (); /* then update the clock counter register */ count_register = 0; /* and then clear it */ dprintf (clk_dev, DEB_CSRW, "Count register cleared\n"); } else { /* otherwise */ limit_register = inbound_value; /* set the limit register to the supplied value */ dprintf (clk_dev, DEB_CSRW, "Limit register value %u set\n", limit_register); coschedulable = (ticks [rate] == 1000 /* the clock can be coscheduled if the rate */ && limit_register == 100); /* is 1 msec and the limit is 100 ticks */ } break; case DSETINT: system_irq = SET; /* set the system interrupt request flip-flop */ dibptr->interrupt_request = SET; /* request an interrupt */ outbound_signals |= INTREQ; /* and notify the IOP */ break; case DRESETINT: dibptr->interrupt_active = CLEAR; /* clear the Interrupt Active flip-flop */ if ((limit_irq == SET || lost_tick_irq == SET) /* if the limit or lost tick flip-flops are set */ && control_word & CN_IRQ_ENABLE) /* and interrupts are enabled */ dibptr->interrupt_request = SET; /* then set the interrupt request flip-flop */ else /* otherwise */ dibptr->interrupt_request = system_irq; /* request an interrupt if the system flip-flop is set */ if (dibptr->interrupt_request) /* if a request is pending */ outbound_signals |= INTREQ; /* then notify the IOP */ break; case INTPOLLIN: if (dibptr->interrupt_request) { /* if a request is pending */ dibptr->interrupt_request = CLEAR; /* then clear it */ dibptr->interrupt_active = SET; /* and mark it as now active */ outbound_signals |= INTACK; /* acknowledge the interrupt */ outbound_value = dibptr->device_number; /* and return our device number */ } else /* otherwise the request has been reset */ outbound_signals |= INTPOLLOUT; /* so let the IOP know to cancel it */ break; case DSTARTIO: /* not used by this interface */ case DSETMASK: /* not used by this interface */ case ACKSR: /* not used by this interface */ case TOGGLESR: /* not used by this interface */ case SETINT: /* not used by this interface */ case PCMD1: /* not used by this interface */ case PCONTSTB: /* not used by this interface */ case SETJMP: /* not used by this interface */ case PSTATSTB: /* not used by this interface */ case PWRITESTB: /* not used by this interface */ case PREADSTB: /* not used by this interface */ case EOT: /* not used by this interface */ case TOGGLEINXFER: /* not used by this interface */ case TOGGLEOUTXFER: /* not used by this interface */ case READNEXTWD: /* not used by this interface */ case TOGGLESIOOK: /* not used by this interface */ case DEVNODB: /* not used by this interface */ case XFERERROR: /* not used by this interface */ case CHANSO: /* not used by this interface */ case PFWARN: /* not used by this interface */ break; } IOCLEARSIG (working_set, signal); /* remove the current signal from the set */ } dprintf (clk_dev, DEB_IOB, "Returned data %06o with signals %s\n", outbound_value, fmt_bitset (outbound_signals, outbound_format)); return IORETURN (outbound_signals, outbound_value); /* return the outbound signals and value */ }
t_stat rp_svc (UNIT *uptr) { int32 f, u, comp, cyl, sect, surf; int32 err, pa, da, wc, awc, i; u = (int32) (uptr - rp_dev.units); /* get drv number */ f = uptr->FUNC; /* get function */ if (f == FN_IDLE) { /* idle? */ rp_busy = 0; /* clear busy */ return SCPE_OK; } if ((f == FN_SEEK) || (f == FN_RECAL)) { /* seek or recal? */ rp_busy = 0; /* not busy */ cyl = (f == FN_SEEK)? GET_CYL (rp_da): 0; /* get cylinder */ sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr->CYL) * rp_swait)); uptr->CYL = cyl; /* on cylinder */ uptr->FUNC = FN_SEEK | FN_2ND; /* set second state */ rp_updsta (0, 0); /* update status */ return SCPE_OK; } if (f == (FN_SEEK | FN_2ND)) { /* seek done? */ rp_updsta (0, rp_stb | (1 << (STB_V_ATT0 - u))); /* set attention */ return SCPE_OK; } if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */ return IORETURN (rp_stopioe, SCPE_UNATT); } if ((f == FN_WRITE) && (uptr->flags & UNIT_WPRT)) { /* write locked? */ rp_updsta (STA_DON | STA_WPE, 0); /* error */ return SCPE_OK; } if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0); if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0); if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0); if (rp_sta & (STA_NXS | STA_NXF | STA_NXC)) { /* or bad disk addr? */ rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */ return SCPE_OK; } pa = rp_ma & AMASK; /* get mem addr */ da = GET_DA (rp_da) * RP_NUMWD; /* get disk addr */ wc = 01000000 - rp_wc; /* get true wc */ if (((uint32) (pa + wc)) > MEMSIZE) { /* memory overrun? */ nexm = 1; /* set nexm flag */ wc = MEMSIZE - pa; /* limit xfer */ } if ((da + wc) > RP_SIZE) { /* disk overrun? */ rp_updsta (0, STB_EOP); /* error */ wc = RP_SIZE - da; /* limit xfer */ } err = fseek (uptr->fileref, da * sizeof (int), SEEK_SET); if ((f == FN_READ) && (err == 0)) { /* read? */ awc = fxread (&M[pa], sizeof (int32), wc, uptr->fileref); for ( ; awc < wc; awc++) M[pa + awc] = 0; err = ferror (uptr->fileref); } if ((f == FN_WRITE) && (err == 0)) { /* write? */ fxwrite (&M[pa], sizeof (int32), wc, uptr->fileref); err = ferror (uptr->fileref); if ((err == 0) && (i = (wc & (RP_NUMWD - 1)))) { fxwrite (fill, sizeof (int), i, uptr->fileref); err = ferror (uptr->fileref); } } if ((f == FN_WRCHK) && (err == 0)) { /* write check? */ for (i = 0; (err == 0) && (i < wc); i++) { awc = fxread (&comp, sizeof (int32), 1, uptr->fileref); if (awc == 0) comp = 0; if (comp != M[pa + i]) rp_updsta (0, STB_WCE); } err = ferror (uptr->fileref); } rp_wc = (rp_wc + wc) & DMASK; /* final word count */ rp_ma = (rp_ma + wc) & DMASK; /* final mem addr */ da = (da + wc + (RP_NUMWD - 1)) / RP_NUMWD; /* final sector num */ cyl = da / (RP_NUMSC * RP_NUMSF); /* get cyl */ if (cyl >= RP_NUMCY) cyl = RP_NUMCY - 1; surf = (da % (RP_NUMSC * RP_NUMSF)) / RP_NUMSC; /* get surface */ sect = (da % (RP_NUMSC * RP_NUMSF)) % RP_NUMSC; /* get sector */ rp_da = (cyl << DA_V_CYL) | (surf << DA_V_SURF) | (sect << DA_V_SECT); rp_busy = 0; /* clear busy */ rp_updsta (STA_DON, 0); /* set done */ if (err != 0) { /* error? */ perror ("RP I/O error"); clearerr (uptr->fileref); return IORETURN (rp_stopioe, SCPE_IOERR); } return SCPE_OK; }
t_stat rk_svc (UNIT *uptr) { int32 err, wc, wc1, awc, swc, pa, da; UNIT *seluptr; if (uptr->FUNC == RKC_SEEK) { /* seek? */ seluptr = rk_dev.units + GET_DRIVE (rk_cmd); /* see if selected */ if ((uptr == seluptr) && ((rk_cmd & RKC_SKDN) != 0)) { rk_sta = rk_sta | RKS_DONE; RK_INT_UPDATE; } return SCPE_OK; } if ((uptr->flags & UNIT_ATT) == 0) { /* not att? abort */ rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT; rk_busy = 0; RK_INT_UPDATE; return IORETURN (rk_stopioe, SCPE_UNATT); } if ((uptr->FUNC == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) { rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */ rk_busy = 0; RK_INT_UPDATE; return SCPE_OK; } pa = GET_MEX (rk_cmd) | rk_ma; /* phys address */ da = GET_DA (rk_cmd, rk_da) * RK_NUMWD * sizeof (int16);/* disk address */ swc = wc = (rk_cmd & RKC_HALF)? RK_NUMWD / 2: RK_NUMWD; /* get transfer size */ if ((wc1 = ((rk_ma + wc) - 010000)) > 0) /* if wrap, limit */ wc = wc - wc1; err = fseek (uptr->fileref, da, SEEK_SET); /* locate sector */ if ((uptr->FUNC == RKC_READ) && (err == 0) && MEM_ADDR_OK (pa)) { /* read? */ awc = fxread (&M[pa], sizeof (int16), wc, uptr->fileref); for ( ; awc < wc; awc++) /* fill if eof */ M[pa + awc] = 0; err = ferror (uptr->fileref); if ((wc1 > 0) && (err == 0)) { /* field wraparound? */ pa = pa & 070000; /* wrap phys addr */ awc = fxread (&M[pa], sizeof (int16), wc1, uptr->fileref); for ( ; awc < wc1; awc++) /* fill if eof */ M[pa + awc] = 0; err = ferror (uptr->fileref); } } if ((uptr->FUNC == RKC_WRITE) && (err == 0)) { /* write? */ fxwrite (&M[pa], sizeof (int16), wc, uptr->fileref); err = ferror (uptr->fileref); if ((wc1 > 0) && (err == 0)) { /* field wraparound? */ pa = pa & 070000; /* wrap phys addr */ fxwrite (&M[pa], sizeof (int16), wc1, uptr->fileref); err = ferror (uptr->fileref); } if ((rk_cmd & RKC_HALF) && (err == 0)) { /* fill half sector */ fxwrite (fill, sizeof (int16), RK_NUMWD/2, uptr->fileref); err = ferror (uptr->fileref); } } rk_ma = (rk_ma + swc) & 07777; /* incr mem addr reg */ rk_sta = rk_sta | RKS_DONE; /* set done */ rk_busy = 0; RK_INT_UPDATE; if (err != 0) { sim_perror ("RK I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; }
uint32 lptio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { uint16 data; IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ while (working_set) { signal = IONEXT (working_set); /* isolate next signal */ switch (signal) { /* dispatch I/O signal */ case ioCLF: /* clear flag flip-flop */ lpt.flag = lpt.flagbuf = CLEAR; break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ lpt.flag = lpt.flagbuf = SET; break; case ioSFC: /* skip if flag is clear */ setstdSKF (lpt); break; case ioSFS: /* skip if flag is set */ setstdSKF (lpt); break; case ioIOI: /* I/O data input */ data = 0; if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */ data = LPT_PWROFF; else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */ if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */ data = LPT_RDY; if (!sim_is_active (&lpt_unit)) /* printer busy? */ data = data | LPT_NBSY; } else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */ data = LPT_PAPO; } stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ break; case ioIOO: /* I/O data output */ lpt_unit.buf = IODATA (stat_data) & (LPT_CTL | 0177); break; case ioPOPIO: /* power-on preset to I/O */ lpt.flag = lpt.flagbuf = SET; /* set flag and flag buffer */ lpt_unit.buf = 0; /* clear output buffer */ break; case ioCRS: /* control reset */ case ioCLC: /* clear control flip-flop */ lpt.control = CLEAR; break; case ioSTC: /* set control flip-flop */ lpt.control = SET; sim_activate (&lpt_unit, /* schedule op */ (lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime); break; case ioSIR: /* set interrupt request */ setstdPRL (lpt); /* set standard PRL signal */ setstdIRQ (lpt); /* set standard IRQ signal */ setstdSRQ (lpt); /* set standard SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ lpt.flagbuf = CLEAR; break; default: /* all other signals */ break; /* are ignored */ } working_set = working_set & ~signal; /* remove current signal from set */ } return stat_data; }
uint32 dqcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { int32 fnc, drv; IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ while (working_set) { signal = IONEXT (working_set); /* isolate next signal */ switch (signal) { /* dispatch I/O signal */ case ioCLF: /* clear flag flip-flop */ dqc.flag = dqc.flagbuf = CLEAR; break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ dqc.flag = dqc.flagbuf = SET; break; case ioSFC: /* skip if flag is clear */ setstdSKF (dqc); break; case ioSFS: /* skip if flag is set */ setstdSKF (dqc); break; case ioIOI: /* I/O data input */ stat_data = IORETURN (SCPE_OK, 0); /* no data */ break; case ioIOO: /* I/O data output */ dqc_obuf = IODATA (stat_data); /* clear supplied status */ break; case ioPOPIO: /* power-on preset to I/O */ dqc.flag = dqc.flagbuf = SET; /* set flag and flag buffer */ dqc_obuf = 0; /* clear output buffer */ break; case ioCRS: /* control reset */ case ioCLC: /* clear control flip-flop */ dqc.command = CLEAR; /* clear command */ dqc.control = CLEAR; /* clear control */ if (dqc_busy) sim_cancel (&dqc_unit[dqc_busy - 1]); sim_cancel (&dqd_unit); /* cancel dch */ dqd_xfer = 0; /* clr dch xfer */ dqc_busy = 0; /* clr busy */ break; case ioSTC: /* set control flip-flop */ dqc.control = SET; /* set ctl */ if (!dqc.command) { /* cmd clr? */ dqc.command = SET; /* set cmd */ drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ switch (fnc) { /* case on fnc */ case FNC_SEEK: case FNC_RCL: /* seek, recal */ case FNC_CHK: /* check */ dqc_sta[drv] = 0; /* clear status */ case FNC_STA: case FNC_LA: /* rd sta, load addr */ dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ break; case FNC_RD: case FNC_WD: /* read, write */ case FNC_RA: case FNC_WA: /* rd addr, wr addr */ case FNC_AS: /* address skip */ dq_goc (fnc, drv, dqc_ctime); /* sched drive */ break; } /* end case */ } /* end if !CMD */ break; case ioSIR: /* set interrupt request */ setstdPRL (dqc); /* set standard PRL signal */ setstdIRQ (dqc); /* set standard IRQ signal */ setstdSRQ (dqc); /* set standard SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ dqc.flagbuf = CLEAR; break; default: /* all other signals */ break; /* are ignored */ } working_set = working_set & ~signal; /* remove current signal from set */ } return stat_data; }
uint32 dqdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ while (working_set) { signal = IONEXT (working_set); /* isolate next signal */ switch (signal) { /* dispatch I/O signal */ case ioCLF: /* clear flag flip-flop */ dqd.flag = dqd.flagbuf = CLEAR; break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ dqd.flag = dqd.flagbuf = SET; break; case ioSFC: /* skip if flag is clear */ setstdSKF (dqd); break; case ioSFS: /* skip if flag is set */ setstdSKF (dqd); break; case ioIOI: /* I/O data input */ stat_data = IORETURN (SCPE_OK, dqd_ibuf); /* merge in return status */ break; case ioIOO: /* I/O data output */ dqd_obuf = IODATA (stat_data); /* clear supplied status */ if (!dqc_busy || dqd_xfer) dqd_wval = 1; /* if !overrun, valid */ break; case ioPOPIO: /* power-on preset to I/O */ dqd.flag = dqd.flagbuf = SET; /* set flag and flag buffer */ dqd_obuf = 0; /* clear output buffer */ break; case ioCRS: /* control reset */ dqd.command = CLEAR; /* clear command */ /* fall into CLC handler */ case ioCLC: /* clear control flip-flop */ dqd.control = CLEAR; /* clear control */ dqd_xfer = 0; /* clr xfer */ break; case ioSTC: /* set control flip-flop */ dqd.command = SET; /* set ctl, cmd */ dqd.control = SET; if (dqc_busy && !dqd_xfer) /* overrun? */ dqc_sta[dqc_busy - 1] |= STA_DTE; break; case ioSIR: /* set interrupt request */ setstdPRL (dqd); /* set standard PRL signal */ setstdIRQ (dqd); /* set standard IRQ signal */ setstdSRQ (dqd); /* set standard SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ dqd.flagbuf = CLEAR; break; default: /* all other signals */ break; /* are ignored */ } working_set = working_set & ~signal; /* remove current signal from set */ } return stat_data; }
t_stat rx_svc (UNIT *uptr) { int32 i, func; uint32 da; int8 *fbuf = uptr->filebuf; func = RXCS_GETFNC (rx_csr); /* get function */ switch (rx_state) { /* case on state */ case IDLE: /* idle */ return SCPE_IERR; /* done */ case EMPTY: /* empty buffer */ if (rx_bptr >= RX_NUMBY) /* done all? */ rx_done (0, 0); else { rx_dbr = rx_buf[rx_bptr]; /* get next */ rx_bptr = rx_bptr + 1; rx_csr = rx_csr | RXCS_TR; /* set xfer */ } break; case FILL: /* fill buffer */ rx_buf[rx_bptr] = rx_dbr; /* write next */ rx_bptr = rx_bptr + 1; if (rx_bptr < RX_NUMBY) /* more? set xfer */ rx_csr = rx_csr | RXCS_TR; else rx_done (0, 0); /* else done */ break; case RWDS: /* wait for sector */ rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */ rx_csr = rx_csr | RXCS_TR; /* set xfer */ rx_state = RWDT; /* advance state */ return SCPE_OK; case RWDT: /* wait for track */ rx_track = rx_dbr & RX_M_TRACK; /* save track */ rx_state = RWXFR; sim_activate (uptr, /* sched done */ rx_swait * abs (rx_track - uptr->TRACK)); return SCPE_OK; case RWXFR: if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ rx_done (0, 0110); /* done, error */ return IORETURN (rx_stopioe, SCPE_UNATT); } if (rx_track >= RX_NUMTR) { /* bad track? */ rx_done (0, 0040); /* done, error */ break; } uptr->TRACK = rx_track; /* now on track */ if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */ rx_done (0, 0070); /* done, error */ break; } da = CALC_DA (rx_track, rx_sector); /* get disk address */ if (func == RXCS_WRDEL) /* del data? */ rx_esr = rx_esr | RXES_DD; if (func == RXCS_READ) { /* read? */ for (i = 0; i < RX_NUMBY; i++) rx_buf[i] = fbuf[da + i]; } else { if (uptr->flags & UNIT_WPRT) { /* write and locked? */ rx_done (RXES_WLK, 0100); /* done, error */ break; } for (i = 0; i < RX_NUMBY; i++) /* write */ fbuf[da + i] = rx_buf[i]; da = da + RX_NUMBY; if (da > uptr->hwmark) uptr->hwmark = da; } rx_done (0, 0); /* done */ break; case CMD_COMPLETE: /* command complete */ if (func == RXCS_ECODE) { /* read ecode? */ rx_dbr = rx_ecode; /* set dbr */ rx_done (0, -1); /* don't update */ } else rx_done (0, 0); break; case INIT_COMPLETE: /* init complete */ rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */ rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */ if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */ rx_done (RXES_ID, 0010); /* init done, error */ break; } da = CALC_DA (1, 1); /* track 1, sector 1 */ for (i = 0; i < RX_NUMBY; i++) /* read sector */ rx_buf[i] = fbuf[da + i]; rx_done (RXES_ID, 0); /* set done */ if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020; break; } /* end case state */ return SCPE_OK; }
t_stat mt_svc (UNIT *uptr) { uint32 i; int32 u = uptr - mt_dev.units; uint32 dev = mt_dib.dno + (u * o_MT0); t_mtrlnt tbc; t_bool passed_eot; t_stat st, r = SCPE_OK; if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ uptr->UCMD = 0; /* clr cmd */ uptr->UST = 0; /* set status */ mt_xfr = 0; /* clr op flags */ mt_sta = STA_ERR | STA_EOM; /* set status */ if (mt_arm[u]) /* interrupt */ SET_INT (v_MT + u); return IORETURN (mt_stopioe, SCPE_UNATT); } if (uptr->UCMD & MTC_STOP2) { /* stop, gen NMTN? */ uptr->UCMD = 0; /* clr cmd */ uptr->UST = uptr->UST | STA_NMTN; /* set nmtn */ mt_xfr = 0; /* clr xfr */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); return SCPE_OK; } if (uptr->UCMD & MTC_STOP1) { /* stop, gen EOM? */ uptr->UCMD = uptr->UCMD | MTC_STOP2; /* clr cmd */ mt_sta = (mt_sta & ~STA_BSY) | STA_EOM; /* clr busy, set eom */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); sim_activate (uptr, mt_rtime); /* schedule */ return SCPE_OK; } passed_eot = sim_tape_eot (uptr); /* passed EOT? */ switch (uptr->UCMD) { /* case on function */ case MTC_REW: /* rewind */ sim_tape_rewind (uptr); /* reposition */ uptr->UCMD = 0; /* clr cmd */ uptr->UST = STA_NMTN | STA_EOT; /* update status */ mt_sta = mt_sta & ~STA_BSY; /* don't set EOM */ if (mt_arm[u]) /* interrupt */ SET_INT (v_MT + u); return SCPE_OK; /* For read, busy = 1 => buffer empty For write, busy = 1 => buffer full For read, data transfers continue for the full length of the record, or the maximum size of the transfer buffer For write, data transfers continue until a write is attempted and the buffer is empty */ case MTC_RD: /* read */ if (mt_blnt == 0) { /* first time? */ st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */ if (st == MTSE_RECE) /* rec in err? */ mt_sta = mt_sta | STA_ERR; else if (st != SCPE_OK) { /* other error? */ r = mt_map_err (uptr, st); /* map error */ if (sch_actv (mt_dib.sch, dev)) /* if sch, stop */ sch_stop (mt_dib.sch); break; } mt_blnt = tbc; /* set buf lnt */ } if (sch_actv (mt_dib.sch, dev)) { /* sch active? */ i = sch_wrmem (mt_dib.sch, mtxb, mt_blnt); /* store rec in mem */ if (sch_actv (mt_dib.sch, dev)) /* sch still active? */ sch_stop (mt_dib.sch); /* stop chan, long rd */ else if (i < mt_blnt) /* process entire rec? */ mt_sta = mt_sta | STA_ERR; /* no, overrun error */ } else if (mt_bptr < mt_blnt) { /* no, if !eor */ if (!(mt_sta & STA_BSY)) /* busy still clr? */ mt_sta = mt_sta | STA_ERR; /* read overrun */ mt_db = mtxb[mt_bptr++]; /* get next byte */ mt_sta = mt_sta & ~STA_BSY; /* !busy = buf full */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); sim_activate (uptr, mt_wtime); /* reschedule */ return SCPE_OK; } break; /* record done */ case MTC_WR: /* write */ if (sch_actv (mt_dib.sch, dev)) { /* sch active? */ mt_bptr = sch_rdmem (mt_dib.sch, mtxb, MT_MAXFR); /* get rec */ if (sch_actv (mt_dib.sch, dev)) /* not done? */ sch_stop (mt_dib.sch); /* stop chan */ } else if (mt_sta & STA_BSY) { /* no, if !eor */ if (mt_bptr < MT_MAXFR) /* if room */ mtxb[mt_bptr++] = mt_db; /* store in buf */ mt_sta = mt_sta & ~STA_BSY; /* !busy = buf emp */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); sim_activate (uptr, mt_wtime); /* reschedule */ return SCPE_OK; } if (mt_bptr) { /* any chars? */ if ((st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)))/* write, err? */ r = mt_map_err (uptr, st); /* map error */ } break; /* record done */ case MTC_WEOF: /* write eof */ if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); break; case MTC_SKFF: /* skip file fwd */ while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; if (st == MTSE_TMK) { /* stopped by tmk? */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); } else r = mt_map_err (uptr, st); /* map error */ break; case MTC_SKFR: /* skip file rev */ while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; if (st == MTSE_TMK) { /* stopped by tmk? */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ SET_INT (v_MT + u); } else r = mt_map_err (uptr, st); /* map error */ break; case MTC_SPCR: /* backspace */ if ((st = sim_tape_sprecr (uptr, &tbc))) /* skip rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; } /* end case */ if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */ uptr->UST = uptr->UST | STA_EOT; uptr->UCMD = uptr->UCMD | MTC_STOP1; /* set stop stage 1 */ sim_activate (uptr, mt_rtime); /* schedule */ return r; }
uint32 ptpio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ while (working_set) { signal = IONEXT (working_set); /* isolate next signal */ switch (signal) { /* dispatch I/O signal */ case ioCLF: /* clear flag flip-flop */ ptp.flag = ptp.flagbuf = CLEAR; break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ ptp.flag = ptp.flagbuf = SET; break; case ioSFC: /* skip if flag is clear */ setstdSKF (ptp); break; case ioSFS: /* skip if flag is set */ setstdSKF (ptp); break; case ioIOI: /* I/O data input */ if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ stat_data = IORETURN (SCPE_OK, PTP_LOW); /* report as out of tape */ else stat_data = IORETURN (SCPE_OK, 0); break; case ioIOO: /* I/O data output */ ptp_unit.buf = IODATA (stat_data); /* clear supplied status */ break; case ioPOPIO: /* power-on preset to I/O */ ptp.flag = ptp.flagbuf = SET; /* set flag and flag buffer */ ptp_unit.buf = 0; /* clear output buffer */ break; case ioCRS: /* control reset */ case ioCLC: /* clear control flip-flop */ ptp.control = CLEAR; break; case ioSTC: /* set control flip-flop */ ptp.control = SET; sim_activate (&ptp_unit, ptp_unit.wait); break; case ioSIR: /* set interrupt request */ setstdPRL (ptp); /* set standard PRL signal */ setstdIRQ (ptp); /* set standard IRQ signal */ setstdSRQ (ptp); /* set standard SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ ptp.flagbuf = CLEAR; break; default: /* all other signals */ break; /* are ignored */ } working_set = working_set & ~signal; /* remove current signal from set */ } return stat_data; }
t_stat mtc_svc (UNIT *uptr) { t_mtrlnt tbc; t_stat st, r = SCPE_OK; if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ return IORETURN (mtc_stopioe, SCPE_UNATT); } switch (mtc_fnc) { /* case on function */ case FNC_REW: /* rewind */ sim_tape_rewind (uptr); /* BOT */ mtc_sta = STA_BOT; /* update status */ break; case FNC_RWS: /* rewind and offline */ sim_tape_rewind (uptr); /* clear position */ return sim_tape_detach (uptr); /* don't set cch flg */ case FNC_WFM: /* write file mark */ if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ mtc_sta = STA_EOF; /* set EOF status */ break; case FNC_GAP: /* erase gap */ break; case FNC_FSR: /* space forward */ if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; case FNC_BSR: /* space reverse */ if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; case FNC_RC: /* read */ if (mtc_1st) { /* first svc? */ mtc_1st = mt_ptr = 0; /* clr 1st flop */ st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */ if (st == MTSE_RECE) mtc_sta = mtc_sta | STA_PAR; /* rec in err? */ else if (st != MTSE_OK) { /* other error? */ r = mt_map_err (uptr, st); /* map error */ if (r == SCPE_OK) { /* recoverable? */ sim_activate (uptr, mtc_gtime); /* sched IRG */ mtc_fnc = 0; /* NOP func */ return SCPE_OK; } break; /* non-recov, done */ } if (mt_max < 12) { /* record too short? */ mtc_sta = mtc_sta | STA_PAR; /* set flag */ break; } } if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */ if (mtd_flag) mtc_sta = mtc_sta | STA_TIM; mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } sim_activate (uptr, mtc_gtime); /* schedule gap */ mtc_fnc = 0; /* nop */ return SCPE_OK; case FNC_WC: /* write */ if (mtc_1st) mtc_1st = 0; /* no xfr on first */ else { if (mt_ptr < DBSIZE) { /* room in buffer? */ mtxb[mt_ptr++] = mtc_unit.buf; mtc_sta = mtc_sta & ~STA_BOT; /* clear BOT */ } else mtc_sta = mtc_sta | STA_PAR; } if (mtc_dtf) { /* xfer flop set? */ mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } if (mt_ptr) { /* write buffer */ if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) { /* write, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* done */ } } sim_activate (uptr, mtc_gtime); /* schedule gap */ mtc_fnc = 0; /* nop */ return SCPE_OK; default: /* unknown */ break; } mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ return r; }
uint32 ttyio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { uint16 data; IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ while (working_set) { signal = IONEXT (working_set); /* isolate next signal */ switch (signal) { /* dispatch I/O signal */ case ioCLF: /* clear flag flip-flop */ tty.flag = tty.flagbuf = CLEAR; break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ tty.flag = tty.flagbuf = SET; break; case ioSFC: /* skip if flag is clear */ setstdSKF (tty); break; case ioSFS: /* skip if flag is set */ setstdSKF (tty); break; case ioIOI: /* I/O data input */ data = tty_buf; if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) data = data | TP_BUSY; stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ break; case ioIOO: /* I/O data output */ data = IODATA (stat_data); /* clear supplied status */ if (data & TM_MODE) tty_mode = data & (TM_KBD|TM_PRI|TM_PUN); tty_buf = data & 0377; break; case ioCRS: /* control reset */ tty.control = CLEAR; /* clear control */ tty.flag = tty.flagbuf = SET; /* set flag and flag buffer */ tty_mode = TM_KBD; /* set tty, clear print/punch */ tty_shin = 0377; /* input inactive */ tty_lf = 0; /* no lf pending */ break; case ioCLC: /* clear control flip-flop */ tty.control = CLEAR; break; case ioSTC: /* set control flip-flop */ tty.control = SET; if (!(tty_mode & TM_KBD)) /* output? */ sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); break; case ioSIR: /* set interrupt request */ setstdPRL (tty); /* set standard PRL signal */ setstdIRQ (tty); /* set standard IRQ signal */ setstdSRQ (tty); /* set standard SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ tty.flagbuf = CLEAR; break; default: /* all other signals */ break; /* are ignored */ } working_set = working_set & ~signal; /* remove current signal from set */ } return stat_data; }
t_stat ry_svc (UNIT *uptr) { int32 i, t, func, bps; static uint8 estat[8]; uint32 ba, da; int8 *fbuf = uptr->filebuf; func = RYCS_GETFNC (ry_csr); /* get function */ bps = (ry_csr & RYCS_DEN)? RY_NUMBY: RX_NUMBY; /* get sector size */ ba = (RYCS_GETUAE (ry_csr) << 16) | ry_ba; /* get mem addr */ switch (ry_state) { /* case on state */ case IDLE: /* idle */ return SCPE_IERR; case FEWC: /* word count */ ry_wc = ry_dbr & 0377; /* save WC */ ry_csr = ry_csr | RYCS_TR; /* set TR */ ry_state = FEBA; /* next state */ return SCPE_OK; case FEBA: /* buffer address */ ry_ba = ry_dbr; /* save buf addr */ ry_state = FEXFR; /* next state */ sim_activate (uptr, ry_cwait); /* schedule xfer */ return SCPE_OK; case FEXFR: /* transfer */ if ((ry_wc << 1) > bps) { /* wc too big? */ ry_done (RYES_WCO, 0230); /* error */ break; } if (func == RYCS_FILL) { /* fill? read */ for (i = 0; i < RY_NUMBY; i++) rx2xb[i] = 0; t = Map_ReadB (ba, ry_wc << 1, rx2xb); } else t = Map_WriteB (ba, ry_wc << 1, rx2xb); ry_wc = t >> 1; /* adjust wc */ ry_done (t? RYES_NXM: 0, 0); /* done */ break; case RWDS: /* wait for sector */ ry_sector = ry_dbr & RX_M_SECTOR; /* save sector */ ry_csr = ry_csr | RYCS_TR; /* set xfer */ ry_state = RWDT; /* advance state */ return SCPE_OK; case RWDT: /* wait for track */ ry_track = ry_dbr & RX_M_TRACK; /* save track */ ry_state = RWXFR; /* next state */ sim_activate (uptr, /* sched xfer */ ry_swait * abs (ry_track - uptr->TRACK)); return SCPE_OK; case RWXFR: /* read/write */ if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ ry_done (0, 0110); /* done, error */ return IORETURN (ry_stopioe, SCPE_UNATT); } if (ry_track >= RX_NUMTR) { /* bad track? */ ry_done (0, 0040); /* done, error */ break; } uptr->TRACK = ry_track; /* now on track */ if ((ry_sector == 0) || (ry_sector > RX_NUMSC)) { /* bad sect? */ ry_done (0, 0070); /* done, error */ break; } if (((uptr->flags & UNIT_DEN) != 0) ^ ((ry_csr & RYCS_DEN) != 0)) { /* densities agree? */ ry_done (RYES_DERR, 0240); /* no, error */ break; } da = CALC_DA (ry_track, ry_sector, bps); /* get disk address */ if (func == RYCS_WRDEL) /* del data? */ ry_esr = ry_esr | RYES_DD; if (func == RYCS_READ) { /* read? */ for (i = 0; i < bps; i++) rx2xb[i] = fbuf[da + i]; } else { if (uptr->flags & UNIT_WPRT) { /* write and locked? */ ry_done (0, 0100); /* done, error */ break; } for (i = 0; i < bps; i++) /* write */ fbuf[da + i] = rx2xb[i]; da = da + bps; if (da > uptr->hwmark) uptr->hwmark = da; } ry_done (0, 0); /* done */ break; case SDCNF: /* confirm set density */ if ((ry_dbr & 0377) != 0111) { /* confirmed? */ ry_done (0, 0250); /* no, error */ break; } ry_state = SDXFR; /* next state */ sim_activate (uptr, ry_cwait * 100); /* schedule operation */ break; case SDXFR: /* erase disk */ for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0; uptr->hwmark = (uint32) uptr->capac; if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN; else uptr->flags = uptr->flags & ~UNIT_DEN; ry_done (0, 0); break; case ESBA: ry_ba = ry_dbr; /* save WC */ ry_state = ESXFR; /* next state */ sim_activate (uptr, ry_cwait); /* schedule xfer */ return SCPE_OK; case ESXFR: estat[0] = ry_ecode; /* fill 8B status */ estat[1] = ry_wc; estat[2] = ry_unit[0].TRACK; estat[3] = ry_unit[1].TRACK; estat[4] = ry_track; estat[5] = ry_sector; estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) | ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) | ((uptr->flags & UNIT_ATT)? 0040: 0) | ((ry_unit[0].flags & UNIT_DEN)? 0020: 0) | ((ry_csr & RYCS_DEN)? 0001: 0); estat[7] = uptr->TRACK; t = Map_WriteB (ba, 8, estat); /* DMA to memory */ ry_done (t? RYES_NXM: 0, 0); /* done */ break; case CMD_COMPLETE: /* command complete */ ry_done (0, 0); break; case INIT_COMPLETE: /* init complete */ ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */ ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */ if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ ry_done (RYES_ID, 0010); /* init done, error */ break; } da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ for (i = 0; i < bps; i++) /* read sector */ rx2xb[i] = fbuf[da + i]; ry_done (RYES_ID, 0); /* set done */ if ((ry_unit[1].flags & UNIT_ATT) == 0) ry_ecode = 0020; break; } /* end case state */ return SCPE_OK; }