int32 clk_cosched (int32 wait) { int32 t; t = sim_activate_time (&clk_unit); return (t? t - 1: wait); }
static t_stat clk_service (UNIT *uptr) { dprintf (clk_dev, DEB_PSERV, "Service entered with counter %u increment %u limit %u\n", count_register, increment, limit_register); prescaler = prescaler - 1; /* decrement the prescaler count */ if (prescaler == 0) { /* if the prescaler count has expired */ count_register = count_register + increment & R_MASK; /* then the count register counts up */ if (count_register == limit_register) { /* if the limit has been reached */ if (limit_irq == SET) /* then if the last limit interrupt wasn't serviced */ lost_tick_irq = SET; /* then set the overflow interrupt */ else /* otherwise */ limit_irq = SET; /* set the limit interrupt */ if (control_word & CN_COUNT_RESET) /* if the counter reset option is selected */ count_register = 0; /* then clear the count register */ if (control_word & CN_IRQ_ENABLE /* if clock interrupts are enabled */ && clk_dib.interrupt_active == CLEAR) { /* and the interrupt active flip-flop is clear */ clk_dib.interrupt_request = SET; /* then request an interrupt */ iop_assert_INTREQ (&clk_dib); /* and notify the IOP of the INTREQ signal */ } } if (uptr->flags & UNIT_CALTIME) /* if in calibrated timing mode */ prescaler = scale [rate]; /* then reset the prescaler */ else /* otherwise */ prescaler = 1; /* the prescaler isn't used */ } if (!(uptr->flags & UNIT_CALTIME)) { /* if the clock is in real timing mode */ uptr->wait = delay [rate]; /* then set an event-based delay */ increment = 1; /* equal to the selected period */ coscheduled = FALSE; /* the clock is not coscheduled with the process clock */ } else if (coschedulable && cpu_is_calibrated) { /* otherwise if the process clock is calibrated */ uptr->wait = sim_activate_time (cpu_pclk_uptr); /* then synchronize with it */ increment = CLK_MULTIPLIER; /* at one-tenth of the selected period */ coscheduled = TRUE; /* the clock is coscheduled with the process clock */ } else { /* otherwise */ uptr->wait = sim_rtcn_calb (ticks [rate], TMR_CLK); /* calibrate the clock to a delay */ increment = 1; /* equal to the selected period */ coscheduled = FALSE; /* the clock is not coscheduled with the process clock */ } dprintf (clk_dev, DEB_PSERV, "Rate %s delay %d service %s\n", rate_name [rate], uptr->wait, (coscheduled ? "coscheduled" : "scheduled")); return sim_activate (uptr, uptr->wait); /* activate the unit and return the status */ }
int32 sync_poll (POLLMODE poll_mode) { int32 poll_time; if (poll_mode == INITIAL) { poll_time = sim_activate_time (&tty_unit[TTI]); if (poll_time) return poll_time; else return POLL_WAIT; } else return tty_unit[TTI].wait; }
static uint32 pclk_get_ctr (void) { uint32 val; int32 rv; if (!sim_is_active (&pclk_unit)) return pclk_ctr; rv = CSR_GETRATE (pclk_csr); /* get rate */ val = (uint32)((sim_activate_time (&pclk_unit) / sim_timer_inst_per_sec ()) * (1000000 / xtim[rv])); val &= DMASK; if (pclk_csr & CSR_UPDN) val = DMASK + 1 - val; return val; }
void clk_update_counter (void) { int32 elapsed, ticks; if (coscheduled) { /* if the clock is coscheduled, then adjust the count */ elapsed = clk_unit [0].wait /* the elapsed time is the original wait time */ - sim_activate_time (&clk_unit [0]); /* less the time remaining before the next service */ ticks = (elapsed * CLK_MULTIPLIER) / clk_unit [0].wait /* the adjustment is the elapsed fraction of the multiplier */ - (CLK_MULTIPLIER - increment); /* less the amount of any adjustment already made */ count_register = count_register + ticks & R_MASK; /* update the clock counter with rollover */ increment = increment - ticks; /* and reduce the amount remaining to add at service */ } return; }
static void resync_clock (void) { coschedulable = (ticks [rate] == 1000 /* the clock can be coscheduled if the rate */ && limit_register == 100); /* is 1 msec and the limit is 100 ticks */ if (clk_unit [0].flags & UNIT_CALTIME /* if the clock is in calibrated timing mode */ && coschedulable /* and may be coscheduled with the process clock */ && cpu_is_calibrated) { /* and the process clock is calibrated */ clk_unit [0].wait = sim_activate_time (cpu_pclk_uptr); /* then synchronize with it */ coscheduled = TRUE; /* the clock is coscheduled with the process clock */ } else { /* otherwise */ clk_unit [0].wait = delay [rate]; /* set up an independent clock */ coscheduled = FALSE; /* the clock is not coscheduled with the process clock */ } dprintf (clk_dev, DEB_PSERV, "Rate %s delay %d service rescheduled\n", rate_name [rate], clk_unit [0].wait); sim_activate_abs (&clk_unit [0], clk_unit [0].wait); /* restart the clock */ return; }
t_stat mtu_svc (UNIT *uptr) { uint32 cmd = uptr->UCMD; uint32 un = uptr - mt_unit; uint32 c; uint32 st; int32 t; t_mtrlnt tbc; t_stat r; if (cmd == MCM_INIT) { /* init state */ if ((t = sim_activate_time (uptr + MT_REW)) != 0) { /* rewinding? */ sim_activate (uptr, t); /* retry later */ return SCPE_OK; } st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((cmd & 0x80) || /* invalid cmd? */ (mt_op[cmd] == 0)) { uptr->UCMD = MCM_END; /* end state */ sim_activate (uptr, chan_ctl_time); /* resched ctlr */ return SCPE_OK; } else { /* valid cmd */ if ((mt_op[cmd] & O_REV) && /* reverse op */ (mt_unit[un].UST & MTDV_BOT)) { /* at load point? */ chan_uen (mt_dib.dva); /* channel end */ return SCPE_OK; } uptr->UCMD = cmd; /* unit state */ if (!(mt_op[cmd] & O_NMT)) /* motion? */ uptr->UST = 0; /* clear status */ } mt_blim = 0; /* no buffer yet */ sim_activate (uptr, chan_ctl_time); /* continue thread */ return SCPE_OK; /* done */ } if (cmd == MCM_END) { /* end state */ st = chan_end (mt_dib.dva); /* set channel end */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if (st == CHS_CCH) { /* command chain? */ uptr->UCMD = MCM_INIT; /* restart thread */ sim_activate (uptr, chan_ctl_time); } else uptr->UCMD = 0; /* ctlr idle */ return SCPE_OK; /* done */ } if ((mt_op[cmd] & O_ATT) && /* op req att and */ ((uptr->flags & UNIT_ATT) == 0)) { /* not attached? */ sim_activate (uptr, mt_ctime); /* retry */ return mt_stopioe? SCPE_UNATT: SCPE_OK; } if ((mt_op[cmd] & O_WRE) && /* write op and */ sim_tape_wrp (uptr)) { /* write protected? */ uptr->UST |= MTDV_WLE; /* set status */ chan_uen (mt_dib.dva); /* unusual end */ return SCPE_OK; } r = SCPE_OK; switch (cmd) { /* case on command */ case MCM_SFWR: /* space forward */ if (r = sim_tape_sprecf (uptr, &tbc)) /* spc rec fwd, err? */ r = mt_map_err (uptr, r); /* map error */ break; case MCM_SBKR: /* space reverse */ if (r = sim_tape_sprecr (uptr, &tbc)) /* spc rec rev, err? */ r = mt_map_err (uptr, r); /* map error */ break; case MCM_SFWF: /* space fwd file */ while ((r = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; if (r != MTSE_TMK) /* stopped by tmk? */ r = mt_map_err (uptr, r); /* no, map error */ else r = SCPE_OK; break; case MCM_SBKF: /* space rev file */ while ((r = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; if (r != MTSE_TMK) /* stopped by tmk? */ r = mt_map_err (uptr, r); /* no, map error */ else r = SCPE_OK; break; case MCM_WTM: /* write eof */ if (r = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = mt_map_err (uptr, r); /* map error */ uptr->UST |= MTDV_EOF; /* set eof */ break; case MCM_RWU: /* rewind unload */ r = detach_unit (uptr); break; case MCM_REW: /* rewind */ case MCM_RWI: /* rewind and int */ if (r = sim_tape_rewind (uptr)) /* rewind */ r = mt_map_err (uptr, r); /* map error */ mt_unit[un + MT_REW].UCMD = uptr->UCMD; /* copy command */ sim_activate (uptr + MT_REW, mt_rwtime); /* sched compl */ break; case MCM_READ: /* read */ if (mt_blim == 0) { /* first read? */ r = sim_tape_rdrecf (uptr, mt_xb, &mt_blim, MT_MAXFR); if (r != MTSE_OK) { /* tape error? */ r = mt_map_err (uptr, r); /* map error */ break; } mt_bptr = 0; /* init rec ptr */ } c = mt_xb[mt_bptr++]; /* get char */ st = chan_WrMemB (mt_dib.dva, c); /* write to memory */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((st != CHS_ZBC) && (mt_bptr != mt_blim)) { /* not done? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } if (((st == CHS_ZBC) ^ (mt_bptr == mt_blim)) && /* length err? */ chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ return SCPE_OK; /* finished */ break; /* normal end */ case MCM_RDBK: /* read reverse */ if (mt_blim == 0) { /* first read? */ r = sim_tape_rdrecr (uptr, mt_xb, &mt_blim, MT_MAXFR); if (r != MTSE_OK) { /* tape error? */ r = mt_map_err (uptr, r); /* map error */ break; } mt_bptr = mt_blim; /* init rec ptr */ } c = mt_xb[--mt_bptr]; /* get char */ st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((st != CHS_ZBC) && (mt_bptr != 0)) { /* not done? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } if (((st == CHS_ZBC) ^ (mt_bptr == 0)) && /* length err? */ chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ return SCPE_OK; /* finished */ break; /* normal end */ case MCM_WRITE: /* write */ st = chan_RdMemB (mt_dib.dva, &c); /* read char */ if (CHS_IFERR (st)) { /* channel error? */ mt_flush_buf (uptr); /* flush buffer */ return mt_chan_err (st); } mt_xb[mt_blim++] = c; /* store in buffer */ if (st != CHS_ZBC) { /* end record? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } r = mt_flush_buf (uptr); /* flush buffer */ break; } if (r != SCPE_OK) /* error? abort */ return CHS_IFERR(r)? SCPE_OK: r; uptr->UCMD = MCM_END; /* end state */ sim_activate (uptr, mt_ctime); /* sched ctlr */ return SCPE_OK; }