diff --git a/PDP10/kl10_fe.c b/PDP10/kl10_fe.c index 8149f38..c73b8b0 100644 --- a/PDP10/kl10_fe.c +++ b/PDP10/kl10_fe.c @@ -156,6 +156,7 @@ #define PRI_EMCDR 006 /* CDR */ #define PRI_EMCLK 007 /* Clock */ #define PRI_EMFED 010 /* Front end device */ +#define PRI_CTYDV 000 /* Line number for CTY */ #if KL_ITS /* ITS Timesharing protocol locations */ @@ -183,9 +184,11 @@ void dte_its(UNIT *uptr); #endif void dte_transfer(UNIT *uptr); void dte_function(UNIT *uptr); +void dte_input(); int dte_start(UNIT *uptr); -int dte_queue(UNIT *uptr, int func, int dev, int dcnt, uint16 *data); +int dte_queue(int func, int dev, int dcnt, uint16 *data); t_stat dtei_svc (UNIT *uptr); +t_stat dte_svc (UNIT *uptr); t_stat dteo_svc (UNIT *uptr); t_stat dtertc_srv(UNIT * uptr); t_stat dte_reset (DEVICE *dptr); @@ -195,6 +198,11 @@ t_stat dte_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cpt const char *dte_description (DEVICE *dptr); extern uint64 SW; /* Switch register */ +char *pri_name[] = { "(0)", "EM2EI", "EM2TI", "EMSTR", "EMLNC", "EMRDS", "(6)", + "EMHDS", "(10)", "EMRDT", "EMHDR", "EMFLO", "EMSNA", "EMDSC", "EMHUD", + "EMACK", "EMXOF", "EMXON", "EMHLS", "EMHLA", "EMRBI", "EMAKA", "EMTDO", + "EMEDR", "EMLDR", "EMLDV" }; + #if KL_ITS #define QITS (cpu_unit[0].flags & UNIT_ITSPAGE) #else @@ -203,7 +211,6 @@ extern uint64 SW; /* Switch register */ #define STATUS u3 #define CNT u4 -#define CHHOLD u5 extern uint32 eb_ptr; static int32 rtc_tps = 60; @@ -237,8 +244,7 @@ struct _buffer { int out_ptr; /* Remove pointer */ char buff[256]; /* Buffer */ } cty_in, cty_out; - -int cty_data; +int cty_done; DIB dte_dib[] = { { DTE_DEVNUM|000, 1, dte_devio, dte_devirq}, @@ -254,15 +260,16 @@ MTAB dte_mod[] = { }; UNIT dte_unit[] = { - { UDATA (&dteo_svc, TT_MODE_7B, 0), 10000 }, - { UDATA (&dtei_svc, TT_MODE_7B|UNIT_DIS, 0), 10000 }, + { UDATA (&dte_svc, TT_MODE_7B, 0), 100}, + { UDATA (&dteo_svc, TT_MODE_7B, 0), 100}, + { UDATA (&dtei_svc, TT_MODE_7B|UNIT_DIS, 0), 1000 }, { UDATA (&dtertc_srv, UNIT_IDLE|UNIT_DIS, 0), 1000 } }; DEVICE dte_dev = { "CTY", dte_unit, NULL, dte_mod, - 3, 10, 31, 1, 8, 8, + 4, 10, 31, 1, 8, 8, NULL, NULL, &dte_reset, NULL, NULL, NULL, &dte_dib, DEV_DEBUG, 0, dev_debug, NULL, NULL, &dte_help, NULL, NULL, &dte_description @@ -343,10 +350,10 @@ DEVICE lpt_dev = { #if (NUM_DEVS_TTY > 0) struct _buffer tty_out[NUM_LINES_TTY], tty_in[NUM_LINES_TTY]; -struct _buffer tty_done, tty_hang; TMLN tty_ldsc[NUM_LINES_TTY] = { 0 }; /* Line descriptors */ TMXR tty_desc = { NUM_LINES_TTY, 0, 0, tty_ldsc }; -int tty_connect[NUM_LINES_TTY];; +int tty_connect[NUM_LINES_TTY]; +int tty_done[NUM_LINES_TTY]; int tty_enable = 0; extern int32 tmxr_poll; @@ -471,7 +478,7 @@ dte_devirq(uint32 dev, int addr) { } /* Handle TO11 interrupts */ -t_stat dteo_svc (UNIT *uptr) +t_stat dte_svc (UNIT *uptr) { t_stat r; @@ -498,7 +505,7 @@ void dte_second(UNIT *uptr) { #if KI_22BIT #if KL_ITS - if ((cpu_unit[0].flags & UNIT_ITSPAGE) == 0) + if (!QITS) #endif base = eb_ptr; #endif @@ -507,7 +514,6 @@ void dte_second(UNIT *uptr) { #if KL_ITS if (word == 0 && QITS && (uptr->STATUS & ITS_ON) != 0) { dte_its(uptr); -// uptr->STATUS |= DTE_10DB; uptr->STATUS &= ~DTE_11DB; return; } @@ -528,6 +534,7 @@ void dte_second(UNIT *uptr) { M[SEC_DTCHR + base] = ch; M[SEC_DTMTD + base] = FMASK; M[SEC_DTF11 + base] = 0; + sim_activate(&dte_unit[1], 100); break; case SEC_SETPRI: enter_pri: @@ -540,9 +547,9 @@ enter_pri: dte_et10_off = dte_dt10_off + 16; dte_et11_off = dte_base + 16; uptr->STATUS &= ~DTE_SEC; - dte_unit[1].STATUS &= ~DTE_SEC; dte_in_ptr = dte_out_ptr = 0; dte_in_cmd = dte_out_res = 0; + cty_done = 0; /* Start input process */ break; case SEC_SETDDT: /* Read character from console */ @@ -557,11 +564,9 @@ enter_pri: break; case SEC_CLRDDT: /* Clear DDT input mode */ uptr->STATUS &= ~DTE_MON; -// sim_cancel(&dte_unit[1]); break; case SEC_MONON: uptr->STATUS |= DTE_MON; -// sim_activate(&dte_unit[1], 100); break; case SEC_RDSW: /* Read switch register */ M[SEC_DTSWR + base] = SW; @@ -585,12 +590,12 @@ enter_pri: case SEC_CLKCTL: /* Clock control: Used by KLDCP */ switch(word) { case SEC_CLKOFF: - dte_unit[2].STATUS &= ~SEC_CLK; + dte_unit[3].STATUS &= ~SEC_CLK; break; case SEC_CLKWT: rtc_wait = (uint16)(M[SEC_DTT11 + base] & 0177777); case SEC_CLKON: - dte_unit[2].STATUS |= SEC_CLK; + dte_unit[3].STATUS |= SEC_CLK; rtc_tick = 0; break; case SEC_CLKRD: @@ -607,6 +612,7 @@ enter_pri: } #if KL_ITS +/* Process ITS Ioeleven locations */ void dte_its(UNIT *uptr) { uint64 word; char ch; @@ -615,16 +621,6 @@ void dte_its(UNIT *uptr) { int ln; t_stat r; - /* Check for output Start */ - word = M[ITS_DTEOST]; - if ((word & SMASK) == 0) { - if (((tty_done.in_ptr + 1) & 0xff) != tty_done.out_ptr) { - tty_done.buff[tty_done.in_ptr] = (char)(word & 0xff); - tty_done.in_ptr = (tty_done.in_ptr + 1) & 0xff; - M[ITS_DTEOST] = FMASK; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEOST = %012llo\n", word); - } - } /* Check for input Start */ word = M[ITS_DTEINP]; if ((word & SMASK) == 0) { @@ -639,48 +635,29 @@ void dte_its(UNIT *uptr) { sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEOUT = %012llo\n", word); while (cnt > 0) { if (ln < 0) { - if (!Mem_read_byte(0, &data)) + if (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) return; - ch = (data >> 8) & 0177; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY type %x\n", ch); - ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); - if ((r = sim_putchar_s (ch)) != SCPE_OK) /* Output errors */ - return; + if (!Mem_read_byte(0, &data, 1)) + return; + ch = data & 0177; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY queue %x\n", ch); + cty_out.buff[cty_out.in_ptr] = ch; + cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; cnt--; - if (cnt) { - ch = data & 0177; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY type %x\n", ch); - ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); - if ((r = sim_putchar_s (ch)) != SCPE_OK) /* Output errors */ - return; - cnt--; - } + sim_activate(&dte_unit[1], 100); +#if (NUM_DEVS_TTY > 0) } else { - if (!Mem_read_byte(0, &data)) + struct _buffer *otty = &tty_out[ln]; + if (((otty->in_ptr + 1) & 0xff) == otty->out_ptr) return; - ch = (data >> 8) & 0177; - if (((tty_out[ln].in_ptr + 1) & 0xff) == tty_out[ln].out_ptr) + if (!Mem_read_byte(0, &data, 1)) return; + ch = data & 0177; sim_debug(DEBUG_DETAIL, &dte_dev, "TTY queue %x %d\n", ch, ln); - tty_out[ln].buff[tty_out[ln].in_ptr] = ch; - tty_out[ln].in_ptr = (tty_out[ln].in_ptr + 1) & 0xff; + otty->buff[otty->in_ptr] = ch; + otty->in_ptr = (otty->in_ptr + 1) & 0xff; cnt--; - if (cnt) { - ch = data & 0177; - if (((tty_out[ln].in_ptr + 1) & 0xff) == tty_out[ln].out_ptr) - return; - sim_debug(DEBUG_DETAIL, &dte_dev, "TTY queue %x %d\n", ch, ln); - tty_out[ln].buff[tty_out[ln].in_ptr] = ch; - tty_out[ln].in_ptr = (tty_out[ln].in_ptr + 1) & 0xff; - cnt--; - } - } - } - /* If on CTY Queue output done response */ - if (ln < 0) { - if (((tty_done.in_ptr + 1) & 0xff) != tty_done.out_ptr) { - tty_done.buff[tty_done.in_ptr] = (char)(0 & 0xff); - tty_done.in_ptr = (tty_done.in_ptr + 1) & 0xff; +#endif } } M[ITS_DTEOUT] = FMASK; @@ -695,60 +672,19 @@ void dte_its(UNIT *uptr) { M[ITS_DTELSP] = FMASK; sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTELSP = %012llo %012llo\n", word, M[ITS_DTELPR]); } - /* Check if any input for it */ - if ((uptr->STATUS & ITS_ON) != 0) { - word = M[ITS_DTETYI]; - if ((word & SMASK) != 0) { /* Ready? */ - if (cty_in.in_ptr != cty_in.out_ptr) { - ch = cty_in.buff[cty_in.out_ptr]; - cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; - word = (uint64)ch; - M[ITS_DTETYI] = word; - /* Tell 10 something is ready */ - uptr->STATUS |= DTE_10DB; - if (uptr->STATUS & DTE_PIE) - set_interrupt(DTE_DEVNUM, uptr->STATUS); - } - } - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTETYI = %012llo\n", word); - } -#if 0 - /* Check for input */ - word = M[ITS_DTETYI]; - if ((word & SMASK) != 0) { - int l = uptr->CNT; - do { - if (tty_connect[l]) { -// if ((ch = dte_unit[1].CHHOLD) != 0) { -// word = ch; -// dte_unit[1].CHHOLD = 0; -// M[ITS_DTETYI] = word; -// /* Tell 10 something is ready */ -// uptr->STATUS |= DTE_10DB; -// if (uptr->STATUS & DTE_PIE) -// set_interrupt(DTE_DEVNUM, uptr->STATUS); -// } - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTETYI = %012llo\n", word); - } -#endif - /* Check for output done */ - word = M[ITS_DTEODN]; - if ((word & SMASK) != 0) { - if (tty_done.in_ptr != tty_done.out_ptr) { - ln = tty_done.buff[tty_done.out_ptr]; - tty_done.out_ptr = (tty_done.out_ptr + 1) & 0xff; - word = M[ITS_DTEODN] = (((uint64)ln) << 18)|1; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEODN = %012llo\n", word); - /* Tell 10 something is ready */ - uptr->STATUS |= DTE_10DB; - if (uptr->STATUS & DTE_PIE) - set_interrupt(DTE_DEVNUM, uptr->STATUS); - } - } - /* Check for hangup */ - word = M[ITS_DTEHNG]; + dte_input(); + /* Check for output Start */ + word = M[ITS_DTEOST]; if ((word & SMASK) == 0) { - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEHNG = %012llo\n", word); + if (word == 0) + cty_done = 1; +#if (NUM_DEVS_TTY > 0) + else if (word > 0 && word < tty_desc.lines) { + tty_done[word-1] = 1; + } +#endif + M[ITS_DTEOST] = FMASK; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEOST = %012llo\n", word); } } #endif @@ -779,7 +715,6 @@ error: uptr->STATUS |= DTE_SEC; return; } - sim_debug(DEBUG_EXP, &dte_dev, "DTE: Read status: %012llo\n", word); if ((word & PRI_CMT_QP) == 0) { uptr->STATUS |= DTE_SEC; @@ -792,23 +727,19 @@ error: fprintf(stderr, "DTE out of sync\n\r"); return; } - word = M[0140 + eb_ptr]; - sim_debug(DEBUG_EXP, &dte_dev, "DTE: Read pointer: %012llo\n", word); - word = M[0141 + eb_ptr]; - sim_debug(DEBUG_EXP, &dte_dev, "DTE: write pointer: %012llo\n", word); /* Get size of transfer */ if (Mem_examine_word(0, dte_et11_off + PRI_CMTW_CNT, &iword)) goto error; - sim_debug(DEBUG_EXP, &dte_dev, "DTE: count: %012llo\n", iword); + sim_debug(DEBUG_EXP, &dte_dev, "DTE: count: %012llo\n", iword); in->dcnt = (uint16)(iword & 0177777); /* Read in data */ dp = &in->data[0]; for (cnt = in->dcnt; cnt >= 0; cnt -=2) { /* Read in data */ - if (!Mem_read_byte(0, dp)) + if (!Mem_read_byte(0, dp, 0)) goto error; - sim_debug(DEBUG_DATA, &dte_dev, "DTE: Read Idata: %06o %03o %03o\n", - *dp, *dp >> 8, *dp & 0377); + sim_debug(DEBUG_DATA, &dte_dev, "DTE: Read Idata: %06o %03o %03o %06o\n", + *dp, *dp >> 8, *dp & 0377, ((*dp & 0377) << 8) | ((*dp >> 8) & 0377)); dp++; } uptr->STATUS &= ~DTE_IND; @@ -817,28 +748,29 @@ error: /* Transfer from 10 */ in->dptr = 0; /* Read in count */ - if (!Mem_read_byte(0, &data1)) + if (!Mem_read_byte(0, &data1, 0)) goto error; in->cnt = data1; cnt = in->cnt-2; - if (!Mem_read_byte(0, &data1)) + if (!Mem_read_byte(0, &data1, 0)) goto error; in->func = data1; cnt -= 2; - if (!Mem_read_byte(0, &data1)) + if (!Mem_read_byte(0, &data1, 0)) goto error; in->dev = data1; cnt -= 2; - if (!Mem_read_byte(0, &data1)) + if (!Mem_read_byte(0, &data1, 0)) goto error; in->spare = data1; cnt -= 2; - sim_debug(DEBUG_DATA, &dte_dev, "DTE: Read CMD: %o %o %o\n", - in->cnt, in->func, in->dev); + sim_debug(DEBUG_DATA, &dte_dev, "DTE: Read CMD: %o %o %s %o\n", + in->cnt, in->func, + ((in->func & 0377) > PRI_EMLDV)?"***":pri_name[in->func & 0377], in->dev); dp = &in->data[0]; for (; cnt > 0; cnt -=2) { /* Read in data */ - if (!Mem_read_byte(0, dp)) + if (!Mem_read_byte(0, dp, 0)) goto error; sim_debug(DEBUG_DATA, &dte_dev, "DTE: Read data: %06o %03o %03o\n", *dp, *dp >> 8, *dp & 0377); @@ -861,8 +793,10 @@ done: uptr->STATUS |= DTE_11DN; if (uptr->STATUS & DTE_PIE) set_interrupt(DTE_DEVNUM, uptr->STATUS); + dte_function(uptr); } +/* Process primary protocol packets */ void dte_function(UNIT *uptr) { @@ -870,6 +804,7 @@ dte_function(UNIT *uptr) int32 ch; struct _dte_queue *cmd; t_stat r; + int func; /* Check if queue is empty */ @@ -880,23 +815,23 @@ dte_function(UNIT *uptr) return; } cmd = &dte_in[dte_in_cmd]; - sim_debug(DEBUG_DATA, &dte_dev, "DTE: func %02o %o %d %d\n", cmd->func & 0377, + func = cmd->func & 0377; + sim_debug(DEBUG_DATA, &dte_dev, "DTE: func %02o %s dev %o cnt %d dcnt %d\n", func, + (func > PRI_EMLDV) ? "***" : pri_name[func], cmd->dev, cmd->dcnt, cmd->dptr ); - switch (cmd->func & 0377) { + switch (func) { case PRI_EM2EI: /* Initial message to 11 */ - data1[0] = 0; - if (dte_queue(uptr, PRI_EM2TI, PRI_EMCTY, 1, data1) == 0) + data1[0] = PRI_CTYDV; + if (dte_queue(PRI_EM2TI, PRI_EMCTY, 1, data1) == 0) + return; +#if (NUM_DEVS_LP > 0) + data1[0] = 140; + if (dte_queue(PRI_EMHLA, PRI_EMLPT, 1, data1) == 0) + return; +#endif + data1[0] = 0; + if (dte_queue(PRI_EMAKA, PRI_EMCLK, 0, data1) == 0) return; -//#if (NUM_DEVS_LP > 0) -// data1[0] = 140; -// if (dte_queue(uptr, PRI_EMHLA, PRI_EMLPT, 1, data1) == 0) -// return; -//#endif - -// data1[0] = ((ln + 1) << 8) | 32; - // (void)dte_queue(uptr, PRI_EMHLA, PRI_EMDL1, 1, data1); -// if (dte_queue(uptr, PRI_EMAKA, PRI_EMDH1, 0, data1) == 0) -// return; break; case PRI_EM2TI: /* Replay to initial message. */ @@ -906,6 +841,7 @@ dte_function(UNIT *uptr) case PRI_EMSTR: /* String data */ +#if (NUM_DEVS_LP > 0) /* Handle printer data */ if (cmd->dev == PRI_EMLPT) { if (!sim_is_active(&lpt_unit)) @@ -925,35 +861,42 @@ dte_function(UNIT *uptr) return; break; } +#endif +#if (NUM_DEVS_TTY > 0) /* Handle terminal data */ if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 1; - if (ln < 0) + int ln = ((cmd->sdev >> 8) & 0377); + struct _buffer *otty; + if (ln == PRI_CTYDV) goto cty; - if (ln >= tty_desc.lines) + ln -= 2; + if (ln > 0 && ln >= tty_desc.lines) break; + otty = &tty_out[ln]; while (cmd->dptr < cmd->dcnt) { - if (((tty_out[ln].in_ptr + 1) & 0xff) == tty_out[ln].out_ptr) + if (((otty->in_ptr + 1) & 0xff) == otty->out_ptr) return; ch = (int32)(cmd->data[cmd->dptr >> 1]); if ((cmd->dptr & 1) == 0) ch >>= 8; ch &= 0177; - sim_debug(DEBUG_DETAIL, &dte_dev, "TTY queue %x %d\n", ch, ln); - tty_out[ln].buff[tty_out[ln].in_ptr] = ch; - tty_out[ln].in_ptr = (tty_out[ln].in_ptr + 1) & 0xff; + sim_debug(DEBUG_DETAIL, &dte_dev, "TTY queue %o %d\n", ch, ln); + otty->buff[otty->in_ptr] = ch; + otty->in_ptr = (otty->in_ptr + 1) & 0xff; cmd->dptr++; } if (cmd->dptr != cmd->dcnt) return; break; } +#endif /* Fall through */ case PRI_EMSNA: /* Send all (ttys) */ if (cmd->dev != PRI_EMCTY) break; cty: + sim_activate(&dte_unit[1], 100); data1[0] = 0; while (cmd->dptr < cmd->dcnt) { if (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) @@ -962,11 +905,10 @@ cty: if ((cmd->dptr & 1) == 0) ch >>= 8; ch &= 0177; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY type %x\n", ch); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY queue %o\n", ch); ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; - cty_data = 1; /* Let output know it needs to ack this */ cmd->dptr++; } if (cmd->dptr != cmd->dcnt) @@ -975,34 +917,16 @@ cty: case PRI_EMLNC: /* Line-Char */ /* Send by DTE only? */ -#if 0 - data1[0] = 0; - while (cmd->dptr < cmd->dcnt) { - ch = (int32)(cmd->data[cmd->dptr >> 1]); - if ((ch >> 8) == PRI_EMCTY) { - ch &= 0177; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ltype %x\n", ch); - ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); - if ((r = sim_putchar_s (ch)) != SCPE_OK) /* Output errors */ - return; - data1[0] = (PRI_EMCTY << 8); - } - cmd->dptr+=2; - } - if (cmd->dptr != cmd->dcnt) - return; - if (dte_queue(uptr, PRI_EMACK, PRI_EMCTY, 1, data1) == 0) - return; -#endif break; case PRI_EMRDS: /* Request device status */ case PRI_EMHDS: /* Here is device status */ case PRI_EMRDT: /* Request Date/Time */ case PRI_EMHDR: /* Here is date and time */ break; +#if (NUM_DEVS_TTY > 0) case PRI_EMFLO: /* Flush output */ if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 1;; + int ln = ((cmd->sdev >> 8) & 0377) - 2;; tty_out[ln].in_ptr = tty_out[ln].out_ptr = 0; } break; @@ -1010,7 +934,7 @@ cty: break; case PRI_EMHUD: /* Hang up dataset */ if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 1; + int ln = ((cmd->sdev >> 8) & 0377) - 2; TMLN *lp = &tty_ldsc[ln]; tmxr_linemsg (lp, "\r\nLine Hangup\r\n"); tmxr_reset_ln(lp); @@ -1019,19 +943,19 @@ cty: break; case PRI_EMXOF: /* XOFF line */ if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 1; + int ln = ((cmd->sdev >> 8) & 0377) - 2; tty_ldsc[ln].rcve = 0; } break; case PRI_EMXON: /* XON line */ if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 1; + int ln = ((cmd->sdev >> 8) & 0377) - 2; tty_ldsc[ln].rcve = 1; } break; case PRI_EMHLS: /* Here is line speeds */ if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 1; + int ln = ((cmd->sdev >> 8) & 0377) - 2; } break; case PRI_EMHLA: /* Here is line allocation */ @@ -1053,6 +977,7 @@ cty: } } break; +#endif case PRI_EMLDR: /* Load LP RAM */ case PRI_EMLDV: /* Load LP VFU */ default: @@ -1142,41 +1067,177 @@ void dte_transfer(UNIT *uptr) { dte_out_ptr = (dte_out_ptr + 1) & 0x1f; done: uptr->STATUS |= DTE_10DN; -//fprintf(stderr, "Xfer done %06o\n\r", uptr->CNT ); if (uptr->STATUS & DTE_PIE) set_interrupt(DTE_DEVNUM, uptr->STATUS); error: return; } +/* Process input from CTY and TTY's to 10. */ void dte_input() { uint16 data1; uint16 dataq[32]; int n; + int ln; int save_ptr; char ch; + int flg; + UNIT *uptr = &dte_unit[0]; - /* Check if CTY done with input */ - if (cty_data && cty_out.in_ptr == cty_out.out_ptr) { - data1 = 0; - if (dte_queue(&dte_unit[0], PRI_EMACK, PRI_EMCTY, 1, &data1) == 0) - return; - cty_data = 0; - } - n = 0; - save_ptr = cty_in.out_ptr; - while (cty_in.in_ptr != cty_in.out_ptr && n < 32) { - ch = cty_in.buff[cty_in.out_ptr]; - cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; - sim_debug(DEBUG_DETAIL, &tty_dev, "CTY recieve %02x\n", ch); - dataq[n++] = ch; - } - if (n > 0 && dte_queue(&dte_unit[0], PRI_EMLNC, PRI_EMCTY, n, dataq) == 0) { - /* Restore the input pointer */ - cty_in.out_ptr = save_ptr; - return; +#if KL_ITS + if (QITS && (uptr->STATUS & ITS_ON) != 0) { + uint64 word; + word = M[ITS_DTEODN]; + /* Check if ready for output done */ + if ((word & SMASK) != 0) { + if (cty_done) { + word = 64LL; + cty_done = 0; +#if (NUM_DEVS_TTY > 0) + } else { + for (ln = 0; ln < tty_desc.lines; ln++) { + if (tty_done[ln]) { + word = (((uint64)ln + 1) << 18); + word |=(tty_connect[ln])? 64: 1; + tty_done[ln] = 0; + break; + } + } +#endif + } + if ((word & SMASK) == 0) { + M[ITS_DTEODN] = word; + /* Tell 10 something is ready */ + uptr->STATUS |= DTE_10DB; + if (uptr->STATUS & DTE_PIE) + set_interrupt(DTE_DEVNUM, uptr->STATUS); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEODN = %012llo\n", word); + } + } + /* Check if ready for any input */ + word = M[ITS_DTETYI]; + if ((word & SMASK) != 0) { + /* CTY first. */ + if (cty_in.in_ptr != cty_in.out_ptr) { + ch = cty_in.buff[cty_in.out_ptr]; + cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; + word = (uint64)ch; +#if (NUM_DEVS_TTY > 0) + } else { + ln = uptr->CNT; + while ((word & SMASK) != 0) { + if (tty_in[ln].in_ptr != tty_in[ln].out_ptr) { + ch = tty_in[ln].buff[tty_in[ln].out_ptr]; + tty_in[ln].out_ptr = (tty_in[ln].out_ptr + 1) & 0xff; + word = ((uint64)(ln+1) << 18) | (uint64)ch; + } + ln++; + if (ln >= tty_desc.lines) + ln = 0; + if (ln == uptr->CNT) + break; + } + uptr->CNT = ln; +#endif + } + if ((word & SMASK) == 0) { + M[ITS_DTETYI] = word; + /* Tell 10 something is ready */ + uptr->STATUS |= DTE_10DB; + if (uptr->STATUS & DTE_PIE) + set_interrupt(DTE_DEVNUM, uptr->STATUS); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTETYI = %012llo\n", word); + } + } +#if (NUM_DEVS_TTY > 0) + /* Check ready for hang up message */ + word = M[ITS_DTEHNG]; + if ((word & SMASK) != 0) { + for (ln = 0; ln < tty_desc.lines; ln++) { + if (tty_connect[ln] != tty_ldsc[ln].conn) { + if (tty_ldsc[ln].conn) + word = 015500 + ln + 1; + else + word = ln + 1; + tty_connect[ln] = tty_ldsc[ln].conn; + tty_done[ln] = tty_ldsc[ln].conn; + break; + } + } + /* Tell 10 something is ready */ + if ((word & SMASK) == 0) { + M[ITS_DTEHNG] = word; + uptr->STATUS |= DTE_10DB; + if (uptr->STATUS & DTE_PIE) + set_interrupt(DTE_DEVNUM, uptr->STATUS); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEHNG = %012llo\n", word); + } + } +#endif + } else +#endif + if ((uptr->STATUS & DTE_SEC) == 0) { + /* Check if CTY done with input */ + if (cty_done) { + data1 = PRI_CTYDV; + if (dte_queue(PRI_EMACK, PRI_EMDLS, 1, &data1) == 0) + return; + cty_done = 0; + } + /* Grab a chunck of input from CTY if any */ + n = 0; + save_ptr = cty_in.out_ptr; + while (cty_in.in_ptr != cty_in.out_ptr && n < 32) { + ch = cty_in.buff[cty_in.out_ptr]; + cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY recieve %02x\n", ch); + dataq[n++] = (PRI_CTYDV << 8) | ch; + } + if (n > 0 && dte_queue(PRI_EMLNC, PRI_EMDLS, n, dataq) == 0) { + /* Restore the input pointer */ + cty_in.out_ptr = save_ptr; + return; + } +#if (NUM_DEVS_TTY > 0) + n = 0; + /* While we have room for one more packet, grab as much input as we can */ + for (ln = 0; ln < tty_desc.lines && ((dte_out_res + 1) & 0x1f) != dte_out_ptr; ln++) { + while (tty_in[ln].in_ptr != tty_in[ln].out_ptr) { + ch = tty_in[ln].buff[tty_in[ln].out_ptr]; + tty_in[ln].out_ptr = (tty_in[ln].out_ptr + 1) & 0xff; + dataq[n++] = ((ln + 2) << 8) | ch; + if (n == 32) { + if (dte_queue(PRI_EMLNC, PRI_EMDLS, n, dataq) == 0) + return; + n = 0; + continue; + } + } + } + if (n > 0 && dte_queue(PRI_EMLNC, PRI_EMDLS, n, dataq) == 0) + return; + n = 0; + for (ln = 0; ln < tty_desc.lines; ln++) { + if (tty_connect[ln] != tty_ldsc[ln].conn) { + data1 = ln + 2; + if (tty_ldsc[ln].conn) + n = PRI_EMDSC; + else + n = PRI_EMHUD; + if (dte_queue(n, PRI_EMDLS, 1, &data1) == 0) + return; + tty_connect[ln] = tty_ldsc[ln].conn; + } + if (tty_done[ln]) { + data1 = ln + 2; + if (dte_queue(PRI_EMACK, PRI_EMDLS, 1, &data1) == 0) + return; + tty_done[ln] = 0; + } + } +#endif } } @@ -1184,11 +1245,10 @@ dte_input() * Queue up a packet to send to 10. */ int -dte_queue(UNIT *uptr, int func, int dev, int dcnt, uint16 *data) +dte_queue(int func, int dev, int dcnt, uint16 *data) { uint64 word; uint16 *dp; - UNIT *optr = &dte_unit[0]; struct _dte_queue *out; /* Check if room in queue for this packet. */ @@ -1202,8 +1262,9 @@ dte_queue(UNIT *uptr, int func, int dev, int dcnt, uint16 *data) out->dev = dev; out->dcnt = (dcnt-1)*2; out->spare = 0; - sim_debug(DEBUG_DATA, &dte_dev, "DTE: %d %d queue resp: %o %o %o\n", - dte_out_ptr, dte_out_res, out->cnt, out->func, out->dev); + sim_debug(DEBUG_DATA, &dte_dev, "DTE: %d %d queue resp: %o %o %s %o\n", + dte_out_ptr, dte_out_res, out->cnt, out->func, + (out->func > PRI_EMLDV)? "***":pri_name[out->func], out->dev); for (dp = &out->data[0]; dcnt > 0; dcnt--) { *dp++ = *data++; } @@ -1256,40 +1317,28 @@ error: } -/* Handle TO10 traffic */ +/* Check for input from CTY and put on queue. */ t_stat dtei_svc (UNIT *uptr) { int32 ch; uint32 base = 0; UNIT *optr = &dte_unit[0]; uint16 data1; + int f; #if KI_22BIT #if KL_ITS - if ((cpu_unit[0].flags & UNIT_ITSPAGE) == 0) + if (!QITS) #endif base = eb_ptr; #endif sim_clock_coschedule (uptr, tmxr_poll); -#if KL_ITS - if ((uptr->STATUS & (DTE_SEC|ITS_ON)) == 0) { -#else - if ((uptr->STATUS & (DTE_SEC)) == 0) { -#endif + dte_input(); + if ((optr->STATUS & (DTE_SEC)) == 0) { dte_function(uptr); /* Process queue */ - dte_input(uptr); dte_start(optr); } - /* Flush out any pending CTY output */ - while(cty_out.in_ptr != cty_out.out_ptr) { - ch = cty_out.buff[cty_out.out_ptr]; - if (sim_putchar(ch) != SCPE_OK) - break; - cty_out.out_ptr = (cty_out.out_ptr + 1) & 0xff; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY outch %x '%c'\n", ch, - ((ch > 040 && ch < 0177)? ch: '.')); - } /* If we have room see if any new lines */ if (((cty_in.in_ptr + 1) & 0xff) != cty_in.out_ptr) { @@ -1298,18 +1347,14 @@ t_stat dtei_svc (UNIT *uptr) ch = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (uptr->flags)); cty_in.buff[cty_in.in_ptr] =ch & 0377; cty_in.in_ptr = (cty_in.in_ptr + 1) & 0xff; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY char %x '%c'\n", ch, + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY char %o '%c'\n", ch, ((ch > 040 && ch < 0177)? ch: '.')); } } -#if KL_ITS - if ((optr->STATUS & (DTE_SEC|ITS_ON)) == (DTE_SEC) && -#else - if ((optr->STATUS & DTE_SEC) != 0 && -#endif - cty_in.in_ptr != cty_in.out_ptr && - (optr->STATUS & DTE_MON) != 0 && - M[SEC_DTMTI + base] == 0) { + + /* If Monitor input, place in buffer */ + if ((optr->STATUS & (DTE_SEC|DTE_MON)) == (DTE_SEC|DTE_MON) && + cty_in.in_ptr != cty_in.out_ptr && M[SEC_DTMTI + base] == 0) { ch = cty_in.buff[cty_in.out_ptr]; cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; M[SEC_DTF11 + base] = ch; @@ -1318,27 +1363,32 @@ t_stat dtei_svc (UNIT *uptr) if (optr->STATUS & DTE_PIE) set_interrupt(DTE_DEVNUM, optr->STATUS); } -#if KL_ITS - if (QITS && (optr->STATUS & ITS_ON) != 0) { - uint64 word = M[ITS_DTETYI]; - if ((word & SMASK) != 0) { - if (cty_in.in_ptr != cty_in.out_ptr) { - ch = cty_in.buff[cty_in.out_ptr]; - cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; - word = (uint64)ch; - M[ITS_DTETYI] = word; - /* Tell 10 something is ready */ - optr->STATUS |= DTE_10DB; - if (optr->STATUS & DTE_PIE) - set_interrupt(DTE_DEVNUM, optr->STATUS); - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTETYI = %012llo\n", word); - } - } - } -#endif return SCPE_OK; } +/* Handle output of characters to CTY. Started whenever there is output pending */ +t_stat dteo_svc (UNIT *uptr) +{ + /* Flush out any pending CTY output */ + while(cty_out.in_ptr != cty_out.out_ptr) { + char ch = cty_out.buff[cty_out.out_ptr]; + if (ch != 0) { + if (sim_putchar(ch) != SCPE_OK) { + sim_activate(uptr, 1000); + return SCPE_OK;; + } + } + cty_out.out_ptr = (cty_out.out_ptr + 1) & 0xff; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY outch %o '%c'\n", ch, + ((ch > 040 && ch < 0177)? ch: '.')); + } + cty_done = 1; + dte_input(); + return SCPE_OK; +} + + +/* Handle FE timer interrupts. And keepalive counts */ t_stat dtertc_srv(UNIT * uptr) { @@ -1373,10 +1423,15 @@ dtertc_srv(UNIT * uptr) word = (M[ITS_DTECHK] + 1) & FMASK; if (word == 0) { optr->STATUS |= ITS_ON; + cty_done = 0; sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS ON\n"); + sim_activate(&tty_unit[0], 1000); + sim_activate(&tty_unit[1], 1000); } else if (word >= (15 * 60)) { optr->STATUS &= ~ITS_ON; word = 15 * 60; + sim_cancel(&tty_unit[0]); + sim_cancel(&tty_unit[1]); sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS OFF\n"); } M[ITS_DTECHK] = word; @@ -1389,12 +1444,11 @@ dtertc_srv(UNIT * uptr) uint64 word; (void)Mem_examine_word(0, dte_et11_off + PRI_CMTW_STS, &word); -//fprintf(stderr, "Timer %06o %012llo\n\r", optr->STATUS, word); addr = (M[addr+1] + dte_off + PRI_CMTW_KAC) & RMASK; word = M[addr]; word = (word + 1) & FMASK; M[addr] = word; - sim_debug(DEBUG_EXP, &dte_dev, "CTY keepalive %06o %012llo %06o\n", + sim_debug(DEBUG_EXP, &dte_dev, "CTY keepalive %06o %012llo %06o\n", addr, word, optr->STATUS); } @@ -1405,17 +1459,12 @@ dtertc_srv(UNIT * uptr) t_stat dte_reset (DEVICE *dptr) { dte_unit[0].STATUS = DTE_SEC; - dte_unit[1].STATUS = DTE_SEC; - dte_unit[1].CHHOLD = 0; + dte_unit[1].STATUS = 0; dte_unit[2].STATUS = 0; -// dte_in_ptr = dte_in_cmd = dte_out_ptr = dte_out_res = 0; -// cty_in.in_ptr = 0; -// cty_in.out_ptr = 0; -// cty_out.in_ptr = 0; -// cty_out.out_ptr = 0; - sim_rtcn_init_unit (&dte_unit[2], dte_unit[2].wait, TMR_RTC); - sim_activate(&dte_unit[1], 100); - sim_activate(&dte_unit[2], 100); + dte_unit[3].STATUS = 0; + sim_rtcn_init_unit (&dte_unit[3], 1000, TMR_RTC); + sim_activate(&dte_unit[3], 1000); + sim_activate(&dte_unit[2], 1000); return SCPE_OK; } @@ -1492,7 +1541,7 @@ lpt_printline(UNIT *uptr, int nl) { uptr->COL = 0; uptr->POS = 0; // if (uptr->LINE == 0) - // (void)dte_queue(&dte_unit[0], PRI_EMHDS, PRI_EMLPT, 1, &data1); + // (void)dte_queue(PRI_EMHDS, PRI_EMLPT, 1, &data1); return; } @@ -1589,7 +1638,7 @@ t_stat lpt_svc (UNIT *uptr) lpt_output(uptr, c); } } - if (dte_queue(&dte_unit[0], PRI_EMACK, PRI_EMLPT, 1, &data1) == 0) + if (dte_queue(PRI_EMACK, PRI_EMLPT, 1, &data1) == 0) sim_activate(uptr, 1000); return SCPE_OK; } @@ -1691,14 +1740,10 @@ t_stat ttyi_svc (UNIT *uptr) sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */ /* If we have room see if any new lines */ - if (((tty_hang.in_ptr + 1) & 0xff) != tty_hang.out_ptr) { - ln = tmxr_poll_conn (&tty_desc); /* look for connect */ - if (ln >= 0) { /* got one? rcv enb*/ - tty_hang.buff[tty_hang.in_ptr] = ln + 1; - tty_hang.in_ptr = (tty_hang.in_ptr + 1) & 0xff; - tty_connect[ln] = 1; + ln = tmxr_poll_conn (&tty_desc); /* look for connect */ + if (ln >= 0) { + tty_ldsc[ln].rcve = 1; sim_debug(DEBUG_DETAIL, &tty_dev, "TTY line connect %d\n", ln); - } } tmxr_poll_tx(&tty_desc); @@ -1706,28 +1751,22 @@ t_stat ttyi_svc (UNIT *uptr) /* Scan each line for input */ for (ln = 0; ln < tty_desc.lines; ln++) { + struct _buffer *iptr = &tty_in[ln]; lp = &tty_ldsc[ln]; + if (lp->conn == 0) + continue; flg = 1; + while (flg && ((iptr->in_ptr + 1) & 0xff) != iptr->out_ptr) { /* Spool up as much as we have room for */ - while (flg && ((tty_out[ln].in_ptr + 1) & 0xff) != tty_out[ln].out_ptr) { int32 ch = tmxr_getc_ln(lp); if ((ch & TMXR_VALID) != 0) { ch = sim_tt_inpcvt (ch, TT_GET_MODE(tty_unit[0].flags) | TTUF_KSR); - tty_in[ln].buff[tty_in[ln].in_ptr] = ch & 0377; - tty_in[ln].in_ptr = (tty_in[ln].in_ptr + 1) & 0xff; - sim_debug(DEBUG_DETAIL, &tty_dev, "TTY recieve %d: %02x\n", ln, ch); + iptr->buff[iptr->in_ptr] = ch & 0377; + iptr->in_ptr = (iptr->in_ptr + 1) & 0xff; + sim_debug(DEBUG_DETAIL, &tty_dev, "TTY recieve %d: %o\n", ln, ch); } else flg = 0; } - /* Look for lines that have been disconnected */ - if (tty_connect[ln] == 1 && lp->conn == 0) { - if (((tty_hang.in_ptr + 1) & 0xff) != tty_hang.out_ptr) { - tty_hang.buff[tty_hang.in_ptr] = ln + 1; - tty_hang.in_ptr = (tty_hang.in_ptr + 1) & 0xff; - tty_connect[ln] = 0; - sim_debug(DEBUG_DETAIL, &tty_dev, "TTY line disconnect %d\n", ln); - } - } } return SCPE_OK; @@ -1748,36 +1787,26 @@ t_stat ttyo_svc (UNIT *uptr) sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */ for (ln = 0; ln < tty_desc.lines; ln++) { + struct _buffer *optr = &tty_out[ln]; lp = &tty_ldsc[ln]; if (lp->conn == 0) continue; - if (((tty_done.in_ptr + 1) & 0xff) == tty_done.out_ptr) - return SCPE_OK; - if (tty_out[ln].out_ptr == tty_out[ln].in_ptr) + if (optr->out_ptr == optr->in_ptr) continue; - while (tty_out[ln].out_ptr != tty_out[ln].in_ptr) { - int32 ch = tty_out[ln].buff[tty_out[ln].out_ptr]; + while (optr->out_ptr != optr->in_ptr) { + int32 ch = optr->buff[optr->out_ptr]; ch = sim_tt_outcvt(ch, TT_GET_MODE (tty_unit[0].flags) | TTUF_KSR); - sim_debug(DEBUG_DATA, &tty_dev, "TTY: %d output %02x\n", ln, ch); + sim_debug(DEBUG_DATA, &tty_dev, "TTY: %d output %o\n", ln, ch); r = tmxr_putc_ln (lp, ch); if (r == SCPE_OK) - tty_out[ln].out_ptr = (tty_out[ln].out_ptr + 1) & 0xff; + optr->out_ptr = (optr->out_ptr + 1) & 0xff; else if (r == SCPE_LOST) { - tty_out[ln].out_ptr = tty_out[ln].in_ptr = 0; + optr->out_ptr = optr->in_ptr = 0; continue; } else continue; } - tty_done.buff[tty_done.in_ptr] = ln + 1; - tty_done.in_ptr = (tty_done.in_ptr + 1) & 0xff; -#if KL_ITS - /* Tell 10 we have something for it */ - if (QITS) { - dte_unit[0].STATUS |= DTE_10DB; - if (dte_unit[0].STATUS & DTE_PIE) - set_interrupt(DTE_DEVNUM, dte_unit[0].STATUS); - } -#endif + tty_done[ln] = 1; } return SCPE_OK; } diff --git a/PDP10/kx10_cpu.c b/PDP10/kx10_cpu.c index 4fb1295..5a7a8f1 100644 --- a/PDP10/kx10_cpu.c +++ b/PDP10/kx10_cpu.c @@ -157,6 +157,7 @@ int pi_enable; /* Interrupts enabled */ int parity_irq; /* Parity interupt */ int pi_pending; /* Interrupt pending. */ int pi_enc; /* Flag for pi */ +int pi_vect; /* Last pi location used for IRQ */ int apr_irq; /* Apr Irq level */ int clk_en; /* Enable clock interrupts */ int clk_irq; /* Clock interrupt */ @@ -266,6 +267,8 @@ int32 tmxr_poll = 10000; /* Physical address range for auxiliary PDP-6. */ #define AUXCPURANGE(addr) ((addr) >= 03000000 && (addr) < 03040000) + +/* List of RH10 & RH20 devices */ DEVICE *rh_devs[] = { #if (NUM_DEVS_RS > 0) &rsa_dev, @@ -287,16 +290,10 @@ DEVICE *rh_devs[] = { #endif NULL, }; - -struct rh_dev rh[] = { - { 0270, NULL, }, - { 0274, NULL, }, - { 0360, NULL, }, - { 0364, NULL, }, - { 0370, NULL, }, - { 0374, NULL, }, - { 0, NULL, }, -}; +/* RH10 device numbers */ +int rh_nums[] = { 0270, 0274, 0360, 0364, 0370, 0374, 0}; +/* Maps RH10 & RH20 device number to DEVICE structure */ +struct rh_dev rh[8]; typedef struct { uint32 pc; @@ -2355,7 +2352,7 @@ int page_lookup(int addr, int flag, int *loc, int wr, int cur_context, int fetch /* Check for access error */ if ((data & RSIGN) == 0 || (wr & ((data & 0100000) == 0))) { -fprintf(stderr, "Page fault %06o a=%o wr=%o w=%o %06o\n\r", addr, (data & RSIGN) == 0, wr, (data & 0100000) == 0, data); +//fprintf(stderr, "Page fault %06o a=%o wr=%o w=%o %06o\n\r", addr, (data & RSIGN) == 0, wr, (data & 0100000) == 0, data); fault_data = BIT8 | (uint64)addr; #if KLB if (QKLB) @@ -2462,7 +2459,7 @@ int Mem_read(int flag, int cur_context, int fetch) { fault_data = (027LL << 30) | (uint64)addr | (((uint64)sect) << 18); if (USER==0) /* U */ fault_data |= SMASK; /* BIT0 */ -fprintf(stderr, "Invalid section %012llo\n\r", fault_data); +//fprintf(stderr, "Invalid section %012llo\n\r", fault_data); page_fault = 1; return 0; } @@ -2508,7 +2505,7 @@ int Mem_write(int flag, int cur_context) { fault_data = (027LL << 30) | (uint64)addr | (((uint64)sect) << 18); if (USER==0) /* U */ fault_data |= SMASK; /* BIT0 */ -fprintf(stderr, "Invalid section %012llo\n\r", fault_data); +//fprintf(stderr, "Invalid section %012llo\n\r", fault_data); page_fault = 1; return 0; } @@ -2615,12 +2612,12 @@ int Mem_deposit_word(int n, int wrd, uint64 *data) { /* * Read in 16 bits of data from a byte pointer. */ -int Mem_read_byte(int n, uint16 *data) { +int Mem_read_byte(int n, uint16 *data, int byte) { int addr; uint64 val; uint64 msk; int p, s, np; - int need = 16; + int need = byte? 8: 16; *data = 0; while (need > 0) { @@ -4222,18 +4219,23 @@ st_pi: * hit at a given level. */ for (f = 0; f < 128; f++) { - if (dev_irqv[f] != 0) - sim_debug(DEBUG_IRQ, &cpu_dev, "vect irq %o %03o \n", - pi_enc, dev_irq[f]); if (dev_irqv[f] != 0 && dev_irq[f] & (0200 >> pi_enc)) { AB = dev_irqv[f](f << 2, AB); + if (dev_irqv[f] != 0) + sim_debug(DEBUG_IRQ, &cpu_dev, "vect irq %o %03o %06o\n", + pi_enc, dev_irq[f], AB); break; } } - AB |= eb_ptr; + if (AB & RSIGN) + AB &= 0777; + else + AB |= eb_ptr; + pi_vect = AB; Mem_read_nopage(); goto no_fetch; #else + pi_vect = AB; goto fetch; #endif } @@ -7022,7 +7024,6 @@ xjrstf: if (QKLB) { pc_sect = (AR >> 18) & 07777; prev_sect = BR & 037; - fprintf(stderr, "xjrstf %012llo %012llo\n\r", BR, AR); } #endif BR = BR >> 23; /* Move flags into position */ @@ -8409,7 +8410,7 @@ last: #if KI | KL if (page_enable && page_fault) { page_fault = 0; -fprintf(stderr, "Page fault trap %06o\n\r", PC); +//fprintf(stderr, "Page fault trap %06o\n\r", PC); pi_cycle = 0; #if KI inout_fail = 1; @@ -8428,9 +8429,8 @@ fprintf(stderr, "Page fault trap %06o\n\r", PC); if ((!pi_hold) & f_inst_fetch) { pi_cycle = 0; } else { - AB = 040 | (pi_enc << 1) | pi_ov | maoff; + AB = pi_vect | pi_ov; #if KI | KL - AB |= eb_ptr; Mem_read_nopage(); #else Mem_read(1, 0, 1); @@ -8441,11 +8441,10 @@ fprintf(stderr, "Page fault trap %06o\n\r", PC); if ((IR & 0700) == 0700) { (void)check_irq_level(); } - AB = 040 | (pi_enc << 1) | pi_ov | maoff; + AB = pi_vect | pi_ov; pi_ov = 0; pi_hold = 0; #if KI | KL - AB |= eb_ptr; Mem_read_nopage(); #else Mem_read(1, 0, 1); @@ -9572,7 +9571,7 @@ t_bool build_dev_tab (void) DEVICE *dptr; DIB *dibp; uint32 i, j, d; -int rh20 = 0540; +int rh20; /* Set trap offset based on MAOFF flag */ maoff = (cpu_unit[0].flags & UNIT_MAOFF)? 0100 : 0; @@ -9626,15 +9625,23 @@ if (QBBN) dev_tab[024>>2] = &dev_pag; #endif -/* Assign all RH10 devices */ +/* Assign all RH10 & RH20 devices */ +rh20 = 0540; for (j = i = 0; (dptr = rh_devs[i]) != NULL; i++) { dibp = (DIB *) dptr->ctxt; if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ - if (rh[j].dev_num == 0) - break; - d = rh[j].dev_num; + d = dibp->dev_num; /* Check type */ + if (d & RH10_DEV) { /* Skip RH10 devices */ + d = rh_nums[j]; + if (d == 0) + break; + } else if (d & RH20_DEV) { /* RH20, grab next device */ + d = rh20; + rh20 += 4; + } dev_tab[(d >> 2)] = dibp->io; dev_irqv[(d >> 2)] = dibp->irq; + rh[j].dev_num = d; rh[j].dev = dptr; j++; } @@ -9653,12 +9660,8 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { for (j = 0; j < dibp->num_devs; j++) { /* loop thru disp */ if (dibp->io) { /* any dispatch? */ d = dibp->dev_num; - if (d & RH10_DEV) /* Skip RH10 devices */ + if (d & (RH10_DEV|RH20_DEV)) /* Skip RH10 & RH20 devices */ continue; - if (d & RH20_DEV) { /* RH20, grab next device */ - d = rh20; - rh20 += 4; - } if (dev_tab[(d >> 2) + j] != &null_dev) { /* already filled? */ sim_printf ("%s device number conflict at %02o\n", diff --git a/PDP10/kx10_defs.h b/PDP10/kx10_defs.h index 8949d15..669a6fe 100644 --- a/PDP10/kx10_defs.h +++ b/PDP10/kx10_defs.h @@ -376,7 +376,7 @@ extern UNIT auxcpu_unit[]; /* DTE memory access functions, n = DTE# */ extern int Mem_examine_word(int n, int wrd, uint64 *data); extern int Mem_deposit_word(int n, int wrd, uint64 *data); -extern int Mem_read_byte(int n, uint16 *data); +extern int Mem_read_byte(int n, uint16 *data, int byte); extern int Mem_write_byte(int n, uint16 *data); extern DEVICE dte_dev; extern DEVICE tty_dev; @@ -541,7 +541,7 @@ int auxcpu_write (int addr, t_uint64); #define NUM_DEVS_TEN11 ITS #define NUM_DEVS_AUXCPU ITS #define NUM_DEVS_IMP 1 -#define NUM_DEVS_CH10 ITS +#define NUM_DEVS_CH10 ITS | KL_ITS #define NUM_DEVS_DPK ITS #define NUM_DEVS_AI ITS #endif diff --git a/PDP10/kx10_imp.c b/PDP10/kx10_imp.c index 897c698..46367a2 100644 --- a/PDP10/kx10_imp.c +++ b/PDP10/kx10_imp.c @@ -145,7 +145,7 @@ #endif #endif -#define IMP_ARPTAB_SIZE 8 +#define IMP_ARPTAB_SIZE 64 #define IMP_ARP_MAX_AGE 100 uint32 mask[] = { @@ -199,6 +199,12 @@ struct tcp { uint32 seq; /* Sequence number */ uint32 ack; /* Ack number */ uint16 flags; /* Flags */ +#define TCP_FL_FIN 0x01 +#define TCP_FL_SYN 0x02 +#define TCP_FL_RST 0x04 +#define TCP_FL_PSH 0x08 +#define TCP_FL_ACK 0x10 +#define TCP_FL_URG 0x20 uint16 window; /* Window size */ uint16 chksum; /* packet checksum */ uint16 urgent; /* Urgent pointer */ @@ -445,6 +451,7 @@ static CONST ETH_MAC broadcast_ethaddr = {0xff,0xff,0xff,0xff,0xff,0xff}; static CONST in_addr_T broadcast_ipaddr = {0xffffffff}; t_stat imp_devio(uint32 dev, uint64 *data); +t_stat imp_devirq(uint32 dev, int addr); t_stat imp_srv(UNIT *); t_stat imp_eth_srv(UNIT *); t_stat imp_tim_srv(UNIT *); @@ -473,6 +480,8 @@ void imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet); void imp_arp_arpout(struct imp_device *imp, in_addr_T ipaddr); struct arp_entry * imp_arp_lookup(struct imp_device *imp, in_addr_T ipaddr); void imp_packet_out(struct imp_device *imp, ETH_PACK *packet); +void imp_packet_debug(struct imp_device *imp, const char *action, ETH_PACK *packet); +void imp_write(struct imp_device *imp, ETH_PACK *packet); void imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *packet); void imp_dhcp_timer(struct imp_device *imp); void imp_dhcp_discover(struct imp_device *imp); @@ -495,7 +504,13 @@ UNIT imp_unit[] = { {UDATA(imp_eth_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ {UDATA(imp_tim_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ }; -DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio, NULL}; +DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio, +#if KL + &imp_devirq, +#else + NULL +#endif +}; MTAB imp_mod[] = { { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", @@ -529,11 +544,38 @@ MTAB imp_mod[] = { { 0 } }; +/* Simulator debug controls */ +DEBTAB imp_debug[] = { + {"CMD", DEBUG_CMD, "Show command execution to devices"}, + {"DATA", DEBUG_DATA, "Show data transfers"}, + {"DETAIL", DEBUG_DETAIL, "Show details about device"}, + {"EXP", DEBUG_EXP, "Show exception information"}, + {"CONI", DEBUG_CONI, "Show coni instructions"}, + {"CONO", DEBUG_CONO, "Show coni instructions"}, + {"DATAIO", DEBUG_DATAIO, "Show datai and datao instructions"}, + {"IRQ", DEBUG_IRQ, "Show IRQ requests"}, +#define DEBUG_DHCP (DEBUG_IRQ<<1) + {"DHCP", DEBUG_DHCP, "Show DHCP activities"}, +#define DEBUG_ARP (DEBUG_DHCP<<1) + {"ARP", DEBUG_ARP, "Show ARP activities"}, +#define DEBUG_TCP (DEBUG_ARP<<1) + {"TCP", DEBUG_TCP, "Show TCP packet activities"}, +#define DEBUG_UDP (DEBUG_TCP<<1) + {"UDP", DEBUG_UDP, "Show UDP packet activities"}, +#define DEBUG_ICMP (DEBUG_UDP<<1) + {"ICMP", DEBUG_ICMP, "Show ICMP packet activities"}, +#define DEBUG_ETHER (DEBUG_ICMP<<1) + {"ETHER", DEBUG_ETHER, "Show ETHER activities"}, + {0, 0} +}; + + + DEVICE imp_dev = { "IMP", imp_unit, NULL, imp_mod, 3, 8, 0, 1, 8, 36, NULL, NULL, &imp_reset, NULL, &imp_attach, &imp_detach, - &imp_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug, + &imp_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, imp_debug, NULL, NULL, &imp_help, NULL, NULL, &imp_description }; #define IMP_OCHN 0000007 @@ -600,6 +642,7 @@ t_stat imp_devio(uint32 dev, uint64 *data) uptr->STATUS |= IMPIHE; if (*data & IMPLHW) /* Last host word. */ uptr->STATUS |= IMPLHW; + check_interrupts(uptr); break; case TYPE_BBN: break; @@ -696,6 +739,20 @@ t_stat imp_devio(uint32 dev, uint64 *data) return SCPE_OK; } +#if KL +/* Handle KL style interrupt vectors for ITS */ +int +imp_devirq(uint32 dev, int addr) { + if ((cpu_unit[0].flags & UNIT_ITSPAGE) != 0 && (imp_data.pia & 7) == 1) { + if (imp_unit[0].STATUS & IMPID && (imp_unit[0].STATUS & IMPLW) == 0) + return 070|RSIGN; + if (imp_unit[0].STATUS & IMPOD) + return 072|RSIGN; + } + return addr; +} +#endif + t_stat imp_srv(UNIT * uptr) { DEVICE *dptr = find_dev_from_unit(uptr); @@ -831,8 +888,8 @@ t_stat imp_eth_srv(UNIT * uptr) imp_data.dhcp_state != DHCP_STATE_REBINDING && imp_data.dhcp_state != DHCP_STATE_RENEWING) return SCPE_OK; - sim_debug(DEBUG_DETAIL, &imp_dev, "IMP init Nop %d\n", - imp_data.init_state); + sim_debug(DEBUG_DETAIL, &imp_dev, "IMP init Nop %d\n", + imp_data.init_state); if (imp_unit[0].ILEN == 0) { /* Queue up a nop packet */ imp_data.rbuffer[0] = 0x4; @@ -922,6 +979,7 @@ imp_packet_in(struct imp_device *imp) } return; } + imp_packet_debug(imp, "Received", &read_buffer); hdr = (struct imp_eth_hdr *)(&read_buffer.msg[0]); type = ntohs(hdr->type); if (type == ETHTYPE_ARP) { @@ -1083,9 +1141,11 @@ imp_packet_in(struct imp_device *imp) /* Lastly check if ICMP */ } else if (ip_hdr->ip_p == ICMP_PROTO) { struct icmp *icmp_hdr = (struct icmp *)payload; - checksumadjust((uint8 *)&icmp_hdr->chksum, - (uint8 *)(&ip_hdr->ip_src), sizeof(in_addr_T), - (uint8 *)(&imp_data.hostip), sizeof(in_addr_T)); + if ((icmp_hdr->type != 0) && /* Not Echo Reply */ + (icmp_hdr->type != 8)) /* and Not Echo */ + checksumadjust((uint8 *)&icmp_hdr->chksum, + (uint8 *)(&ip_hdr->ip_src), sizeof(in_addr_T), + (uint8 *)(&imp_data.hostip), sizeof(in_addr_T)); } checksumadjust((uint8 *)&ip_hdr->ip_sum, (uint8 *)(&ip_hdr->ip_dst), sizeof(in_addr_T), @@ -1309,9 +1369,11 @@ imp_packet_out(struct imp_device *imp, ETH_PACK *packet) { /* Lastly check if ICMP */ } else if (pkt->iphdr.ip_p == ICMP_PROTO) { struct icmp *icmp_hdr = (struct icmp *)payload; - checksumadjust((uint8 *)&icmp_hdr->chksum, - (uint8 *)(&pkt->iphdr.ip_src), sizeof(in_addr_T), - (uint8 *)(&imp->ip), sizeof(in_addr_T)); + if ((icmp_hdr->type != 0) && /* Not Echo Reply */ + (icmp_hdr->type != 8)) /* and Not Echo */ + checksumadjust((uint8 *)&icmp_hdr->chksum, + (uint8 *)(&pkt->iphdr.ip_src), sizeof(in_addr_T), + (uint8 *)(&imp->ip), sizeof(in_addr_T)); } /* Lastly update the header and IP address */ checksumadjust((uint8 *)&pkt->iphdr.ip_sum, @@ -1337,7 +1399,7 @@ imp_packet_out(struct imp_device *imp, ETH_PACK *packet) { memcpy(&pkt->ethhdr.dest, &tabptr->ethaddr, 6); memcpy(&pkt->ethhdr.src, &imp->mac, 6); pkt->ethhdr.type = htons(ETHTYPE_IP); - eth_write(&imp->etherface, packet, NULL); + imp_write(imp, packet); imp->rfnm_count++; return; } @@ -1357,6 +1419,259 @@ imp_packet_out(struct imp_device *imp, ETH_PACK *packet) { } +void imp_packet_debug(struct imp_device *imp, const char *action, ETH_PACK *packet) { + struct imp_eth_hdr *eth = (struct imp_eth_hdr *)&packet->msg[0]; + struct arp_hdr *arp = (struct arp_hdr *)eth; + struct ip *ip = (struct ip *)&packet->msg[sizeof(struct imp_eth_hdr)]; + struct udp *udp; + struct tcp *tcp; + struct icmp *icmp; + uint8 *payload; + struct in_addr ipaddr; + size_t len; + int flag; + char src_ip[20]; + char dst_ip[20]; + char src_port[8]; + char dst_port[8]; + char mac_buf[20]; + char flags[64]; + static struct tcp_flag_bits { + const char *name; + uint16 bitmask; + } bits[] = { + {"FIN", TCP_FL_FIN}, + {"SYN", TCP_FL_SYN}, + {"RST", TCP_FL_RST}, + {"PSH", TCP_FL_PSH}, + {"ACK", TCP_FL_ACK}, + {"URG", TCP_FL_URG}, + {NULL, 0} + }; + static const char *icmp_types[] = { + "Echo Reply", // Type 0 + "Type 1 - Unassigned", + "Type 2 - Unassigned", + "Destination Unreachable", // Type 3 + "Source Quench (Deprecated)", // Type 4 + "Redirect", // Type 5 + "Type 6 - Alternate Host Address (Deprecated)", + "Type 7 - Unassigned", + "Echo Request", // Type 8 + "Router Advertisement", // Type 9 + "Router Selection", // Type 10 + "Time Exceeded", // Type 11 + "Type 12 - Parameter Problem", + "Type 13 - Timestamp", + "Type 14 - Timestamp Reply", + "Type 15 - Information Request (Deprecated)", + "Type 16 - Information Reply (Deprecated)", + "Type 17 - Address Mask Request (Deprecated)", + "Type 18 - Address Mask Reply (Deprecated)", + "Type 19 - Reserved (for Security)", + "Type 20 - Reserved (for Robustness Experiment)", + "Type 21 - Reserved (for Robustness Experiment)", + "Type 22 - Reserved (for Robustness Experiment)", + "Type 23 - Reserved (for Robustness Experiment)", + "Type 24 - Reserved (for Robustness Experiment)", + "Type 25 - Reserved (for Robustness Experiment)", + "Type 26 - Reserved (for Robustness Experiment)", + "Type 27 - Reserved (for Robustness Experiment)", + "Type 28 - Reserved (for Robustness Experiment)", + "Type 29 - Reserved (for Robustness Experiment)", + "Type 30 - Traceroute (Deprecated)", + "Type 31 - Datagram Conversion Error (Deprecated)", + "Type 32 - Mobile Host Redirect (Deprecated)", + "Type 33 - IPv6 Where-Are-You (Deprecated)", + "Type 34 - IPv6 I-Am-Here (Deprecated)", + "Type 35 - Mobile Registration Request (Deprecated)", + "Type 36 - Mobile Registration Reply (Deprecated)", + "Type 37 - Domain Name Request (Deprecated)", + "Type 38 - Domain Name Reply (Deprecated)", + "Type 39 - SKIP (Deprecated)", + "Type 40 - Photuris", + "Type 41 - ICMP messages utilized by experimental mobility protocols such as Seamoby", + "Type 42 - Extended Echo Request", + "Type 43 - Extended Echo Reply" + }; + + if (ntohs(eth->type) == ETHTYPE_ARP) { + struct in_addr in_addr; + const char *arp_op = (ARP_REQUEST == ntohs(arp->opcode)) ? "REQUEST" : ((ARP_REPLY == ntohs(arp->opcode)) ? "REPLY" : "Unknown"); + char eth_src[20], eth_dst[20]; + char arp_shwaddr[20], arp_dhwaddr[20]; + char arp_sipaddr[20], arp_dipaddr[20]; + + if (!(imp_dev.dctrl & DEBUG_ARP)) + return; + eth_mac_fmt(&arp->ethhdr.src, eth_src); + eth_mac_fmt(&arp->ethhdr.dest, eth_dst); + eth_mac_fmt(&arp->shwaddr, arp_shwaddr); + memcpy(&in_addr, &arp->sipaddr, sizeof(in_addr)); + strlcpy(arp_sipaddr, ipv4_inet_ntoa(in_addr), sizeof(arp_sipaddr)); + eth_mac_fmt(&arp->dhwaddr, arp_dhwaddr); + memcpy(&in_addr, &arp->dipaddr, sizeof(in_addr)); + strlcpy(arp_dipaddr, ipv4_inet_ntoa(in_addr), sizeof(arp_dipaddr)); + sim_debug(DEBUG_ARP, &imp_dev, + "%s %s EthDst=%s EthSrc=%s shwaddr=%s sipaddr=%s dhwaddr=%s dipaddr=%s\n", + action, arp_op, eth_dst, eth_src, arp_shwaddr, arp_sipaddr, arp_dhwaddr, arp_dipaddr); + return; + } + if (ntohs(eth->type) != ETHTYPE_IP) + return; + if (!(imp_dev.dctrl & (DEBUG_TCP|DEBUG_UDP|DEBUG_ICMP))) + return; + memcpy(&ipaddr, &ip->ip_src, sizeof(ipaddr)); + strlcpy(src_ip, ipv4_inet_ntoa(ipaddr), sizeof(src_ip)); + memcpy(&ipaddr, &ip->ip_dst, sizeof(ipaddr)); + strlcpy(dst_ip, ipv4_inet_ntoa(ipaddr), sizeof(dst_ip)); + payload = (uint8 *)&packet->msg[sizeof(struct imp_eth_hdr) + (ip->ip_v_hl & 0xf) * 4]; + switch (ip->ip_p) { + case UDP_PROTO: + udp = (struct udp *)payload; + snprintf(src_port, sizeof(src_port), "%d", ntohs(udp->udp_sport)); + snprintf(dst_port, sizeof(dst_port), "%d", ntohs(udp->udp_dport)); + sim_debug(DEBUG_UDP, &imp_dev, "%s %d byte packet from %s:%s to %s:%s\n", action, + ntohs(udp->len), src_ip, src_port, dst_ip, dst_port); + if ((imp_dev.dctrl & DEBUG_DHCP) && + (((ntohs(udp->udp_sport) == DHCP_UDP_PORT_CLIENT) && + (ntohs(udp->udp_dport) == DHCP_UDP_PORT_SERVER)) || + ((ntohs(udp->udp_dport) == DHCP_UDP_PORT_CLIENT) && + (ntohs(udp->udp_sport) == DHCP_UDP_PORT_SERVER)))) { + struct dhcp *dhcp = (struct dhcp *)(payload + sizeof(struct udp)); + uint8 *opt = &dhcp->options[0]; + + sim_debug(DEBUG_DHCP, &imp_dev, "%s XID=%08X", + (dhcp->op == DHCP_BOOTREQUEST) ? "REQUEST" : + (dhcp->op == DHCP_BOOTREPLY) ? "REPLY" : + "??????", + dhcp->xid); + if (dhcp->ciaddr) { + memcpy(&ipaddr, &dhcp->ciaddr, sizeof(ipaddr)); + sim_debug(DEBUG_DHCP, &imp_dev, ", ciaddr=%s", ipv4_inet_ntoa(ipaddr)); + } + if (dhcp->yiaddr) { + memcpy(&ipaddr, &dhcp->yiaddr, sizeof(ipaddr)); + sim_debug(DEBUG_DHCP, &imp_dev, ", yiaddr=%s", ipv4_inet_ntoa(ipaddr)); + } + if (dhcp->siaddr) { + memcpy(&ipaddr, &dhcp->siaddr, sizeof(ipaddr)); + sim_debug(DEBUG_DHCP, &imp_dev, ", siaddr=%s", ipv4_inet_ntoa(ipaddr)); + } + if (dhcp->giaddr) { + memcpy(&ipaddr, &dhcp->giaddr, sizeof(ipaddr)); + sim_debug(DEBUG_DHCP, &imp_dev, ", giaddr=%s", ipv4_inet_ntoa(ipaddr)); + } + eth_mac_fmt((ETH_MAC*)&dhcp->chaddr, mac_buf); + sim_debug(DEBUG_DHCP, &imp_dev, ", chaddr=%s Options: ", mac_buf); + while (*opt != DHCP_OPTION_END) { + int opt_len; + u_long numeric; + static const char *opr_names[] = { + "", "DISCOVER", "OFFER", "REQUEST", + "DECLINE", "ACK", "NAK", "RELEASE", + "INFORM" + }; + + + switch(*opt++) { + case DHCP_OPTION_PAD: + break; + default: + opt_len = *opt++; + opt += opt_len; + break; + case DHCP_OPTION_SUBNET_MASK: + opt_len = *opt++; + memcpy(&ipaddr, opt, 4); + sim_debug(DEBUG_DHCP, &imp_dev, ", mask=%s", ipv4_inet_ntoa(ipaddr)); + opt += opt_len; + break; + case DHCP_OPTION_ROUTER: + opt_len = *opt++; + memcpy(&ipaddr, opt, 4); + sim_debug(DEBUG_DHCP, &imp_dev, ", router=%s", ipv4_inet_ntoa(ipaddr)); + opt += opt_len; + break; + case DHCP_OPTION_REQUESTED_IP: + opt_len = *opt++; + memcpy(&ipaddr, opt, 4); + sim_debug(DEBUG_DHCP, &imp_dev, ", requested-ip=%s", ipv4_inet_ntoa(ipaddr)); + opt += opt_len; + break; + case DHCP_OPTION_LEASE_TIME: + opt_len = *opt++; + memcpy(&numeric, opt, 4); + sim_debug(DEBUG_DHCP, &imp_dev, ", lease-time=%d", ntohl(numeric)); + opt += opt_len; + break; + case DHCP_OPTION_T1: + opt_len = *opt++; + memcpy(&numeric, opt, 4); + sim_debug(DEBUG_DHCP, &imp_dev, ", renew-time=%d", ntohl(numeric)); + opt += opt_len; + break; + case DHCP_OPTION_T2: + opt_len = *opt++; + memcpy(&numeric, opt, 4); + sim_debug(DEBUG_DHCP, &imp_dev, ", rebind-time=%d", ntohl(numeric)); + opt += opt_len; + break; + case DHCP_OPTION_SERVER_ID: + opt_len = *opt++; + memcpy(&ipaddr, opt, 4); + sim_debug(DEBUG_DHCP, &imp_dev, ", server-ip=%s", ipv4_inet_ntoa(ipaddr)); + opt += opt_len; + break; + case DHCP_OPTION_MESSAGE_TYPE: + opt_len = *opt++; + sim_debug(DEBUG_DHCP, &imp_dev, "MessageType=%s", opr_names[*opt]); + opt += opt_len; + break; + } + } + sim_debug(DEBUG_DHCP, &imp_dev, "\n"); + } else { + if (udp->len && (imp_dev.dctrl & DEBUG_UDP)) + sim_data_trace(&imp_dev, imp_unit, payload + sizeof(struct udp), "", + ntohs(udp->len), "", DEBUG_DATA); + } + break; + case TCP_PROTO: + tcp = (struct tcp *)payload; + snprintf(src_port, sizeof(src_port), "%d", ntohs(tcp->tcp_sport)); + snprintf(dst_port, sizeof(dst_port), "%d", ntohs(tcp->tcp_dport)); + strlcpy(flags, "", sizeof(flags)); + for (flag=0; bits[flag].name; flag++) { + if (ntohs(tcp->flags) & bits[flag].bitmask) { + if (*flags) + strlcat(flags, ",", sizeof(flags)); + strlcat(flags, bits[flag].name, sizeof(flags)); + } + + } + len = ntohs(ip->ip_len) - ((ip->ip_v_hl & 0xf) * 4 + (ntohs(tcp->flags) >> 12) * 4); + sim_debug(DEBUG_TCP, &imp_dev, "%s %s%s %d byte packet from %s:%s to %s:%s\n", action, + flags, *flags ? ":" : "", (int)len, src_ip, src_port, dst_ip, dst_port); + if (len && (imp_dev.dctrl & DEBUG_TCP)) + sim_data_trace(&imp_dev, imp_unit, payload + 4 * (ntohs(tcp->flags) >> 12), "", len, "", DEBUG_DATA); + break; + case ICMP_PROTO: + icmp = (struct icmp *)payload; + len = ntohs(ip->ip_len) - (ip->ip_v_hl & 0xf) * 4; + sim_debug(DEBUG_ICMP, &imp_dev, "%s %s %d byte packet from %s to %s\n", action, + (icmp->type < sizeof(icmp_types)/sizeof(icmp_types[0])) ? icmp_types[icmp->type] : "", (int)len, src_ip, dst_ip); + if (len && (imp_dev.dctrl & DEBUG_ICMP)) + sim_data_trace(&imp_dev, imp_unit, payload + sizeof(struct icmp), "", len, "", DEBUG_DATA); + break; + } +} + +void imp_write(struct imp_device *imp, ETH_PACK *packet) { + imp_packet_debug(imp, "Sending", packet); + eth_write(&imp->etherface, packet, NULL); +} + /* * Update the ARP table, first use free entry, else use oldest. */ @@ -1365,6 +1680,7 @@ imp_arp_update(struct imp_device *imp, in_addr_T ipaddr, ETH_MAC *ethaddr, int a { struct arp_entry *tabptr; int i; + char mac_buf[20]; /* Check if entry already in the table. */ for (i = 0; i < IMP_ARPTAB_SIZE; i++) { @@ -1372,7 +1688,13 @@ imp_arp_update(struct imp_device *imp, in_addr_T ipaddr, ETH_MAC *ethaddr, int a if (tabptr->ipaddr != 0) { if (tabptr->ipaddr == ipaddr) { - memcpy(&tabptr->ethaddr, ethaddr, sizeof(ETH_MAC)); + if (0 != memcmp(&tabptr->ethaddr, ethaddr, sizeof(ETH_MAC))) { + memcpy(&tabptr->ethaddr, ethaddr, sizeof(ETH_MAC)); + eth_mac_fmt(ethaddr, mac_buf); + sim_debug(DEBUG_ARP, &imp_dev, + "updating entry for IP %s to %s\n", + ipv4_inet_ntoa(*((struct in_addr *)&ipaddr)), mac_buf); + } if (tabptr->age != ARP_DONT_AGE) tabptr->age = age; return; @@ -1402,10 +1724,14 @@ imp_arp_update(struct imp_device *imp, in_addr_T ipaddr, ETH_MAC *ethaddr, int a tabptr = &imp->arp_table[fnd]; } - /* Now update the entry */ + /* Now save the entry */ memcpy(&tabptr->ethaddr, ethaddr, sizeof(ETH_MAC)); tabptr->ipaddr = ipaddr; tabptr->age = age; + eth_mac_fmt(ethaddr, mac_buf); + sim_debug(DEBUG_ARP, &imp_dev, + "creating entry for IP %s to %s, initial age=%d\n", + ipv4_inet_ntoa(*((struct in_addr *)&ipaddr)), mac_buf, age); } /* @@ -1423,6 +1749,12 @@ void imp_arp_age(struct imp_device *imp) tabptr->age++; /* Age it */ /* expire too old entries */ if (tabptr->age > IMP_ARP_MAX_AGE) { + char mac_buf[20]; + + eth_mac_fmt(&tabptr->ethaddr, mac_buf); + sim_debug(DEBUG_ARP, &imp_dev, + "discarding ARP entry for IP %s %s after %d seconds\n", + ipv4_inet_ntoa(*((struct in_addr *)&tabptr->ipaddr)), mac_buf, IMP_ARP_MAX_AGE); memset(tabptr, 0, sizeof(*tabptr)); } } @@ -1438,18 +1770,20 @@ void imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet) { struct arp_hdr *arp; + struct in_addr in_addr; int op; + char mac_buf[20]; /* Ignore packet if too short */ if (packet->len < sizeof(struct arp_hdr)) return; arp = (struct arp_hdr *)(&packet->msg[0]); op = ntohs(arp->opcode); + imp_arp_update(imp, arp->sipaddr, &arp->shwaddr, 0); switch (op) { case ARP_REQUEST: if (arp->dipaddr == imp->ip) { - imp_arp_update(imp, arp->sipaddr, &arp->shwaddr, 0); arp->opcode = htons(ARP_REPLY); memcpy(&arp->dhwaddr, &arp->shwaddr, 6); @@ -1461,7 +1795,10 @@ imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet) arp->sipaddr = imp->ip; arp->ethhdr.type = htons(ETHTYPE_ARP); packet->len = sizeof(struct arp_hdr); - eth_write(&imp->etherface, packet, NULL); + imp_write(imp, packet); + eth_mac_fmt(&arp->dhwaddr, mac_buf); + sim_debug(DEBUG_ARP, &imp_dev, "replied to received request for IP %s from %s\n", + ipv4_inet_ntoa(*((struct in_addr *)&imp->ip)), mac_buf); } break; @@ -1469,7 +1806,11 @@ imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet) /* Check if this is our address */ if (arp->dipaddr == imp->ip) { struct imp_packet *nq = NULL; /* New send queue */ - imp_arp_update(imp, arp->sipaddr, &arp->shwaddr, 0); + + eth_mac_fmt(&arp->shwaddr, mac_buf); + memcpy(&in_addr, &arp->sipaddr, sizeof(in_addr)); + sim_debug(DEBUG_ARP, &imp_dev, "received reply for IP %s as %s\n", + ipv4_inet_ntoa(in_addr), mac_buf); /* Scan send queue, and send all packets for this host */ while (imp->sendq != NULL) { struct imp_packet *temp = imp->sendq; @@ -1481,7 +1822,7 @@ imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet) memcpy(&pkt->ethhdr.dest, &arp->shwaddr, 6); memcpy(&pkt->ethhdr.src, &imp->mac, 6); pkt->ethhdr.type = htons(ETHTYPE_IP); - eth_write(&imp->etherface, &temp->packet, NULL); + imp_write(imp, &temp->packet); imp->rfnm_count++; imp_free_packet(imp, temp); } else { @@ -1522,7 +1863,8 @@ imp_arp_arpout(struct imp_device *imp, in_addr_T ipaddr) arp->protolen = 4; arp_pkt.len = sizeof(struct arp_hdr); - eth_write(&imp->etherface, &arp_pkt, NULL); + imp_write(imp, &arp_pkt); + sim_debug(DEBUG_ARP, &imp_dev, "sending request for IP %s\n", ipv4_inet_ntoa(*((struct in_addr *)&ipaddr))); } /* @@ -1625,7 +1967,9 @@ imp_do_send_dhcp(struct imp_device *imp, struct ip_hdr *pkt; struct udp *udp; struct udp_hdr udp_hdr; + struct in_addr in_addr; int len; + char mac_buf[20]; pkt = (struct ip_hdr *)(&packet->msg[0]); udp = (struct udp *)(&packet->msg[sizeof(struct imp_eth_hdr) + @@ -1658,9 +2002,13 @@ imp_do_send_dhcp(struct imp_device *imp, checksumadjust((uint8 *)&udp->chksum, (uint8 *)(&udp_hdr), 0, (uint8 *)(&udp_hdr), sizeof(udp_hdr)); packet->len = len + sizeof(struct ip_hdr); - eth_write(&imp->etherface, packet, NULL); - sim_debug(DEBUG_DETAIL, &imp_dev, - "DHCP client sent %s packet\n", op); + imp_write(imp, packet); + + eth_mac_fmt (&pkt->ethhdr.dest, mac_buf); + memcpy(&in_addr, &udp_hdr.ip_dst, sizeof(in_addr)); + sim_debug(DEBUG_DHCP, &imp_dev, + "client sent %s packet to: %s:%d(%s)\n", + op, ipv4_inet_ntoa(in_addr), ntohs(udp->udp_dport), mac_buf); } /* Handle incoming DCHP offer and other requests */ @@ -1674,6 +2022,7 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) struct dhcp *dhcp; struct udp *upkt; struct udp_hdr udp_hdr; + struct in_addr in_addr; uint8 *opt; uint16 sum; int len; @@ -1685,6 +2034,7 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) int rebind_time = 0; /* Rebind time */ in_addr_T dhcpip = 0; /* DHCP server address */ int opr = -1; /* DHCP operation */ + char mac_buf[20]; /* Source MAC address */ upkt = (struct udp *)(&((uint8 *)(ip_hdr))[hl]); dhcp = (struct dhcp *)(&((uint8 *)(upkt))[sizeof(struct udp)]); @@ -1771,10 +2121,13 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) } } - sim_debug(DEBUG_DETAIL, &imp_dev, - "DHCP client incoming %s packet: dhcp_state=%s - wait_time=%d\n", + eth_mac_fmt(ð->src, mac_buf); + memcpy(&in_addr, &udp_hdr.ip_src, sizeof(in_addr)); + sim_debug(DEBUG_DHCP, &imp_dev, + "client incoming %s packet: dhcp_state=%s - wait_time=%d from: %s:%d(%s)\n", (opr == -1) ? "" : dhcp_opr_names[opr], - dhcp_state_names[imp->dhcp_state], imp->dhcp_wait_time); + dhcp_state_names[imp->dhcp_state], imp->dhcp_wait_time, + ipv4_inet_ntoa(in_addr), ntohs(upkt->udp_sport), mac_buf); /* Process an offer message */ if (opr == DHCP_OFFER && imp->dhcp_state == DHCP_STATE_SELECTING) { @@ -1829,7 +2182,7 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) arp->hwlen = 6; arp->protolen = 4; arp_pkt.len = sizeof(struct arp_hdr); - eth_write(&imp->etherface, &arp_pkt, NULL); + imp_write(imp, &arp_pkt); } } if (opr == DHCP_NAK && (imp->dhcp_state == DHCP_STATE_REQUESTING || @@ -2338,7 +2691,7 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr) if (tptr == NULL) return SCPE_MEM; strcpy(tptr, cptr); - status = eth_open(&imp_data.etherface, cptr, &imp_dev, 0xFFFF); + status = eth_open(&imp_data.etherface, cptr, &imp_dev, DEBUG_ETHER); if (status != SCPE_OK) { free(tptr); return status; diff --git a/makefile b/makefile index f7e9174..f32920e 100644 --- a/makefile +++ b/makefile @@ -107,10 +107,11 @@ ifneq (,$(findstring besm6,$(MAKECMDGOALS))) VIDEO_USEFUL = true BESM6_BUILD = true endif -# building the KA10 needs video support +# building the PDP6, KA10 or KI10 needs video support ifneq (,$(or $(findstring pdp6,$(MAKECMDGOALS)),$(findstring pdp10-ka,$(MAKECMDGOALS)),$(findstring pdp10-ki,$(MAKECMDGOALS)))) VIDEO_USEFUL = true endif +# building the KA10, KI10 or KL10 networking can be used. ifneq (,$(or $(findstring pdp10-ka,$(MAKECMDGOALS)),$(findstring pdp10-ki,$(MAKECMDGOALS),$(findstring pdp10-kl,$MAKECMDGOALS)))) NETWORK_USEFUL = true endif @@ -1269,7 +1270,7 @@ KL10D = PDP10 KL10 = ${KL10D}/kx10_cpu.c ${KL10D}/kx10_sys.c ${KL10D}/kx10_df.c \ ${KL10D}/kx10_mt.c ${KL10D}/kx10_dc.c ${KL10D}/kx10_rp.c \ ${KL10D}/kx10_tu.c ${KL10D}/kx10_rs.c ${KL10D}/kx10_imp.c \ - ${KL10D}/kl10_fe.c ${KL10D}/ka10_pd.c + ${KL10D}/kl10_fe.c ${KL10D}/ka10_pd.c ${KL10D}/ka10_ch10.c KL10_OPT = -DKL=1 -DUSE_INT64 -I $(KL10D) -DUSE_SIM_CARD ${NETWORK_OPT} PDP1D = PDP1