diff --git a/H316/h316_hi.c b/H316/h316_hi.c index 152eca29..3f61b21a 100644 --- a/H316/h316_hi.c +++ b/H316/h316_hi.c @@ -119,7 +119,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, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, HI_TXBPS} +#define HI_HIDB(N) {FALSE, FALSE, 0, {0}, 0, 0, 0, 0, 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); @@ -228,6 +228,7 @@ void hi_reset_rx (uint16 host) PHIDB(host)->iloop = PHIDB(host)->error = PHIDB(host)->enabled = FALSE; PHIDB(host)->ready = TRUE; // XXX PHIDB(host)->eom = FALSE; + PHIDB(host)->rxsize = PHIDB(host)->rxnext = 0; PHIDB(host)->rxtotal = 0; CLR_RX_IRQ(host); CLR_RX_IEN(host); } @@ -401,7 +402,6 @@ void hi_poll_rx (uint16 line) // the receive operation. If a packet is waiting but no receive is pending // then the packet is discarded... uint16 next, last, maxbuf; uint16 *pdata; int16 count; - uint16 *tmp = NULL; uint16 i; // If the modem isn't attached, then the read never completes! @@ -420,39 +420,47 @@ void hi_poll_rx (uint16 line) // struct // uint16 flags; // uint16 data [MAXDATA - 1]; - // Read the packet into a temp buffer for disassembly. - tmp = (uint16 *)malloc (MAXDATA * sizeof (*tmp)); + + if (PHIDB(line)->rxnext < PHIDB(line)->rxsize) { + // There is data left from a previously recieved UDP packet. + count = PHIDB(line)->rxsize - PHIDB(line)->rxnext; + } else if (!PHIDB(line)->eom && (PHIDB(line)->rxdata[0] & PFLG_FINAL) + && PHIDB(line)->rxsize > 1) { + // No data left, time to signal end of message if the UDP packet said so. + PHIDB(line)->eom = TRUE; + } else { + // Get a new UDP packet. + count = udp_receive(PDEVICE(line), PHIDB(line)->link, PHIDB(line)->rxdata, MAXDATA); + PHIDB(line)->eom = FALSE; + PHIDB(line)->rxsize = count; + if (count == 0) { return; } + if (count < 0) { hi_link_error(line); return; } + // Exclude the flags from the count. + PHIDB(line)->rxnext = 1; count--; + if (count == 0) return; + PHIDB(line)->rxtotal++; + } - count = udp_receive(PDEVICE(line), PHIDB(line)->link, tmp, maxbuf+1); - if (count == 0) {free (tmp); return; } - if (count < 0) {free (tmp); hi_link_error(line); return; } + // We really got a packet! Update the DMC pointers to reflect the actual + // size of the packet received. + if (count > maxbuf) { + // Limit data to the DMC word count. Keep the UDP packet for next round. + 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++]; - PHIDB(line)->eom = !! tmp[0] & PFLG_FINAL; - for (i = 0; i < count - 1; i ++) - * (pdata + i) = tmp [i + 1]; - free (tmp); - tmp = NULL; // Now would be a good time to worry about whether a receive is pending! if (!PHIDB(line)->rxpending) { sim_debug(IMP_DBG_WARN, PDEVICE(line), "data received with no input pending\n"); return; } - // Exclude the flags from the count. - count--; - - // We really got a packet! Update the DMC pointers to reflect the actual - // size of the packet received. If the packet length would have exceeded the - // receiver buffer, then that sets the error flag too. - if (count > maxbuf) { - sim_debug(IMP_DBG_WARN, PDEVICE(line), "receiver overrun (length=%d maxbuf=%d)\n", count, maxbuf); - PHIDB(line)->rxerror = TRUE; count = maxbuf; - } - hi_update_dmc(PDIB(line)->rxdmc, count); - hi_debug_msg (line, next, count, "received"); - // Assert the interrupt request and we're done! - SET_RX_IRQ(line); PHIDB(line)->rxpending = FALSE; PHIDB(line)->rxtotal++; + SET_RX_IRQ(line); PHIDB(line)->rxpending = FALSE; sim_debug(IMP_DBG_IOT, PDEVICE(line), "receive done (message #%d, intreq=%06o)\n", PHIDB(line)->rxtotal, dev_ext_int); } @@ -584,7 +592,7 @@ t_stat hi_rx_service (UNIT *uptr) // queue entry expires. It just polls the receiver and reschedules itself. // That's it! uint16 line = uptr->hline; - hi_poll_rx(line); + if (PHIDB(line)->rxpending) hi_poll_rx(line); sim_activate(uptr, uptr->wait); return SCPE_OK; } diff --git a/H316/h316_imp.h b/H316/h316_imp.h index 8aadb1ce..e73fbb3d 100644 --- a/H316/h316_imp.h +++ b/H316/h316_imp.h @@ -136,6 +136,16 @@ #define rxint inum // dib->rxint #define txint inum2 // dib->txint +// This constant determines the longest possible IMP data payload that can be +// sent. Most IMP messages are trivially small - 68 words or so - but, when one +// IMP asks for a reload the neighbor IMP sends the entire memory image in a +// single message! That message is about 14K words long. +// The next thing you should worry about is whether the underlying IP network +// can actually send a UDP packet of this size. It turns out that there's no +// simple answer to that - it'll be fragmented for sure, but as long as all +// the fragments arrive intact then the destination should reassemble them. +#define MAXDATA 16384 // longest possible IMP packet (in H316 words) + // Modem interface data block .... // One of these is allocated to every modem interface to keep track of the // current state, COM port, UDP connection , etc... @@ -162,6 +172,9 @@ struct _HIDB { t_bool rxpending; // TRUE if a read is pending on this line t_bool rxerror; // TRUE if any modem error detected uint32 rxtotal; // total host messages received + uint16 rxdata[MAXDATA]; // UDP packet received. + uint16 rxnext; // Index to next word in UDP packet. + uint16 rxsize; // Size of UDP packet. // Transmitter (IMP -> HOST) data ... uint32 txdelay; // RTC ticks until TX done interrupt uint32 txtotal; // total host messages sent @@ -193,16 +206,6 @@ typedef struct _HIDB HIDB; extern uint32 rtc_interval; extern t_stat mi_tx_service (uint32 quantum); -// This constant determines the longest possible IMP data payload that can be -// sent. Most IMP messages are trivially small - 68 words or so - but, when one -// IMP asks for a reload the neighbor IMP sends the entire memory image in a -// single message! That message is about 14K words long. -// The next thing you should worry about is whether the underlying IP network -// can actually send a UDP packet of this size. It turns out that there's no -// simple answer to that - it'll be fragmented for sure, but as long as all -// the fragments arrive intact then the destination should reassemble them. -#define MAXDATA 16384 // longest possible IMP packet (in H316 words) - // Prototypes for UDP modem/host interface emulation routines ... #define NOLINK (-1) t_stat udp_create (DEVICE *pdtr, const char *premote, int32 *plink);