diff --git a/H316/h316_hi.c b/H316/h316_hi.c index 00c45191..f8d6239b 100644 --- a/H316/h316_hi.c +++ b/H316/h316_hi.c @@ -105,6 +105,8 @@ void hi_rx_local (uint16 line, uint16 txnext, uint16 txcount); t_stat hi_reset (DEVICE *dptr); t_stat hi_attach (UNIT *uptr, CONST char *cptr); t_stat hi_detach (UNIT *uptr); +t_stat hi_set_convert (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat hi_show_convert (FILE *st, UNIT *uptr, int32 val, CONST void *desc); @@ -115,7 +117,7 @@ t_stat hi_detach (UNIT *uptr); // Host interface data blocks ... // The HIDB is our own internal data structure for each host. It keeps data // about the TCP/IP connection, buffers, etc. -#define HI_HIDB(N) {FALSE, FALSE, 0, {0}, 0, 0, 0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, HI_TXBPS} +#define HI_HIDB(N) {FALSE, FALSE, 0, {0}, 0, 0, 0, FALSE, 0, 0, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, HI_TXBPS} HIDB hi1_db = HI_HIDB(1), hi2_db = HI_HIDB(2); HIDB hi3_db = HI_HIDB(3), hi4_db = HI_HIDB(4); @@ -161,8 +163,9 @@ REG hi3_reg[] = HI_REG(3), hi4_reg[] = HI_REG(4); // Host Device Modifiers ... // These are the modifiers simh uses for the "SET MIxn" and "SHOW MIx" commands. -#define HI_MOD(N) { \ - { 0 } \ +#define HI_MOD(N) { \ + { MTAB_XTD|MTAB_VDV, 0, NULL, "CONVERT", &hi_set_convert, &hi_show_convert, NULL }, \ + { MTAB_XTD|MTAB_VDV, 1, NULL, "NOCONVERT", &hi_set_convert, &hi_show_convert, NULL }, \ } MTAB hi1_mod[] = HI_MOD(1), hi2_mod[] = HI_MOD(2); MTAB hi3_mod[] = HI_MOD(3), hi4_mod[] = HI_MOD(4); @@ -196,6 +199,25 @@ UNIT *const hi_units [HI_NUM] = {&hi1_unit, &hi2_unit, &hi3_unit, &hi4_unit}; DIB *const hi_dibs [HI_NUM] = {&hi1_dib, &hi2_dib, &hi3_dib, &hi4_dib }; HIDB *const hi_hidbs [HI_NUM] = {&hi1_db, &hi2_db, &hi3_db, &hi4_db }; +// Old message type field set to this to signal new format leader. +#define NEW_FORMAT_FLAG (15 << 8) + +// 1822 message types (or subtypes). +#define LEADER_REGULAR 000 +#define LEADER_UNCONTROLLED 003 +#define LEADER_NOP 004 + +// 1822 new leader flags. +#define NLEADER_TRACE 010 +#define NLEADER_OCTAL 004 +#define NLEADER_FOR_IMP 252 +#define NLEADER_PRIORITY 0200 + +// 1822 old leader flags. +#define OLEADER_PRIORITY 010 +#define OLEADER_FOR_IMP 004 +#define OLEADER_TRACE 002 +#define OLEADER_OCTAL 001 //////////////////////////////////////////////////////////////////////////////// @@ -235,6 +257,7 @@ void hi_reset_tx (uint16 host) { PHIDB(host)->iloop = PHIDB(host)->enabled = PHIDB(host)->full = FALSE; PHIDB(host)->txtotal = 0; + PHIDB(host)->txfirst = TRUE; CLR_TX_IRQ(host); CLR_TX_IEN(host); } @@ -309,6 +332,123 @@ void hi_debug_msg (uint16 line, uint16 next, uint16 count, const char *ptext) ///////////////// T R A N S M I T A N D R E C E I V E ////////////////// //////////////////////////////////////////////////////////////////////////////// +// Convert 1822 long header from host, to short leader for IMP. +static int16 hi_convert_long_to_short(uint16 line, int16 count) +{ + uint16 nflags, mtype, htype, host, imp, id, stype, length; + uint16 oflags; + uint16 *data = PHIDB(line)->rxdata; + + if (count == 0) + return 0; + + if (count < 7 || (data[1] & 0x0F00) != NEW_FORMAT_FLAG) + return count; // This is not a long leader message. + + nflags = (data[2] & 0x0F00) >> 8; + mtype = data[2] & 0xFF; + htype = (data[3] & 0xFF00) >> 8; + host = data[3] & 0xFF; + imp = data[4]; + id = (data[5] & 0xFFF0) >> 4; + stype = data[5] & 0x000F; + length = data[6]; + + // Keep track of padding. + if (mtype == LEADER_NOP) + PHIDB(line)->padding = stype; + + // Sorry, can't handle these addresses. + if (host > 3) + return 0; + if (imp > 63) + return 0; + + if (mtype == LEADER_REGULAR && stype == LEADER_UNCONTROLLED) + mtype = LEADER_UNCONTROLLED, stype = 0; + else if (mtype == LEADER_NOP) + stype = 0; + + oflags = 0; + if (nflags & NLEADER_TRACE) + oflags |= OLEADER_TRACE; + if (nflags & NLEADER_OCTAL) + oflags |= OLEADER_OCTAL; + if (host >= NLEADER_FOR_IMP) { + oflags |= OLEADER_FOR_IMP; + host -= NLEADER_FOR_IMP; + } + if (htype & NLEADER_PRIORITY) + oflags |= OLEADER_PRIORITY; + + oflags <<= 12; + mtype <<= 8; + host <<= 6; + id <<= 4; + data[1] = oflags | mtype | host | imp; + data[2] = id | stype; + + if (mtype == LEADER_REGULAR) { + count -= 4 + PHIDB(line)->padding; + memmove(&data[3], &data[7 + PHIDB(line)->padding], 2 * count); + } else { + count = 3; + } + + return count; +} + +// Convert 1822 short header from IMP, to long leader for host. +static uint16 hi_convert_short_to_long(uint16 line, uint16 *data, uint16 count) +{ + uint16 oflags, mtype, host, imp, id, stype; + uint16 nflags = 0, htype = 0, length = 0; + + oflags = (data[1] & 0xF000) >> 12; + mtype = (data[1] & 0x0F00) >> 8; + host = (data[1] & 0x00C0) >> 6; + imp = data[1] & 0x003F; + id = (data[2] & 0xFFF0) >> 4; + stype = data[2] & 0x000F; + + if (mtype == LEADER_REGULAR) { + memmove(&data[7 + PHIDB(line)->padding], &data[3], 2 * (count - 3)); + memset(&data[7], 0, 2 * PHIDB(line)->padding); + length = 16 * (count - 3); + count += PHIDB(line)->padding; + } + count += 4; + + if (oflags & OLEADER_PRIORITY) + htype |= NLEADER_PRIORITY; + htype |= 7; + if (oflags & OLEADER_FOR_IMP) + host += NLEADER_FOR_IMP; + if (oflags & OLEADER_TRACE) + nflags |= NLEADER_TRACE; + if (oflags & OLEADER_OCTAL) + nflags |= OLEADER_OCTAL; + + if (mtype == LEADER_REGULAR) + stype = 0; + else if (mtype == LEADER_UNCONTROLLED) + mtype = LEADER_REGULAR, stype = LEADER_UNCONTROLLED; + else if (mtype == LEADER_NOP) + stype = 0; + + nflags <<= 8; + htype <<= 8; + id <<= 4; + data[1] = NEW_FORMAT_FLAG; + data[2] = nflags | mtype; + data[3] = htype | host; + data[4] = imp; + data[5] = id | stype; + data[6] = length; + + return count; +} + // Start the transmitter ... void hi_start_tx (uint16 line, uint16 flags) { @@ -337,7 +477,7 @@ void hi_start_tx (uint16 line, uint16 flags) // uint16 flags; // uint16 data [MAXDATA - 1]; // Put the packet into a temp buffer for assembly. - uint16 *tmp = (uint16 *)malloc ((count + 1) * sizeof (*tmp)); + static uint16 tmp[1500]; uint16 i; tmp [0] = flags; @@ -345,8 +485,11 @@ void hi_start_tx (uint16 line, uint16 flags) tmp [0] |= PFLG_READY; for (i = 0; i < count; i ++) tmp [i + 1] = M [next+i]; - ret = udp_send(PDEVICE(line), PHIDB(line)->link, tmp, count + 1); - free (tmp); + count++; + if (PHIDB(line)->convert && PHIDB(line)->txfirst) + count = hi_convert_short_to_long(line, tmp, count); + PHIDB(line)->txfirst = !!(flags & PFLG_FINAL); + ret = udp_send(PDEVICE(line), PHIDB(line)->link, tmp, count); if (ret != SCPE_OK && ret != 66) hi_link_error(line); } @@ -426,6 +569,7 @@ void hi_poll_rx (uint16 line) } else { // Get a new UDP packet. count = udp_receive(PDEVICE(line), PHIDB(line)->link, PHIDB(line)->rxdata, MAXDATA); + if (PHIDB(line)->convert) count = hi_convert_long_to_short(line, count); PHIDB(line)->eom = FALSE; PHIDB(line)->rxsize = count; if (count == 0) { return; } @@ -433,7 +577,7 @@ void hi_poll_rx (uint16 line) // Make note of the host ready bit. PHIDB(line)->ready = !! (PHIDB(line)->rxdata[0] & PFLG_READY); // Exclude the flags from the count. - PHIDB(line)->rxnext = 1; count--; + PHIDB(line)->rxnext = 1; count--; if (count == 0) return; PHIDB(line)->rxtotal++; } @@ -445,10 +589,10 @@ void hi_poll_rx (uint16 line) count = maxbuf; } hi_update_dmc(PDIB(line)->rxdmc, count); - hi_debug_msg (line, next, count, "received"); for (i = 0; i < count; i ++) * (pdata + i) = PHIDB(line)->rxdata[PHIDB(line)->rxnext++]; + hi_debug_msg (line, next, count, "received"); // Now would be a good time to worry about whether a receive is pending! if (!PHIDB(line)->rxpending) { @@ -682,4 +826,19 @@ t_stat hi_detach (UNIT *uptr) } +t_stat hi_set_convert (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + PHIDB(uptr->hline)->convert = !val; + return SCPE_OK; +} + +t_stat hi_show_convert (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + if (PHIDB(uptr->hline)->convert) + fprintf (st, "Convert short leaders"); + else + fprintf (st, "Do not convert short leaders"); + return SCPE_OK; +} + #endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_imp.h b/H316/h316_imp.h index ffdf104d..cfc60f15 100644 --- a/H316/h316_imp.h +++ b/H316/h316_imp.h @@ -176,9 +176,12 @@ struct _HIDB { uint16 rxdata[MAXDATA]; // UDP packet received. uint16 rxnext; // Index to next word in UDP packet. uint16 rxsize; // Size of UDP packet. + uint16 padding; // Padding for long leaders. + t_bool convert; // Convert between 1822 short/long messages. // Transmitter (IMP -> HOST) data ... uint32 txdelay; // RTC ticks until TX done interrupt uint32 txtotal; // total host messages sent + t_bool txfirst; // First packet in a series // Other data ... t_bool iloop; // local loop back enabled t_bool enabled; // TRUE if the host is enabled