First Commit of my working state
[simh.git] / NOVA / nova_tt.c
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
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
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
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
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
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
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
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 }