1 /* nova_qty.c: NOVA multiplexor (QTY/ALM) simulator
3 Copyright (c) 2000-2008, Robert M. Supnik
4 Written by Bruce Ray and used with his gracious permission.
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of Robert M Supnik shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from Robert M Supnik.
27 qty multiplexor: QTY = 4060, ALM = 42xx
29 04-Jul-07 BKR fixed QTY output line number calculation (affected higher line numbers),
30 25-Mar-04 RMS Updated for V3.2
31 12-Jan-04 BKR Initial release
32 includes both original DG "quad" multiplexor (QTY)
33 and later Asynchronous Line Multiplexor (ALM) support.
37 /*----------------------------------------------------------------------*/
38 /* QTY [4060-compatible] multiplexor */
39 /*----------------------------------------------------------------------*/
42 * Emulate the DG 4060 "quad" (QTY) serial port multiplexor. DG modem
43 * control is not supported in this revision due to its obtuse nature
44 * of using a separate [semi-secret] device MDM which is actually part
45 * of the DG 4026/4027 multiplexor hardware(!).
46 * (Full modem support is provided in the ALM driver.)
51 * device code: 030 [primary],
53 * interrupt mask: B14 [000002]
57 * 4060 Input/Output Word Format:
59 * _________________________________________________________________
60 * | RI| TI| channel | character |
61 * ----+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
62 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
65 * RI - receiver interrupt
66 * TI - transmitter interrupt
67 * channel - channel number, 0 - 63.
68 * character- character (valid if receiver interrupt, undefined if transmitter)
72 * Maximum 64 lines supported.
73 * DONE set whenever any received character fully assembled and ready,
74 * or when any output character transmitted and line is ready
75 * to accept next output character.
76 * BUSY set whenever output character is being sent on any line.
77 * Note that early 4060s did NOT have a busy flag!
78 * IORST clears device Done, no other user instruction does.
79 * IORST clears each line's individual R.I. and T.I.
84 * DIA get multiplexor status word [format defined above]
85 * DOA send character to QTY line [format defined above, RI & SI ]
86 * DIB <ignored> [returns backplane bus noise]
88 * DIC <ignored> [returns backplace bus noise]
90 * 'C' clears global done, then checks for RI and TI;
96 #include "nova_defs.h"
102 #define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */
103 #define UNIT_8B (1 << UNIT_V_8B)
107 extern int32 int_req
, dev_busy
, dev_done
, dev_disable
;
108 extern int32 sim_switches
;
109 extern FILE * sim_log
;
110 extern int32 tmxr_poll
; /* calibrated delay */
112 t_stat
qty_summary ( FILE * st
, UNIT
* uptr
, int32 val
, void * desc
) ;
113 t_stat
qty_show ( FILE * st
, UNIT
* uptr
, int32 val
, void * desc
) ;
114 t_stat
qty_setnl ( UNIT
* uptr
, int32 val
, char * cptr
, void * desc
) ;
116 t_stat
qty_attach ( UNIT
* uptr
, char * cptr
) ;
117 t_stat
qty_detach ( UNIT
* uptr
) ;
118 t_stat
qty_reset ( DEVICE
* dptr
) ;
119 t_stat
qty_svc ( UNIT
* uptr
) ;
120 int32
qty ( int32 pulse
, int32 code
, int32 AC
) ;
122 t_stat
alm_reset ( DEVICE
* dptr
) ;
123 t_stat
alm_svc ( UNIT
* uptr
) ;
124 int32
alm ( int32 pulse
, int32 code
, int32 AC
) ;
129 #define QTY_MAX 64 /* max number of QTY lines - hardware */
132 int32 qty_brkio
= SCPE_OK
; /* default I/O status code */
133 int32 qty_max
= QTY_MAX
; /* max # QTY lines - user */
135 int32 qty_mdm
= 0 ; /* QTY modem control active? */
136 int32 qty_auto
= 0 ; /* QTY auto disconnect active? */
137 int32 qty_polls
= 0 ; /* total 'qty_svc' polls */
140 TMLN qty_ldsc
[ QTY_MAX
] = { 0 } ; /* QTY line descriptors */
141 TMXR qty_desc
= { QTY_MAX
, 0, 0, qty_ldsc
} ; /* mux descriptor */
142 int32 qty_status
[ QTY_MAX
] = { 0 } ; /* QTY line status */
143 /* (must be at least 32 bits) */
144 int32 qty_tx_chr
[ QTY_MAX
] = { 0 } ; /* QTY line output character */
147 /* QTY data structures
149 qty_dev QTY device descriptor
150 qty_unit QTY unit descriptor
151 qty_reg QTY register list
154 DIB qty_dib
= { DEV_QTY
, INT_QTY
, PI_QTY
, &qty
} ;
158 UDATA (&qty_svc
, (UNIT_ATTABLE
), 0)
161 REG qty_nlreg
= { DRDATA (NLINES
, qty_desc
.lines
, 7), PV_LEFT
};
163 REG qty_reg
[] = /* ('alm_reg' should be similar to this except for device code related items) */
165 { ORDATA (BUF
, qty_unit
.buf
, 8) },
166 { FLDATA (BUSY
, dev_busy
, INT_V_QTY
) },
167 { FLDATA (DONE
, dev_done
, INT_V_QTY
) },
168 { FLDATA (DISABLE
, dev_disable
, INT_V_QTY
) },
169 { FLDATA (INT
, int_req
, INT_V_QTY
) },
171 { FLDATA (MDMCTL
, qty_mdm
, 0) },
172 { FLDATA (AUTODS
, qty_auto
, 0) },
173 { DRDATA (POLLS
, qty_polls
, 32) },
179 { UNIT_8B
, 0, "7b", "7B", NULL
},
180 { UNIT_8B
, UNIT_8B
, "8b", "8B", NULL
},
181 { MTAB_XTD
| MTAB_VDV
, 1, NULL
, "DISCONNECT",
182 &tmxr_dscln
, NULL
, &qty_desc
},
183 { UNIT_ATT
, UNIT_ATT
, "connections", NULL
, NULL
, &qty_summary
},
184 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 1, "CONNECTIONS", NULL
,
185 NULL
, &qty_show
, NULL
},
186 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "STATISTICS", NULL
,
187 NULL
, &qty_show
, NULL
},
188 { MTAB_XTD
| MTAB_VDV
| MTAB_VAL
, 0, "lines", "LINES",
189 &qty_setnl
, NULL
, &qty_nlreg
},
195 "QTY", &qty_unit
, qty_reg
, qty_mod
,
197 NULL
, NULL
, &qty_reset
,
198 NULL
, &qty_attach
, &qty_detach
,
199 &qty_dib
, (DEV_DISABLE
| DEV_DIS
| DEV_NET
)
202 #define DG_RETURN( status, data ) (int32)(((status) << IOT_V_REASON) | ((data) & 0x0FFFF) )
205 * QTY_S_xxx QTY device status reference
206 * QTY_L_xxx QTY line status word reference (qty_status[])
209 /*----------------------------------------------*/
210 /* QTY device status */
211 /*----------------------------------------------*/
213 #define QTY_S_RI 0x8000 /* Receiver Interrupt */
214 #define QTY_S_TI 0x4000 /* Transmitter interrupt */
215 #define QTY_S_LMASK 0x3F00 /* line mask */
216 #define QTY_S_DMASK 0x00FF /* data mask (received char) */
220 #define QTY_MASTER_ACTIVE( desc ) ( (desc)->master )
222 #define QTY_LINE_EXTRACT( x ) (((x) & QTY_S_LMASK) >> 8)
224 #define QTY_LINE_TX_CHAR( line ) qty_tx_chr[ ((line) % QTY_MAX) ]
225 #define QTY_LINE_RX_CHAR( line ) (qty_status[ (line) ] & QTY_S_DMASK)
226 #define QTY_UNIT_ACTIVE( unitp ) ( (unitp)->conn )
228 #define QTY_LINE_BITS( line, bits ) qty_status[ (line) ] & bits
230 #define QTY_LINE_SET_BIT( line, bit ) qty_status[ (line) ] |= (bit) ;
231 #define QTY_LINE_CLEAR_BIT( line, bit ) qty_status[ (line) ] &= ~(bit) ;
232 #define QTY_LINE_BIT_SET( line, bit ) (qty_status[ (line) ] & (bit))
235 /*----------------------------------------------*/
236 /* QTY line status */
237 /*----------------------------------------------*/
239 #define QTY_L_RXE 0x800000 /* receiver enabled? */
240 #define QTY_L_RXBZ 0x400000 /* receiver busy? */
241 #define QTY_L_RXDN 0x200000 /* receiver done? */
242 #define QTY_L_TXE 0x080000 /* transmitter enabled? */
243 #define QTY_L_TXBZ 0x040000 /* transmitter busy? */
244 #define QTY_L_TXDN 0x020000 /* transmitter done? */
246 #define QTY_L_BREAK 0x008000 /* BREAK character received */
247 #define QTY_L_RING 0x004000 /* Ring interrupt */
248 #define QTY_L_CD 0x002000 /* Carrier Detect */
249 #define QTY_L_DTR 0x001000 /* Data Terminal Ready */
250 /* <0x00FF = character> */
252 #define QTY_L_LOOPBK 0x00010000 /* loopback mode */
253 #define QTY_L_OVRERR 0x00020000 /* overrun error */
254 #define QTY_L_FRMERR 0x00040000 /* framing error */
255 #define QTY_L_PARERR 0x00080000 /* parity error */
258 /* CD, CTS, DSR, RI */
261 #define QTY_L_MODEM 0x0080 /* <not yet used> */
262 #define QTY_L_TELNET 0x0040 /* <not yet used> */
263 #define QTY_L_AUTODIS 0x0020 /* <not yet used> */
266 #define QTY_L_BAUD /* <4 bits> */
269 #define QTY_L_DMASK 0x000FF /* data mask (always 8 bits) */
271 /* Note: use at least an 'int32' for this guy */
273 /*------------------------------*/
275 /*------------------------------*/
277 int qty_tmxr_putc( int line
, TMLN
* lp
, int kar
)
281 /*----------------------------------------------*/
282 /* Send character to given QTY/telnet line. */
284 /* enter: line QTY line # */
285 /* lp Telnet unit def ptr */
286 /* kar character to send */
288 /* return: SCPE_OK */
291 /*----------------------------------------------*/
293 a
= tmxr_putc_ln( lp
, kar
) ;
296 QTY_LINE_SET_BIT( line
, QTY_L_TXDN
)
297 QTY_LINE_CLEAR_BIT( line
, QTY_L_TXBZ
)
299 else if ( a
== SCPE_STALL
)
302 (should we try to output the buffer
303 and then regroup...?)
305 QTY_LINE_SET_BIT( line
, QTY_L_TXBZ
)
306 QTY_LINE_CLEAR_BIT( line
, QTY_L_TXDN
)
307 QTY_LINE_TX_CHAR( line
) = kar
;
309 else if ( a
== SCPE_LOST
)
311 /* no connection - hangup? */
312 QTY_LINE_SET_BIT( line
, QTY_L_TXBZ
)
313 QTY_LINE_CLEAR_BIT( line
, QTY_L_TXDN
)
314 QTY_LINE_TX_CHAR( line
) = kar
;
317 } /* end of 'qty_tmxr_putc' */
320 /*----------------------------------------------*/
321 /* qty_update_rcvi */
322 /*----------------------------------------------*/
324 int qty_update_rcvi( TMXR
* mp
)
331 /*------------------------------------------------------*/
332 /* Search through connected telnet lines for any input */
335 /* enter: mp master telnet qty desc ptr */
337 /* return: int change count (0 = none seen) */
338 /*------------------------------------------------------*/
340 for ( changes
= line
= 0; line
< mp
->lines
; ++line
)
341 if ( (lp
=mp
->ldsc
+line
)->conn
&& lp
->rcve
)
342 if ( (datum
=tmxr_getc_ln(lp
)) )
344 if ( datum
& SCPE_BREAK
)
346 /* what should we do here - set QTY_L_BREAK? */
347 datum
= datum
& 0x00FF ;
351 datum
= datum
& 0x00FF ;
353 /* <check parity, masking, forced parity, CR/LF xlation> */
355 QTY_LINE_CLEAR_BIT( line
, (QTY_L_RXBZ
| QTY_L_DMASK
) ) ;
356 QTY_LINE_SET_BIT( line
, (QTY_L_RXDN
| datum
) ) ;
360 } /* end of 'qty_update_rcvi' */
363 /*----------------------------------------------*/
364 /* qty_update_xmti */
365 /*----------------------------------------------*/
367 int qty_update_xmti( TMXR
* mp
)
373 /*------------------------------------------------------*/
374 /* Search through connected telnet lines for any de- */
375 /* ferred output activity. */
377 /* enter: mp master telnet qty desc ptr */
379 /* return: int change count (0 = none seen) */
380 /*------------------------------------------------------*/
382 /* any TX DONE flags set
383 * any TX BUSY flags set
386 for ( changes
= line
= 0; line
< mp
->lines
; ++line
)
387 if ( QTY_LINE_BIT_SET(line
,QTY_L_TXBZ
) )
388 if ( (lp
=mp
->ldsc
+line
)->conn
&& lp
->xmte
)
390 /* why are we busy? buffer was full? */
391 /* now some space available - try
392 * to stuff pending character in
393 * buffer and free up the world
395 qty_tmxr_putc( line
, lp
, QTY_LINE_TX_CHAR(line
) ) ;
399 } /* end of 'qty_update_xmti' */
402 /*----------------------------------------------*/
403 /* qty_update_status */
404 /*----------------------------------------------*/
406 int qty_update_status( DIB
* dibp
, TMXR
* tmxr_desc
)
412 /*----------------------------------------------*/
413 /* return global device status for current qty */
416 /* Receiver interrupts have higher priority */
417 /* than transmitter interrupts according to DG */
418 /* but this routine could be modified to use */
419 /* different priority criteria. */
421 /* Round-robin polling could also be used in */
422 /* some future release rather than starting */
423 /* with line 0 each time. */
425 /* Return <QTY_S_RI + line # + character> of */
426 /* first waiting character, else return */
427 /* <QTY_S_TI + line #> of first finished line */
428 /* output, else return 0. */
430 /* This routine does -not- clear input line */
431 /* BZ/DN flags; caller should do this. */
433 /* Global device done and busy flags are */
435 /*----------------------------------------------*/
437 for ( txbusy
= status
= line
= 0 ; line
< qty_max
; ++line
)
439 txbusy
|= (QTY_LINE_BIT_SET(line
,QTY_L_TXBZ
)) ;
440 if ( QTY_LINE_BIT_SET(line
,QTY_L_RXDN
) )
444 status
= QTY_LINE_BITS( line
, QTY_S_DMASK
) | QTY_S_RI
;
445 status
= status
| (line
<< 8) ;
449 else if ( QTY_LINE_BIT_SET(line
,QTY_L_TXDN
) )
451 if ( ! (status
& QTY_S_RI
) )
452 if ( ! (status
& QTY_S_RI
) )
455 status
= status
| (line
<< 8) ;
459 /* <we could check each line for TX busy to set DEV_SET_BUSY)?> */
460 DEV_CLR_BUSY( INT_QTY
) ;
461 DEV_CLR_DONE( INT_QTY
) ;
464 DEV_SET_BUSY( INT_QTY
) ;
466 if ( status
& (QTY_S_RI
| QTY_S_TI
) )
468 DEV_SET_DONE( INT_QTY
) ;
470 DEV_UPDATE_INTR
; /* update final intr status */
472 } /* end of 'qty_update_status' */
475 /*--------------------------------------------------------------*/
477 /*--------------------------------------------------------------*/
479 t_stat
qty_attach( UNIT
* unitp
, char * cptr
)
484 /* switches: A auto-disconnect
488 qty_mdm
= qty_auto
= 0; /* modem ctl off */
489 r
= tmxr_attach( &qty_desc
, unitp
, cptr
) ; /* attach QTY */
492 return ( r
) ; /* error! */
494 if ( sim_switches
& SWMASK('M') ) /* modem control? */
497 printf( "Modem control activated\n" ) ;
498 if ( sim_log
) fprintf( sim_log
, "Modem control activated\n" ) ;
499 if ( sim_switches
& SWMASK ('A') ) /* autodisconnect? */
502 printf( "Auto disconnect activated\n" ) ;
503 if ( sim_log
) fprintf( sim_log
, "Auto disconnect activated\n" ) ;
507 for ( a
= 0 ; a
< QTY_MAX
; ++a
)
509 /* QTY lines are always enabled - force RX and TX to 'enabled' */
510 qty_status
[ a
] = (QTY_L_RXE
| QTY_L_TXE
) ;
512 sim_activate( unitp
, tmxr_poll
) ;
514 } /* end of 'qty_attach' */
517 /*--------------------------------------------------------------*/
519 /*--------------------------------------------------------------*/
521 t_stat
qty_detach( UNIT
* unitp
)
523 sim_cancel( unitp
) ;
524 return ( tmxr_detach(&qty_desc
,unitp
) ) ;
525 } /* end of 'qty_detach' */
528 /*--------------------------------------------------------------*/
530 /*--------------------------------------------------------------*/
532 t_stat
qty_clear( t_bool flag
)
536 for ( line
= 0 ; line
< qty_max
; ++line
)
538 qty_ldsc
[line
].xmte
= 0 ;
539 qty_ldsc
[line
].rcve
= 0 ;
540 if ( ! qty_ldsc
[line
].conn
)
542 qty_ldsc
[line
].xmte
= 1 ; /* set xmt enb */
543 qty_ldsc
[line
].rcve
= 1 ; /* clr rcv enb */
547 } /* end of 'qty_clear' */
550 /*----------------------------------------------*/
551 /* qty_common_reset */
552 /*----------------------------------------------*/
554 t_stat
qty_common_reset( DIB
* dibp
, UNIT
* unitp
, DEVICE
* dptr
)
556 if ((dptr
->flags
& DEV_DIS
) == 0)
558 if (dptr
== &qty_dev
) alm_dev
.flags
|= DEV_DIS
;
559 else qty_dev
.flags
|= DEV_DIS
;
562 DEV_CLR_BUSY( INT_QTY
) ; /* clear busy */
563 DEV_CLR_DONE( INT_QTY
) ; /* clear done, int */
565 if ( QTY_MASTER_ACTIVE(&qty_desc
) )
567 sim_activate( unitp
, tmxr_poll
) ;
571 sim_cancel( unitp
) ;
574 } /* end of 'qty_common_reset' */
577 /*--------------------------------------------------------------*/
579 /*--------------------------------------------------------------*/
581 t_stat
qty_reset( DEVICE
* dptr
)
583 return ( qty_common_reset(&qty_dib
,&qty_unit
,dptr
) ) ;
584 } /* end of 'qty_reset' */
587 /* Unit service routine
589 The QTY/ALM polls to see if asynchronous activity has occurred and now
590 needs to be processed. The polling interval is controlled by the clock
591 simulator, so for most environments, it is calibrated to real time.
593 The simulator assumes that software enables all of the multiplexors,
597 /*----------------------------------------------*/
599 /*----------------------------------------------*/
601 t_stat
qty_common_svc( DIB
* dibp
, UNIT
* unitp
)
607 ++qty_polls
; /* another time 'round the track */
608 newln
= tmxr_poll_conn( &qty_desc
) ; /* anybody knocking at the door? */
609 if ( (newln
>= 0) && qty_mdm
)
610 if ( newln
>= qty_max
)
612 return SCPE_IERR
; /* WTF - sanity check failed, over? */
616 line
= newln
; /* handle modem control */
617 tmlnp
=&qty_ldsc
[ line
] ;
618 tmlnp
->rcve
= tmlnp
->xmte
= 1 ;
619 /* do QTY_LINE_ bit fiddling and state machine
620 * manipulation with modem control signals
624 tmxr_poll_rx( &qty_desc
) ; /* poll input */
625 qty_update_rcvi( &qty_desc
) ; /* update receiver interrupt status */
627 tmxr_poll_tx( &qty_desc
) ; /* poll output */
628 qty_update_xmti( &qty_desc
) ; /* update transmitter interrupt status */
630 qty_update_status( dibp
, &qty_desc
) ; /* update device status */
632 sim_activate( unitp
, tmxr_poll
) ; /* restart the bubble machine */
634 } /* end of 'qty_common_svc' */
637 /*--------------------------------------------------------------*/
639 /*--------------------------------------------------------------*/
641 t_stat
qty_svc( UNIT
* uptr
)
643 return ( qty_common_svc(&qty_dib
,uptr
) ) ;
644 } /* end of 'qty_svc' */
647 /*--------------------------------------------------------------*/
649 /*--------------------------------------------------------------*/
651 int32
qty( int32 pulse
, int32 code
, int32 AC
)
660 /*--------------------------------------------------------------*/
661 /* DG 4060[-compatible] "quad" multiplexor instruction handler */
662 /*--------------------------------------------------------------*/
664 ioresult
= qty_brkio
; /* (assume returning I/O break value */
665 iodata
= 0 ; /* (assume 16-bit Nova/Eclipse bus) */
668 case ioNIO
: /* <no operation> */
671 case ioDIA
: /* get current QTY status */
672 iodata
= qty_update_status( &qty_dib
, &qty_desc
) ;
673 if ( iodata
& QTY_S_RI
)
674 { /* clear line's input buffer */
675 QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(iodata
)), (QTY_L_RXBZ
| QTY_L_RXDN
) )
682 qty_update_status( &qty_dib
, &qty_desc
) ;
685 case ioDOA
: /* send character to QTY */
686 line
= QTY_LINE_EXTRACT( AC
) ;
687 if ( line
< qty_max
)
688 if ( QTY_LINE_BIT_SET(line
,QTY_L_TXE
) )
691 perform any character translation:
695 kar
= AC
& ((qty_unit
.flags
& UNIT_8B
)? 0377: 0177) ;
696 /* do any parity calculations also */
698 tmlnp
= &qty_ldsc
[ line
] ;
699 a
= qty_tmxr_putc( line
, tmlnp
, kar
) ;
702 /* do anything at this point? */
704 qty_update_status( &qty_dib
, &qty_desc
) ;
708 case ioDIB
: /* no QTY function - return bus noise in AC */
711 case ioDOB
: /* clear QTY output channel busy and done flag */
712 QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(AC
)), (QTY_L_TXBZ
| QTY_L_TXDN
) )
713 qty_update_status( &qty_dib
, &qty_desc
) ;
716 case ioDIC
: /* no QTY function - return bus noise in AC */
719 case ioDOC
: /* no QTY function - ignore */
722 case ioSKP
: /* I/O skip test - should never come here */
726 /* <illegal I/O operation value> */
732 case iopN
: /* <ignored (of course)> */
735 case iopS
: /* <ignored> */
738 case iopP
: /* <ignored> */
742 qty_update_status( &qty_dib
, &qty_desc
) ;
746 /* <illegal pulse value> */
750 return ( DG_RETURN( ioresult
, iodata
) ) ;
753 /*--------------------------------------------------------------*/
755 /*--------------------------------------------------------------*/
757 t_stat
qty_summary( FILE * st
, UNIT
* uptr
, int32 val
, void * desc
)
761 for (i
= t
= 0 ; i
< qty_desc
.lines
; ++i
)
762 if ( qty_ldsc
[i
].conn
)
766 fprintf( st
, "%d connection%s", t
, ((t
)? "s" : "") ) ;
768 } /* end of 'qty_summ' */
771 /*--------------------------------------------------------------*/
773 /*--------------------------------------------------------------*/
775 t_stat
qty_show( FILE * st
, UNIT
* uptr
, int32 val
, void * desc
)
779 for (i
= t
= 0 ; i
< qty_desc
.lines
; ++i
)
780 if ( qty_ldsc
[i
].conn
)
785 tmxr_fconns( st
, &qty_ldsc
[i
], i
) ;
789 tmxr_fstats( st
, &qty_ldsc
[i
], i
) ;
792 if ( t
== 0 ) fprintf( st
, "none connected\n" ) ;
794 } /* end of 'qty_show' */
797 /*--------------------------------------------------------------*/
799 /*--------------------------------------------------------------*/
801 t_stat
qty_setnl( UNIT
* uptr
, int32 val
, char * cptr
, void * desc
)
808 return ( SCPE_ARG
) ;
810 newln
= (int32
) get_uint( cptr
, 10, QTY_MAX
, &r
) ;
811 if ( (r
!= SCPE_OK
) || (newln
== qty_desc
.lines
) )
815 if ( (newln
== 0) || (newln
> QTY_MAX
) )
817 return ( SCPE_ARG
) ;
819 if ( newln
< qty_desc
.lines
)
821 for ( i
= newln
, t
= 0 ; i
< qty_desc
.lines
; ++i
)
823 t
= t
| qty_ldsc
[i
].conn
;
825 if ( t
&& ! get_yn("This will disconnect users; proceed [N]?", FALSE
) )
829 for ( i
= newln
; i
< qty_desc
.lines
; ++i
)
831 if ( qty_ldsc
[i
].conn
)
833 tmxr_msg( qty_ldsc
[i
].conn
, "\r\nOperator disconnected line\r\n" ) ;
834 tmxr_reset_ln( &qty_ldsc
[i
] ) ;
836 qty_clear( TRUE
) ; /* reset mux */
839 qty_max
= qty_desc
.lines
= newln
;
840 /* Huh, I don't understand this yet...
841 qty_max = ((qty_dev.flags & DEV_DIS)? 0 : (qty_desc.lines / QTY_MAX)) ;
844 } /* end of 'qty_setnl' */
847 /*----------------------------------------------------------------------*/
848 /* ALM [425x-compatible] multiplexor */
849 /*----------------------------------------------------------------------*/
852 * device code: 034 [primary],
854 * interrupt mask: B14 [000002]
857 * ALM [4255-4258] I/O instructions
859 * DIA read line and section requesting service
860 * DOA select line and section (lines 0-255, 8-bits) + rcvr/xmit
862 * DOB 00 transmit data
864 * 10 set modem control status
866 * DIC read receiver or modem status
867 * DOC 00 control line section and diag mode
869 * 10 specify line characteristics
872 * undocumented DG "features":
874 * NIOS sets board offline
875 * NIOC sets board online
876 * Modem control signal state change can signal interrupt
877 * explicit line select with DOA
878 * implicit line select with DIA
880 * We support 64 lines maximum in this release although some ALM's could
881 * theoretically support up to 256.
885 DIB alm_dib
= { DEV_ALM
, INT_ALM
, PI_ALM
, &alm
} ;
888 UDATA (&alm_svc
, (UNIT_ATTABLE
), 0)
891 REG alm_reg
[] = /* ('qty_reg' should be similar to this except for device code related items) */
893 { ORDATA (BUF
, alm_unit
.buf
, 8) },
894 { FLDATA (BUSY
, dev_busy
, INT_V_ALM
) },
895 { FLDATA (DONE
, dev_done
, INT_V_ALM
) },
896 { FLDATA (DISABLE
, dev_disable
, INT_V_ALM
) },
897 { FLDATA (INT
, int_req
, INT_V_ALM
) },
899 { FLDATA (MDMCTL
, qty_mdm
, 0) },
900 { FLDATA (AUTODS
, qty_auto
, 0) },
901 { DRDATA (POLLS
, qty_polls
, 32) },
907 "ALM", &alm_unit
, alm_reg
, qty_mod
,
909 NULL
, NULL
, &alm_reset
,
910 NULL
, &qty_attach
, &qty_detach
,
911 &alm_dib
, (DEV_DISABLE
| DEV_NET
)
914 int alm_section
= -1 ; /* current line "section" (0 = RCV, 1 = XMT) */
915 int alm_line
= -1 ; /* current line [0-63] */
916 int alm_diag_mode
= 0 ; /* <not yet supported> */
917 int alm_line_mask
= 0x003F ; /* maximum of 64 lines in this rev */
920 #define ALM_LINE_EXTRACT( x ) (((x) >> 1) & alm_line_mask)
921 #define ALM_SECT_EXTRACT( x ) ((x) & 0x0001)
924 /*--------------------------------------------------------------*/
926 /*--------------------------------------------------------------*/
928 t_stat
alm_reset( DEVICE
* dptr
)
930 return ( qty_common_reset(&alm_dib
,&alm_unit
,dptr
) ) ;
931 } /* end of 'alm_reset' */
934 /*--------------------------------------------------------------*/
936 /*--------------------------------------------------------------*/
938 t_stat
alm_svc( UNIT
* uptr
)
940 return ( qty_common_svc(&alm_dib
,uptr
) ) ;
941 } /* end of 'alm_svc' */
944 /*--------------------------------------------------------------*/
946 /*--------------------------------------------------------------*/
948 int32
alm( int32 pulse
, int32 code
, int32 AC
)
956 /*--------------------------------------------------------------*/
957 /* DG 425x[-compatible] "ALM" multiplexor instruction handler */
958 /*--------------------------------------------------------------*/
960 ioresult
= qty_brkio
; /* (assume returning I/O break value */
961 iodata
= 0 ; /* (assume 16-bit Nova/Eclipse bus) */
964 case ioNIO
: /* <no operation> */
967 case ioDIA
: /* read line and section requesting service */
968 iodata
= qty_update_status( &alm_dib
, &qty_desc
) ;
969 alm_line
= (QTY_LINE_EXTRACT(iodata
) & alm_line_mask
) ;
970 /* (mask with 'alm_line_mask' in case ALM mask is different than QTY */
972 if ( ! ( iodata
& QTY_S_RI
) )
973 if ( iodata
& QTY_S_TI
)
975 alm_section
= 1 ; /* receiver quiet - transmitter done */
977 iodata
= (alm_line
<< 1) | alm_section
;
980 case ioDOA
: /* set line and section */
981 alm_section
= ALM_SECT_EXTRACT( AC
) ;
982 alm_line
= ALM_LINE_EXTRACT( AC
) ;
985 case ioDIB
: /* no ALM function - return bus noise in AC */
986 if ( alm_line
< qty_max
)
988 iodata
= QTY_LINE_RX_CHAR( alm_line
) ;
992 case ioDOB
: /* output and modem control functions */
993 switch ( (AC
>> 14) & 03 )
995 case 00 : /* transmit data */
996 if ( alm_line
< qty_max
)
997 if ( QTY_LINE_BIT_SET(alm_line
,QTY_L_TXE
) )
1000 perform any character translation:
1004 kar
= AC
& ((alm_unit
.flags
& UNIT_8B
)? 0377: 0177) ;
1005 /* do any parity calculations also */
1007 tmlnp
= &qty_ldsc
[ alm_line
] ;
1008 a
= qty_tmxr_putc( alm_line
, tmlnp
, kar
) ;
1011 /* do anything at this point? */
1013 qty_update_status( &alm_dib
, &qty_desc
) ;
1017 case 01 : /* transmit break */
1018 if ( alm_line
< qty_max
)
1019 if ( QTY_LINE_BIT_SET(alm_line
,QTY_L_TXE
) )
1021 tmlnp
= &qty_ldsc
[ alm_line
] ;
1023 a = qty_tmxr_putc( alm_line, tmlnp, kar ) ;
1028 qty_update_status( &alm_dib
, &qty_desc
) ;
1032 case 02 : /* set modem control status */
1035 case 03 : /* unused */
1040 case ioDIC
: /* get modem or receiver status */
1041 if ( alm_line
< qty_max
)
1044 /* get modem section status */
1045 if ( qty_ldsc
[ alm_line
].xmte
)
1047 iodata
= 0035 ; /* set CD, CTS, DSR, MDM flags */
1052 /* get receiver section status */
1053 iodata
= 0 ; /* receiver error status - no errors by default */
1057 case ioDOC
: /* set line attributes */
1058 switch ( (AC
>> 14) & 03 )
1060 case 00 : /* control line section */
1063 case 01 : /* unused */
1066 case 02 : /* set line characteristics */
1069 case 03 : /* unused */
1074 case ioSKP
: /* I/O skip test - should never come here */
1078 /* <illegal I/O operation value> */
1084 case iopN
: /* <ignored (of course)> */
1087 case iopS
: /* set device busy
1088 * set all lines on board offline
1089 * clear each line's done
1090 * clear internal system
1093 for ( a
= 0 ; a
< qty_max
; ++a
)
1094 if ( 1 /* (not yet optimized) */ )
1096 QTY_LINE_CLEAR_BIT( a
, (QTY_L_RXBZ
| QTY_L_RXDN
| QTY_L_TXBZ
| QTY_L_TXDN
) ) ;
1098 qty_update_status( &alm_dib
, &qty_desc
) ;
1101 case iopP
: /* stop clock for all boards in off-line mode */
1105 for ( a
= 0 ; a
< qty_max
; ++a
)
1106 if ( 1 /* (not yet optimized) */ )
1108 QTY_LINE_CLEAR_BIT( a
, (QTY_L_RXBZ
| QTY_L_RXDN
| QTY_L_TXBZ
| QTY_L_TXDN
) ) ;
1110 qty_update_status( &alm_dib
, &qty_desc
) ;
1114 /* <illegal pulse value> */
1118 return ( DG_RETURN( ioresult
, iodata
) ) ;
1119 } /* end of 'alm' */