t_stat clk_svc (UNIT *uptr) { tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */ return SCPE_OK; }
t_stat clk_svc (UNIT *uptr) { tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */ if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */ tmr_incr (TMR_INC); /* do timer service */ return SCPE_OK; }
void tmr_sched (uint32 nicr) { uint32 usecs = (nicr) ? (~nicr + 1) : 0xFFFFFFFF; clk_tps = (int32)((1000000.0 / usecs) + 0.5); sim_debug (TMR_DB_SCHED, &tmr_dev, "tmr_sched(nicr=0x%08X-usecs=0x%08X) - tps=%d\n", nicr, usecs, clk_tps); tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); sim_activate_after (&tmr_unit, usecs); }
t_stat ng_svc(UNIT *uptr) { if (ng_cycle(uptr->wait, 0)) sim_activate_after (uptr, uptr->wait); if (ng_stop_flag) { ng_stop_flag = FALSE; return SCPE_STOP; } return SCPE_OK; }
void tmr_sched (uint32 nicr) { uint32 usecs = (nicr) ? (~nicr + 1) : 0xFFFFFFFF; clk_tps = 1000000 / usecs; sim_debug (TMR_DB_SCHED, &tmr_dev, "tmr_sched(nicr=0x%08X-usecs=0x%08X) - tps=%d\n", nicr, usecs, clk_tps); tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); if (SCPE_OK == sim_activate_after (&tmr_unit, usecs)) tmr_sav = sim_grtime(); /* Save interval base time */ }
static void pclk_set_ctr (uint32 val) { if ((pclk_csr & CSR_GO) == 0) /* stopped? */ pclk_ctr = val; /* save */ else { uint32 delay = DMASK & ((pclk_csr & CSR_UPDN) ? (DMASK + 1 - val) : val); int32 rv; rv = CSR_GETRATE (pclk_csr); /* get rate */ sim_activate_after (&pclk_unit, xtim[rv] * delay); /* schedule interrupt */ } }
t_stat clk_svc (UNIT *uptr) { int32 t; clk_csr = clk_csr | CSR_DONE; /* set done */ if ((clk_csr & CSR_IE) || clk_fie) SET_INT (CLK); t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ tmr_poll = t; /* set timer poll */ tmxr_poll = t; /* set mux poll */ return SCPE_OK; }
t_stat clk_svc (UNIT *uptr) { int32 t; if (clk_csr & CSR_IE) SET_INT (CLK); t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate_after (&clk_unit, 1000000/clk_tps); /* reactivate unit */ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ if (!todr_blow && todr_reg) /* if running? */ todr_reg = todr_reg + 1; /* incr TODR */ return SCPE_OK; }
t_stat fe_reset (DEVICE *dptr) { tmxr_set_console_units (&fe_unit[0], &fe_unit[1]); fei_unit.buf = feo_unit.buf = 0; M[FE_CTYIN] = M[FE_CTYOUT] = 0; M[FE_KLININ] = M[FE_KLINOUT] = 0; M[FE_KEEPA] = INT64_C(0003740000000); /* PARITY STOP, CRM, DP PAREN, CACHE EN, 1MSTMR, TRAPEN */ kaf_unit.u3 = 0; kaf_unit.u4 = 0; apr_flg = apr_flg & ~(APRF_ITC | APRF_CON); sim_activate (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll)); sim_activate_after (&kaf_unit, kaf_unit.wait); return SCPE_OK; }
t_stat clk_svc (UNIT *uptr) { int32 t; if ( DEV_IS_BUSY(INT_CLK) ) { DEV_CLR_BUSY( INT_CLK ) ; DEV_SET_DONE( INT_CLK ) ; DEV_UPDATE_INTR ; } t = sim_rtc_calb (clk_tps[clk_sel]); /* calibrate delay */ sim_activate_after (uptr, 1000000/clk_tps[clk_sel]); /* reactivate unit */ if (clk_adj[clk_sel] > 0) /* clk >= 60Hz? */ tmxr_poll = t * clk_adj[clk_sel]; /* poll is longer */ else tmxr_poll = t / (-clk_adj[clk_sel]); /* poll is shorter */ return SCPE_OK; }
t_stat clk_reset (DEVICE *dptr) { int32 t; clk_csr = 0; CLR_INT (CLK); if (!sim_is_running) { /* RESET (not IORESET)? */ t = sim_rtcn_init_unit (&clk_unit, clk_unit.wait, TMR_CLK);/* init 100Hz timer */ sim_activate_after (&clk_unit, 1000000/clk_tps); /* activate 100Hz unit */ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ } if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */ clk_unit.filebuf = calloc(sizeof(TOY), 1); if (clk_unit.filebuf == NULL) return SCPE_MEM; todr_resync (); } return SCPE_OK; }
/* Keep-alive service * If the 8080 detects the 'force reload' bit, it initiates a disk * boot. IO is reset, but memory is preserved. * * If the keep-alive enable bit is set, the -10 updates the keep-alive * count field every second. The 8080 also checks the word every second. * If the 8080 finds that the count hasn't changed for 15 consecutive seconds, * a Keep-Alive Failure is declared. This forces the -10 to execute the * contents of exec location 71 to collect status and initiate error recovery. */ static t_stat kaf_svc (UNIT *uptr) { if (M[FE_KEEPA] & INT64_C(0020000000000)) { /* KSRLD - "Forced" (actually, requested) reload */ uint32 oldsw = sim_switches; DEVICE *bdev = NULL; int32 i; sim_switches &= ~SWMASK ('P'); reset_all (4); /* RESET IO starting with UBA */ sim_switches = oldsw; M[FE_KEEPA] &= ~INT64_C(0030000177777); /* Clear KAF, RLD, KPALIV & reason * 8080 ucode actually clears HW * status too, but that's a bug. */ M[FE_KEEPA] |= 02; /* Reason = FORREL */ fei_unit.buf = feo_unit.buf = 0; M[FE_CTYIN] = M[FE_CTYOUT] = 0; M[FE_KLININ] = M[FE_KLINOUT] = 0; /* The 8080 has the disk RH address & unit in its memory, even if * the previous boot was from tape. It has no NVM, so the last opr * selection will do here. The case of DS MT <rld> would require a * SET FE command. It's not a common case. */ /* The device may have been detached, disabled or reconfigured since boot time. * Therefore, search for it by CSR address & validate that it's bootable. * If there are problems, the processor is halted. */ for (i = 0; fe_bootrh && (bdev = sim_devices[i]) != NULL; i++ ) { DIB *dibp = (DIB *)bdev->ctxt; if (dibp && (fe_bootrh >= dibp->ba) && (fe_bootrh < (dibp->ba + dibp->lnt))) { break; } } fe_xct = 2; if ((bdev != NULL) && (fe_bootunit >= 0) && (fe_bootunit < (int32) bdev->numunits)) { UNIT *bunit = bdev->units + fe_bootunit; if (!(bunit->flags & UNIT_DIS) && (bunit->flags & UNIT_ATTABLE) && (bunit->flags & UNIT_ATT)) { if (bdev->boot (fe_bootunit, bdev) == SCPE_OK) /* boot the device */ fe_xct = 1; } } } else if (M[FE_KEEPA] & INT64_C(0010000000000)) { /* KPACT */ d10 kav = M[FE_KEEPA] & INT64_C(0000000177400); /* KPALIV */ if (kaf_unit.u3 != (int32)kav) { kaf_unit.u3 = (int32)kav; kaf_unit.u4 = 0; } else if (++kaf_unit.u4 >= 15) { kaf_unit.u4 = 0; M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0000000000377)) | 01; /* RSN = KAF (leaves enabled) */ fei_unit.buf = feo_unit.buf = 0; M[FE_CTYIN] = M[FE_CTYOUT] = 0; M[FE_KLININ] = M[FE_KLINOUT] = 0; fe_xct = 071; } } sim_activate_after (&kaf_unit, kaf_unit.wait); if (fe_xct == 2) { fe_xct = 0; return STOP_CONSOLE; } return SCPE_OK; }
void tmr_sched (uint32 nicr) { sim_activate_after (&tmr_unit, (nicr) ? (~nicr + 1) : 0xFFFFFFFF); tmr_sav = sim_grtime(); }
static void ports_cmd(uint8 cid, cio_entry *rentry, uint8 *rapp_data) { cio_entry centry = {0}; uint32 ln, i; PORTS_OPTIONS opts; char line_config[16]; uint8 app_data[4] = {0}; centry.address = rentry->address; cio[cid].op = rentry->opcode; ln = LN(cid, rentry->subdevice & 0xf); switch(rentry->opcode) { case CIO_DLM: for (i = 0; i < rentry->byte_count; i++) { ports_crc = cio_crc32_shift(ports_crc, pread_b(rentry->address + i)); } centry.address = rentry->address + rentry->byte_count; sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] CIO Download Memory: bytecnt=%04x " "addr=%08x return_addr=%08x subdev=%02x (CRC=%08x)\n", R[NUM_PC], rentry->byte_count, rentry->address, centry.address, centry.subdevice, ports_crc); /* We intentionally do not set the subdevice in * the completion entry */ cio_cexpress(cid, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_DLM); break; case CIO_ULM: sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] CIO Upload Memory\n", R[NUM_PC]); cio_cexpress(cid, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_ULM); break; case CIO_FCF: sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] CIO Force Function Call (CRC=%08x)\n", R[NUM_PC], ports_crc); /* If the currently running program is a diagnostics program, * we are expected to write results into memory at address * 0x200f000 */ if (ports_crc == PORTS_DIAG_CRC1 || ports_crc == PORTS_DIAG_CRC2 || ports_crc == PORTS_DIAG_CRC3) { pwrite_h(0x200f000, 0x1); /* Test success */ pwrite_h(0x200f002, 0x0); /* Test Number */ pwrite_h(0x200f004, 0x0); /* Actual */ pwrite_h(0x200f006, 0x0); /* Expected */ pwrite_b(0x200f008, 0x1); /* Success flag again */ } /* An interesting (?) side-effect of FORCE FUNCTION CALL is * that it resets the card state such that a new SYSGEN is * required in order for new commands to work. In fact, an * INT0/INT1 combo _without_ a RESET can sysgen the board. So, * we reset the command bits here. */ cio[cid].sysgen_s = 0; cio_cexpress(cid, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_FCF); break; case CIO_DOS: sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] CIO Determine Op Status\n", R[NUM_PC]); cio_cexpress(cid, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_DOS); break; case CIO_DSD: /* Determine Sub-Devices. We have none. */ sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] Determine Sub-Devices.\n", R[NUM_PC]); /* The system wants us to write sub-device structures * at the supplied address */ pwrite_h(rentry->address, 0x0); cio_cexpress(cid, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_DSD); break; case PPC_OPTIONS: sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] PPC Options Operation\n", R[NUM_PC]); opts.line = pread_h(rentry->address); opts.iflag = pread_h(rentry->address + 4); opts.oflag = pread_h(rentry->address + 6); opts.cflag = pread_h(rentry->address + 8); opts.lflag = pread_h(rentry->address + 10); opts.cerase = pread_b(rentry->address + 11); opts.ckill = pread_b(rentry->address + 12); opts.cinter = pread_b(rentry->address + 13); opts.cquit = pread_b(rentry->address + 14); opts.ceof = pread_b(rentry->address + 15); opts.ceol = pread_b(rentry->address + 16); opts.itime = pread_b(rentry->address + 17); opts.vtime = pread_b(rentry->address + 18); opts.vcount = pread_b(rentry->address + 19); sim_debug(TRACE_DBG, &ports_dev, " PPC Options: iflag=%04x\n", opts.iflag); sim_debug(TRACE_DBG, &ports_dev, " PPC Options: oflag=%04x\n", opts.oflag); sim_debug(TRACE_DBG, &ports_dev, " PPC Options: cflag=%04x\n", opts.cflag); sim_debug(TRACE_DBG, &ports_dev, " PPC Options: lflag=%04x\n", opts.lflag); sim_debug(TRACE_DBG, &ports_dev, " PPC Options: itime=%02x\n", opts.itime); sim_debug(TRACE_DBG, &ports_dev, " PPC Options: vtime=%02x\n", opts.vtime); sim_debug(TRACE_DBG, &ports_dev, " PPC Options: vcount=%02x\n", opts.vcount); ports_state[ln].iflag = opts.iflag; ports_state[ln].oflag = opts.oflag; if ((rentry->subdevice & 0xf) < PORTS_LINES) { /* Adjust baud rate */ sprintf(line_config, "%s-8N1", ports_baud[opts.cflag&0xf]); sim_debug(TRACE_DBG, &ports_dev, "Setting PORTS line %d to %s\n", ln, line_config); tmxr_set_config_line(&ports_ldsc[ln], line_config); } centry.byte_count = sizeof(PPC_OPTIONS); centry.opcode = PPC_OPTIONS; centry.subdevice = rentry->subdevice; centry.address = rentry->address; cio_cqueue(cid, CIO_STAT, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_OPTIONS); break; case PPC_VERS: sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] PPC Version\n", R[NUM_PC]); /* Write the version number at the supplied address */ pwrite_b(rentry->address, PORTS_VERSION); centry.opcode = CIO_ULM; /* TODO: It's unknown what the value 0x50 means, but this * is what a real board sends. */ app_data[0] = 0x50; cio_cqueue(cid, CIO_STAT, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_VERS); break; case PPC_CONN: /* CONNECT - Full request and completion queues */ sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] PPC CONNECT - subdevice = %02x\n", R[NUM_PC], rentry->subdevice); ports_state[ln].conn = TRUE; centry.opcode = PPC_CONN; centry.subdevice = rentry->subdevice; centry.address = rentry->address; cio_cqueue(cid, CIO_STAT, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_CONN); break; case PPC_XMIT: /* XMIT - Full request and completion queues */ /* The port being referred to is in the subdevice. */ sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] PPC XMIT - subdevice = %02x, address=%08x, byte_count=%d\n", R[NUM_PC], rentry->subdevice, rentry->address, rentry->byte_count); /* Set state for xmit */ ports_state[ln].tx_addr = rentry->address; ports_state[ln].tx_req_addr = rentry->address; ports_state[ln].tx_chars = rentry->byte_count + 1; ports_state[ln].tx_req_chars = rentry->byte_count + 1; sim_activate_after(&ports_unit[1], ports_unit[1].wait); break; case PPC_DEVICE: /* DEVICE Control - Express request and completion queues */ /* The port being referred to is in the subdevice. */ sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] PPC DEVICE - subdevice = %02x\n", R[NUM_PC], rentry->subdevice); centry.subdevice = rentry->subdevice; centry.opcode = PPC_DEVICE; cio_cexpress(cid, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_DEVICE); break; case PPC_RECV: /* RECV - Full request and completion queues */ /* The port being referred to is in the subdevice. */ sim_debug(TRACE_DBG, &ports_dev, "[%08x] [ports_cmd] PPC RECV - subdevice = %02x addr=%08x\n", R[NUM_PC], rentry->subdevice, rentry->address); break; case PPC_DISC: /* Disconnect */ centry.subdevice = rentry->subdevice; centry.opcode = PPC_DISC; ports_ldsc[ln].rcve = 0; cio_cqueue(cid, CIO_STAT, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_STD); break; case PPC_BRK: case PPC_CLR: default: sim_debug(TRACE_DBG, &ports_dev, ">>> Op %d Not Handled Yet\n", rentry->opcode); cio_cexpress(cid, PPQESIZE, ¢ry, app_data); cio_irq(cid, rentry->subdevice, DELAY_STD); break; } }