Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator\r |
2 | \r | |
3 | Copyright (c) 2007-2008, J. David Bryan\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of the author shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from the author.\r | |
25 | \r | |
26 | BACI 12966A BACI card\r | |
27 | \r | |
28 | 13-Jun-08 JDB Cleaned up debug reporting for sim_activate calls\r | |
29 | 16-Apr-08 JDB Separated terminal I/O and Telnet poll for idle compatibility\r | |
30 | 07-Dec-07 JDB Created BACI device\r | |
31 | \r | |
32 | References:\r | |
33 | - HP 12966A Buffered Asynchronous Data Communications Interface Installation\r | |
34 | and Reference Manual (12966-90001, Jul-1982)\r | |
35 | - Western Digital Communications Products Handbook (Jun-1984)\r | |
36 | \r | |
37 | \r | |
38 | The 12966A BACI card supplanted the 12531C Teletype and 12880A CRT interfaces\r | |
39 | as the primary terminal connection for HP 1000 systems. The main advantage\r | |
40 | of this card over the others was its 128-character FIFO memory. While this\r | |
41 | allowed more efficient I/O than its interrupt-per-character predecessors, the\r | |
42 | most significant advantage was that block input from the 264x-series of CRT\r | |
43 | terminals was supported. The 264x were the first HP-supported terminals to\r | |
44 | provide local editing and character storage, as well as mass storage via dual\r | |
45 | DC-100 minicartridge drives. This support meant that input from the terminal\r | |
46 | could come in bursts at the full baud rate, which would overrun the older\r | |
47 | cards that needed a small intercharacter handling time. Also, the older\r | |
48 | cards placed a substantial load on the CPU in high-baud-rate output\r | |
49 | applications. Indeed, block output under RTE on a 1000 M-Series with a\r | |
50 | 12880A CRT card would saturate the CPU at about 5700 baud.\r | |
51 | \r | |
52 | For a while, the BACI and the earlier cards were both supported as the system\r | |
53 | console interface, and RTE primary systems were generated with drivers for\r | |
54 | both cards. The boot-time I/O reconfigurator would detect the presence of\r | |
55 | the BACI card and would dynamically select the correct driver (DVR05 vs.\r | |
56 | DVR00). However, the 12880A card faded quickly as the 264x and later 262x\r | |
57 | terminals gained in popularity, and support for the 12880A was dropped in\r | |
58 | favor of the BACI. This meant that later RTE primary systems could only be\r | |
59 | run on CPUs containing a BACI card.\r | |
60 | \r | |
61 | The simulation supports terminal and diagnostic modes. The latter simulates\r | |
62 | the installation of the 12966-60003 diagnostic loopback connector on the\r | |
63 | card.\r | |
64 | \r | |
65 | Fifteen programmable baud rates were supported by the BACI. We simulate\r | |
66 | these "realistic" rates by scheduling I/O service based on the appropriate\r | |
67 | number of 1000 E-Series instructions for the rate selected. We also provide\r | |
68 | an "external rate" that is equivalent to 9600 baud, as most terminals were\r | |
69 | set to their maximum speeds.\r | |
70 | \r | |
71 | We support the 12966A connected to an HP terminal emulator via Telnet.\r | |
72 | Internally, we model the BACI as a terminal multiplexer with one line. The\r | |
73 | simulation is complicated by the half-duplex nature of the card (there is\r | |
74 | only one FIFO, used selectively either for transmission or reception) and the\r | |
75 | double-buffered UART (a Western Digital TR1863A), which has holding registers\r | |
76 | as well as a shift registers for transmission and reception. We model both\r | |
77 | sets of device registers.\r | |
78 | \r | |
79 | During an output operation, the first character output to the card passes\r | |
80 | through the FIFO and into the transmitter holding register. Subsequent\r | |
81 | characters remain in the FIFO. If the FIFO is then turned around by a mode\r | |
82 | switch from transmission to reception, the second character output becomes\r | |
83 | the first character input to the CPU, as the first character output remains\r | |
84 | in the THR. Also, the FIFO counter reflects the combined state of the FIFO\r | |
85 | and the THR: it is incremented by a "shift in" to the FIFO and decremented by\r | |
86 | the "transmit complete" signal from the UART. This has two implications:\r | |
87 | \r | |
88 | 1. If the FIFO is turned around before the character in the THR is\r | |
89 | transmitted, the counter will not decrement when transmission is\r | |
90 | complete, so the FIFO will show as "empty" when the counter reads "1".\r | |
91 | \r | |
92 | 2. The FIFO counter will indicate "half full" and "full" one character\r | |
93 | before the FIFO itself reaches those stages.\r | |
94 | \r | |
95 | The diagnostic hood connects the UART clock to a spare output register. This\r | |
96 | allows the diagnostic to supply programmed clock pulses to the UART. The\r | |
97 | serial transmit and receive lines from the UART are also available to the\r | |
98 | diagnostic. Functional operation is checked by supplying or testing serial\r | |
99 | data while clocking the UART sixteen times for each bit. This meant that we\r | |
100 | had to model the UART shift registers for faithful hardware simulation.\r | |
101 | \r | |
102 | The simulation provides both the "realistic timing" described above, as well\r | |
103 | as an "optimized (fast) timing" option. Optimization makes three\r | |
104 | improvements:\r | |
105 | \r | |
106 | 1. On output, characters in the FIFO are emptied into the Telnet buffer as a\r | |
107 | block, rather than one character per service call, and on input, all of\r | |
108 | the characters available in the Telnet buffer are loaded into the FIFO as\r | |
109 | a block.\r | |
110 | \r | |
111 | 2. The ENQ/ACK handshake is done locally, without involving the Telnet\r | |
112 | client.\r | |
113 | \r | |
114 | 3. Input occurring during an output operation is delayed until the second or\r | |
115 | third consecutive ENQ/ACK handshake.\r | |
116 | \r | |
117 | During development, it was noted that a comparatively long time elapsed\r | |
118 | (approximately 30 milliseconds on a 3 GHz system) between the transmission of\r | |
119 | an ENQ and the reception of the ACK. As the RTE BACI driver, DVR05, does\r | |
120 | three ENQ/ACKs at the end of each line, plus an additional ENQ/ACK every 33\r | |
121 | characters within a line, maximum throughput was about ten lines per second.\r | |
122 | The source of this delay is not understood but apparently lies within the\r | |
123 | terminal emulator, as it was observed with two emulators from two different\r | |
124 | companies. Absorbing the ENQ and generating the ACK locally provided a\r | |
125 | dramatic improvement in output speed.\r | |
126 | \r | |
127 | However, as a result, RTE break-mode became effectively impossible, i.e.,\r | |
128 | striking a key during output no longer produced the break-mode prompt. This\r | |
129 | was traced to the RTE driver. DVR05 only checks for an input character\r | |
130 | during ENQ/ACK processing, and then only during the second and third\r | |
131 | end-of-line handshakes. When the ENQ/ACKs were eliminated, break-mode also\r | |
132 | disappeared.\r | |
133 | \r | |
134 | The workaround is to save a character received during output and supply it\r | |
135 | during the second or third consecutive handshake. This ensures that\r | |
136 | break-mode is recognized. Because the driver tries to "cheat" the card by\r | |
137 | selecting receive mode before the ENQ has actually been transmitted (in order\r | |
138 | to save an interrupt), the FIFO counter becomes "off by one" and is reset\r | |
139 | with a master clear at the end of each handshake. This would normally clear\r | |
140 | the UART receiving register, thereby losing the deferred character. We work\r | |
141 | around this by skipping the register clear in "fast timing" mode.\r | |
142 | */\r | |
143 | \r | |
144 | #include <ctype.h>\r | |
145 | \r | |
146 | #include "hp2100_defs.h"\r | |
147 | #include "sim_sock.h"\r | |
148 | #include "sim_tmxr.h"\r | |
149 | \r | |
150 | \r | |
151 | /* Program limits */\r | |
152 | \r | |
153 | #define FIFO_SIZE 128 /* read/write buffer size */\r | |
154 | \r | |
155 | \r | |
156 | /* Character constants */\r | |
157 | \r | |
158 | #define ENQ '\005'\r | |
159 | #define ACK '\006'\r | |
160 | \r | |
161 | \r | |
162 | /* Unit flags */\r | |
163 | \r | |
164 | #define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */\r | |
165 | #define UNIT_V_FASTTIME (UNIT_V_UF + 1) /* fast timing mode */\r | |
166 | #define UNIT_V_CAPSLOCK (UNIT_V_UF + 2) /* caps lock mode */\r | |
167 | \r | |
168 | #define UNIT_DIAG (1 << UNIT_V_DIAG)\r | |
169 | #define UNIT_FASTTIME (1 << UNIT_V_FASTTIME)\r | |
170 | #define UNIT_CAPSLOCK (1 << UNIT_V_CAPSLOCK)\r | |
171 | \r | |
172 | \r | |
173 | /* Debug flags */\r | |
174 | \r | |
175 | #define DEB_CMDS (1 << 0) /* commands and status */\r | |
176 | #define DEB_CPU (1 << 1) /* CPU I/O */\r | |
177 | #define DEB_BUF (1 << 2) /* buffer gets and puts */\r | |
178 | #define DEB_XFER (1 << 3) /* character reads and writes */\r | |
179 | \r | |
180 | \r | |
181 | /* Bit flags */\r | |
182 | \r | |
183 | #define OUT_MR 0100000 /* common master reset */\r | |
184 | \r | |
185 | #define OUT_ENCM 0000040 /* ID1: enable character mode */\r | |
186 | #define OUT_ENCB 0000020 /* ID1: enable CB */\r | |
187 | #define OUT_ENCC 0000010 /* ID1: enable CC */\r | |
188 | #define OUT_ENCE 0000004 /* ID1: enable CE */\r | |
189 | #define OUT_ENCF 0000002 /* ID1: enable CF */\r | |
190 | #define OUT_ENSXX 0000001 /* ID1: enable SBB/SCF */\r | |
191 | \r | |
192 | #define OUT_DIAG 0000040 /* ID2: diagnostic output */\r | |
193 | #define OUT_REFCB 0000020 /* ID2: reference CB */\r | |
194 | #define OUT_REFCC 0000010 /* ID2: reference CC */\r | |
195 | #define OUT_REFCE 0000004 /* ID2: reference CE */\r | |
196 | #define OUT_REFCF 0000002 /* ID2: reference CF */\r | |
197 | #define OUT_REFSXX 0000001 /* ID2: reference SBB/SCF */\r | |
198 | \r | |
199 | #define OUT_STBITS 0000040 /* ID3: number of stop bits */\r | |
200 | #define OUT_ECHO 0000020 /* ID3: enable echo */\r | |
201 | #define OUT_PARITY 0000010 /* ID3: enable parity */\r | |
202 | #define OUT_PAREVEN 0000004 /* ID3: even parity or odd */\r | |
203 | \r | |
204 | #define OUT_XMIT 0000400 /* ID4: transmit or receive */\r | |
205 | #define OUT_CA 0000200 /* ID4: CA on */\r | |
206 | #define OUT_CD 0000100 /* ID4: CD on */\r | |
207 | #define OUT_SXX 0000040 /* ID4: SBA/SCA on */\r | |
208 | #define OUT_DCPC 0000020 /* ID4: DCPC on */\r | |
209 | \r | |
210 | #define OUT_CSC 0000040 /* ID5: clear special char interrupt */\r | |
211 | #define OUT_CBH 0000020 /* ID5: clear buffer half-full interrupt */\r | |
212 | #define OUT_CBF 0000010 /* ID5: clear buffer full interrupt */\r | |
213 | #define OUT_CBE 0000004 /* ID5: clear buffer empty interrupt */\r | |
214 | #define OUT_CBRK 0000002 /* ID5: clear break interrupt */\r | |
215 | #define OUT_COVR 0000001 /* ID5: clear overrun/parity interrupt */\r | |
216 | \r | |
217 | #define OUT_SPFLAG 0000400 /* ID6: special character */\r | |
218 | \r | |
219 | #define OUT_IRQCLR (OUT_CBH | OUT_CBF | OUT_CBE | OUT_CBRK | OUT_COVR)\r | |
220 | \r | |
221 | \r | |
222 | #define IN_VALID 0100000 /* received data: character valid */\r | |
223 | #define IN_SPFLAG 0040000 /* received data: is special character */\r | |
224 | \r | |
225 | #define IN_DEVINT 0100000 /* status: device interrupt */\r | |
226 | #define IN_SPCHAR 0040000 /* status: special char has been recd */\r | |
227 | #define IN_SPARE 0010000 /* status: spare receiver state */\r | |
228 | #define IN_TEST 0004000 /* status: unprocessed serial data line */\r | |
229 | #define IN_BUFHALF 0001000 /* status: buffer is half full */\r | |
230 | #define IN_BUFFULL 0000400 /* status: buffer is full */\r | |
231 | #define IN_BUFEMPTY 0000200 /* status: buffer is empty */\r | |
232 | #define IN_BREAK 0000100 /* status: break detected */\r | |
233 | #define IN_OVRUNPE 0000040 /* status: overrun or parity error */\r | |
234 | #define IN_CB 0000020 /* status: CB is on */\r | |
235 | #define IN_CC 0000010 /* status: CC is on */\r | |
236 | #define IN_CE 0000004 /* status: CE is on */\r | |
237 | #define IN_CF 0000002 /* status: CF is on */\r | |
238 | #define IN_SXX 0000001 /* status: SBB/SCF is on */\r | |
239 | \r | |
240 | #define IN_MODEM (IN_CB | IN_CC | IN_CE | IN_CF | IN_SXX)\r | |
241 | #define IN_LOOPBACK (IN_DEVINT | IN_SPARE | IN_TEST | IN_MODEM)\r | |
242 | #define IN_STDIRQ (IN_DEVINT | IN_SPCHAR | IN_BREAK | IN_OVRUNPE)\r | |
243 | #define IN_FIFOIRQ (IN_BUFEMPTY | IN_BUFHALF | IN_BUFFULL)\r | |
244 | \r | |
245 | \r | |
246 | /* Packed starting bit numbers */\r | |
247 | \r | |
248 | #define OUT_V_ID 12 /* common output word ID */\r | |
249 | #define OUT_V_DATA 0 /* ID 0: output data character */\r | |
250 | #define OUT_V_CHARSIZE 0 /* ID 3: character size */\r | |
251 | #define OUT_V_BAUDRATE 0 /* ID 4: baud rate */\r | |
252 | #define OUT_V_SPCHAR 0 /* ID 6: special character */\r | |
253 | \r | |
254 | #define IN_V_CHARCNT 8 /* data: char count in buffer */\r | |
255 | #define IN_V_DATA 0 /* data: input character */\r | |
256 | #define IN_V_IRQCLR 5 /* status: interrupt status clear */\r | |
257 | \r | |
258 | \r | |
259 | /* Packed bit widths */\r | |
260 | \r | |
261 | #define OUT_W_ID 3\r | |
262 | #define OUT_W_DATA 8\r | |
263 | #define OUT_W_CHARSIZE 2\r | |
264 | #define OUT_W_BAUDRATE 4\r | |
265 | #define OUT_W_SPCHAR 8\r | |
266 | \r | |
267 | #define IN_W_CHARCNT 6\r | |
268 | #define IN_W_DATA 8\r | |
269 | \r | |
270 | /* Packed bit masks */\r | |
271 | \r | |
272 | #define OUT_M_ID ((1 << OUT_W_ID) - 1)\r | |
273 | #define OUT_M_DATA ((1 << OUT_W_DATA) - 1)\r | |
274 | #define OUT_M_CHARSIZE ((1 << OUT_W_CHARSIZE) - 1)\r | |
275 | #define OUT_M_BAUDRATE ((1 << OUT_W_BAUDRATE) - 1)\r | |
276 | #define OUT_M_SPCHAR ((1 << OUT_W_SPCHAR) - 1)\r | |
277 | \r | |
278 | #define IN_M_CHARCNT ((1 << IN_W_CHARCNT) - 1)\r | |
279 | #define IN_M_DATA ((1 << IN_W_DATA) - 1)\r | |
280 | \r | |
281 | /* Packed field masks */\r | |
282 | \r | |
283 | #define OUT_ID (OUT_M_ID << OUT_V_ID)\r | |
284 | #define OUT_DATA (OUT_M_DATA << OUT_V_DATA)\r | |
285 | #define OUT_CHARSIZE (OUT_M_CHARSIZE << OUT_V_CHARSIZE)\r | |
286 | #define OUT_BAUDRATE (OUT_M_BAUDRATE << OUT_V_BAUDRATE)\r | |
287 | #define OUT_SPCHAR (OUT_M_SPCHAR << OUT_V_SPCHAR)\r | |
288 | \r | |
289 | #define IN_CHARCNT (IN_M_CHARCNT << IN_V_CHARCNT)\r | |
290 | #define IN_DATA (IN_M_DATA << IN_V_DATA)\r | |
291 | \r | |
292 | \r | |
293 | /* Command helpers */\r | |
294 | \r | |
295 | #define TO_CHARCNT(c) (((c) << IN_V_CHARCNT) & IN_CHARCNT)\r | |
296 | \r | |
297 | #define GET_ID(i) (((i) & OUT_ID) >> OUT_V_ID)\r | |
298 | #define GET_BAUDRATE(b) (((b) & OUT_BAUDRATE) >> OUT_V_BAUDRATE)\r | |
299 | \r | |
300 | #define IO_MODE (baci_icw & OUT_XMIT)\r | |
301 | #define XMIT OUT_XMIT\r | |
302 | #define RECV 0\r | |
303 | \r | |
304 | #define CLEAR_HR 0 /* UART holding register clear value */\r | |
305 | #define CLEAR_R -1 /* UART register clear value */\r | |
306 | \r | |
307 | \r | |
308 | /* Unit references */\r | |
309 | \r | |
310 | #define baci_term baci_unit[0] /* terminal I/O unit */\r | |
311 | #define baci_poll baci_unit[1] /* Telnet polling unit */\r | |
312 | \r | |
313 | \r | |
314 | /* External variables */\r | |
315 | \r | |
316 | extern uint32 PC;\r | |
317 | extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r | |
318 | extern FILE *sim_deb;\r | |
319 | \r | |
320 | \r | |
321 | /* BACI state variables */\r | |
322 | \r | |
323 | uint16 baci_ibuf = 0; /* status/data in */\r | |
324 | uint16 baci_obuf = 0; /* command/data out */\r | |
325 | uint16 baci_status = 0; /* current status */\r | |
326 | \r | |
327 | uint16 baci_edsiw = 0; /* enable device status word */\r | |
328 | uint16 baci_dsrw = 0; /* device status reference word */\r | |
329 | uint16 baci_cfcw = 0; /* character frame control word */\r | |
330 | uint16 baci_icw = 0; /* interface control word */\r | |
331 | uint16 baci_isrw = 0; /* interrupt status reset word */\r | |
332 | \r | |
333 | uint32 baci_fput = 0; /* FIFO buffer add index */\r | |
334 | uint32 baci_fget = 0; /* FIFO buffer remove index */\r | |
335 | uint32 baci_fcount = 0; /* FIFO buffer counter */\r | |
336 | uint32 baci_bcount = 0; /* break counter */\r | |
337 | \r | |
338 | uint8 baci_fifo [FIFO_SIZE]; /* read/write buffer FIFO */\r | |
339 | uint8 baci_spchar [256]; /* special character RAM */\r | |
340 | \r | |
341 | uint16 baci_uart_thr = CLEAR_HR; /* UART transmitter holding register */\r | |
342 | uint16 baci_uart_rhr = CLEAR_HR; /* UART receiver holding register */\r | |
343 | int32 baci_uart_tr = CLEAR_R; /* UART transmitter register */\r | |
344 | int32 baci_uart_rr = CLEAR_R; /* UART receiver register */\r | |
345 | uint32 baci_uart_clk = 0; /* UART transmit/receive clock */\r | |
346 | \r | |
347 | t_bool baci_enq_seen = FALSE; /* ENQ seen flag */\r | |
348 | uint32 baci_enq_cntr = 0; /* ENQ seen counter */\r | |
349 | \r | |
350 | \r | |
351 | /* Terminal multiplexer library interface */\r | |
352 | \r | |
353 | TMLN baci_ldsc = { 0 }; /* line descriptor */\r | |
354 | TMXR baci_desc = { 1, 0, 0, &baci_ldsc }; /* device descriptor */\r | |
355 | \r | |
356 | \r | |
357 | /* BACI local routines */\r | |
358 | \r | |
359 | static int32 service_time (uint32 control_word);\r | |
360 | static const char *fmt_char (uint8 ch);\r | |
361 | static void update_status (void);\r | |
362 | static void master_reset (uint32 selcode);\r | |
363 | \r | |
364 | static uint32 fifo_get (void);\r | |
365 | static void fifo_put (uint8 ch);\r | |
366 | static void clock_uart (void);\r | |
367 | \r | |
368 | /* BACI global routines */\r | |
369 | \r | |
370 | int32 baci_io (int32 inst, int32 IR, int32 dat);\r | |
371 | t_stat baci_term_svc (UNIT *uptr);\r | |
372 | t_stat baci_poll_svc (UNIT *uptr);\r | |
373 | t_stat baci_reset (DEVICE *dptr);\r | |
374 | t_stat baci_attach (UNIT *uptr, char *cptr);\r | |
375 | t_stat baci_detach (UNIT *uptr);\r | |
376 | t_stat baci_show (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
377 | \r | |
378 | \r | |
379 | /* BACI data structures\r | |
380 | \r | |
381 | baci_dib BACI device information block\r | |
382 | baci_dev BACI device descriptor\r | |
383 | baci_unit BACI unit list\r | |
384 | baci_reg BACI register list\r | |
385 | baci_mod BACI modifier list\r | |
386 | baci_deb BACI debug list\r | |
387 | \r | |
388 | Two units are used: one to handle character I/O via the Telnet library, and\r | |
389 | another to poll for connections and input. The character I/O service routine\r | |
390 | runs only when there are characters to read or write. It operates at the\r | |
391 | approximate baud rate of the terminal (in CPU instructions per second) in\r | |
392 | order to be compatible with the OS drivers. The Telnet poll must run\r | |
393 | continuously, but it can operate much more slowly, as the only requirement is\r | |
394 | that it must not present a perceptible lag to human input. To be compatible\r | |
395 | with CPU idling, it is co-scheduled with the master poll timer, which uses a\r | |
396 | ten millisecond period.\r | |
397 | */\r | |
398 | \r | |
399 | DIB baci_dib = { BACI, 0, 0, 0, 0, 0, &baci_io };\r | |
400 | \r | |
401 | DEVICE baci_dev;\r | |
402 | \r | |
403 | UNIT baci_unit[] =\r | |
404 | { { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */\r | |
405 | { UDATA (&baci_poll_svc, UNIT_DIS, POLL_WAIT) } }; /* Telnet poll unit */\r | |
406 | \r | |
407 | REG baci_reg[] = {\r | |
408 | { ORDATA (IBUF, baci_ibuf, 16) },\r | |
409 | { ORDATA (OBUF, baci_obuf, 16) },\r | |
410 | { ORDATA (STATUS, baci_status, 16) },\r | |
411 | \r | |
412 | { ORDATA (EDSIW, baci_edsiw, 16) },\r | |
413 | { ORDATA (DSRW, baci_dsrw, 16) },\r | |
414 | { ORDATA (CFCW, baci_cfcw, 16) },\r | |
415 | { ORDATA (ICW, baci_icw, 16) },\r | |
416 | { ORDATA (ISRW, baci_isrw, 16) },\r | |
417 | \r | |
418 | { DRDATA (FIFOPUT, baci_fput, 8) },\r | |
419 | { DRDATA (FIFOGET, baci_fget, 8) },\r | |
420 | { DRDATA (FIFOCNTR, baci_fcount, 8) },\r | |
421 | { DRDATA (BRKCNTR, baci_bcount, 16) },\r | |
422 | \r | |
423 | { BRDATA (FIFO, baci_fifo, 8, 8, FIFO_SIZE) },\r | |
424 | { BRDATA (SPCHAR, baci_spchar, 8, 1, 256) },\r | |
425 | \r | |
426 | { ORDATA (UARTTHR, baci_uart_thr, 16) },\r | |
427 | { ORDATA (UARTTR, baci_uart_tr, 16), REG_NZ },\r | |
428 | { ORDATA (UARTRHR, baci_uart_rhr, 16) },\r | |
429 | { ORDATA (UARTRR, baci_uart_rr, 16), REG_NZ },\r | |
430 | { DRDATA (UARTCLK, baci_uart_clk, 16) },\r | |
431 | \r | |
432 | { DRDATA (CTIME, baci_term.wait, 19), REG_RO },\r | |
433 | \r | |
434 | { FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO },\r | |
435 | { DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO },\r | |
436 | \r | |
437 | { FLDATA (LKO, baci_dib.cmd, 0) },\r | |
438 | { FLDATA (CTL, baci_dib.ctl, 0) },\r | |
439 | { FLDATA (FLG, baci_dib.flg, 0) },\r | |
440 | { FLDATA (FBF, baci_dib.fbf, 0) },\r | |
441 | { FLDATA (SRQ, baci_dib.srq, 0) },\r | |
442 | { ORDATA (DEVNO, baci_dib.devno, 6), REG_HRO },\r | |
443 | { NULL }\r | |
444 | };\r | |
445 | \r | |
446 | MTAB baci_mod[] = {\r | |
447 | { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL, NULL, NULL },\r | |
448 | { UNIT_DIAG, 0, "terminal mode", "TERMINAL", NULL, NULL, NULL },\r | |
449 | \r | |
450 | { UNIT_FASTTIME, UNIT_FASTTIME, "fast timing", "FASTTIME", NULL, NULL, NULL },\r | |
451 | { UNIT_FASTTIME, 0, "realistic timing", "REALTIME", NULL, NULL, NULL },\r | |
452 | \r | |
453 | { UNIT_CAPSLOCK, UNIT_CAPSLOCK, "CAPS LOCK down", "CAPSLOCK", NULL, NULL, NULL },\r | |
454 | { UNIT_CAPSLOCK, 0, "CAPS LOCK up", "NOCAPSLOCK", NULL, NULL, NULL },\r | |
455 | \r | |
456 | { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &baci_desc },\r | |
457 | { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &baci_desc },\r | |
458 | \r | |
459 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTION", NULL, NULL, &baci_show, NULL },\r | |
460 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &baci_show, NULL },\r | |
461 | { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &baci_desc },\r | |
462 | \r | |
463 | { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &baci_dev },\r | |
464 | { 0 }\r | |
465 | };\r | |
466 | \r | |
467 | DEBTAB baci_deb[] = {\r | |
468 | { "CMDS", DEB_CMDS },\r | |
469 | { "CPU", DEB_CPU },\r | |
470 | { "BUF", DEB_BUF },\r | |
471 | { "XFER", DEB_XFER },\r | |
472 | { NULL, 0 }\r | |
473 | };\r | |
474 | \r | |
475 | DEVICE baci_dev = {\r | |
476 | "BACI", /* device name */\r | |
477 | baci_unit, /* unit array */\r | |
478 | baci_reg, /* register array */\r | |
479 | baci_mod, /* modifier array */\r | |
480 | 2, /* number of units */\r | |
481 | 10, /* address radix */\r | |
482 | 31, /* address width */\r | |
483 | 1, /* address increment */\r | |
484 | 8, /* data radix */\r | |
485 | 8, /* data width */\r | |
486 | &tmxr_ex, /* examine routine */\r | |
487 | &tmxr_dep, /* deposit routine */\r | |
488 | &baci_reset, /* reset routine */\r | |
489 | NULL, /* boot routine */\r | |
490 | &baci_attach, /* attach routine */\r | |
491 | &baci_detach, /* detach routine */\r | |
492 | &baci_dib, /* device information block */\r | |
493 | DEV_NET | DEV_DEBUG | DEV_DISABLE, /* device flags */\r | |
494 | 0, /* debug control flags */\r | |
495 | baci_deb, /* debug flag name table */\r | |
496 | NULL, /* memory size change routine */\r | |
497 | NULL }; /* logical device name */\r | |
498 | \r | |
499 | \r | |
500 | \r | |
501 | /* I/O instruction processor.\r | |
502 | \r | |
503 | The BACI processes seven types of output words and supplies two types of\r | |
504 | input words. Output word type is identified by an ID code in bits 14-12.\r | |
505 | Input word type is determined by the state of the control flip-flop.\r | |
506 | \r | |
507 | The card has the usual control, flag buffer, flag, and SRQ flip-flops.\r | |
508 | However, they have the following unusual characteristics:\r | |
509 | \r | |
510 | - STC is not required to transfer a character.\r | |
511 | - Flag is not set after character transfer completes.\r | |
512 | - FLAG and SRQ are decoupled.\r | |
513 | \r | |
514 | An interrupt lockout flip-flop is used to prevent the generation of multiple\r | |
515 | interrupts until the cause of the first interrupt is identified and cleared.\r | |
516 | CMD is used to model the lockout flip-flop.\r | |
517 | */\r | |
518 | \r | |
519 | int32 baci_io (int32 inst, int32 IR, int32 dat)\r | |
520 | {\r | |
521 | uint8 ch;\r | |
522 | uint32 mask;\r | |
523 | uint32 dev = IR & I_DEVMASK;\r | |
524 | \r | |
525 | switch (inst) { /* dispatch by instruction */\r | |
526 | \r | |
527 | case ioFLG: /* set or clear flag */\r | |
528 | if ((IR & I_HC) == 0) { /* STF? */\r | |
529 | setFSR (dev); /* set flag, flag buffer, and SRQ */\r | |
530 | setCMD (dev); /* set lockout */\r | |
531 | \r | |
532 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
533 | fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb);\r | |
534 | }\r | |
535 | break; /* CLF handled by H/C below */\r | |
536 | \r | |
537 | \r | |
538 | case ioSFC: /* skip if flag clear */\r | |
539 | if (FLG (dev) == 0) /* flag clear? */\r | |
540 | PC = (PC + 1) & VAMASK; /* skip next instruction */\r | |
541 | break;\r | |
542 | \r | |
543 | \r | |
544 | case ioSFS: /* skip if flag set */\r | |
545 | if (FLG (dev) != 0) /* flag set? */\r | |
546 | PC = (PC + 1) & VAMASK; /* skip next instruction */\r | |
547 | break;\r | |
548 | \r | |
549 | \r | |
550 | case ioCRS: /* control reset */\r | |
551 | master_reset (dev); /* issue master reset */\r | |
552 | \r | |
553 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
554 | fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb);\r | |
555 | break;\r | |
556 | \r | |
557 | \r | |
558 | case ioOTX: /* output word */\r | |
559 | if (DEBUG_PRI (baci_dev, DEB_CPU))\r | |
560 | fprintf (sim_deb, ">>BACI cpu: [OTx] Command = %06o\n", dat);\r | |
561 | \r | |
562 | baci_obuf = dat;\r | |
563 | \r | |
564 | if (baci_obuf & OUT_MR) { /* master reset? */\r | |
565 | master_reset (dev); /* do before processing */\r | |
566 | \r | |
567 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
568 | fputs (">>BACI cmds: [OTx] Master reset\n", sim_deb);\r | |
569 | }\r | |
570 | \r | |
571 | switch (GET_ID (baci_obuf)) { /* isolate ID code */\r | |
572 | \r | |
573 | case 0: /* transmit data */\r | |
574 | if (IO_MODE == XMIT) { /* transmitting? */\r | |
575 | ch = baci_obuf & OUT_DATA; /* mask to character */\r | |
576 | fifo_put (ch); /* queue character */\r | |
577 | \r | |
578 | if (baci_term.flags & UNIT_ATT) { /* attached to network? */\r | |
579 | if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */\r | |
580 | (sim_is_active (&baci_term) == 0)) /* service stopped? */\r | |
581 | fprintf (sim_deb, ">>BACI cmds: [OTx] Terminal service scheduled, "\r | |
582 | "time = %d\n", baci_term.wait);\r | |
583 | \r | |
584 | if (baci_fcount == 1) /* first char to xmit? */\r | |
585 | sim_activate_abs (&baci_term, /* start service with full char time */\r | |
586 | baci_term.wait);\r | |
587 | else\r | |
588 | sim_activate (&baci_term, /* start service if not running */\r | |
589 | baci_term.wait);\r | |
590 | }\r | |
591 | }\r | |
592 | break;\r | |
593 | \r | |
594 | case 1: /* enable device status interrupt */\r | |
595 | baci_edsiw = baci_obuf; /* load new enable word */\r | |
596 | update_status (); /* may have enabled an interrupt */\r | |
597 | break;\r | |
598 | \r | |
599 | case 2: /* device status reference */\r | |
600 | if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */\r | |
601 | (baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */\r | |
602 | !(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */\r | |
603 | !(baci_icw & OUT_BAUDRATE)) /* and clock is external? */\r | |
604 | clock_uart (); /* pulse UART clock */\r | |
605 | \r | |
606 | baci_dsrw = baci_obuf; /* load new reference word */\r | |
607 | update_status (); /* clocking UART may interrupt */\r | |
608 | break;\r | |
609 | \r | |
610 | case 3: /* character frame control */\r | |
611 | baci_cfcw = baci_obuf; /* load new frame word */\r | |
612 | break;\r | |
613 | \r | |
614 | case 4: /* interface control */\r | |
615 | if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */\r | |
616 | baci_term.wait = service_time (baci_obuf); /* set service time to match rate */\r | |
617 | \r | |
618 | if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */\r | |
619 | if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */\r | |
620 | sim_activate (&baci_term, /* activate I/O service */\r | |
621 | baci_term.wait);\r | |
622 | \r | |
623 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
624 | fprintf (sim_deb, ">>BACI cmds: [OTx] Terminal service scheduled, "\r | |
625 | "time = %d\n", baci_term.wait);\r | |
626 | }\r | |
627 | \r | |
628 | else { /* external rate */\r | |
629 | sim_cancel (&baci_term); /* stop I/O service */\r | |
630 | \r | |
631 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
632 | fputs (">>BACI cmds: [OTx] Terminal service stopped\n", sim_deb);\r | |
633 | }\r | |
634 | }\r | |
635 | \r | |
636 | baci_icw = baci_obuf; /* load new reference word */\r | |
637 | update_status (); /* loopback may change status */\r | |
638 | break;\r | |
639 | \r | |
640 | case 5: /* interrupt status reset */\r | |
641 | baci_isrw = baci_obuf; /* load new reset word */\r | |
642 | \r | |
643 | mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */\r | |
644 | IN_V_IRQCLR; /* for common irqs */\r | |
645 | \r | |
646 | if (baci_isrw & OUT_CSC) /* add special char mask bit */\r | |
647 | mask = mask | IN_SPCHAR; /* if requested */\r | |
648 | \r | |
649 | baci_status = baci_status & ~mask; /* clear specified status bits */\r | |
650 | break;\r | |
651 | \r | |
652 | case 6: /* special character */\r | |
653 | baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */\r | |
654 | ((baci_obuf & OUT_SPFLAG) != 0);\r | |
655 | break;\r | |
656 | }\r | |
657 | \r | |
658 | break;\r | |
659 | \r | |
660 | \r | |
661 | case ioLIX: /* load word */\r | |
662 | dat = 0;\r | |
663 | \r | |
664 | case ioMIX: /* merge word */\r | |
665 | if (CTL (dev)) { /* control set? */\r | |
666 | baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */\r | |
667 | \r | |
668 | if (IO_MODE == RECV) /* receiving? */\r | |
669 | baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */\r | |
670 | \r | |
671 | dat = dat | baci_ibuf; /* return received data */\r | |
672 | \r | |
673 | if (DEBUG_PRI (baci_dev, DEB_CPU))\r | |
674 | fprintf (sim_deb, ">>BACI cpu: [LIx] Received data = %06o\n", dat);\r | |
675 | }\r | |
676 | \r | |
677 | else { /* control clear? */\r | |
678 | dat = dat | baci_status; /* return status */\r | |
679 | \r | |
680 | if (DEBUG_PRI (baci_dev, DEB_CPU))\r | |
681 | fprintf (sim_deb, ">>BACI cpu: [LIx] Status = %06o\n", dat);\r | |
682 | }\r | |
683 | break;\r | |
684 | \r | |
685 | \r | |
686 | case ioCTL: /* control set/clear */\r | |
687 | if (IR & I_CTL) { /* CLC */\r | |
688 | clrCTL (dev); /* clear control */\r | |
689 | \r | |
690 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
691 | fputs (">>BACI cmds: [CLC] Control cleared\n", sim_deb);\r | |
692 | }\r | |
693 | \r | |
694 | else { /* STC */\r | |
695 | setCTL (dev); /* set control */\r | |
696 | clrCMD (dev); /* clear lockout */\r | |
697 | \r | |
698 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
699 | fputs (">>BACI cmds: [STC] Control set and lockout cleared\n", sim_deb);\r | |
700 | \r | |
701 | update_status (); /* clearing lockout might interrupt */\r | |
702 | }\r | |
703 | break;\r | |
704 | \r | |
705 | \r | |
706 | default: /* all others */\r | |
707 | break; /* do nothing */\r | |
708 | }\r | |
709 | \r | |
710 | \r | |
711 | if (IR & I_HC) { /* H/C option */\r | |
712 | clrFSR (dev); /* clear flag and SRQ */\r | |
713 | \r | |
714 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
715 | fprintf (sim_deb, ">>BACI cmds: [%s] Flag and SRQ cleared\n",\r | |
716 | (inst == ioFLG ? "CLF" : "x,C"));\r | |
717 | \r | |
718 | update_status (); /* FLG might set when SRQ clears */\r | |
719 | }\r | |
720 | \r | |
721 | return dat;\r | |
722 | }\r | |
723 | \r | |
724 | \r | |
725 | /* BACI terminal service.\r | |
726 | \r | |
727 | The terminal service routine is used to transmit and receive characters.\r | |
728 | \r | |
729 | In terminal mode, it is started when a character is ready for output or when\r | |
730 | the Telnet poll routine determines that there are characters ready for input\r | |
731 | and stopped when there are no more characters to output or input. When the\r | |
732 | terminal is quiescent, this routine does not run.\r | |
733 | \r | |
734 | In diagnostic mode, it is started whenever an internal baud rate is set and\r | |
735 | stopped when the external clock is requested. In this mode, the routine will\r | |
736 | be called without an attached socket, so character I/O will be skipped.\r | |
737 | \r | |
738 | Because there is only one FIFO, the card is half-duplex and must be\r | |
739 | configured for transmit or receive mode. The UART, though, is double-\r | |
740 | buffered, so it may transmit and receive simultaneously. We implement both\r | |
741 | the UART shift and holding registers for each mode.\r | |
742 | \r | |
743 | If a character is received by the UART while the card is in transmit mode, it\r | |
744 | will remain in the receiver holding register (RHR). When the mode is\r | |
745 | reversed, the RHR contents will be unloaded into the FIFO. Conversely,\r | |
746 | transmit mode enables the output of the FIFO to be unloaded into the\r | |
747 | transmitter holding register (THR). Characters received or transmitted pass\r | |
748 | through the receiver register (RR) or transmitter register (TR),\r | |
749 | respectively. They are not strictly necessary in terminal (Telnet)\r | |
750 | transactions but are critical to diagnostic operations.\r | |
751 | \r | |
752 | The UART signals an overrun if a complete character is received while the RHR\r | |
753 | still contains the previous character. The BACI does not use this signal,\r | |
754 | though; an overrun is only indicated if the FIFO is full, and another\r | |
755 | character is received.\r | |
756 | \r | |
757 | In "fast timing" mode, we defer the recognition of a received character until\r | |
758 | the card is put into receive mode for the second or third consecutive ENQ/ACK\r | |
759 | handshake. This improves RTE break-mode recognition. "Realistic timing"\r | |
760 | mode behaves as the hardware does: a character present in the RHR is unloaded\r | |
761 | into the FIFO as soon as receive mode is set.\r | |
762 | \r | |
763 | Fast timing mode also enables internal ENQ/ACK handshaking. We allow one\r | |
764 | character time for the RTE driver to turn the card around, as otherwise the\r | |
765 | ACK may not be seen by the driver. Also, the local ACK is supplied after any\r | |
766 | received characters, as the driver detects operator attention only when the\r | |
767 | first character after an ENQ is not an ACK.\r | |
768 | \r | |
769 | Finally, fast timing enables buffer combining. For output, all characters\r | |
770 | present in the FIFO are unloaded into the Telnet buffer before initiating a\r | |
771 | packet send. For input, all characters present in the Telnet buffer are\r | |
772 | loaded into the FIFO. This reduces network traffic and decreases simulator\r | |
773 | overhead (there is only one service routine entry per block, rather than one\r | |
774 | per character).\r | |
775 | \r | |
776 | In fast output mode, it is imperative that not less than 1500 instructions\r | |
777 | elapse between the first character load to the FIFO and the initiation of\r | |
778 | transmission. The RTE driver must have enough time to output the maximum\r | |
779 | number of contiguous characters (33) and reset the interrupt status flags\r | |
780 | before the service routine is entered. Because all of the characters are\r | |
781 | transmitted as a block, the FIFO empty flag will be set by the service\r | |
782 | routine. If the driver has not yet exited at that time, the buffer-empty\r | |
783 | interrupt will be cleared when the interrupt status reset is done. The\r | |
784 | symptom will be a 3.8-second pause in output until the driver times out.\r | |
785 | \r | |
786 | To avoid this, the OTx output character handler does an absolute schedule for\r | |
787 | the first character to ensure that a full character time is used.\r | |
788 | */\r | |
789 | \r | |
790 | t_stat baci_term_svc (UNIT *uptr)\r | |
791 | {\r | |
792 | uint32 data_bits, data_mask;\r | |
793 | const t_bool fast_timing = (baci_term.flags & UNIT_FASTTIME) != 0;\r | |
794 | const t_bool is_attached = (baci_term.flags & UNIT_ATT) != 0;\r | |
795 | t_stat status = SCPE_OK;\r | |
796 | t_bool xmit_loop = TRUE;\r | |
797 | t_bool recv_loop = TRUE;\r | |
798 | \r | |
799 | \r | |
800 | /* Transmission */\r | |
801 | \r | |
802 | while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UART? */\r | |
803 | data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */\r | |
804 | data_mask = (1 << data_bits) - 1; /* generate mask for data bits */\r | |
805 | baci_uart_tr = baci_uart_thr & data_mask; /* mask data into transmitter register */\r | |
806 | \r | |
807 | if ((baci_uart_tr == ENQ) && fast_timing) { /* char is ENQ and fast timing? */\r | |
808 | baci_enq_seen = TRUE; /* set flag instead of transmitting */\r | |
809 | baci_enq_cntr = baci_enq_cntr + 1; /* bump ENQ counter */\r | |
810 | recv_loop = FALSE; /* skip recv to allow time before ACK */\r | |
811 | \r | |
812 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
813 | fprintf (sim_deb, ">>BACI xfer: Character ENQ absorbed internally, "\r | |
814 | "ENQ count = %d\n", baci_enq_cntr);\r | |
815 | }\r | |
816 | \r | |
817 | else { /* character is not an ENQ */\r | |
818 | baci_enq_cntr = 0; /* reset ENQ counter */\r | |
819 | \r | |
820 | if (is_attached) { /* attached to network? */\r | |
821 | status = tmxr_putc_ln (&baci_ldsc, /* transmit the character */\r | |
822 | baci_uart_tr);\r | |
823 | \r | |
824 | if ((status == SCPE_OK) && /* transmitted OK? */\r | |
825 | DEBUG_PRI (baci_dev, DEB_XFER))\r | |
826 | fprintf (sim_deb, ">>BACI xfer: Character %s "\r | |
827 | "transmitted from UART\n", fmt_char (baci_uart_tr));\r | |
828 | }\r | |
829 | }\r | |
830 | \r | |
831 | if (status == SCPE_OK) { /* transmitted OK? */\r | |
832 | baci_uart_tr = CLEAR_R; /* clear transmitter register */\r | |
833 | \r | |
834 | if (IO_MODE == XMIT) { /* transmit mode? */\r | |
835 | baci_fcount = baci_fcount - 1; /* decrement occupancy counter */\r | |
836 | baci_uart_thr = fifo_get (); /* get next char into UART */\r | |
837 | update_status (); /* update FIFO status */\r | |
838 | }\r | |
839 | \r | |
840 | else /* receive mode */\r | |
841 | baci_uart_thr = CLEAR_HR; /* clear holding register */\r | |
842 | \r | |
843 | xmit_loop = fast_timing && !baci_enq_seen; /* loop if fast mode and char not ENQ */\r | |
844 | }\r | |
845 | \r | |
846 | else\r | |
847 | xmit_loop = FALSE;\r | |
848 | }\r | |
849 | \r | |
850 | \r | |
851 | /* Deferred reception */\r | |
852 | \r | |
853 | if (recv_loop && /* ok to process? */\r | |
854 | baci_uart_rhr && (IO_MODE == RECV) && /* and deferred char in RHR in recv mode? */\r | |
855 | (!baci_enq_seen || (baci_enq_cntr >= 2))) { /* and either no ENQ or at least 2nd ENQ? */\r | |
856 | \r | |
857 | baci_uart_rhr = baci_uart_rhr & ~IN_VALID; /* clear valid bit */\r | |
858 | \r | |
859 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
860 | fprintf (sim_deb, ">>BACI xfer: Deferred character %s processed\n",\r | |
861 | fmt_char ((uint8) baci_uart_rhr));\r | |
862 | \r | |
863 | fifo_put ((uint8) baci_uart_rhr); /* move deferred character to FIFO */\r | |
864 | baci_uart_rhr = CLEAR_HR; /* clear RHR */\r | |
865 | update_status (); /* update FIFO status */\r | |
866 | }\r | |
867 | \r | |
868 | \r | |
869 | /* Reception */\r | |
870 | \r | |
871 | while (recv_loop && /* OK to process? */\r | |
872 | (baci_uart_rr = tmxr_getc_ln (&baci_ldsc))) { /* and new character available? */\r | |
873 | \r | |
874 | if (baci_uart_rr & SCPE_BREAK) /* break detected? */\r | |
875 | baci_status = baci_status | IN_BREAK; /* set break status */\r | |
876 | \r | |
877 | data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */\r | |
878 | data_mask = (1 << data_bits) - 1; /* generate mask for data bits */\r | |
879 | baci_uart_rhr = baci_uart_rr & data_mask; /* mask data into holding register */\r | |
880 | baci_uart_rr = CLEAR_R; /* clear receiver register */\r | |
881 | \r | |
882 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
883 | fprintf (sim_deb, ">>BACI xfer: Character %s received by UART\n",\r | |
884 | fmt_char ((uint8) baci_uart_rhr));\r | |
885 | \r | |
886 | if (baci_term.flags & UNIT_CAPSLOCK) /* caps lock mode? */\r | |
887 | baci_uart_rhr = toupper (baci_uart_rhr); /* convert to upper case if lower */\r | |
888 | \r | |
889 | if (baci_cfcw & OUT_ECHO) /* echo wanted? */\r | |
890 | tmxr_putc_ln (&baci_ldsc, baci_uart_rhr); /* send it back */\r | |
891 | \r | |
892 | if ((IO_MODE == RECV) && !baci_enq_seen) { /* receive mode and not ENQ/ACK? */\r | |
893 | fifo_put ((uint8) baci_uart_rhr); /* put data in FIFO */\r | |
894 | baci_uart_rhr = CLEAR_HR; /* clear RHR */\r | |
895 | update_status (); /* update FIFO status (may set flag) */\r | |
896 | \r | |
897 | recv_loop = fast_timing && !FLG (baci_dib.devno); /* loop if fast mode and no IRQ */\r | |
898 | }\r | |
899 | \r | |
900 | else { /* xmit or ENQ/ACK, leave char in RHR */\r | |
901 | baci_uart_rhr = baci_uart_rhr | IN_VALID; /* set character valid bit */\r | |
902 | recv_loop = FALSE; /* terminate loop */\r | |
903 | }\r | |
904 | }\r | |
905 | \r | |
906 | \r | |
907 | /* Housekeeping */\r | |
908 | \r | |
909 | if (recv_loop && baci_enq_seen) { /* OK to process and ENQ seen? */\r | |
910 | baci_enq_seen = FALSE; /* reset flag */\r | |
911 | \r | |
912 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
913 | fputs (">>BACI xfer: Character ACK generated internally\n", sim_deb);\r | |
914 | \r | |
915 | fifo_put (ACK); /* fake ACK from terminal */\r | |
916 | update_status (); /* update FIFO status */\r | |
917 | }\r | |
918 | \r | |
919 | if (is_attached) /* attached to network? */\r | |
920 | tmxr_poll_tx (&baci_desc); /* output any accumulated chars */\r | |
921 | \r | |
922 | if ((baci_uart_thr & IN_VALID) || baci_enq_seen || /* more to transmit? */\r | |
923 | tmxr_rqln (&baci_ldsc)) /* or more to receive? */\r | |
924 | sim_activate (uptr, uptr->wait); /* reschedule service */\r | |
925 | else\r | |
926 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
927 | fputs (">>BACI cmds: Terminal service stopped\n", sim_deb);\r | |
928 | \r | |
929 | return status;\r | |
930 | }\r | |
931 | \r | |
932 | \r | |
933 | /* BACI Telnet poll service.\r | |
934 | \r | |
935 | This service routine is used to poll for Telnet connections and incoming\r | |
936 | characters. If characters are available, the terminal I/O service routine is\r | |
937 | scheduled. It starts when the socket is attached and stops when the socket\r | |
938 | is detached.\r | |
939 | */\r | |
940 | \r | |
941 | t_stat baci_poll_svc (UNIT *uptr)\r | |
942 | {\r | |
943 | if (baci_term.flags & UNIT_ATT) { /* attached to network? */\r | |
944 | if (tmxr_poll_conn (&baci_desc) >= 0) /* new connection established? */\r | |
945 | baci_ldsc.rcve = 1; /* enable line to receive */\r | |
946 | \r | |
947 | tmxr_poll_rx (&baci_desc); /* poll for input */\r | |
948 | \r | |
949 | if (tmxr_rqln (&baci_ldsc)) /* chars available? */\r | |
950 | sim_activate (&baci_term, baci_term.wait); /* activate I/O service */\r | |
951 | }\r | |
952 | \r | |
953 | uptr->wait = sync_poll (SERVICE); /* synchronize poll */\r | |
954 | sim_activate (uptr, uptr->wait); /* continue polling */\r | |
955 | \r | |
956 | return SCPE_OK;\r | |
957 | }\r | |
958 | \r | |
959 | \r | |
960 | /* Simulator reset routine */\r | |
961 | \r | |
962 | t_stat baci_reset (DEVICE *dptr)\r | |
963 | {\r | |
964 | master_reset (0); /* do master reset */\r | |
965 | \r | |
966 | baci_dib.ctl = 0; /* clear control */\r | |
967 | baci_dib.flg = 1; /* set flag */\r | |
968 | baci_dib.fbf = 1; /* set flag buffer */\r | |
969 | baci_dib.srq = 1; /* set SRQ */\r | |
970 | baci_dib.cmd = 1; /* set lockout */\r | |
971 | \r | |
972 | baci_ibuf = 0; /* clear input buffer */\r | |
973 | baci_obuf = 0; /* clear output buffer */\r | |
974 | \r | |
975 | baci_enq_seen = FALSE; /* reset ENQ seen flag */\r | |
976 | baci_enq_cntr = 0; /* clear ENQ counter */\r | |
977 | \r | |
978 | baci_term.wait = service_time (baci_icw); /* set terminal I/O time */\r | |
979 | \r | |
980 | if (baci_term.flags & UNIT_ATT) { /* device attached? */\r | |
981 | baci_poll.wait = sync_poll (INITIAL); /* synchronize poll */\r | |
982 | sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll */\r | |
983 | }\r | |
984 | else\r | |
985 | sim_cancel (&baci_poll); /* else stop Telnet poll */\r | |
986 | \r | |
987 | return SCPE_OK;\r | |
988 | }\r | |
989 | \r | |
990 | \r | |
991 | /* Attach controller */\r | |
992 | \r | |
993 | t_stat baci_attach (UNIT *uptr, char *cptr)\r | |
994 | {\r | |
995 | t_stat status = SCPE_OK;\r | |
996 | \r | |
997 | status = tmxr_attach (&baci_desc, uptr, cptr); /* attach to socket */\r | |
998 | \r | |
999 | if (status == SCPE_OK) {\r | |
1000 | baci_poll.wait = sync_poll (INITIAL); /* synchronize poll */\r | |
1001 | sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll */\r | |
1002 | }\r | |
1003 | return status;\r | |
1004 | }\r | |
1005 | \r | |
1006 | /* Detach controller */\r | |
1007 | \r | |
1008 | t_stat baci_detach (UNIT *uptr)\r | |
1009 | {\r | |
1010 | t_stat status;\r | |
1011 | \r | |
1012 | status = tmxr_detach (&baci_desc, uptr); /* detach socket */\r | |
1013 | baci_ldsc.rcve = 0; /* disable line reception */\r | |
1014 | sim_cancel (&baci_poll); /* stop Telnet poll */\r | |
1015 | return status;\r | |
1016 | }\r | |
1017 | \r | |
1018 | /* Show connection status and statistics */\r | |
1019 | \r | |
1020 | t_stat baci_show (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1021 | {\r | |
1022 | if (baci_ldsc.conn)\r | |
1023 | if (val)\r | |
1024 | tmxr_fconns (st, &baci_ldsc, -1);\r | |
1025 | else\r | |
1026 | tmxr_fstats (st, &baci_ldsc, -1);\r | |
1027 | else\r | |
1028 | fprintf (st, "terminal disconnected\n");\r | |
1029 | \r | |
1030 | return SCPE_OK;\r | |
1031 | }\r | |
1032 | \r | |
1033 | \r | |
1034 | /* Local routines */\r | |
1035 | \r | |
1036 | \r | |
1037 | /* Master reset.\r | |
1038 | \r | |
1039 | This is the programmed card master reset, not the simulator reset routine.\r | |
1040 | It is called from the simulator reset routine with "selcode" = 0; the latter\r | |
1041 | routine will take care of setting the card flip-flops appropriately.\r | |
1042 | \r | |
1043 | Master reset normally clears the UART registers. However, if we are in "fast\r | |
1044 | timing" mode, the receiver holding register may hold a deferred character.\r | |
1045 | In this case, we do not clear the RHR, unless we are called from the\r | |
1046 | simulator reset routine.\r | |
1047 | \r | |
1048 | The HP BACI manual states that master reset "Clears Service Request (SRQ)."\r | |
1049 | An examination of the schematic, though, shows that it sets SRQ instead.\r | |
1050 | */\r | |
1051 | \r | |
1052 | static void master_reset (uint32 selcode)\r | |
1053 | {\r | |
1054 | baci_fput = baci_fget = 0; /* clear FIFO indexes */\r | |
1055 | baci_fcount = 0; /* clear FIFO counter */\r | |
1056 | memset (baci_fifo, 0, sizeof (baci_fifo)); /* clear FIFO data */\r | |
1057 | \r | |
1058 | baci_uart_thr = CLEAR_HR; /* clear transmitter holding register */\r | |
1059 | \r | |
1060 | if (!(baci_term.flags & UNIT_FASTTIME) || !selcode) /* real time mode or power-on init? */\r | |
1061 | baci_uart_rhr = CLEAR_HR; /* clear receiver holding register */\r | |
1062 | \r | |
1063 | baci_uart_tr = CLEAR_R; /* clear transmitter register */\r | |
1064 | baci_uart_rr = CLEAR_R; /* clear receiver register */\r | |
1065 | \r | |
1066 | baci_uart_clk = 0; /* clear UART clock */\r | |
1067 | baci_bcount = 0; /* clear break counter */\r | |
1068 | \r | |
1069 | if (selcode) {\r | |
1070 | clrCTL (selcode); /* clear control */\r | |
1071 | setFLG (selcode); /* set flag and flag buffer */\r | |
1072 | setSRQ (selcode); /* set SRQ */\r | |
1073 | setCMD (selcode); /* set lockout flip-flop */\r | |
1074 | }\r | |
1075 | \r | |
1076 | baci_edsiw = 0; /* clear interrupt enables */\r | |
1077 | baci_dsrw = 0; /* clear status reference */\r | |
1078 | baci_cfcw = baci_cfcw & ~OUT_ECHO; /* clear echo flag */\r | |
1079 | baci_icw = baci_icw & OUT_BAUDRATE; /* clear interface control */\r | |
1080 | \r | |
1081 | if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */\r | |
1082 | baci_status = baci_status & ~IN_MODEM | IN_SPARE; /* clear loopback status, set BA */\r | |
1083 | \r | |
1084 | return;\r | |
1085 | }\r | |
1086 | \r | |
1087 | \r | |
1088 | /* Update status.\r | |
1089 | \r | |
1090 | In diagnostic mode, several of the modem output lines are looped back to the\r | |
1091 | input lines. Also, CD is tied to BB (received data), which is presented on\r | |
1092 | the TEST status bit via an inversion. Echo mode couples BB to BA\r | |
1093 | (transmitted data), which is presented on the SPARE status bit.\r | |
1094 | \r | |
1095 | If a modem line interrupt condition is present and enabled, the DEVINT status\r | |
1096 | bit is set. Other potential "standard" interrupt sources are the special\r | |
1097 | character, break detected, and overrun/parity error bits. If DCPC transfers\r | |
1098 | are not selected, then the FIFO interrupts (buffer empty, half-full, and\r | |
1099 | full) and the "data ready" condition (i.e., receive and character modes\r | |
1100 | enabled and FIFO not empty) also produces an interrupt request.\r | |
1101 | \r | |
1102 | An interrupt request will set the card flag unless either the lockout or SRQ\r | |
1103 | flip-flops are set. SRQ will set if DCPC mode is enabled and there is room\r | |
1104 | (transmit mode) or data (receive mode) in the FIFO.\r | |
1105 | */\r | |
1106 | \r | |
1107 | static void update_status (void)\r | |
1108 | {\r | |
1109 | if (baci_term.flags & UNIT_DIAG) { /* diagnostic mode? */\r | |
1110 | baci_status = baci_status & ~IN_LOOPBACK; /* prepare loopback flags */\r | |
1111 | \r | |
1112 | if (baci_icw & OUT_SXX) /* SCA to SCF and CF */\r | |
1113 | baci_status = baci_status | IN_SXX | IN_CF;\r | |
1114 | if ((baci_icw & OUT_CA) && (baci_fcount < 128)) /* CA to CC and CE */\r | |
1115 | baci_status = baci_status | IN_CC | IN_CE;\r | |
1116 | if (baci_icw & OUT_CD) /* CD to CB */\r | |
1117 | baci_status = baci_status | IN_CB;\r | |
1118 | else {\r | |
1119 | baci_status = baci_status | IN_TEST; /* BB is inversion of CD */\r | |
1120 | if (baci_cfcw & OUT_ECHO)\r | |
1121 | baci_status = baci_status | IN_SPARE; /* BB couples to BA with echo */\r | |
1122 | }\r | |
1123 | \r | |
1124 | if (!(baci_cfcw & OUT_ECHO) && (baci_uart_tr & 1)) /* no echo and UART TR set? */\r | |
1125 | baci_status = baci_status | IN_SPARE; /* BA to SPARE */\r | |
1126 | }\r | |
1127 | \r | |
1128 | if (baci_edsiw & (baci_status ^ baci_dsrw) & IN_MODEM) /* device interrupt? */\r | |
1129 | baci_status = baci_status | IN_DEVINT; /* set flag */\r | |
1130 | \r | |
1131 | if ((baci_status & IN_STDIRQ) || /* standard interrupt? */\r | |
1132 | !(baci_icw & OUT_DCPC) && /* or under program control */\r | |
1133 | (baci_status & IN_FIFOIRQ) || /* and FIFO interrupt? */\r | |
1134 | (IO_MODE == RECV) && /* or receiving */\r | |
1135 | (baci_edsiw & OUT_ENCM) && /* and char mode */\r | |
1136 | (baci_fget != baci_fput)) { /* and FIFO not empty? */\r | |
1137 | \r | |
1138 | if (CMD (baci_dib.devno)) { /* interrupt lockout? */\r | |
1139 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
1140 | fputs (">>BACI cmds: Lockout prevents flag set", sim_deb);\r | |
1141 | }\r | |
1142 | \r | |
1143 | else if (SRQ (baci_dib.devno)) { /* SRQ? */\r | |
1144 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
1145 | fputs (">>BACI cmds: SRQ prevents flag set", sim_deb);\r | |
1146 | }\r | |
1147 | \r | |
1148 | else {\r | |
1149 | setFLG (baci_dib.devno); /* set device flag and flag buffer */\r | |
1150 | setCMD (baci_dib.devno); /* set lockout */\r | |
1151 | \r | |
1152 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
1153 | fputs (">>BACI cmds: Flag and lockout set", sim_deb);\r | |
1154 | }\r | |
1155 | \r | |
1156 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
1157 | fprintf (sim_deb, ", status = %06o\n", baci_status);\r | |
1158 | }\r | |
1159 | \r | |
1160 | if ((baci_icw & OUT_DCPC) && /* DCPC enabled? */\r | |
1161 | ((IO_MODE == XMIT) && (baci_fcount < 128) || /* and xmit and room in FIFO */\r | |
1162 | (IO_MODE == RECV) && (baci_fcount > 0))) { /* or recv and data in FIFO? */\r | |
1163 | \r | |
1164 | if (CMD (baci_dib.devno)) { /* interrupt lockout? */\r | |
1165 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
1166 | fputs (">>BACI cmds: Lockout prevents SRQ set", sim_deb);\r | |
1167 | }\r | |
1168 | \r | |
1169 | else {\r | |
1170 | setSRQ (baci_dib.devno); /* set SRQ */\r | |
1171 | \r | |
1172 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
1173 | fputs (">>BACI cmds: SRQ set", sim_deb);\r | |
1174 | }\r | |
1175 | \r | |
1176 | if (DEBUG_PRI (baci_dev, DEB_CMDS))\r | |
1177 | fprintf (sim_deb, ", status = %06o\n", baci_status);\r | |
1178 | }\r | |
1179 | \r | |
1180 | return;\r | |
1181 | }\r | |
1182 | \r | |
1183 | \r | |
1184 | /* Calculate service time from baud rate.\r | |
1185 | \r | |
1186 | Service times are based on 1580 instructions per second, which is the 1000\r | |
1187 | E-Series execution speed. The "external clock" rate uses the 9600 baud rate,\r | |
1188 | as most real terminals were set to their maximum rate.\r | |
1189 | \r | |
1190 | Note that the RTE driver has a race condition that will trip if the service\r | |
1191 | time is less than 1500 instructions. Therefore, these times cannot be\r | |
1192 | shortened arbitrarily.\r | |
1193 | */\r | |
1194 | \r | |
1195 | static int32 service_time (uint32 control_word)\r | |
1196 | {\r | |
1197 | static const int32 ticks [] = { 1646, 316000, 210667, 143636, 117472, 105333, 52667, 26333,\r | |
1198 | 17556, 13667, 8778, 6583, 4389, 3292, 2194, 1646 };\r | |
1199 | \r | |
1200 | return ticks [GET_BAUDRATE (control_word)]; /* return service time for indicated rate */\r | |
1201 | }\r | |
1202 | \r | |
1203 | \r | |
1204 | /* Format a character into a printable string.\r | |
1205 | \r | |
1206 | Control characters are translated to readable strings. Printable characters\r | |
1207 | retain their original form but are enclosed in single quotes. Characters\r | |
1208 | outside of the ASCII range are represented as escaped octal values.\r | |
1209 | */\r | |
1210 | \r | |
1211 | static const char *fmt_char (uint8 ch)\r | |
1212 | {\r | |
1213 | static const char *const ctl[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",\r | |
1214 | "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",\r | |
1215 | "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",\r | |
1216 | "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" };\r | |
1217 | static char rep[5];\r | |
1218 | \r | |
1219 | if (ch <= '\037') /* ASCII control character? */\r | |
1220 | return ctl [ch]; /* return string representation */\r | |
1221 | \r | |
1222 | else if (ch == '\177') /* ASCII delete? */\r | |
1223 | return "DEL"; /* return string representation */\r | |
1224 | \r | |
1225 | else if (ch > '\177') { /* beyond printable range? */\r | |
1226 | sprintf (rep, "\\%03o", ch); /* format value */\r | |
1227 | return rep; /* return escaped octal code */\r | |
1228 | }\r | |
1229 | \r | |
1230 | else { /* printable character */\r | |
1231 | rep[0] = '\''; /* form string */\r | |
1232 | rep[1] = ch; /* containing character */\r | |
1233 | rep[2] = '\'';\r | |
1234 | rep[3] = '\0';\r | |
1235 | return rep; /* return quoted character */\r | |
1236 | }\r | |
1237 | }\r | |
1238 | \r | |
1239 | \r | |
1240 | /* FIFO manipulation routines.\r | |
1241 | \r | |
1242 | The BACI is a half-duplex device that has a single 128-byte FIFO that is used\r | |
1243 | for both transmitting and receiving. Whether the FIFO is connected to the\r | |
1244 | input or output of the UART is determined by the XMIT bit in word 4. A\r | |
1245 | separate 8-bit FIFO up/down counter is used to track the number of bytes\r | |
1246 | available. FIFO operations are complicated slightly by the UART, which is\r | |
1247 | double-buffered.\r | |
1248 | \r | |
1249 | The FIFO is modeled as a circular 128-byte array. Separate get and put\r | |
1250 | indexes track the current data extent. A FIFO character counter is used to\r | |
1251 | derive empty, half-full, and full status indications, and counts greater than\r | |
1252 | 128 are possible.\r | |
1253 | \r | |
1254 | In the transmit mode, an OTA/B with word type 0 generates SI (shift in) to\r | |
1255 | load the FIFO and increment the FIFO counter. When the UART is ready for a\r | |
1256 | character, THRE (UART transmitter holding register empty) and OR (FIFO output\r | |
1257 | ready) generate THRL (transmitter holding register load) and SO (FIFO shift\r | |
1258 | out) to unload the FIFO into the UART. When transmission of the character\r | |
1259 | over the serial line is complete, TRE (UART transmitter register empty)\r | |
1260 | decrements the FIFO counter.\r | |
1261 | \r | |
1262 | In the receive mode, the UART sets DR (data received) when has obtained a\r | |
1263 | character, which generates SI (FIFO shift in) to load the FIFO and increment\r | |
1264 | the FIFO counter. This also clocks PE (UART parity error) and IR (FIFO input\r | |
1265 | ready) into the overrun/parity error flip-flop. An LIA/B with control set\r | |
1266 | and with OR (FIFO output ready) set, indicating valid data is available,\r | |
1267 | generates SO (FIFO shift out) to unload the FIFO and decrement the FIFO\r | |
1268 | counter.\r | |
1269 | \r | |
1270 | Presuming an empty FIFO and UART, double-buffering in the transmit mode means\r | |
1271 | that the first byte deposited into the FIFO is removed and loaded into the\r | |
1272 | UART transmitter holding register. Even though the FIFO is actually empty,\r | |
1273 | the FIFO counter remains at 1, because FIFO decrement does not occur until\r | |
1274 | the UART actually transmits the data byte. The intended mode of operation is\r | |
1275 | to wait until the buffer-empty interrupt occurs, which will happen when the\r | |
1276 | final character is transmitted from the UART, before switching the BACI into\r | |
1277 | receive mode. The counter will match the FIFO contents properly, i.e., will\r | |
1278 | be zero, when the UART transmission completes.\r | |
1279 | \r | |
1280 | However, during diagnostic operation, FIFO testing will take this "extra"\r | |
1281 | count into consideration. For example, after a master reset, if ten bytes\r | |
1282 | are written to the FIFO in transmit mode, the first byte will pass through to\r | |
1283 | the UART transmitter holding register, and the next nine bytes will fill the\r | |
1284 | FIFO. The first byte read in receive mode will be byte 2, not byte 1; the\r | |
1285 | latter remains in the UART. After the ninth byte is read, OR (FIFO output\r | |
1286 | ready) will drop, resetting the valid data flip-flop and inhibiting any\r | |
1287 | further FIFO counter decrement pulses. The counter will remain at 1 until\r | |
1288 | another master reset is done.\r | |
1289 | \r | |
1290 | The same situation occurs in the RTE driver during ENQ/ACK handshakes. The\r | |
1291 | driver sets the card to transmit mode, sends an ENQ, waits for a short time\r | |
1292 | for the character to "bubble through" the FIFO and into the UART transmitter\r | |
1293 | holding register, and then switches the card to receive mode to await the\r | |
1294 | interrupt from the reception of the ACK. This is done to avoid the overhead\r | |
1295 | of the interrupt after the ENQ is transmitted. However, switching the card\r | |
1296 | into receive mode before the ENQ is actually transmitted means that the FIFO\r | |
1297 | counter will not decrement when that occurs, leaving the counter in an "off\r | |
1298 | by one" configuration. To remedy this, the driver does a master reset after\r | |
1299 | the ACK is received.\r | |
1300 | \r | |
1301 | Therefore, for proper operation, we must simulate both the UART\r | |
1302 | double-buffering and the decoupling of the FIFO and FIFO character counter.\r | |
1303 | */\r | |
1304 | \r | |
1305 | \r | |
1306 | /* Get a character from the FIFO.\r | |
1307 | \r | |
1308 | In receive mode, getting a character from the FIFO decrements the character\r | |
1309 | counter concurrently. In transmit mode, the counter must not be decremented\r | |
1310 | until the character is actually sent; in this latter case, the caller is\r | |
1311 | responsible for decrementing. Attempting to get a character when the FIFO is\r | |
1312 | empty returns the last valid data and does not alter the FIFO indexes.\r | |
1313 | \r | |
1314 | Because the FIFO counter may indicate more characters than are actually in\r | |
1315 | the FIFO, the count is not an accurate indicator of FIFO fill status. We\r | |
1316 | account for this by examining the get and put indexes. If these are equal,\r | |
1317 | then the FIFO is either empty or exactly full. We differentiate by examining\r | |
1318 | the FIFO counter and seeing if it is >= 128, indicating an (over)full\r | |
1319 | condition. If it is < 128, then the FIFO is empty, even if the counter is\r | |
1320 | not 0.\r | |
1321 | */\r | |
1322 | \r | |
1323 | static uint32 fifo_get (void)\r | |
1324 | {\r | |
1325 | uint32 data;\r | |
1326 | \r | |
1327 | data = baci_fifo [baci_fget]; /* get character */\r | |
1328 | \r | |
1329 | if ((baci_fget != baci_fput) || (baci_fcount >= 128)) { /* FIFO occupied? */\r | |
1330 | if (IO_MODE == RECV) /* receive mode? */\r | |
1331 | baci_fcount = baci_fcount - 1; /* decrement occupancy counter */\r | |
1332 | \r | |
1333 | if (DEBUG_PRI (baci_dev, DEB_BUF))\r | |
1334 | fprintf (sim_deb, ">>BACI buf: Character %s get from FIFO [%d], "\r | |
1335 | "character counter = %d\n", fmt_char (data), baci_fget, baci_fcount);\r | |
1336 | \r | |
1337 | baci_fget = (baci_fget + 1) % FIFO_SIZE; /* bump index modulo array size */\r | |
1338 | \r | |
1339 | if (baci_spchar [data]) /* is it a special character? */\r | |
1340 | data = data | IN_SPFLAG; /* set flag */\r | |
1341 | \r | |
1342 | data = data | IN_VALID; /* set valid flag in return */\r | |
1343 | }\r | |
1344 | \r | |
1345 | else /* FIFO empty */\r | |
1346 | if (DEBUG_PRI (baci_dev, DEB_BUF))\r | |
1347 | fprintf (sim_deb, ">>BACI buf: Attempted get on empty FIFO, "\r | |
1348 | "character count = %d\n", baci_fcount);\r | |
1349 | \r | |
1350 | if (baci_fcount == 0) /* count now zero? */\r | |
1351 | baci_status = baci_status | IN_BUFEMPTY; /* set buffer empty flag */\r | |
1352 | \r | |
1353 | update_status (); /* update FIFO status */\r | |
1354 | \r | |
1355 | return data; /* return character */\r | |
1356 | }\r | |
1357 | \r | |
1358 | \r | |
1359 | /* Put a character into the FIFO.\r | |
1360 | \r | |
1361 | In transmit mode, available characters are unloaded from the FIFO into the\r | |
1362 | UART transmitter holding register as soon as the THR is empty. That is,\r | |
1363 | given an empty FIFO and THR, a stored character will pass through the FIFO\r | |
1364 | and into the THR immediately. Otherwise, the character will remain in the\r | |
1365 | FIFO. In either case, the FIFO character counter is incremented.\r | |
1366 | \r | |
1367 | In receive mode, characters are only unloaded from the FIFO explicitly, so\r | |
1368 | stores always load the FIFO and increment the counter.\r | |
1369 | */\r | |
1370 | \r | |
1371 | static void fifo_put (uint8 ch)\r | |
1372 | {\r | |
1373 | uint32 index = 0;\r | |
1374 | t_bool pass_thru;\r | |
1375 | \r | |
1376 | pass_thru = (IO_MODE == XMIT) && /* pass thru if XMIT and THR empty */\r | |
1377 | !(baci_uart_thr & IN_VALID);\r | |
1378 | \r | |
1379 | if (pass_thru) /* pass char thru to UART */\r | |
1380 | baci_uart_thr = ch | IN_VALID; /* and set valid character flag */\r | |
1381 | \r | |
1382 | else { /* RECV or THR occupied */\r | |
1383 | index = baci_fput; /* save current index */\r | |
1384 | baci_fifo [baci_fput] = ch; /* put char in FIFO */\r | |
1385 | baci_fput = (baci_fput + 1) % FIFO_SIZE; /* bump index modulo array size */\r | |
1386 | }\r | |
1387 | \r | |
1388 | baci_fcount = baci_fcount + 1; /* increment occupancy counter */\r | |
1389 | \r | |
1390 | if (DEBUG_PRI (baci_dev, DEB_BUF))\r | |
1391 | if (pass_thru)\r | |
1392 | fprintf (sim_deb, ">>BACI buf: Character %s put to UART transmitter holding register, "\r | |
1393 | "character counter = 1\n", fmt_char (ch));\r | |
1394 | else\r | |
1395 | fprintf (sim_deb, ">>BACI buf: Character %s put to FIFO [%d], "\r | |
1396 | "character counter = %d\n", fmt_char (ch), index, baci_fcount);\r | |
1397 | \r | |
1398 | if ((IO_MODE == RECV) && (baci_spchar [ch])) /* receive mode and special character? */\r | |
1399 | baci_status = baci_status | IN_SPCHAR; /* set special char seen flag */\r | |
1400 | \r | |
1401 | if (baci_fcount == 64) /* FIFO half full? */\r | |
1402 | baci_status = baci_status | IN_BUFHALF;\r | |
1403 | \r | |
1404 | else if (baci_fcount == 128) /* FIFO completely full? */\r | |
1405 | baci_status = baci_status | IN_BUFFULL;\r | |
1406 | \r | |
1407 | else if (baci_fcount > 128) /* FIFO overrun? */\r | |
1408 | baci_status = baci_status | IN_OVRUNPE;\r | |
1409 | \r | |
1410 | update_status (); /* update FIFO status */\r | |
1411 | \r | |
1412 | return;\r | |
1413 | }\r | |
1414 | \r | |
1415 | \r | |
1416 | /* Clock the UART.\r | |
1417 | \r | |
1418 | In the diagnostic mode, the DIAG output is connected to the EXT CLK input.\r | |
1419 | If the baud rate of the Interface Control Word is set to "external clock,"\r | |
1420 | then raising and lowering the DIAG output will pulse the UART transmitter and\r | |
1421 | receiver clock lines, initiating transmission or reception of serial data.\r | |
1422 | Sixteen pulses are needed to shift one bit through the UART.\r | |
1423 | \r | |
1424 | The diagnostic hood ties CD to BB (received data), so bits presented to CD\r | |
1425 | via the Interface Control Word can be clocked into the UART receiver register\r | |
1426 | (RR). Similarly, the UART transmitter register (TR) shifts data onto BA\r | |
1427 | (transmitted data), and the hood ties BA to SPARE, so transmitted bits are\r | |
1428 | presented to the SPARE bit in the status word.\r | |
1429 | \r | |
1430 | "baci_uart_clk" contains the number of clock pulses remaining for the current\r | |
1431 | character transfer. Calling this routine with "baci_uart_clk" = 0 initiates\r | |
1432 | a transfer. The value will be a multiple of 16 and will account for the\r | |
1433 | start bit, the data bits, the optional parity bit, and the stop bits. The\r | |
1434 | transfer terminates when the count reaches zero (or eight, if 1.5 stop bits\r | |
1435 | is selected during transmission).\r | |
1436 | \r | |
1437 | Every sixteen pulses when the lower four bits of the clock count are zero,\r | |
1438 | the transmitter or receiver register will be shifted to present or receive a\r | |
1439 | new serial bit. The registers are initialized to all ones for proper\r | |
1440 | handling of the stop bits.\r | |
1441 | \r | |
1442 | A break counter is maintained and incremented whenever a space (0) condition\r | |
1443 | is seen on the serial line. After 160 clock times (10 bits) of continuous\r | |
1444 | zero data, the "break seen" status is set.\r | |
1445 | \r | |
1446 | This routine is not used in terminal mode.\r | |
1447 | */\r | |
1448 | \r | |
1449 | static void clock_uart (void)\r | |
1450 | {\r | |
1451 | uint32 uart_bits, data_bits, data_mask, parity, bit_low, i;\r | |
1452 | \r | |
1453 | if (baci_uart_clk > 0) { /* transfer in progress? */\r | |
1454 | bit_low = (baci_icw & OUT_CD); /* get current receive bit */\r | |
1455 | \r | |
1456 | if ((baci_uart_clk & 017) == 0) /* end of a bit? */\r | |
1457 | if (IO_MODE == XMIT) /* transmit? */\r | |
1458 | baci_uart_tr = baci_uart_tr >> 1; /* shift new bit onto line */\r | |
1459 | else /* receive? */\r | |
1460 | baci_uart_rr = (baci_uart_rr >> 1) & /* shift new bit in */\r | |
1461 | (bit_low ? ~SIGN : -1); /* (inverted sense) */\r | |
1462 | \r | |
1463 | if (bit_low) { /* another low bit? */\r | |
1464 | baci_bcount = baci_bcount + 1; /* update break counter */\r | |
1465 | \r | |
1466 | if (baci_bcount == 160) { /* break held long enough? */\r | |
1467 | baci_status = baci_status | IN_BREAK; /* set break flag */\r | |
1468 | \r | |
1469 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
1470 | fputs (">>BACI xfer: Break detected\n", sim_deb);\r | |
1471 | }\r | |
1472 | }\r | |
1473 | \r | |
1474 | else /* high bit? */\r | |
1475 | baci_bcount = 0; /* reset break counter */\r | |
1476 | \r | |
1477 | baci_uart_clk = baci_uart_clk - 1; /* decrement clocks remaining */\r | |
1478 | \r | |
1479 | if ((IO_MODE == XMIT) && /* transmit mode? */\r | |
1480 | ((baci_uart_clk == 0) || /* and end of character? */\r | |
1481 | (baci_uart_clk == 8) && /* or last stop bit */\r | |
1482 | (baci_cfcw & OUT_STBITS) && /* and extra stop bit requested */\r | |
1483 | ((baci_cfcw & OUT_CHARSIZE) == 0))) { /* and 1.5 stop bits used? */\r | |
1484 | \r | |
1485 | baci_uart_clk = 0; /* clear clock count */\r | |
1486 | \r | |
1487 | baci_fcount = baci_fcount - 1; /* decrement occupancy counter */\r | |
1488 | baci_uart_thr = fifo_get (); /* get next char into THR */\r | |
1489 | update_status (); /* update FIFO status */\r | |
1490 | \r | |
1491 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
1492 | fprintf (sim_deb, ">>BACI xfer: UART transmitter empty, "\r | |
1493 | "holding register = %06o\n", baci_uart_thr);\r | |
1494 | }\r | |
1495 | \r | |
1496 | else if ((IO_MODE == RECV) && /* receive mode? */\r | |
1497 | (baci_uart_clk == 0)) { /* and end of character? */\r | |
1498 | \r | |
1499 | data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */\r | |
1500 | data_mask = (1 << data_bits) - 1; /* generate mask for data bits */\r | |
1501 | \r | |
1502 | uart_bits = data_bits + /* calculate UART bits as data bits */\r | |
1503 | ((baci_cfcw & OUT_PARITY) != 0) + /* plus parity bit if used */\r | |
1504 | ((baci_cfcw & OUT_STBITS) != 0); /* plus extra stop bit if used */\r | |
1505 | \r | |
1506 | baci_uart_rhr = baci_uart_rr >> (16 - uart_bits); /* position data to right align */\r | |
1507 | baci_uart_rr = CLEAR_R; /* clear receiver register */\r | |
1508 | \r | |
1509 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
1510 | fprintf (sim_deb, ">>BACI xfer: UART receiver = %06o (%s)\n",\r | |
1511 | baci_uart_rhr, fmt_char (baci_uart_rhr & data_mask));\r | |
1512 | \r | |
1513 | fifo_put (baci_uart_rhr & data_mask); /* put data in FIFO */\r | |
1514 | update_status (); /* update FIFO status */\r | |
1515 | \r | |
1516 | if (baci_cfcw & OUT_PARITY) { /* parity present? */\r | |
1517 | data_mask = data_mask << 1 | 1; /* widen mask to encompass parity */\r | |
1518 | uart_bits = baci_uart_rhr & data_mask; /* get data plus parity */\r | |
1519 | \r | |
1520 | parity = (baci_cfcw & OUT_PAREVEN) == 0; /* preset for even/odd parity */\r | |
1521 | \r | |
1522 | for (i = 0; i < data_bits + 1; i++) { /* calc parity of data + parity bit */\r | |
1523 | parity = parity ^ uart_bits; /* parity calculated in LSB */\r | |
1524 | uart_bits = uart_bits >> 1;\r | |
1525 | }\r | |
1526 | \r | |
1527 | if (parity & 1) { /* parity error? */\r | |
1528 | baci_status = baci_status | IN_OVRUNPE; /* report it */\r | |
1529 | \r | |
1530 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
1531 | fputs (">>BACI xfer: Parity error detected\n", sim_deb);\r | |
1532 | }\r | |
1533 | }\r | |
1534 | }\r | |
1535 | }\r | |
1536 | \r | |
1537 | if ((baci_uart_clk == 0) && /* start of transfer? */\r | |
1538 | ((IO_MODE == RECV) || /* and receive mode */\r | |
1539 | (baci_uart_thr & IN_VALID))) { /* or character ready to transmit? */\r | |
1540 | \r | |
1541 | data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */\r | |
1542 | \r | |
1543 | uart_bits = data_bits + /* calculate UART bits as data bits */\r | |
1544 | ((baci_cfcw & OUT_PARITY) != 0) + /* plus parity bit if used */\r | |
1545 | 2 + ((baci_cfcw & OUT_STBITS) != 0); /* plus start/stop and extra stop if used */\r | |
1546 | \r | |
1547 | baci_uart_clk = 16 * uart_bits; /* calculate clocks pulses expected */\r | |
1548 | \r | |
1549 | if (IO_MODE == XMIT) { /* transmit mode? */\r | |
1550 | data_mask = (1 << data_bits) - 1; /* generate mask for data bits */\r | |
1551 | baci_uart_tr = baci_uart_thr & data_mask; /* mask data into holding register */\r | |
1552 | \r | |
1553 | if (baci_cfcw & OUT_PARITY) { /* add parity to this transmission? */\r | |
1554 | uart_bits = baci_uart_tr; /* copy data bits */\r | |
1555 | parity = (baci_cfcw & OUT_PAREVEN) == 0; /* preset for even/odd parity */\r | |
1556 | \r | |
1557 | for (i = 0; i < data_bits; i++) { /* calculate parity of data */\r | |
1558 | parity = parity ^ uart_bits; /* parity calculated in LSB */\r | |
1559 | uart_bits = uart_bits >> 1;\r | |
1560 | }\r | |
1561 | \r | |
1562 | data_mask = data_mask << 1 | 1; /* extend mask for the parity bit */\r | |
1563 | baci_uart_tr = baci_uart_tr | /* include parity in transmission register */\r | |
1564 | (parity & 1) << data_bits; /* (mask to parity bit and position it) */\r | |
1565 | }\r | |
1566 | \r | |
1567 | baci_uart_tr = (~data_mask | baci_uart_tr) << 2 | 1; /* form serial data stream */\r | |
1568 | \r | |
1569 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
1570 | fprintf (sim_deb, ">>BACI xfer: UART transmitter = %06o (%s), "\r | |
1571 | "clock count = %d\n", baci_uart_tr & DMASK,\r | |
1572 | fmt_char (baci_uart_thr & data_mask), baci_uart_clk);\r | |
1573 | }\r | |
1574 | \r | |
1575 | else {\r | |
1576 | baci_uart_rr = CLEAR_R; /* clear receiver register */\r | |
1577 | \r | |
1578 | if (DEBUG_PRI (baci_dev, DEB_XFER))\r | |
1579 | fprintf (sim_deb, ">>BACI xfer: UART receiver empty, "\r | |
1580 | "clock count = %d\n", baci_uart_clk);\r | |
1581 | }\r | |
1582 | }\r | |
1583 | \r | |
1584 | return;\r | |
1585 | }\r |