diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index eee129a4..9978bf22 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2016-03-04 + Last update: 2016-07-28 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -6936,3 +6936,83 @@ "hp2100_ds.c" and "hp2100_di_da.c" to use the new include file name. STATUS: Fixed in version 4.0-0. + + + +271. PROBLEM: The MPX device incorrectly reports a currently filling read + buffer as complete. + + VERSION: 4.0-0 + + OBSERVATION: Using Kermit to upload a file to RTE and specifying a packet + size larger than 254 bytes fails with transmission errors. Uploads with + packet sizes under 254 bytes work properly. + + CAUSE: The 12792 multiplexer provides two 254-byte receive buffers per + line. A single reception larger than 254 bytes returns "partial buffer" + status when the initial read terminates because of the buffer full + condition. This informs RTE that the reception is incomplete and that it + should issue additional reads to obtain the remainder of the data. + Complete reception is indicated by the final read not returning "partial + buffer" status. + + When Kermit sends a large packet, the multiplexer fills the first 254-byte + buffer, terminating on the buffer-full condition, and sends an unsolicited + interrupt to the CPU with "read buffer available" status. In response, RTE + sends an "acknowledge" command to the multiplexer, which returns the + "partial buffer" status and the buffer length. RTE then follows with a + "read buffer" command and prepares to receive the first buffer data. + Concurrently, the multiplexer begins filling the second 254-byte buffer. + + RTE uses DCPC to transfer the data from the multiplexer, which is faster + than the incoming data rate. Therefore, the transfer completes while the + second buffer is still filling. On DCPC completion, the multiplexer checks + to see if the other receive buffer is complete, and if it is, issues + another unsolicited interrupt with "read buffer available" status. + + The buffer completion check incorrectly returns TRUE if the buffer contains + received data. It should return TRUE only if the buffer contains data and + it is not currently being filled. + + For short reads, such as EDIT screen reads, the second buffer fill + completes before the first buffer DCPC transfer, and the returned "read + buffer available" status is appropriate. For long reads, such as Kermit + transfers, the incorrect buffer check causes RTE to transfer data from the + second buffer while it is incomplete. This leads to corrupted data and + Kermit transmission errors. + + RESOLUTION: Modify "mpx_cntl_svc" (hp2100_mpx.c) to indicate read buffer + availability only when filling is complete. + + STATUS: Fixed in version 4.0-0. + + + +272. PROBLEM: An MPX binary read larger than 254 bytes never completes. + + VERSION: 4.0-0. + + OBSERVATION: The MPX device may be configured to terminate a read on + reception of either a special character (e.g., CR) or a certain character + count. Counts up to 64K bytes are permitted, and such reads will succeed + if the alternating buffers are concurrently transferred to the CPU before + filling completely. However, while reads that specify character counts of + 254 or less complete as expected, reads of more than 254 bytes never + complete. + + CAUSE: As each character is received, the current character count is + compared to the termination count, and the read completes if the counts are + equal. However, the current character count is determined by the number of + characters in the current buffer and not the accumulated count of all + characters received. As the read buffers are 254 bytes long, the current + count will never exceed 254. Therefore, any read terminating on a count + greater than that will never complete. + + RESOLUTION: Define a new "mpx_termcnt" array to hold the termination + counts for the eight lines, and reassign the "mpx_charcnt" array to hold + the current character counts. Modify "exec_command" and "mpx_line_svc" + (hp2100_mpx.c) to set the termination count, compare it against the current + character count as characters are received, and terminate reception if + enabled and the values are equal. + + STATUS: Fixed in version 4.0-0. diff --git a/HP2100/hp2100_mpx.c b/HP2100/hp2100_mpx.c index 15068160..fa913bc3 100644 --- a/HP2100/hp2100_mpx.c +++ b/HP2100/hp2100_mpx.c @@ -25,6 +25,8 @@ MPX 12792C 8-channel multiplexer card + 28-Jul-16 JDB Fixed buffer ready check at read completion + Fixed terminate on character counts > 254 13-May-16 JDB Modified for revised SCP API function parameter types 24-Dec-14 JDB Added casts for explicit downward conversions 10-Jan-13 MP Added DEV_MUX and additional DEVICE field values @@ -123,6 +125,7 @@ Because this is a functional simulation of the multiplexer and not a Z80 emulation, the diagnostic cannot be used to test the implementation. + Implementation notes: 1. The 12792 had two baud-rate generators that were assigned to lines by the @@ -508,7 +511,12 @@ BITFIELD (FL_DO_ENQACK, 0, 1) /* Port flags: do ENQ/AC /* Multiplexer controller state variables */ -typedef enum { idle, cmd, param, exec } STATE; +typedef enum { /* execution state */ + idle, + cmd, + param, + exec + } STATE; STATE mpx_state = idle; /* controller state */ @@ -535,7 +543,8 @@ struct { uint8 mpx_key [MPX_PORTS]; /* port keys */ uint16 mpx_config [MPX_PORTS]; /* port configuration */ uint16 mpx_rcvtype [MPX_PORTS]; /* receive type */ -uint16 mpx_charcnt [MPX_PORTS]; /* character count */ +uint16 mpx_charcnt [MPX_PORTS]; /* current character count */ +uint16 mpx_termcnt [MPX_PORTS]; /* termination character count */ uint16 mpx_flowcntl [MPX_PORTS]; /* flow control */ uint8 mpx_enq_cntr [MPX_PORTS]; /* ENQ character counter */ uint16 mpx_ack_wait [MPX_PORTS]; /* ACK wait timer */ @@ -675,6 +684,7 @@ REG mpx_reg [] = { { BRDATA (PCONFIG, mpx_config, 8, 16, MPX_PORTS) }, { BRDATA (RCVTYPE, mpx_rcvtype, 8, 16, MPX_PORTS) }, { BRDATA (CHARCNT, mpx_charcnt, 8, 16, MPX_PORTS) }, + { BRDATA (TERMCNT, mpx_termcnt, 8, 16, MPX_PORTS) }, { BRDATA (FLOWCNTL, mpx_flowcntl, 8, 16, MPX_PORTS) }, { BRDATA (ENQCNTR, mpx_enq_cntr, 10, 7, MPX_PORTS) }, @@ -1128,17 +1138,21 @@ switch (mpx_cmd) { if (port >= 0) /* port defined? */ buf_cancel (ioread, port, get); /* cancel get buffer */ - if ((buf_avail (ioread, port) == 1) && /* one buffer remaining? */ - !(mpx_flags [port] & FL_RDFILL)) /* and not filling it? */ - mpx_flags [port] |= FL_HAVEBUF; /* indicate buffer availability */ + if (buf_avail (ioread, port) == 2) /* if all buffers are now clear */ + mpx_charcnt [port] = 0; /* then clear the current character count */ + + else if (!(mpx_flags [port] & FL_RDFILL)) /* otherwise if the other buffer is not filling */ + mpx_flags [port] |= FL_HAVEBUF; /* then indicate buffer availability */ break; case CMD_CANCEL_ALL: /* cancel all read buffers */ port = key_to_port (mpx_portkey); /* get port */ - if (port >= 0) /* port defined? */ + if (port >= 0) { /* port defined? */ buf_init (ioread, port); /* reinitialize read buffers */ + mpx_charcnt [port] = 0; /* and clear the current character count */ + } break; @@ -1208,8 +1222,10 @@ switch (mpx_cmd) { case CMD_SET_COUNT: /* set character count */ port = key_to_port (mpx_portkey); /* get port */ - if (port >= 0) /* port defined? */ - mpx_charcnt [port] = (uint16) mpx_param; /* save port character count */ + if (port >= 0) { /* port defined? */ + mpx_termcnt [port] = (uint16) mpx_param; /* save port termination character count */ + mpx_charcnt [port] = 0; /* and clear the current character count */ + } break; @@ -1262,13 +1278,14 @@ switch (mpx_cmd) { if (port >= 0) /* port defined? */ if (buf_len (ioread, port, put) > 0) { /* any chars in buffer? */ buf_term (ioread, port, 0); /* terminate buffer and set header */ + mpx_charcnt [port] = 0; /* then clear the current character count */ if (buf_avail (ioread, port) == 1) /* first read buffer? */ mpx_flags [port] |= FL_HAVEBUF; /* indicate availability */ } else { /* buffer is empty */ - mpx_charcnt [port] = 1; /* set to terminate on one char */ + mpx_termcnt [port] = 1; /* set to terminate on one char */ mpx_flags [port] |= FL_ALERT; /* set alert flag */ } break; @@ -1520,8 +1537,9 @@ switch (mpx_state) { /* dispatch if (buf_len (ioread, mpx_port, get) == 0) { /* buffer now empty? */ buf_free (ioread, mpx_port); /* free buffer */ - if (buf_avail (ioread, mpx_port) == 1) /* another buffer available? */ - mpx_flags [mpx_port] |= FL_HAVEBUF; /* indicate availability */ + if ((buf_avail (ioread, mpx_port) == 1) && /* one buffer remaining? */ + !(mpx_flags [mpx_port] & FL_RDFILL)) /* and not filling it? */ + mpx_flags [mpx_port] |= FL_HAVEBUF; /* indicate buffer availability */ } mpx_state = idle; /* idle controller */ @@ -1675,7 +1693,6 @@ const t_bool fast_binary_read = (mpx_cmd == CMD_BINARY_READ); /* fast binary r uint8 ch; int32 chx; -uint16 read_length; t_stat status = SCPE_OK; t_bool recv_loop = !fast_binary_read; /* bypass if fast binary read */ t_bool xmit_loop = !(fast_binary_read || /* bypass if fast read or output suspended */ @@ -1854,25 +1871,26 @@ while (recv_loop) { /* OK to process? */ recv_loop = TRUE; /* no termination */ } - if (recv_loop) /* no termination condition? */ + if (recv_loop) { /* no termination condition? */ buf_put (ioread, port, ch); /* put character in buffer */ - - read_length = buf_len (ioread, port, put); /* get current buffer length */ + mpx_charcnt [port]++; /* and count it */ + } if ((rt & RT_END_ON_CNT) && /* end on count */ - (read_length == mpx_charcnt [port])) { /* and count reached? */ + (mpx_charcnt [port] == mpx_termcnt [port])) { /* and termination count reached? */ recv_loop = FALSE; /* set termination */ mpx_param = 0; /* no extra termination info */ + mpx_charcnt [port] = 0; /* clear the current character count */ if (mpx_flags [port] & FL_ALERT) { /* was this alert for term rcv buffer? */ mpx_flags [port] &= ~FL_ALERT; /* clear alert flag */ - mpx_charcnt [port] = RD_BUF_LIMIT; /* reset character count */ + mpx_termcnt [port] = RD_BUF_LIMIT; /* reset termination character count */ } } - else if (read_length == RD_BUF_LIMIT) { /* buffer now full? */ - recv_loop = FALSE; /* set termination */ - mpx_param = mpx_param | RS_PARTIAL; /* and partial buffer flag */ + else if (buf_len (ioread, port, put) == RD_BUF_LIMIT) { /* buffer now full? */ + recv_loop = FALSE; /* set termination */ + mpx_param = mpx_param | RS_PARTIAL; /* and partial buffer flag */ } if (recv_loop) /* no termination condition? */ @@ -1887,7 +1905,7 @@ while (recv_loop) { /* OK to process? */ else if (rt & RT_END_ON_CHAR) fprintf (sim_deb, "character %s\n", fmt_char (ch)); else - fprintf (sim_deb, "count = %d\n", mpx_charcnt [port]); + fprintf (sim_deb, "count = %d\n", mpx_termcnt [port]); } if (buf_len (ioread, port, put) == 0) { /* zero-length read? */ @@ -2070,7 +2088,7 @@ return SCPE_OK; A direct attach to the poll unit is only allowed when restoring a previously saved session. - + The Telnet poll service routine is synchronized with the other input polling devices in the simulator to facilitate idling. */ @@ -2227,7 +2245,8 @@ for (i = 0; i < MPX_PORTS; i++) { /* clear per-line variab mpx_config [i] = (uint16) (SK_PWRUP_1 | i); mpx_rcvtype [i] = RT_PWRUP; /* power on config for echoplex */ - mpx_charcnt [i] = 0; /* default character count */ + mpx_charcnt [i] = 0; /* clear character count */ + mpx_termcnt [i] = 0; /* default termination character count */ mpx_flowcntl [i] = 0; /* default flow control */ mpx_flags [i] = 0; /* clear state flags */ mpx_enq_cntr [i] = 0; /* clear ENQ counter */ diff --git a/doc/hp2100_doc.doc b/doc/hp2100_doc.doc index 8d58d115..13d16124 100644 Binary files a/doc/hp2100_doc.doc and b/doc/hp2100_doc.doc differ