1 /* nova_tt.c: NOVA console terminal simulator
2 
3    Copyright (c) 1993-2008, Robert M. Supnik
4 
5    Permission is hereby granted, free of charge, to any person obtaining a
6    copy of this software and associated documentation files (the "Software"),
7    to deal in the Software without restriction, including without limitation
8    the rights to use, copy, modify, merge, publish, distribute, sublicense,
9    and/or sell copies of the Software, and to permit persons to whom the
10    Software is furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be included in
13    all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18    ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22    Except as contained in this notice, the name of Robert M Supnik shall not be
23    used in advertising or otherwise to promote the sale, use or other dealings
24    in this Software without prior written authorization from Robert M Supnik.
25 
26    tti          terminal input
27    tto          terminal output
28 
29    04-Jul-07    BKR     fixed Dasher CR/LF swap function in 'tti_svc()',
30                         DEV_SET/CLR macros now used,
31                         TTO device may now be DISABLED
32    29-Dec-03    RMS     Added console backpressure support
33    25-Apr-03    RMS     Revised for extended file support
34    05-Jan-02    RMS     Fixed calling sequence for setmod
35    03-Oct-02    RMS     Added DIBs
36    30-May-02    RMS     Widened POS to 32b
37    30-Nov-01    RMS     Added extended SET/SHOW support
38    17-Sep-01    RMS     Removed multiconsole support
39    07-Sep-01    RMS     Moved function prototypes
40    31-May-01    RMS     Added multiconsole support
41 
42    Notes:
43     - TTO output is always masked to 7 bits in this rev
44     - TTO "Dasher" attribute sends '\b' to console instead of '\031'
45     - TTO may be disabled
46     - TTI input is always masked to 7 bits in this rev
47     - TTI "Dasher" attribute swaps <CR> and <LF>
48     - TTI may not be disabled
49 */
50 
51 #include "nova_defs.h"
52 
53 #define UNIT_V_DASHER   (UNIT_V_UF + 0)                 /* Dasher mode */
54 #define UNIT_DASHER     (1 << UNIT_V_DASHER)
55 
56 extern int32 int_req, dev_busy, dev_done, dev_disable;
57 
58 int32 tti (int32 pulse, int32 code, int32 AC);
59 int32 tto (int32 pulse, int32 code, int32 AC);
60 t_stat tti_svc (UNIT *uptr);
61 t_stat tto_svc (UNIT *uptr);
62 t_stat tti_reset (DEVICE *dptr);
63 t_stat tto_reset (DEVICE *dptr);
64 t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr, void *desc);
65 
66 /* TTI data structures
67 
68    tti_dev      TTI device descriptor
69    tti_unit     TTI unit descriptor
70    tti_reg      TTI register list
71    ttx_mod      TTI/TTO modifiers list
72 */
73 
74 DIB tti_dib = { DEV_TTI, INT_TTI, PI_TTI, &tti };
75 
76 UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
77 
78 REG tti_reg[] = {
79     { ORDATA (BUF, tti_unit.buf, 8) },
80     { FLDATA (BUSY, dev_busy, INT_V_TTI) },
81     { FLDATA (DONE, dev_done, INT_V_TTI) },
82     { FLDATA (DISABLE, dev_disable, INT_V_TTI) },
83     { FLDATA (INT, int_req, INT_V_TTI) },
84     { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
85     { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
86     { NULL }
87     };
88 
89 MTAB ttx_mod[] = {
90     { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod },
91     { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod },
92     { 0 }
93     } ;
94 
95 DEVICE tti_dev = {
96     "TTI", &tti_unit, tti_reg, ttx_mod,
97     1, 10, 31, 1, 8, 8,
98     NULL, NULL, &tti_reset,
99     NULL, NULL, NULL,
100     &tti_dib, 0
101     };
102 
103 /* TTO data structures
104 
105    tto_dev      TTO device descriptor
106    tto_unit     TTO unit descriptor
107    tto_reg      TTO register list
108 */
109 
110 DIB tto_dib = { DEV_TTO, INT_TTO, PI_TTO, &tto };
111 
112 UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
113 
114 REG tto_reg[] = {
115     { ORDATA (BUF, tto_unit.buf, 8) },
116     { FLDATA (BUSY, dev_busy, INT_V_TTO) },
117     { FLDATA (DONE, dev_done, INT_V_TTO) },
118     { FLDATA (DISABLE, dev_disable, INT_V_TTO) },
119     { FLDATA (INT, int_req, INT_V_TTO) },
120     { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
121     { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
122     { NULL }
123     };
124 
125 DEVICE tto_dev = {
126     "TTO", &tto_unit, tto_reg, ttx_mod,
127     1, 10, 31, 1, 8, 8,
128     NULL, NULL, &tto_reset,
129     NULL, NULL, NULL,
130     &tto_dib, DEV_DISABLE
131     };
132 
133 /* Terminal input: IOT routine */
134 
tti(int32 pulse,int32 code,int32 AC)135 int32 tti (int32 pulse, int32 code, int32 AC)
136 {
137 int32 iodata;
138 
139 
140 if (code == ioDIA)
141     iodata = tti_unit.buf & 0377;
142 else iodata = 0;
143 
144 switch (pulse)
145     {                                                   /* decode IR<8:9> */
146   case iopS:                                            /* start */
147     DEV_SET_BUSY( INT_TTI ) ;
148     DEV_CLR_DONE( INT_TTI ) ;
149     DEV_UPDATE_INTR ;
150     break;
151 
152   case iopC:                                            /* clear */
153     DEV_CLR_BUSY( INT_TTI ) ;
154     DEV_CLR_DONE( INT_TTI ) ;
155     DEV_UPDATE_INTR ;
156     break;
157     }                                                   /* end switch */
158 
159 return iodata;
160 }
161 
162 /* Unit service */
163 
tti_svc(UNIT * uptr)164 t_stat tti_svc (UNIT *uptr)
165 {
166 int32 temp;
167 
168 sim_activate (&tti_unit, tti_unit.wait);                /* continue poll */
169 if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
170     return temp;                                        /* no char or error? */
171 tti_unit.buf = temp & 0177;
172 if (tti_unit.flags & UNIT_DASHER) {
173     if (tti_unit.buf == '\r')
174         tti_unit.buf = '\n';                            /* Dasher: cr -> nl */
175     else if (tti_unit.buf == '\n')
176         tti_unit.buf = '\r' ;                           /* Dasher: nl -> cr */
177     }
178 DEV_CLR_BUSY( INT_TTI ) ;
179 DEV_SET_DONE( INT_TTI ) ;
180 DEV_UPDATE_INTR ;
181 ++(uptr->pos) ;
182 return SCPE_OK;
183 }
184 
185 /* Reset routine */
186 
tti_reset(DEVICE * dptr)187 t_stat tti_reset (DEVICE *dptr)
188 {
189 tti_unit.buf = 0;                                       /* <not DG compatible>  */
190 DEV_CLR_BUSY( INT_TTI ) ;
191 DEV_CLR_DONE( INT_TTI ) ;
192 DEV_UPDATE_INTR ;
193 sim_activate (&tti_unit, tti_unit.wait);                /* activate unit */
194 return SCPE_OK;
195 }
196 
197 /* Terminal output: IOT routine */
198 
tto(int32 pulse,int32 code,int32 AC)199 int32 tto (int32 pulse, int32 code, int32 AC)
200 {
201 if (code == ioDOA)
202     tto_unit.buf = AC & 0377;
203 
204 switch (pulse)
205     {                                                   /* decode IR<8:9> */
206   case iopS:                                            /* start */
207     DEV_SET_BUSY( INT_TTO ) ;
208     DEV_CLR_DONE( INT_TTO ) ;
209     DEV_UPDATE_INTR ;
210     sim_activate (&tto_unit, tto_unit.wait);            /* activate unit */
211     break;
212 
213   case iopC:                                            /* clear */
214     DEV_CLR_BUSY( INT_TTO ) ;
215     DEV_CLR_DONE( INT_TTO ) ;
216     DEV_UPDATE_INTR ;
217     sim_cancel (&tto_unit);                             /* deactivate unit */
218     break;
219     }                                                   /* end switch */
220 return 0;
221 }
222 
223 
224 /* Unit service */
225 
tto_svc(UNIT * uptr)226 t_stat tto_svc (UNIT *uptr)
227 {
228 int32   c;
229 t_stat  r;
230 
231 c = tto_unit.buf & 0177;
232 if ((tto_unit.flags & UNIT_DASHER) && (c == 031))
233     c = '\b';
234 if ((r = sim_putchar_s (c)) != SCPE_OK) {               /* output; error? */
235     sim_activate (uptr, uptr->wait);                    /* try again */
236     return ((r == SCPE_STALL)? SCPE_OK : r);            /* !stall? report */
237     }
238 DEV_CLR_BUSY( INT_TTO ) ;
239 DEV_SET_DONE( INT_TTO ) ;
240 DEV_UPDATE_INTR ;
241 ++(tto_unit.pos);
242 return SCPE_OK;
243 }
244 
245 /* Reset routine */
246 
tto_reset(DEVICE * dptr)247 t_stat tto_reset (DEVICE *dptr)
248 {
249 tto_unit.buf = 0;                                       /* <not DG compatible!>  */
250 DEV_CLR_BUSY( INT_TTO ) ;
251 DEV_CLR_DONE( INT_TTO ) ;
252 DEV_UPDATE_INTR ;
253 sim_cancel (&tto_unit);                                 /* deactivate unit */
254 return SCPE_OK;
255 }
256 
ttx_setmod(UNIT * uptr,int32 val,char * cptr,void * desc)257 t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr, void *desc)
258 {
259 tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | val;
260 tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | val;
261 return SCPE_OK;
262 }
263