diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index c80ce356..382221e4 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -428,9 +428,31 @@ while (reason == 0) { /* loop until halted */ int_reqhi = api_findreq (); /* recalc int req */ } else { /* normal instr */ - if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; + if (sim_brk_summ) { + uint32 btyp = SWMASK ('E'); + + if (nml_mode) + btyp = SWMASK ('E') | SWMASK ('N'); + else + btyp = usr_mode ? SWMASK ('E') | SWMASK ('U') + : SWMASK ('E') | SWMASK ('M'); + btyp = sim_brk_test (P, btyp); + if (btyp) { + if (btyp & SWMASK ('E')) /* unqualified breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + else switch (btyp) { /* qualified breakpoint */ + case SWMASK ('M'): /* monitor mode */ + reason = STOP_MBKPT; /* stop simulation */ + break; + case SWMASK ('N'): /* normal (SDS 930) mode */ + reason = STOP_NBKPT; /* stop simulation */ + break; + case SWMASK ('U'): /* user mode */ + reason = STOP_UBKPT; /* stop simulation */ + break; + } + break; + } } reason = Read (save_P = P, &inst); /* get instr */ P = (P + 1) & VA_MASK; /* incr PC */ @@ -448,6 +470,8 @@ while (reason == 0) { /* loop until halted */ } /* end if r == 0 */ if (reason < 0) { /* mm (fet or ex)? */ pa = -reason; /* get vector */ + if (reason == MM_MONUSR) /* record P of user-mode */ + save_P = P; /* transition point */ reason = 0; /* defang */ tinst = ReadP (pa); /* get inst */ if (I_GETOP (tinst) != BRM) { /* not BRM? */ @@ -505,7 +529,7 @@ if (inst & I_POP) { /* POP? */ if ((r = Write (0, dat))) return r; } - } + } else { /* mon mode */ dat = (OV << 21) | dat; /* ov in <2> */ WriteP (0, dat); /* store return */ @@ -776,7 +800,7 @@ switch (op) { /* case on opcode */ return r; inst = dat; goto EXU_LOOP; - + case BRU: if (nml_mode && (inst & I_IND)) api_dismiss (); /* normal BRU*, dism */ if ((r = Ea (inst, &va))) /* decode eff addr */ @@ -785,6 +809,11 @@ switch (op) { /* case on opcode */ return r; PCQ_ENTRY; P = va & VA_MASK; /* branch */ + if ((va & VA_USR) && !nml_mode && !usr_mode) { /* user ref from mon. mode? */ + usr_mode = 1; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } break; case BRX: @@ -796,6 +825,11 @@ switch (op) { /* case on opcode */ return r; PCQ_ENTRY; P = va & VA_MASK; /* branch */ + if ((va & VA_USR) && !nml_mode && !usr_mode) { /* user ref from mon. mode? */ + usr_mode = 1; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } } break; @@ -810,6 +844,11 @@ switch (op) { /* case on opcode */ return r; PCQ_ENTRY; P = (va + 1) & VA_MASK; /* branch */ + if ((va & VA_USR) && !nml_mode && !usr_mode) { /* user ref from mon. mode? */ + usr_mode = 1; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } break; case BRR: @@ -1191,7 +1230,7 @@ uint32 nml = nml_mode, usr = usr_mode; uint32 pa, pgn, map; if (sw & SWMASK ('N')) /* -n: normal */ - nml = 1; + nml = 1; else if (sw & SWMASK ('X')) /* -x: mon */ nml = usr = 0; else if (sw & SWMASK ('U')) { /* -u: user */ @@ -1269,7 +1308,7 @@ return; /* Divide - the SDS 940 uses a non-restoring divide. The algorithm runs even for overflow cases. Hence it must be emulated precisely - to give the right answers for diagnostics. If the dividend is + to give the right answers for diagnostics. If the dividend is negative, AB are 2's complemented starting at B<22>, and B<23> is unchanged. */ @@ -1456,7 +1495,8 @@ pcq_r = find_reg ("PCQ", NULL, dptr); if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); +sim_brk_dflt = SWMASK ('E'); +sim_brk_types = SWMASK ('E') | SWMASK ('M') | SWMASK ('N') | SWMASK ('U'); return SCPE_OK; } @@ -1542,13 +1582,17 @@ return SCPE_OK; a unit service routine and a reset routine. The service routine sets an interrupt that invokes the clock counter. The clock counter is a "one instruction interrupt", and only MIN/SKR are valid. + + Temporarily divide rtc_tps by 2 because clock is running twice as + fast as it should. Eventually have to find problem in the clock + calibration or setup code. */ t_stat rtc_svc (UNIT *uptr) { if (rtc_pie) /* set pulse intr */ int_req = int_req | INT_RTCP; -sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate */ +sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps/2, TMR_RTC)); /* reactivate */ return SCPE_OK; } @@ -1572,7 +1616,7 @@ if ((r = Read (va, &dat))) /* get operand */ dat = AddM24 (dat, val); /* mem +/- 1 */ if ((r = Write (va, dat))) /* rewrite */ return r; -if (dat == 0) /* set clk sync int */ +if ((op == MIN && dat == 0) || (dat & SIGN)) /* set clk sync int */ int_req = int_req | INT_RTCS; return SCPE_OK; } diff --git a/SDS/sds_defs.h b/SDS/sds_defs.h index 8277a144..82955c8b 100644 --- a/SDS/sds_defs.h +++ b/SDS/sds_defs.h @@ -1,4 +1,4 @@ -/* sds_defs.h: SDS 940 simulator definitions +/* sds_defs.h: SDS 940 simulator definitions Copyright (c) 2001-2010, Robert M. Supnik @@ -52,6 +52,9 @@ #define STOP_RTCINS 12 /* rtc inst not MIN/SKR */ #define STOP_ILLVEC 13 /* zero vector */ #define STOP_CCT 14 /* runaway CCT */ +#define STOP_MBKPT 15 /* monitor-mode breakpoint */ +#define STOP_NBKPT 16 /* normal-mode breakpoint */ +#define STOP_UBKPT 17 /* user-mode breakpoint */ /* Trap codes */ diff --git a/SDS/sds_io.c b/SDS/sds_io.c index dc5e7618..e021cf5f 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -148,7 +148,7 @@ extern void set_dyn_map (void); Channels could, optionally, handle 12b or 24b characters. The simulator can support all widths. */ - + t_stat chan_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc); struct aldisp { @@ -233,11 +233,11 @@ t_stat (*dev3_dsp[64])() = { NULL }; struct aldisp dev_alt[] = { { NULL, NULL }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, - { NULL, &pot_ilc }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, - { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, - { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { &pin_adr, NULL }, { &pin_adr, NULL }, @@ -330,15 +330,22 @@ switch (mod) { if (INV_DEV (dev, ch)) /* inv dev? err */ CRETDEV; chan_war[ch] = chan_cnt[ch] = 0; /* init chan */ - chan_flag[ch] = chan_dcr[ch] = 0; - chan_mode[ch] = chan_uar[ch] = 0; - if (ch >= CHAN_E) - chan_mode[ch] = CHM_CE; + chan_dcr[ch] = 0; + chan_uar[ch] = 0; + if (!(chan_flag[ch] & CHF_ILCE) && /* ignore if ilc */ + !QAILCE (alert)) { /* already alerted */ + chan_flag[ch] = chan_mode[ch] = 0; + if (ch >= CHAN_E) + chan_mode[ch] = CHM_CE; + } if ((r = dev_dsp[dev][ch] (IO_CONN, inst, NULL)))/* connect */ return r; - if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ - alert = POT_ILCY + ch; - chan_mar[ch] = chan_wcr[ch] = 0; + if (!(chan_flag[ch] & CHF_ILCE) && /* ignore if ilc */ + !QAILCE (alert)) { /* already alerted */ + if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ + alert = POT_ILCY + ch; + chan_mar[ch] = chan_wcr[ch] = 0; + } } if (chan_flag[ch] & CHF_24B) /* 24B? 1 ch/wd */ chan_cpw[ch] = 0; @@ -390,7 +397,7 @@ switch (mod) { } /* end else change scan */ } /* end else term output */ } /* end else chan EOM */ - break; + break; case 2: /* internal */ if (ch >= CHAN_E) { /* EOD? */ @@ -432,6 +439,8 @@ switch (mod) { case 3: /* special */ dev = I_GETDEV3 (inst); /* special device */ + if (dev == DEV3_SMUX && !(cpu_unit.flags & UNIT_GENIE)) + dev = DEV3_GMUX; if (dev3_dsp[dev]) /* defined? */ return dev3_dsp[dev] (IO_CONN, inst, NULL); CRETINS; @@ -493,8 +502,10 @@ switch (mod) { case 3: /* special */ dev = I_GETDEV3 (inst); /* special device */ + if (dev == DEV3_SMUX && !(cpu_unit.flags & UNIT_GENIE)) + dev = DEV3_GMUX; if (dev3_dsp[dev]) - dev3_dsp[dev] (IO_SKS, inst, dat); + dev3_dsp[dev] (IO_SKS, inst, dat); else CRETINS; } /* end case */ @@ -540,9 +551,9 @@ return SCPE_OK; t_stat pot_fork (uint32 num, uint32 *dat) { uint32 igrp = SYI_GETGRP (*dat); /* get group */ -uint32 fbit = (1 << (VEC_FORK & 017)); /* bit in group */ +uint32 fbit = (0100000 >> (VEC_FORK & 017)); /* bit in group */ -if (igrp == (VEC_FORK / 020)) { /* right group? */ +if (igrp == ((VEC_FORK-0200) / 020)) { /* right group? */ if ((*dat & SYI_ARM) && (*dat & fbit)) /* arm, bit set? */ int_req = int_req | INT_FORK; if ((*dat & SYI_DIS) && !(*dat & fbit)) /* disarm, bit clr? */ @@ -568,7 +579,7 @@ return SCPE_OK; Note that the channel can be disconnected if CHN_EOR is set, but must not be if XFR_REQ is set */ - + t_stat chan_read (int32 ch) { uint32 dat = 0; @@ -626,7 +637,7 @@ if (TST_EOR (ch)) { /* end record? */ } /* end else if cnt */ return chan_eor (ch); /* eot/eor int */ } -return r; +return r; } void chan_write_mem (int32 ch) diff --git a/SDS/sds_mux.c b/SDS/sds_mux.c index 2b5054ab..abc8a5d4 100644 --- a/SDS/sds_mux.c +++ b/SDS/sds_mux.c @@ -54,6 +54,7 @@ #define MUX_SETFLG(l,x) mux_flags[((l) * MUX_FLAGS) + (x)] = 1 #define MUX_SETINT(x) int_req = int_req | (INT_MUXR >> (x)) #define MUX_CLRINT(x) int_req = int_req & ~(INT_MUXR >> (x)) +#define MUX_CHKINT(x) (int_req & (INT_MUXR >> (x))) /* PIN/POT */ @@ -274,7 +275,7 @@ switch (fnc) { ((inst & SKS_DSR) && !(mux_sta[ln] & MUX_SDSR))) *dat = 0; /* no skip if fail */ } - else CRETINS; + else CRETINS; default: return SCPE_IERR; @@ -290,6 +291,8 @@ t_stat pin_mux (uint32 num, uint32 *dat) uint32 ln = mux_scan >> 2; uint32 flag = mux_scan & MUX_FLAGMASK; +if (!mux_slck) /* scanner must be locked */ + return SCPE_IERR; mux_scan = mux_scan & MUX_SCANMASK; /* mask scan */ mux_flags[mux_scan] = 0; /* clear flag */ if (flag == MUX_FRCV) { /* rcv event? */ @@ -333,6 +336,12 @@ else { /* enabled */ else mux_sta[ln] = mux_sta[ln] & ~MUX_SXIE; mux_sta[ln] = mux_sta[ln] | MUX_SLNE; /* line is enabled */ mux_ldsc[ln].rcve = 1; + if ((*dat & POT_NOX) && /* if no transmit char && */ + (mux_sta[ln] & MUX_SXIE) && /* line enabled && */ + !sim_is_active (&muxl_unit[ln])) { /* tx buffer empty */ + MUX_SETFLG (ln, MUX_FXMT); /* then set flag to request */ + mux_scan_next (); /* a tx interrupt */ + } } return SCPE_OK; } @@ -407,7 +416,23 @@ if (mux_sta[ln] & MUX_SXIE) { return SCPE_OK; } -/* Kick scanner */ +/* Kick scanner +* +* Per 940 Ref Man: +* If more than one raised flag is encountered by the scanner, only +* the one of highest priority will result in an interrupt. The others +* will be ignored until the scanner has completed scanning all other +* channels. The receive flag will be given highest priority, followed +* by the transmit flag, the carrier-on flag, and the carrier-off flag. +* +* To implement, advance mux_scan to last flag of current channel (by +* merging MUX_FLAGMASK) so scan loop commences with receive flag of next +* channel. +* +* When two or more channels are active, do not queue an interrupt +* request if the same interrupt is already requesting. To do so will +* cause an interrupt to be lost. +*/ void mux_scan_next (void) { @@ -415,9 +440,12 @@ int32 i; if (mux_slck) /* locked? */ return; +mux_scan |= MUX_FLAGMASK; /* last flag of current ch. */ + /* will be Rx flag of next ch. */ for (i = 0; i < MUX_SCANMAX; i++) { /* scan flags */ mux_scan = (mux_scan + 1) & MUX_SCANMASK; /* next flag */ - if (mux_flags[mux_scan]) { /* flag set? */ + if (mux_flags[mux_scan] && /* flag set */ + !MUX_CHKINT (mux_scan & MUX_FLAGMASK)) { /* and not requesting int? */ mux_slck = 1; /* lock scanner */ MUX_SETINT (mux_scan & MUX_FLAGMASK); /* request int */ return; diff --git a/SDS/sds_rad.c b/SDS/sds_rad.c index 4194c755..d1475230 100644 --- a/SDS/sds_rad.c +++ b/SDS/sds_rad.c @@ -116,7 +116,7 @@ DEVICE rad_dev = { }; /* Fixed head disk routine - + conn - inst = EOM0, dat = NULL eom1 - inst = EOM1, dat = NULL sks - inst = SKS, dat = ptr to result @@ -157,7 +157,7 @@ switch (fnc) { /* case function */ if (new_ch != rad_dib.chan) /* wrong chan? */ return SCPE_IERR; if ((inst & 00600) == 00200) /* alert for sec */ - alert = POT_RADS; + alert = POT_RADS; else if ((inst & 06600) == 0) { /* alert for addr */ if (sim_is_active (&rad_unit)) /* busy? */ rad_err = 1; @@ -287,7 +287,7 @@ if (rad_sba >= (RAD_NUMWD * 2)) { /* next sector? */ ((rad_da + 1) & RAD_SCMASK); else rad_da = (rad_da & ~RAD_TRSCMASK) + /* cross band */ ((rad_da + 1) & RAD_TRSCMASK); - sba = 0; /* start new sec */ + sba = 1; /* start new sec */ } return sba; } diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index b446169a..14a03c82 100644 --- a/SDS/sds_sys.c +++ b/SDS/sds_sys.c @@ -96,7 +96,10 @@ const char *sim_stop_messages[] = { "Trap instruction not BRM", "RTC instruction not MIN or SKR", "Interrupt vector zero", - "Runaway carriage control tape" + "Runaway carriage control tape", + "Monitor-mode Breakpoint", + "Normal-mode Breakpoint", + "User-mode Breakpoint" }; /* Character conversion tables */ @@ -212,7 +215,7 @@ for (i = wd = 0; i < 4; ) { } return wd; } - + t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 i, wd, buf[8]; @@ -227,7 +230,7 @@ for (i = 0; i < 8; i++) { /* read boot */ if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_FMT; buf[i] = wd; - } + } if ((buf[0] != 023200012) || /* 2 = WIM 12,2 */ (buf[1] != 004100002) || /* 3 = BRX 2 */ (buf[2] != 007100011) || /* 4 = LDX 11 */ @@ -260,15 +263,15 @@ return SCPE_NXM; #define I_V_OPO 006 /* opcode only */ #define I_V_CHC 007 /* chan cmd */ #define I_V_CHT 010 /* chan test */ -#define I_NPN (I_V_NPN << I_V_FL) -#define I_PPO (I_V_PPO << I_V_FL) -#define I_IOI (I_V_IOI << I_V_FL) -#define I_MRF (I_V_MRF << I_V_FL) -#define I_REG (I_V_REG << I_V_FL) -#define I_SHF (I_V_SHF << I_V_FL) +#define I_NPN (I_V_NPN << I_V_FL) +#define I_PPO (I_V_PPO << I_V_FL) +#define I_IOI (I_V_IOI << I_V_FL) +#define I_MRF (I_V_MRF << I_V_FL) +#define I_REG (I_V_REG << I_V_FL) +#define I_SHF (I_V_SHF << I_V_FL) #define I_OPO (I_V_OPO << I_V_FL) #define I_CHC (I_V_CHC << I_V_FL) -#define I_CHT (I_V_CHT << I_V_FL) +#define I_CHT (I_V_CHT << I_V_FL) static const int32 masks[] = { 037777777, 010000000, 017700000, @@ -299,7 +302,7 @@ static const char *opcode[] = { "SKM", "LDX", "SKA", "SKG", "SKD", "LDB", "LDA", "EAX", - "BRU*", + "BRU*", "MIY*", "BRI*", "MIW*", "POT*", "ETR*", "MRG*", "EOR*", "EXU*", @@ -430,17 +433,17 @@ va = inst & VA_MASK; shf = inst & I_SHFMSK; nonop = inst & 077777; -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) - return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); +if (sw & SWMASK ('A')) { /* SDS internal ASCII? */ + for (i = 16; i >= 0; i -= 8) { + ch = (inst >> i) & 0377; /* map printable chars */ + ch = ch <= 0137 ? ch += 040 : '.'; /* from int. to ext. ASCII */ + fprintf (of, "%c", ch); + } return SCPE_OK; } -if (sw & SWMASK ('C')) { /* character? */ - fprintf (of, "%c", sds_to_ascii[(inst >> 18) & 077]); - fprintf (of, "%c", sds_to_ascii[(inst >> 12) & 077]); - fprintf (of, "%c", sds_to_ascii[(inst >> 6) & 077]); - fprintf (of, "%c", sds_to_ascii[inst & 077]); +if (sw & SWMASK ('C')) { /* six-bit character? */ + for (i = 18; i >= 0; i -= 6) + fprintf (of, "%c", sds_to_ascii[(inst >> i) & 077]); return SCPE_OK; } if (!(sw & SWMASK ('M'))) return SCPE_ARG; @@ -539,7 +542,7 @@ return cptr; /* no change */ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 i, j, k; +int32 i, j, k, ch; t_value d, tag; t_stat r; char gbuf[CBUFSIZE]; @@ -554,10 +557,21 @@ for (i = 1; (i < 4) && (cptr[i] != 0); i++) { if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if (cptr[0] == 0) /* must have 1 char */ return SCPE_ARG; - val[0] = (t_value) cptr[0] | 0200; + for (i = j = 0, val[0] = 0; i < 3; i++) { + if (cptr[i] == 0) /* latch str end */ + j = 1; + ch = cptr[i] & 0377; + if (ch <= 037 || ch >= 0200) + k = -1; + else + k = ch - 040; /* map ext. to int. ASCII */ + if (j || (k < 0)) /* bad, end? spc */ + k = 0; + val[0] = (val[0] << 8) | k; + } return SCPE_OK; } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string? */ +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string of 6-bit chars? */ if (cptr[0] == 0) /* must have 1 char */ return SCPE_ARG; for (i = j = 0, val[0] = 0; i < 4; i++) { diff --git a/doc/sds_doc.doc b/doc/sds_doc.doc index 6e694c44..4460270f 100644 Binary files a/doc/sds_doc.doc and b/doc/sds_doc.doc differ