Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* nova_qty.c: NOVA multiplexor (QTY/ALM) simulator\r |
2 | \r | |
3 | Copyright (c) 2000-2008, Robert M. Supnik\r | |
4 | Written by Bruce Ray and used with his gracious permission.\r | |
5 | \r | |
6 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
7 | copy of this software and associated documentation files (the "Software"),\r | |
8 | to deal in the Software without restriction, including without limitation\r | |
9 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
10 | and/or sell copies of the Software, and to permit persons to whom the\r | |
11 | Software is furnished to do so, subject to the following conditions:\r | |
12 | \r | |
13 | The above copyright notice and this permission notice shall be included in\r | |
14 | all copies or substantial portions of the Software.\r | |
15 | \r | |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
19 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
22 | \r | |
23 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
24 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
25 | in this Software without prior written authorization from Robert M Supnik.\r | |
26 | \r | |
27 | qty multiplexor: QTY = 4060, ALM = 42xx\r | |
28 | \r | |
29 | 04-Jul-07 BKR fixed QTY output line number calculation (affected higher line numbers),\r | |
30 | 25-Mar-04 RMS Updated for V3.2\r | |
31 | 12-Jan-04 BKR Initial release\r | |
32 | includes both original DG "quad" multiplexor (QTY)\r | |
33 | and later Asynchronous Line Multiplexor (ALM) support.\r | |
34 | */\r | |
35 | \r | |
36 | \r | |
37 | /*----------------------------------------------------------------------*/\r | |
38 | /* QTY [4060-compatible] multiplexor */\r | |
39 | /*----------------------------------------------------------------------*/\r | |
40 | \r | |
41 | /*\r | |
42 | * Emulate the DG 4060 "quad" (QTY) serial port multiplexor. DG modem\r | |
43 | * control is not supported in this revision due to its obtuse nature\r | |
44 | * of using a separate [semi-secret] device MDM which is actually part\r | |
45 | * of the DG 4026/4027 multiplexor hardware(!).\r | |
46 | * (Full modem support is provided in the ALM driver.)\r | |
47 | *\r | |
48 | *\r | |
49 | * 4060 Hardware\r | |
50 | *\r | |
51 | * device code: 030 [primary],\r | |
52 | * 070 [secondary]\r | |
53 | * interrupt mask: B14 [000002]\r | |
54 | * ASM mnemonic: QTY\r | |
55 | *\r | |
56 | *\r | |
57 | * 4060 Input/Output Word Format:\r | |
58 | *\r | |
59 | * _________________________________________________________________\r | |
60 | * | RI| TI| channel | character |\r | |
61 | * ----+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r | |
62 | * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\r | |
63 | *\r | |
64 | *\r | |
65 | * RI - receiver interrupt\r | |
66 | * TI - transmitter interrupt\r | |
67 | * channel - channel number, 0 - 63.\r | |
68 | * character- character (valid if receiver interrupt, undefined if transmitter)\r | |
69 | *\r | |
70 | * Notes:\r | |
71 | *\r | |
72 | * Maximum 64 lines supported.\r | |
73 | * DONE set whenever any received character fully assembled and ready,\r | |
74 | * or when any output character transmitted and line is ready\r | |
75 | * to accept next output character.\r | |
76 | * BUSY set whenever output character is being sent on any line.\r | |
77 | * Note that early 4060s did NOT have a busy flag!\r | |
78 | * IORST clears device Done, no other user instruction does.\r | |
79 | * IORST clears each line's individual R.I. and T.I.\r | |
80 | *\r | |
81 | *\r | |
82 | * Instructions:\r | |
83 | *\r | |
84 | * DIA get multiplexor status word [format defined above]\r | |
85 | * DOA send character to QTY line [format defined above, RI & SI ]\r | |
86 | * DIB <ignored> [returns backplane bus noise]\r | |
87 | * DOB clear QTY line\r | |
88 | * DIC <ignored> [returns backplace bus noise]\r | |
89 | * DOC <ignored>\r | |
90 | * 'C' clears global done, then checks for RI and TI;\r | |
91 | * 'P' <ignored>\r | |
92 | * 'S' <ignored>\r | |
93 | */\r | |
94 | \r | |
95 | \r | |
96 | #include "nova_defs.h"\r | |
97 | \r | |
98 | #include "sim_sock.h"\r | |
99 | #include "sim_tmxr.h"\r | |
100 | \r | |
101 | \r | |
102 | #define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */\r | |
103 | #define UNIT_8B (1 << UNIT_V_8B)\r | |
104 | \r | |
105 | \r | |
106 | \r | |
107 | extern int32 int_req, dev_busy, dev_done, dev_disable ;\r | |
108 | extern int32 sim_switches ;\r | |
109 | extern FILE * sim_log ;\r | |
110 | extern int32 tmxr_poll ; /* calibrated delay */\r | |
111 | \r | |
112 | t_stat qty_summary ( FILE * st, UNIT * uptr, int32 val, void * desc ) ;\r | |
113 | t_stat qty_show ( FILE * st, UNIT * uptr, int32 val, void * desc ) ;\r | |
114 | t_stat qty_setnl ( UNIT * uptr, int32 val, char * cptr, void * desc ) ;\r | |
115 | \r | |
116 | t_stat qty_attach ( UNIT * uptr, char * cptr ) ;\r | |
117 | t_stat qty_detach ( UNIT * uptr ) ;\r | |
118 | t_stat qty_reset ( DEVICE * dptr ) ;\r | |
119 | t_stat qty_svc ( UNIT * uptr ) ;\r | |
120 | int32 qty ( int32 pulse, int32 code, int32 AC ) ;\r | |
121 | \r | |
122 | t_stat alm_reset ( DEVICE * dptr ) ;\r | |
123 | t_stat alm_svc ( UNIT * uptr ) ;\r | |
124 | int32 alm ( int32 pulse, int32 code, int32 AC ) ;\r | |
125 | \r | |
126 | DEVICE alm_dev ;\r | |
127 | \r | |
128 | \r | |
129 | #define QTY_MAX 64 /* max number of QTY lines - hardware */\r | |
130 | \r | |
131 | \r | |
132 | int32 qty_brkio = SCPE_OK ; /* default I/O status code */\r | |
133 | int32 qty_max = QTY_MAX ; /* max # QTY lines - user */\r | |
134 | /* controllable */\r | |
135 | int32 qty_mdm = 0 ; /* QTY modem control active? */\r | |
136 | int32 qty_auto = 0 ; /* QTY auto disconnect active? */\r | |
137 | int32 qty_polls = 0 ; /* total 'qty_svc' polls */\r | |
138 | \r | |
139 | \r | |
140 | TMLN qty_ldsc[ QTY_MAX ] = { 0 } ; /* QTY line descriptors */\r | |
141 | TMXR qty_desc = { QTY_MAX, 0, 0, qty_ldsc } ; /* mux descriptor */\r | |
142 | int32 qty_status[ QTY_MAX ] = { 0 } ; /* QTY line status */\r | |
143 | /* (must be at least 32 bits) */\r | |
144 | int32 qty_tx_chr[ QTY_MAX ] = { 0 } ; /* QTY line output character */\r | |
145 | \r | |
146 | \r | |
147 | /* QTY data structures\r | |
148 | \r | |
149 | qty_dev QTY device descriptor\r | |
150 | qty_unit QTY unit descriptor\r | |
151 | qty_reg QTY register list\r | |
152 | */\r | |
153 | \r | |
154 | DIB qty_dib = { DEV_QTY, INT_QTY, PI_QTY, &qty } ;\r | |
155 | \r | |
156 | UNIT qty_unit =\r | |
157 | {\r | |
158 | UDATA (&qty_svc, (UNIT_ATTABLE), 0)\r | |
159 | } ;\r | |
160 | \r | |
161 | REG qty_nlreg = { DRDATA (NLINES, qty_desc.lines, 7), PV_LEFT };\r | |
162 | \r | |
163 | REG qty_reg[] = /* ('alm_reg' should be similar to this except for device code related items) */\r | |
164 | {\r | |
165 | { ORDATA (BUF, qty_unit.buf, 8) },\r | |
166 | { FLDATA (BUSY, dev_busy, INT_V_QTY) },\r | |
167 | { FLDATA (DONE, dev_done, INT_V_QTY) },\r | |
168 | { FLDATA (DISABLE, dev_disable, INT_V_QTY) },\r | |
169 | { FLDATA (INT, int_req, INT_V_QTY) },\r | |
170 | \r | |
171 | { FLDATA (MDMCTL, qty_mdm, 0) },\r | |
172 | { FLDATA (AUTODS, qty_auto, 0) },\r | |
173 | { DRDATA (POLLS, qty_polls, 32) },\r | |
174 | { NULL }\r | |
175 | } ;\r | |
176 | \r | |
177 | MTAB qty_mod[] =\r | |
178 | {\r | |
179 | { UNIT_8B, 0, "7b", "7B", NULL },\r | |
180 | { UNIT_8B, UNIT_8B, "8b", "8B", NULL },\r | |
181 | { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",\r | |
182 | &tmxr_dscln, NULL, &qty_desc },\r | |
183 | { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &qty_summary },\r | |
184 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,\r | |
185 | NULL, &qty_show, NULL },\r | |
186 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,\r | |
187 | NULL, &qty_show, NULL },\r | |
188 | { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",\r | |
189 | &qty_setnl, NULL, &qty_nlreg },\r | |
190 | { 0 }\r | |
191 | } ;\r | |
192 | \r | |
193 | DEVICE qty_dev =\r | |
194 | {\r | |
195 | "QTY", &qty_unit, qty_reg, qty_mod,\r | |
196 | 1, 10, 31, 1, 8, 8,\r | |
197 | NULL, NULL, &qty_reset,\r | |
198 | NULL, &qty_attach, &qty_detach,\r | |
199 | &qty_dib, (DEV_DISABLE | DEV_DIS | DEV_NET)\r | |
200 | };\r | |
201 | \r | |
202 | #define DG_RETURN( status, data ) (int32)(((status) << IOT_V_REASON) | ((data) & 0x0FFFF) )\r | |
203 | \r | |
204 | /*\r | |
205 | * QTY_S_xxx QTY device status reference\r | |
206 | * QTY_L_xxx QTY line status word reference (qty_status[])\r | |
207 | */\r | |
208 | \r | |
209 | /*----------------------------------------------*/\r | |
210 | /* QTY device status */\r | |
211 | /*----------------------------------------------*/\r | |
212 | \r | |
213 | #define QTY_S_RI 0x8000 /* Receiver Interrupt */\r | |
214 | #define QTY_S_TI 0x4000 /* Transmitter interrupt */\r | |
215 | #define QTY_S_LMASK 0x3F00 /* line mask */\r | |
216 | #define QTY_S_DMASK 0x00FF /* data mask (received char) */\r | |
217 | \r | |
218 | \r | |
219 | \r | |
220 | #define QTY_MASTER_ACTIVE( desc ) ( (desc)->master )\r | |
221 | \r | |
222 | #define QTY_LINE_EXTRACT( x ) (((x) & QTY_S_LMASK) >> 8)\r | |
223 | \r | |
224 | #define QTY_LINE_TX_CHAR( line ) qty_tx_chr[ ((line) % QTY_MAX) ]\r | |
225 | #define QTY_LINE_RX_CHAR( line ) (qty_status[ (line) ] & QTY_S_DMASK)\r | |
226 | #define QTY_UNIT_ACTIVE( unitp ) ( (unitp)->conn )\r | |
227 | \r | |
228 | #define QTY_LINE_BITS( line, bits ) qty_status[ (line) ] & bits\r | |
229 | \r | |
230 | #define QTY_LINE_SET_BIT( line, bit ) qty_status[ (line) ] |= (bit) ;\r | |
231 | #define QTY_LINE_CLEAR_BIT( line, bit ) qty_status[ (line) ] &= ~(bit) ;\r | |
232 | #define QTY_LINE_BIT_SET( line, bit ) (qty_status[ (line) ] & (bit))\r | |
233 | \r | |
234 | \r | |
235 | /*----------------------------------------------*/\r | |
236 | /* QTY line status */\r | |
237 | /*----------------------------------------------*/\r | |
238 | \r | |
239 | #define QTY_L_RXE 0x800000 /* receiver enabled? */\r | |
240 | #define QTY_L_RXBZ 0x400000 /* receiver busy? */\r | |
241 | #define QTY_L_RXDN 0x200000 /* receiver done? */\r | |
242 | #define QTY_L_TXE 0x080000 /* transmitter enabled? */\r | |
243 | #define QTY_L_TXBZ 0x040000 /* transmitter busy? */\r | |
244 | #define QTY_L_TXDN 0x020000 /* transmitter done? */\r | |
245 | \r | |
246 | #define QTY_L_BREAK 0x008000 /* BREAK character received */\r | |
247 | #define QTY_L_RING 0x004000 /* Ring interrupt */\r | |
248 | #define QTY_L_CD 0x002000 /* Carrier Detect */\r | |
249 | #define QTY_L_DTR 0x001000 /* Data Terminal Ready */\r | |
250 | /* <0x00FF = character> */\r | |
251 | \r | |
252 | #define QTY_L_LOOPBK 0x00010000 /* loopback mode */\r | |
253 | #define QTY_L_OVRERR 0x00020000 /* overrun error */\r | |
254 | #define QTY_L_FRMERR 0x00040000 /* framing error */\r | |
255 | #define QTY_L_PARERR 0x00080000 /* parity error */\r | |
256 | \r | |
257 | \r | |
258 | /* CD, CTS, DSR, RI */\r | |
259 | /* <future> */\r | |
260 | \r | |
261 | #define QTY_L_MODEM 0x0080 /* <not yet used> */\r | |
262 | #define QTY_L_TELNET 0x0040 /* <not yet used> */\r | |
263 | #define QTY_L_AUTODIS 0x0020 /* <not yet used> */\r | |
264 | #define QTY_L_PARITY\r | |
265 | #define QTY_L_7BIT\r | |
266 | #define QTY_L_BAUD /* <4 bits> */\r | |
267 | \r | |
268 | \r | |
269 | #define QTY_L_DMASK 0x000FF /* data mask (always 8 bits) */\r | |
270 | \r | |
271 | /* Note: use at least an 'int32' for this guy */\r | |
272 | \r | |
273 | /*------------------------------*/\r | |
274 | /* qty_tmxr_putc */\r | |
275 | /*------------------------------*/\r | |
276 | \r | |
277 | int qty_tmxr_putc( int line, TMLN * lp, int kar )\r | |
278 | {\r | |
279 | int a ;\r | |
280 | \r | |
281 | /*----------------------------------------------*/\r | |
282 | /* Send character to given QTY/telnet line. */\r | |
283 | /* */\r | |
284 | /* enter: line QTY line # */\r | |
285 | /* lp Telnet unit def ptr */\r | |
286 | /* kar character to send */\r | |
287 | /* */\r | |
288 | /* return: SCPE_OK */\r | |
289 | /* SCPE_STALL */\r | |
290 | /* SCPE_LOST */\r | |
291 | /*----------------------------------------------*/\r | |
292 | \r | |
293 | a = tmxr_putc_ln( lp, kar ) ;\r | |
294 | if ( a == SCPE_OK)\r | |
295 | {\r | |
296 | QTY_LINE_SET_BIT( line, QTY_L_TXDN )\r | |
297 | QTY_LINE_CLEAR_BIT( line, QTY_L_TXBZ )\r | |
298 | }\r | |
299 | else if ( a == SCPE_STALL )\r | |
300 | {\r | |
301 | /*\r | |
302 | (should we try to output the buffer\r | |
303 | and then regroup...?)\r | |
304 | */\r | |
305 | QTY_LINE_SET_BIT( line, QTY_L_TXBZ )\r | |
306 | QTY_LINE_CLEAR_BIT( line, QTY_L_TXDN )\r | |
307 | QTY_LINE_TX_CHAR( line ) = kar ;\r | |
308 | }\r | |
309 | else if ( a == SCPE_LOST )\r | |
310 | {\r | |
311 | /* no connection - hangup? */\r | |
312 | QTY_LINE_SET_BIT( line, QTY_L_TXBZ )\r | |
313 | QTY_LINE_CLEAR_BIT( line, QTY_L_TXDN )\r | |
314 | QTY_LINE_TX_CHAR( line ) = kar ;\r | |
315 | }\r | |
316 | return ( a ) ;\r | |
317 | } /* end of 'qty_tmxr_putc' */\r | |
318 | \r | |
319 | \r | |
320 | /*----------------------------------------------*/\r | |
321 | /* qty_update_rcvi */\r | |
322 | /*----------------------------------------------*/\r | |
323 | \r | |
324 | int qty_update_rcvi( TMXR * mp )\r | |
325 | {\r | |
326 | int line ;\r | |
327 | TMLN * lp ;\r | |
328 | int32 datum ;\r | |
329 | int changes ;\r | |
330 | \r | |
331 | /*------------------------------------------------------*/\r | |
332 | /* Search through connected telnet lines for any input */\r | |
333 | /* activity. */\r | |
334 | /* */\r | |
335 | /* enter: mp master telnet qty desc ptr */\r | |
336 | /* */\r | |
337 | /* return: int change count (0 = none seen) */\r | |
338 | /*------------------------------------------------------*/\r | |
339 | \r | |
340 | for ( changes = line = 0; line < mp->lines; ++line )\r | |
341 | if ( (lp=mp->ldsc+line)->conn && lp->rcve )\r | |
342 | if ( (datum=tmxr_getc_ln(lp)) )\r | |
343 | {\r | |
344 | if ( datum & SCPE_BREAK )\r | |
345 | {\r | |
346 | /* what should we do here - set QTY_L_BREAK? */\r | |
347 | datum = datum & 0x00FF ;\r | |
348 | }\r | |
349 | else\r | |
350 | {\r | |
351 | datum = datum & 0x00FF ;\r | |
352 | }\r | |
353 | /* <check parity, masking, forced parity, CR/LF xlation> */\r | |
354 | \r | |
355 | QTY_LINE_CLEAR_BIT( line, (QTY_L_RXBZ | QTY_L_DMASK) ) ;\r | |
356 | QTY_LINE_SET_BIT( line, (QTY_L_RXDN | datum) ) ;\r | |
357 | ++changes ;\r | |
358 | }\r | |
359 | return ( changes ) ;\r | |
360 | } /* end of 'qty_update_rcvi' */\r | |
361 | \r | |
362 | \r | |
363 | /*----------------------------------------------*/\r | |
364 | /* qty_update_xmti */\r | |
365 | /*----------------------------------------------*/\r | |
366 | \r | |
367 | int qty_update_xmti( TMXR * mp )\r | |
368 | {\r | |
369 | int line ;\r | |
370 | TMLN * lp ;\r | |
371 | int changes ;\r | |
372 | \r | |
373 | /*------------------------------------------------------*/\r | |
374 | /* Search through connected telnet lines for any de- */\r | |
375 | /* ferred output activity. */\r | |
376 | /* */\r | |
377 | /* enter: mp master telnet qty desc ptr */\r | |
378 | /* */\r | |
379 | /* return: int change count (0 = none seen) */\r | |
380 | /*------------------------------------------------------*/\r | |
381 | \r | |
382 | /* any TX DONE flags set\r | |
383 | * any TX BUSY flags set\r | |
384 | */\r | |
385 | \r | |
386 | for ( changes = line = 0; line < mp->lines; ++line )\r | |
387 | if ( QTY_LINE_BIT_SET(line,QTY_L_TXBZ) )\r | |
388 | if ( (lp=mp->ldsc+line)->conn && lp->xmte )\r | |
389 | {\r | |
390 | /* why are we busy? buffer was full? */\r | |
391 | /* now some space available - try\r | |
392 | * to stuff pending character in\r | |
393 | * buffer and free up the world\r | |
394 | */\r | |
395 | qty_tmxr_putc( line, lp, QTY_LINE_TX_CHAR(line) ) ;\r | |
396 | ++changes ;\r | |
397 | }\r | |
398 | return ( changes ) ;\r | |
399 | } /* end of 'qty_update_xmti' */\r | |
400 | \r | |
401 | \r | |
402 | /*----------------------------------------------*/\r | |
403 | /* qty_update_status */\r | |
404 | /*----------------------------------------------*/\r | |
405 | \r | |
406 | int qty_update_status( DIB * dibp, TMXR * tmxr_desc )\r | |
407 | {\r | |
408 | int line ;\r | |
409 | int status ;\r | |
410 | int txbusy ;\r | |
411 | \r | |
412 | /*----------------------------------------------*/\r | |
413 | /* return global device status for current qty */\r | |
414 | /* state. */\r | |
415 | /* */\r | |
416 | /* Receiver interrupts have higher priority */\r | |
417 | /* than transmitter interrupts according to DG */\r | |
418 | /* but this routine could be modified to use */\r | |
419 | /* different priority criteria. */\r | |
420 | /* */\r | |
421 | /* Round-robin polling could also be used in */\r | |
422 | /* some future release rather than starting */\r | |
423 | /* with line 0 each time. */\r | |
424 | /* */\r | |
425 | /* Return <QTY_S_RI + line # + character> of */\r | |
426 | /* first waiting character, else return */\r | |
427 | /* <QTY_S_TI + line #> of first finished line */\r | |
428 | /* output, else return 0. */\r | |
429 | /* */\r | |
430 | /* This routine does -not- clear input line */\r | |
431 | /* BZ/DN flags; caller should do this. */\r | |
432 | /* */\r | |
433 | /* Global device done and busy flags are */\r | |
434 | /* updated. */\r | |
435 | /*----------------------------------------------*/\r | |
436 | \r | |
437 | for ( txbusy = status = line = 0 ; line < qty_max ; ++line )\r | |
438 | {\r | |
439 | txbusy |= (QTY_LINE_BIT_SET(line,QTY_L_TXBZ)) ;\r | |
440 | if ( QTY_LINE_BIT_SET(line,QTY_L_RXDN) )\r | |
441 | {\r | |
442 | if ( ! status )\r | |
443 | {\r | |
444 | status = QTY_LINE_BITS( line, QTY_S_DMASK ) | QTY_S_RI ;\r | |
445 | status = status | (line << 8) ;\r | |
446 | }\r | |
447 | break ;\r | |
448 | }\r | |
449 | else if ( QTY_LINE_BIT_SET(line,QTY_L_TXDN) )\r | |
450 | {\r | |
451 | if ( ! (status & QTY_S_RI) )\r | |
452 | if ( ! (status & QTY_S_RI) )\r | |
453 | {\r | |
454 | status = QTY_S_TI ;\r | |
455 | status = status | (line << 8) ;\r | |
456 | }\r | |
457 | }\r | |
458 | }\r | |
459 | /* <we could check each line for TX busy to set DEV_SET_BUSY)?> */\r | |
460 | DEV_CLR_BUSY( INT_QTY ) ;\r | |
461 | DEV_CLR_DONE( INT_QTY ) ;\r | |
462 | if ( txbusy )\r | |
463 | {\r | |
464 | DEV_SET_BUSY( INT_QTY ) ;\r | |
465 | }\r | |
466 | if ( status & (QTY_S_RI | QTY_S_TI) )\r | |
467 | {\r | |
468 | DEV_SET_DONE( INT_QTY ) ;\r | |
469 | }\r | |
470 | DEV_UPDATE_INTR ; /* update final intr status */\r | |
471 | return ( status ) ;\r | |
472 | } /* end of 'qty_update_status' */\r | |
473 | \r | |
474 | \r | |
475 | /*--------------------------------------------------------------*/\r | |
476 | /* qty_attach */\r | |
477 | /*--------------------------------------------------------------*/\r | |
478 | \r | |
479 | t_stat qty_attach( UNIT * unitp, char * cptr )\r | |
480 | {\r | |
481 | t_stat r ;\r | |
482 | int a ;\r | |
483 | \r | |
484 | /* switches: A auto-disconnect\r | |
485 | * M modem control\r | |
486 | */\r | |
487 | \r | |
488 | qty_mdm = qty_auto = 0; /* modem ctl off */\r | |
489 | r = tmxr_attach( &qty_desc, unitp, cptr ) ; /* attach QTY */\r | |
490 | if ( r != SCPE_OK )\r | |
491 | {\r | |
492 | return ( r ) ; /* error! */\r | |
493 | }\r | |
494 | if ( sim_switches & SWMASK('M') ) /* modem control? */\r | |
495 | {\r | |
496 | qty_mdm = 1;\r | |
497 | printf( "Modem control activated\n" ) ;\r | |
498 | if ( sim_log ) fprintf( sim_log, "Modem control activated\n" ) ;\r | |
499 | if ( sim_switches & SWMASK ('A') ) /* autodisconnect? */\r | |
500 | {\r | |
501 | qty_auto = 1 ;\r | |
502 | printf( "Auto disconnect activated\n" ) ;\r | |
503 | if ( sim_log ) fprintf( sim_log, "Auto disconnect activated\n" ) ;\r | |
504 | }\r | |
505 | }\r | |
506 | qty_polls = 0 ;\r | |
507 | for ( a = 0 ; a < QTY_MAX ; ++a )\r | |
508 | {\r | |
509 | /* QTY lines are always enabled - force RX and TX to 'enabled' */\r | |
510 | qty_status[ a ] = (QTY_L_RXE | QTY_L_TXE) ;\r | |
511 | }\r | |
512 | sim_activate( unitp, tmxr_poll ) ;\r | |
513 | return ( SCPE_OK ) ;\r | |
514 | } /* end of 'qty_attach' */\r | |
515 | \r | |
516 | \r | |
517 | /*--------------------------------------------------------------*/\r | |
518 | /* qty_detach */\r | |
519 | /*--------------------------------------------------------------*/\r | |
520 | \r | |
521 | t_stat qty_detach( UNIT * unitp )\r | |
522 | {\r | |
523 | sim_cancel( unitp ) ;\r | |
524 | return ( tmxr_detach(&qty_desc,unitp) ) ;\r | |
525 | } /* end of 'qty_detach' */\r | |
526 | \r | |
527 | \r | |
528 | /*--------------------------------------------------------------*/\r | |
529 | /* qty_clear */\r | |
530 | /*--------------------------------------------------------------*/\r | |
531 | \r | |
532 | t_stat qty_clear( t_bool flag )\r | |
533 | {\r | |
534 | int line ;\r | |
535 | \r | |
536 | for ( line = 0 ; line < qty_max ; ++line )\r | |
537 | {\r | |
538 | qty_ldsc[line].xmte = 0 ;\r | |
539 | qty_ldsc[line].rcve = 0 ;\r | |
540 | if ( ! qty_ldsc[line].conn )\r | |
541 | {\r | |
542 | qty_ldsc[line].xmte = 1 ; /* set xmt enb */\r | |
543 | qty_ldsc[line].rcve = 1 ; /* clr rcv enb */\r | |
544 | }\r | |
545 | }\r | |
546 | return ( SCPE_OK ) ;\r | |
547 | } /* end of 'qty_clear' */\r | |
548 | \r | |
549 | \r | |
550 | /*----------------------------------------------*/\r | |
551 | /* qty_common_reset */\r | |
552 | /*----------------------------------------------*/\r | |
553 | \r | |
554 | t_stat qty_common_reset( DIB * dibp, UNIT * unitp, DEVICE * dptr )\r | |
555 | {\r | |
556 | if ((dptr->flags & DEV_DIS) == 0)\r | |
557 | {\r | |
558 | if (dptr == &qty_dev) alm_dev.flags |= DEV_DIS;\r | |
559 | else qty_dev.flags |= DEV_DIS;\r | |
560 | }\r | |
561 | qty_clear( TRUE ) ;\r | |
562 | DEV_CLR_BUSY( INT_QTY ) ; /* clear busy */\r | |
563 | DEV_CLR_DONE( INT_QTY ) ; /* clear done, int */\r | |
564 | DEV_UPDATE_INTR ;\r | |
565 | if ( QTY_MASTER_ACTIVE(&qty_desc) )\r | |
566 | {\r | |
567 | sim_activate( unitp, tmxr_poll ) ;\r | |
568 | }\r | |
569 | else\r | |
570 | {\r | |
571 | sim_cancel( unitp ) ;\r | |
572 | }\r | |
573 | return ( SCPE_OK ) ;\r | |
574 | } /* end of 'qty_common_reset' */\r | |
575 | \r | |
576 | \r | |
577 | /*--------------------------------------------------------------*/\r | |
578 | /* qty_reset */\r | |
579 | /*--------------------------------------------------------------*/\r | |
580 | \r | |
581 | t_stat qty_reset( DEVICE * dptr )\r | |
582 | {\r | |
583 | return ( qty_common_reset(&qty_dib,&qty_unit,dptr) ) ;\r | |
584 | } /* end of 'qty_reset' */\r | |
585 | \r | |
586 | \r | |
587 | /* Unit service routine\r | |
588 | \r | |
589 | The QTY/ALM polls to see if asynchronous activity has occurred and now\r | |
590 | needs to be processed. The polling interval is controlled by the clock\r | |
591 | simulator, so for most environments, it is calibrated to real time.\r | |
592 | \r | |
593 | The simulator assumes that software enables all of the multiplexors,\r | |
594 | or none of them.\r | |
595 | */\r | |
596 | \r | |
597 | /*----------------------------------------------*/\r | |
598 | /* qty_common_svc */\r | |
599 | /*----------------------------------------------*/\r | |
600 | \r | |
601 | t_stat qty_common_svc( DIB * dibp, UNIT * unitp )\r | |
602 | {\r | |
603 | int line ;\r | |
604 | int newln ;\r | |
605 | TMLN * tmlnp ;\r | |
606 | \r | |
607 | ++qty_polls ; /* another time 'round the track */\r | |
608 | newln = tmxr_poll_conn( &qty_desc ) ; /* anybody knocking at the door? */\r | |
609 | if ( (newln >= 0) && qty_mdm )\r | |
610 | if ( newln >= qty_max )\r | |
611 | {\r | |
612 | return SCPE_IERR; /* WTF - sanity check failed, over? */\r | |
613 | }\r | |
614 | else\r | |
615 | {\r | |
616 | line = newln ; /* handle modem control */\r | |
617 | tmlnp =&qty_ldsc[ line ] ;\r | |
618 | tmlnp->rcve = tmlnp->xmte = 1 ;\r | |
619 | /* do QTY_LINE_ bit fiddling and state machine\r | |
620 | * manipulation with modem control signals\r | |
621 | */\r | |
622 | }\r | |
623 | \r | |
624 | tmxr_poll_rx( &qty_desc ) ; /* poll input */\r | |
625 | qty_update_rcvi( &qty_desc ) ; /* update receiver interrupt status */\r | |
626 | \r | |
627 | tmxr_poll_tx( &qty_desc ) ; /* poll output */\r | |
628 | qty_update_xmti( &qty_desc ) ; /* update transmitter interrupt status */\r | |
629 | \r | |
630 | qty_update_status( dibp, &qty_desc ) ; /* update device status */\r | |
631 | \r | |
632 | sim_activate( unitp, tmxr_poll ) ; /* restart the bubble machine */\r | |
633 | return ( SCPE_OK ) ;\r | |
634 | } /* end of 'qty_common_svc' */\r | |
635 | \r | |
636 | \r | |
637 | /*--------------------------------------------------------------*/\r | |
638 | /* qty_svc */\r | |
639 | /*--------------------------------------------------------------*/\r | |
640 | \r | |
641 | t_stat qty_svc( UNIT * uptr )\r | |
642 | {\r | |
643 | return ( qty_common_svc(&qty_dib,uptr) ) ;\r | |
644 | } /* end of 'qty_svc' */\r | |
645 | \r | |
646 | \r | |
647 | /*--------------------------------------------------------------*/\r | |
648 | /* qty */\r | |
649 | /*--------------------------------------------------------------*/\r | |
650 | \r | |
651 | int32 qty( int32 pulse, int32 code, int32 AC )\r | |
652 | {\r | |
653 | int32 iodata ;\r | |
654 | int32 ioresult ;\r | |
655 | int line ;\r | |
656 | TMLN * tmlnp ;\r | |
657 | int a ;\r | |
658 | int kar ;\r | |
659 | \r | |
660 | /*--------------------------------------------------------------*/\r | |
661 | /* DG 4060[-compatible] "quad" multiplexor instruction handler */\r | |
662 | /*--------------------------------------------------------------*/\r | |
663 | \r | |
664 | ioresult= qty_brkio ; /* (assume returning I/O break value */\r | |
665 | iodata = 0 ; /* (assume 16-bit Nova/Eclipse bus) */\r | |
666 | switch ( code )\r | |
667 | {\r | |
668 | case ioNIO : /* <no operation> */\r | |
669 | break ;\r | |
670 | \r | |
671 | case ioDIA : /* get current QTY status */\r | |
672 | iodata = qty_update_status( &qty_dib, &qty_desc ) ;\r | |
673 | if ( iodata & QTY_S_RI )\r | |
674 | { /* clear line's input buffer */\r | |
675 | QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(iodata)), (QTY_L_RXBZ | QTY_L_RXDN) )\r | |
676 | /*\r | |
677 | character masking ;\r | |
678 | parity checking ;\r | |
679 | parity generating ;\r | |
680 | */\r | |
681 | }\r | |
682 | qty_update_status( &qty_dib, &qty_desc ) ;\r | |
683 | break ;\r | |
684 | \r | |
685 | case ioDOA : /* send character to QTY */\r | |
686 | line = QTY_LINE_EXTRACT( AC ) ;\r | |
687 | if ( line < qty_max )\r | |
688 | if ( QTY_LINE_BIT_SET(line,QTY_L_TXE) )\r | |
689 | {\r | |
690 | /*\r | |
691 | perform any character translation:\r | |
692 | 7 bit/ 8 bit\r | |
693 | parity generation\r | |
694 | */\r | |
695 | kar = AC & ((qty_unit.flags & UNIT_8B)? 0377: 0177) ;\r | |
696 | /* do any parity calculations also */\r | |
697 | \r | |
698 | tmlnp = &qty_ldsc[ line ] ;\r | |
699 | a = qty_tmxr_putc( line, tmlnp, kar ) ;\r | |
700 | if ( a != SCPE_OK)\r | |
701 | {\r | |
702 | /* do anything at this point? */\r | |
703 | }\r | |
704 | qty_update_status( &qty_dib, &qty_desc ) ;\r | |
705 | }\r | |
706 | break ;\r | |
707 | \r | |
708 | case ioDIB : /* no QTY function - return bus noise in AC */\r | |
709 | break ;\r | |
710 | \r | |
711 | case ioDOB : /* clear QTY output channel busy and done flag */\r | |
712 | QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(AC)), (QTY_L_TXBZ | QTY_L_TXDN) )\r | |
713 | qty_update_status( &qty_dib, &qty_desc ) ;\r | |
714 | break ;\r | |
715 | \r | |
716 | case ioDIC : /* no QTY function - return bus noise in AC */\r | |
717 | break ;\r | |
718 | \r | |
719 | case ioDOC : /* no QTY function - ignore */\r | |
720 | break ;\r | |
721 | \r | |
722 | case ioSKP : /* I/O skip test - should never come here */\r | |
723 | break ;\r | |
724 | \r | |
725 | default :\r | |
726 | /* <illegal I/O operation value> */\r | |
727 | break ;\r | |
728 | }\r | |
729 | \r | |
730 | switch ( pulse )\r | |
731 | {\r | |
732 | case iopN : /* <ignored (of course)> */\r | |
733 | break ;\r | |
734 | \r | |
735 | case iopS : /* <ignored> */\r | |
736 | break ;\r | |
737 | \r | |
738 | case iopP : /* <ignored> */\r | |
739 | break ;\r | |
740 | \r | |
741 | case iopC :\r | |
742 | qty_update_status( &qty_dib, &qty_desc ) ;\r | |
743 | break ;\r | |
744 | \r | |
745 | default :\r | |
746 | /* <illegal pulse value> */\r | |
747 | break ;\r | |
748 | }\r | |
749 | \r | |
750 | return ( DG_RETURN( ioresult, iodata ) ) ;\r | |
751 | } /* end of 'qty' */\r | |
752 | \r | |
753 | /*--------------------------------------------------------------*/\r | |
754 | /* qty_summary */\r | |
755 | /*--------------------------------------------------------------*/\r | |
756 | \r | |
757 | t_stat qty_summary( FILE * st, UNIT * uptr, int32 val, void * desc )\r | |
758 | {\r | |
759 | int32 i, t ;\r | |
760 | \r | |
761 | for (i = t = 0 ; i < qty_desc.lines ; ++i )\r | |
762 | if ( qty_ldsc[i].conn )\r | |
763 | {\r | |
764 | ++t ;\r | |
765 | }\r | |
766 | fprintf( st, "%d connection%s", t, ((t)? "s" : "") ) ;\r | |
767 | return ( SCPE_OK ) ;\r | |
768 | } /* end of 'qty_summ' */\r | |
769 | \r | |
770 | \r | |
771 | /*--------------------------------------------------------------*/\r | |
772 | /* qty_show */\r | |
773 | /*--------------------------------------------------------------*/\r | |
774 | \r | |
775 | t_stat qty_show( FILE * st, UNIT * uptr, int32 val, void * desc )\r | |
776 | {\r | |
777 | int32 i, t ;\r | |
778 | \r | |
779 | for (i = t = 0 ; i < qty_desc.lines ; ++i )\r | |
780 | if ( qty_ldsc[i].conn )\r | |
781 | {\r | |
782 | t = 1; \r | |
783 | if ( val )\r | |
784 | {\r | |
785 | tmxr_fconns( st, &qty_ldsc[i], i ) ;\r | |
786 | }\r | |
787 | else\r | |
788 | {\r | |
789 | tmxr_fstats( st, &qty_ldsc[i], i ) ;\r | |
790 | }\r | |
791 | }\r | |
792 | if ( t == 0 ) fprintf( st, "none connected\n" ) ;\r | |
793 | return ( SCPE_OK ) ;\r | |
794 | } /* end of 'qty_show' */\r | |
795 | \r | |
796 | \r | |
797 | /*--------------------------------------------------------------*/\r | |
798 | /* qty_setnl */\r | |
799 | /*--------------------------------------------------------------*/\r | |
800 | \r | |
801 | t_stat qty_setnl( UNIT * uptr, int32 val, char * cptr, void * desc )\r | |
802 | {\r | |
803 | int32 newln, i, t ;\r | |
804 | \r | |
805 | t_stat r ;\r | |
806 | if ( cptr == NULL )\r | |
807 | {\r | |
808 | return ( SCPE_ARG ) ;\r | |
809 | }\r | |
810 | newln = (int32) get_uint( cptr, 10, QTY_MAX, &r ) ;\r | |
811 | if ( (r != SCPE_OK) || (newln == qty_desc.lines) )\r | |
812 | {\r | |
813 | return ( r ) ;\r | |
814 | }\r | |
815 | if ( (newln == 0) || (newln > QTY_MAX) )\r | |
816 | {\r | |
817 | return ( SCPE_ARG ) ;\r | |
818 | }\r | |
819 | if ( newln < qty_desc.lines )\r | |
820 | {\r | |
821 | for ( i = newln, t = 0 ; i < qty_desc.lines ; ++i )\r | |
822 | {\r | |
823 | t = t | qty_ldsc[i].conn ;\r | |
824 | }\r | |
825 | if ( t && ! get_yn("This will disconnect users; proceed [N]?", FALSE) )\r | |
826 | {\r | |
827 | return ( SCPE_OK ) ;\r | |
828 | }\r | |
829 | for ( i = newln ; i < qty_desc.lines ; ++i )\r | |
830 | {\r | |
831 | if ( qty_ldsc[i].conn )\r | |
832 | { /* reset line */\r | |
833 | tmxr_msg( qty_ldsc[i].conn, "\r\nOperator disconnected line\r\n" ) ;\r | |
834 | tmxr_reset_ln( &qty_ldsc[i] ) ;\r | |
835 | }\r | |
836 | qty_clear( TRUE ) ; /* reset mux */\r | |
837 | }\r | |
838 | }\r | |
839 | qty_max = qty_desc.lines = newln ;\r | |
840 | /* Huh, I don't understand this yet...\r | |
841 | qty_max = ((qty_dev.flags & DEV_DIS)? 0 : (qty_desc.lines / QTY_MAX)) ;\r | |
842 | */\r | |
843 | return ( SCPE_OK ) ;\r | |
844 | } /* end of 'qty_setnl' */\r | |
845 | \r | |
846 | \r | |
847 | /*----------------------------------------------------------------------*/\r | |
848 | /* ALM [425x-compatible] multiplexor */\r | |
849 | /*----------------------------------------------------------------------*/\r | |
850 | \r | |
851 | /*\r | |
852 | * device code: 034 [primary],\r | |
853 | * 074 [secondary]\r | |
854 | * interrupt mask: B14 [000002]\r | |
855 | * ASM mnemonic: ALM\r | |
856 | *\r | |
857 | * ALM [4255-4258] I/O instructions\r | |
858 | *\r | |
859 | * DIA read line and section requesting service\r | |
860 | * DOA select line and section (lines 0-255, 8-bits) + rcvr/xmit\r | |
861 | * DIB receive data\r | |
862 | * DOB 00 transmit data\r | |
863 | * 01 transmit BREAK\r | |
864 | * 10 set modem control status\r | |
865 | * 11 <ignored>\r | |
866 | * DIC read receiver or modem status\r | |
867 | * DOC 00 control line section and diag mode\r | |
868 | * 01 \r | |
869 | * 10 specify line characteristics\r | |
870 | * 11\r | |
871 | *\r | |
872 | * undocumented DG "features":\r | |
873 | *\r | |
874 | * NIOS sets board offline\r | |
875 | * NIOC sets board online\r | |
876 | * Modem control signal state change can signal interrupt\r | |
877 | * explicit line select with DOA\r | |
878 | * implicit line select with DIA\r | |
879 | *\r | |
880 | * We support 64 lines maximum in this release although some ALM's could\r | |
881 | * theoretically support up to 256.\r | |
882 | */\r | |
883 | \r | |
884 | \r | |
885 | DIB alm_dib = { DEV_ALM, INT_ALM, PI_ALM, &alm } ;\r | |
886 | UNIT alm_unit =\r | |
887 | {\r | |
888 | UDATA (&alm_svc, (UNIT_ATTABLE), 0)\r | |
889 | } ;\r | |
890 | \r | |
891 | REG alm_reg[] = /* ('qty_reg' should be similar to this except for device code related items) */\r | |
892 | {\r | |
893 | { ORDATA (BUF, alm_unit.buf, 8) },\r | |
894 | { FLDATA (BUSY, dev_busy, INT_V_ALM) },\r | |
895 | { FLDATA (DONE, dev_done, INT_V_ALM) },\r | |
896 | { FLDATA (DISABLE, dev_disable, INT_V_ALM) },\r | |
897 | { FLDATA (INT, int_req, INT_V_ALM) },\r | |
898 | \r | |
899 | { FLDATA (MDMCTL, qty_mdm, 0) },\r | |
900 | { FLDATA (AUTODS, qty_auto, 0) },\r | |
901 | { DRDATA (POLLS, qty_polls, 32) },\r | |
902 | { NULL }\r | |
903 | } ;\r | |
904 | \r | |
905 | DEVICE alm_dev =\r | |
906 | {\r | |
907 | "ALM", &alm_unit, alm_reg, qty_mod,\r | |
908 | 1, 10, 31, 1, 8, 8,\r | |
909 | NULL, NULL, &alm_reset,\r | |
910 | NULL, &qty_attach, &qty_detach,\r | |
911 | &alm_dib, (DEV_DISABLE | DEV_NET)\r | |
912 | } ;\r | |
913 | \r | |
914 | int alm_section = -1 ; /* current line "section" (0 = RCV, 1 = XMT) */\r | |
915 | int alm_line = -1 ; /* current line [0-63] */\r | |
916 | int alm_diag_mode = 0 ; /* <not yet supported> */\r | |
917 | int alm_line_mask = 0x003F ; /* maximum of 64 lines in this rev */\r | |
918 | \r | |
919 | \r | |
920 | #define ALM_LINE_EXTRACT( x ) (((x) >> 1) & alm_line_mask)\r | |
921 | #define ALM_SECT_EXTRACT( x ) ((x) & 0x0001)\r | |
922 | \r | |
923 | \r | |
924 | /*--------------------------------------------------------------*/\r | |
925 | /* alm_reset */\r | |
926 | /*--------------------------------------------------------------*/\r | |
927 | \r | |
928 | t_stat alm_reset( DEVICE * dptr )\r | |
929 | {\r | |
930 | return ( qty_common_reset(&alm_dib,&alm_unit,dptr) ) ;\r | |
931 | } /* end of 'alm_reset' */\r | |
932 | \r | |
933 | \r | |
934 | /*--------------------------------------------------------------*/\r | |
935 | /* alm_svc */\r | |
936 | /*--------------------------------------------------------------*/\r | |
937 | \r | |
938 | t_stat alm_svc( UNIT * uptr )\r | |
939 | {\r | |
940 | return ( qty_common_svc(&alm_dib,uptr) ) ;\r | |
941 | } /* end of 'alm_svc' */\r | |
942 | \r | |
943 | \r | |
944 | /*--------------------------------------------------------------*/\r | |
945 | /* alm */\r | |
946 | /*--------------------------------------------------------------*/\r | |
947 | \r | |
948 | int32 alm( int32 pulse, int32 code, int32 AC )\r | |
949 | {\r | |
950 | int32 iodata ;\r | |
951 | int32 ioresult ;\r | |
952 | TMLN * tmlnp ;\r | |
953 | int a ;\r | |
954 | int kar ;\r | |
955 | \r | |
956 | /*--------------------------------------------------------------*/\r | |
957 | /* DG 425x[-compatible] "ALM" multiplexor instruction handler */\r | |
958 | /*--------------------------------------------------------------*/\r | |
959 | \r | |
960 | ioresult= qty_brkio ; /* (assume returning I/O break value */\r | |
961 | iodata = 0 ; /* (assume 16-bit Nova/Eclipse bus) */\r | |
962 | switch ( code )\r | |
963 | {\r | |
964 | case ioNIO : /* <no operation> */\r | |
965 | break ;\r | |
966 | \r | |
967 | case ioDIA : /* read line and section requesting service */\r | |
968 | iodata = qty_update_status( &alm_dib, &qty_desc ) ;\r | |
969 | alm_line = (QTY_LINE_EXTRACT(iodata) & alm_line_mask) ;\r | |
970 | /* (mask with 'alm_line_mask' in case ALM mask is different than QTY */\r | |
971 | alm_section = 0 ;\r | |
972 | if ( ! ( iodata & QTY_S_RI) )\r | |
973 | if ( iodata & QTY_S_TI )\r | |
974 | {\r | |
975 | alm_section = 1 ; /* receiver quiet - transmitter done */\r | |
976 | }\r | |
977 | iodata = (alm_line << 1) | alm_section ;\r | |
978 | break ;\r | |
979 | \r | |
980 | case ioDOA : /* set line and section */\r | |
981 | alm_section = ALM_SECT_EXTRACT( AC ) ;\r | |
982 | alm_line = ALM_LINE_EXTRACT( AC ) ;\r | |
983 | break ;\r | |
984 | \r | |
985 | case ioDIB : /* no ALM function - return bus noise in AC */\r | |
986 | if ( alm_line < qty_max )\r | |
987 | {\r | |
988 | iodata = QTY_LINE_RX_CHAR( alm_line ) ;\r | |
989 | }\r | |
990 | break ;\r | |
991 | \r | |
992 | case ioDOB : /* output and modem control functions */\r | |
993 | switch ( (AC >> 14) & 03 )\r | |
994 | {\r | |
995 | case 00 : /* transmit data */\r | |
996 | if ( alm_line < qty_max )\r | |
997 | if ( QTY_LINE_BIT_SET(alm_line,QTY_L_TXE) )\r | |
998 | {\r | |
999 | /*\r | |
1000 | perform any character translation:\r | |
1001 | 7 bit/ 8 bit\r | |
1002 | parity generation\r | |
1003 | */\r | |
1004 | kar = AC & ((alm_unit.flags & UNIT_8B)? 0377: 0177) ;\r | |
1005 | /* do any parity calculations also */\r | |
1006 | \r | |
1007 | tmlnp = &qty_ldsc[ alm_line ] ;\r | |
1008 | a = qty_tmxr_putc( alm_line, tmlnp, kar ) ;\r | |
1009 | if ( a != SCPE_OK)\r | |
1010 | {\r | |
1011 | /* do anything at this point? */\r | |
1012 | }\r | |
1013 | qty_update_status( &alm_dib, &qty_desc ) ;\r | |
1014 | }\r | |
1015 | break ;\r | |
1016 | \r | |
1017 | case 01 : /* transmit break */\r | |
1018 | if ( alm_line < qty_max )\r | |
1019 | if ( QTY_LINE_BIT_SET(alm_line,QTY_L_TXE) )\r | |
1020 | {\r | |
1021 | tmlnp = &qty_ldsc[ alm_line ] ;\r | |
1022 | /*\r | |
1023 | a = qty_tmxr_putc( alm_line, tmlnp, kar ) ;\r | |
1024 | if ( a != SCPE_OK)\r | |
1025 | {\r | |
1026 | }\r | |
1027 | */\r | |
1028 | qty_update_status( &alm_dib, &qty_desc ) ;\r | |
1029 | }\r | |
1030 | break ;\r | |
1031 | \r | |
1032 | case 02 : /* set modem control status */\r | |
1033 | break ;\r | |
1034 | \r | |
1035 | case 03 : /* unused */\r | |
1036 | break ;\r | |
1037 | }\r | |
1038 | break ;\r | |
1039 | \r | |
1040 | case ioDIC : /* get modem or receiver status */\r | |
1041 | if ( alm_line < qty_max )\r | |
1042 | if ( alm_section )\r | |
1043 | {\r | |
1044 | /* get modem section status */\r | |
1045 | if ( qty_ldsc[ alm_line ].xmte )\r | |
1046 | {\r | |
1047 | iodata = 0035 ; /* set CD, CTS, DSR, MDM flags */\r | |
1048 | }\r | |
1049 | }\r | |
1050 | else\r | |
1051 | {\r | |
1052 | /* get receiver section status */\r | |
1053 | iodata = 0 ; /* receiver error status - no errors by default */\r | |
1054 | }\r | |
1055 | break ;\r | |
1056 | \r | |
1057 | case ioDOC : /* set line attributes */\r | |
1058 | switch ( (AC >> 14) & 03 )\r | |
1059 | {\r | |
1060 | case 00 : /* control line section */\r | |
1061 | break ;\r | |
1062 | \r | |
1063 | case 01 : /* unused */\r | |
1064 | break ;\r | |
1065 | \r | |
1066 | case 02 : /* set line characteristics */\r | |
1067 | break ;\r | |
1068 | \r | |
1069 | case 03 : /* unused */\r | |
1070 | break ;\r | |
1071 | }\r | |
1072 | break ;\r | |
1073 | \r | |
1074 | case ioSKP : /* I/O skip test - should never come here */\r | |
1075 | break ;\r | |
1076 | \r | |
1077 | default :\r | |
1078 | /* <illegal I/O operation value> */\r | |
1079 | break ;\r | |
1080 | }\r | |
1081 | \r | |
1082 | switch ( pulse )\r | |
1083 | {\r | |
1084 | case iopN : /* <ignored (of course)> */\r | |
1085 | break ;\r | |
1086 | \r | |
1087 | case iopS : /* set device busy\r | |
1088 | * set all lines on board offline\r | |
1089 | * clear each line's done\r | |
1090 | * clear internal system\r | |
1091 | * clear device busy\r | |
1092 | */\r | |
1093 | for ( a = 0 ; a < qty_max ; ++a )\r | |
1094 | if ( 1 /* (not yet optimized) */ )\r | |
1095 | {\r | |
1096 | QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ;\r | |
1097 | }\r | |
1098 | qty_update_status( &alm_dib, &qty_desc ) ;\r | |
1099 | break ;\r | |
1100 | \r | |
1101 | case iopP : /* stop clock for all boards in off-line mode */\r | |
1102 | break ;\r | |
1103 | \r | |
1104 | case iopC :\r | |
1105 | for ( a = 0 ; a < qty_max ; ++a )\r | |
1106 | if ( 1 /* (not yet optimized) */ )\r | |
1107 | {\r | |
1108 | QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ;\r | |
1109 | }\r | |
1110 | qty_update_status( &alm_dib, &qty_desc ) ;\r | |
1111 | break ;\r | |
1112 | \r | |
1113 | default :\r | |
1114 | /* <illegal pulse value> */\r | |
1115 | break ;\r | |
1116 | }\r | |
1117 | \r | |
1118 | return ( DG_RETURN( ioresult, iodata ) ) ;\r | |
1119 | } /* end of 'alm' */\r |