First Commit of my working state
[simh.git] / NOVA / eclipse_tt.c
1 /* eclipse_tt.c: Eclipse console terminal simulator
2
3 Copyright (c) 1998-2005, Charles E Owen
4 Portions copyright (c) 1993-2002, Robert M Supnik
5 Written by Charles Owen, used by gracious permission
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 and/or sell copies of the Software, and to permit persons to whom the
12 Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 Except as contained in this notice, the name of the author shall not be
25 used in advertising or otherwise to promote the sale, use or other dealings
26 in this Software without prior written authorization from the author.
27
28 tti terminal input
29 tto terminal output
30
31 25-Apr-03 RMS Revised for extended file support
32 03-Oct-02 RMS Added DIBs
33 30-May-02 RMS Widened POS to 32b
34 28-Jan-02 RMS Cleaned up compiler warnings
35 */
36
37 #include "nova_defs.h"
38
39 #define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */
40 #define UNIT_DASHER (1 << UNIT_V_DASHER)
41
42 extern int32 int_req, dev_busy, dev_done, dev_disable;
43
44 int32 tti (int32 pulse, int32 code, int32 AC);
45 int32 tto (int32 pulse, int32 code, int32 AC);
46 t_stat tti_svc (UNIT *uptr);
47 t_stat tto_svc (UNIT *uptr);
48 t_stat tti_reset (DEVICE *dptr);
49 t_stat tto_reset (DEVICE *dptr);
50 t_stat ttx_setmod (UNIT *uptr, int32 value, char *cptr, void *desc);
51 void translate_in();
52 int32 translate_out(int32 c);
53 int32 putseq(char *seq);
54
55 /* TTI data structures
56
57 tti_dev TTI device descriptor
58 tti_unit TTI unit descriptor
59 tti_reg TTI register list
60 ttx_mod TTI/TTO modifiers list
61 */
62
63 DIB tti_dib = { DEV_TTI, INT_TTI, PI_TTI, &tti };
64
65 UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
66
67 REG tti_reg[] = {
68 { ORDATA (BUF, tti_unit.buf, 8) },
69 { FLDATA (BUSY, dev_busy, INT_V_TTI) },
70 { FLDATA (DONE, dev_done, INT_V_TTI) },
71 { FLDATA (DISABLE, dev_disable, INT_V_TTI) },
72 { FLDATA (INT, int_req, INT_V_TTI) },
73 { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
74 { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
75 { NULL }
76 };
77
78 MTAB ttx_mod[] = {
79 { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod },
80 { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod },
81 { 0 }
82 };
83
84 DEVICE tti_dev = {
85 "TTI", &tti_unit, tti_reg, ttx_mod,
86 1, 10, 31, 1, 8, 8,
87 NULL, NULL, &tti_reset,
88 NULL, NULL, NULL,
89 &tti_dib, 0
90 };
91
92 /* TTO data structures
93
94 tto_dev TTO device descriptor
95 tto_unit TTO unit descriptor
96 tto_reg TTO register list
97 */
98
99 DIB tto_dib = { DEV_TTO, INT_TTO, PI_TTO, &tto };
100
101 UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
102
103 REG tto_reg[] = {
104 { ORDATA (BUF, tto_unit.buf, 8) },
105 { FLDATA (BUSY, dev_busy, INT_V_TTO) },
106 { FLDATA (DONE, dev_done, INT_V_TTO) },
107 { FLDATA (DISABLE, dev_disable, INT_V_TTO) },
108 { FLDATA (INT, int_req, INT_V_TTO) },
109 { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
110 { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
111 { NULL }
112 };
113
114 DEVICE tto_dev = {
115 "TTO", &tto_unit, tto_reg, ttx_mod,
116 1, 10, 31, 1, 8, 8,
117 NULL, NULL, &tto_reset,
118 NULL, NULL, NULL,
119 &tto_dib, 0
120 };
121
122
123
124 /* Terminal input: IOT routine */
125
126 int32 tti (int32 pulse, int32 code, int32 AC)
127 {
128 int32 iodata;
129
130 iodata = (code == ioDIA)? tti_unit.buf & 0377: 0;
131 switch (pulse) { /* decode IR<8:9> */
132
133 case iopS: /* start */
134 dev_busy = dev_busy | INT_TTI; /* set busy */
135 dev_done = dev_done & ~INT_TTI; /* clear done, int */
136 int_req = int_req & ~INT_TTI;
137 break;
138
139 case iopC: /* clear */
140 dev_busy = dev_busy & ~INT_TTI; /* clear busy */
141 dev_done = dev_done & ~INT_TTI; /* clear done, int */
142 int_req = int_req & ~INT_TTI;
143 break;
144 } /* end switch */
145
146 return iodata;
147 }
148
149 /* Unit service */
150
151 t_stat tti_svc (UNIT *uptr)
152 {
153 int32 temp;
154
155 sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
156 if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
157 tti_unit.buf = temp & 0177;
158 /* --- BEGIN MODIFIED CODE --- */
159 if (tti_unit.flags & UNIT_DASHER) /* translate input */
160 translate_in();
161 /* --- END MODIFIED CODE --- */
162 dev_busy = dev_busy & ~INT_TTI; /* clear busy */
163 dev_done = dev_done | INT_TTI; /* set done */
164 int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
165 tti_unit.pos = tti_unit.pos + 1;
166 return SCPE_OK;
167 }
168
169 /* -------------------- BEGIN INSERTION -----------------------*/
170
171 int curpos = 0; /* used by translate_out() */
172 int row = 0, col = 0; /* ditto - for cursor positioning */
173 int spec200 = 0; /* signals next char is 'special' */
174
175 /* Translation: VT100 input to D200 keycodes. */
176
177 void translate_in()
178 {
179 char rev = 0;
180
181 if (tti_unit.buf == '\r')
182 rev = '\n';
183 if (tti_unit.buf == '\n')
184 rev = '\r';
185 if (rev)
186 tti_unit.buf = rev;
187 }
188
189 /* -------------------- END INSERTION -----------------------*/
190
191 /* Reset routine */
192
193 t_stat tti_reset (DEVICE *dptr)
194 {
195 tti_unit.buf = 0;
196 dev_busy = dev_busy & ~INT_TTI; /* clear busy */
197 dev_done = dev_done & ~INT_TTI; /* clear done, int */
198 int_req = int_req & ~INT_TTI;
199 sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
200 return SCPE_OK;
201 }
202
203 /* Terminal output: IOT routine */
204
205 int32 tto (int32 pulse, int32 code, int32 AC)
206 {
207 if (code == ioDOA) tto_unit.buf = AC & 0377;
208 switch (pulse) { /* decode IR<8:9> */
209
210 case iopS: /* start */
211 dev_busy = dev_busy | INT_TTO; /* set busy */
212 dev_done = dev_done & ~INT_TTO; /* clear done, int */
213 int_req = int_req & ~INT_TTO;
214 sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
215 break;
216
217 case iopC: /* clear */
218 dev_busy = dev_busy & ~INT_TTO; /* clear busy */
219 dev_done = dev_done & ~INT_TTO; /* clear done, int */
220 int_req = int_req & ~INT_TTO;
221 sim_cancel (&tto_unit); /* deactivate unit */
222 break;
223 } /* end switch */
224
225 return 0;
226 }
227
228 /* Unit service */
229
230 t_stat tto_svc (UNIT *uptr)
231 {
232 int32 c, temp;
233
234 dev_busy = dev_busy & ~INT_TTO; /* clear busy */
235 dev_done = dev_done | INT_TTO; /* set done */
236 int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
237 c = tto_unit.buf & 0177;
238 /* --- BEGIN MODIFIED CODE --- */
239 if (tto_unit.flags & UNIT_DASHER) {
240 if ((temp = translate_out(c)) != SCPE_OK) return temp;
241 } else {
242 if ((temp = sim_putchar (c)) != SCPE_OK) return temp;
243 tto_unit.pos = tto_unit.pos + 1;
244 }
245 /* --- END MODIFIED CODE --- */
246 return SCPE_OK;
247 }
248
249 /* -------------------- BEGIN INSERTION -----------------------*/
250
251 /* Translation routine - D200 screen controls to VT-100 controls. */
252
253 int32 translate_out(int32 c)
254 {
255 int32 temp;
256 char outstr[32];
257
258 if (spec200 == 1) { /* Special terminal control seq */
259 spec200 = 0;
260 switch (c) {
261 case 'C': /* read model ID */
262 return SCPE_OK;
263 case 'E': /* Reverse video off */
264 return SCPE_OK;
265 case 'D': /* Reverse video on */
266 return SCPE_OK;
267 default:
268 return SCPE_OK;
269 }
270 }
271 if (curpos == 1) { /* 2nd char of cursor position */
272 col = c & 0x7f;
273 curpos++;
274 return (SCPE_OK);
275 }
276 if (curpos == 2) { /* 3rd char of cursor position */
277 row = c & 0x7f;
278 curpos = 0;
279 sprintf(outstr, "\033[%d;%dH", row+1, col+1);
280 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
281 return (SCPE_OK);
282 }
283 switch (c) { /* Single-char command or data */
284 case 003: /* Blink enable */
285 break;
286 case 004: /* Blink disable */
287 break;
288 case 005: /* Read cursor address */
289 break;
290 case 010: /* Cursor home */
291 sprintf(outstr, "\033[1;1H");
292 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
293 row = col = 0;
294 return (SCPE_OK);
295 case 012: /* Newline */
296 if ((temp = sim_putchar('\r')) != SCPE_OK) return temp;
297 tto_unit.pos += 1;
298 if ((temp = sim_putchar(c)) != SCPE_OK) return temp;
299 tto_unit.pos += 1;
300 col = 1;
301 row++;
302 if (row > 24) row = 1;
303 return (SCPE_OK);
304 case 013: /* Erase EOL */
305 sprintf(outstr, "\033[K");
306 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
307 return (SCPE_OK);
308 case 014: /* Erase screen */
309 sprintf(outstr, "\033[1;1H\033[2J");
310 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
311 row = col = 0;
312 return (SCPE_OK);
313 case 015: /* CR */
314 if ((temp = sim_putchar(c)) != SCPE_OK) return temp;
315 tto_unit.pos += 1;
316 col = 1;
317 return (SCPE_OK);
318 case 016: /* Blink On */
319 sprintf(outstr, "\033[5m");
320 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
321 return (SCPE_OK);
322 case 017: /* Blink off */
323 sprintf(outstr, "\033[25m");
324 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
325 return (SCPE_OK);
326 case 020: /* Write cursor address */
327 curpos = 1;
328 return SCPE_OK;
329 case 024: /* underscore on */
330 sprintf(outstr, "\033[4m");
331 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
332 return (SCPE_OK);
333 case 025: /* underscore off */
334 sprintf(outstr, "\033[24m");
335 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
336 return (SCPE_OK);
337 break;
338 case 027: /* cursor up */
339 sprintf(outstr, "\033[A");
340 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
341 row--;
342 if (row < 1) row = 24;
343 return (SCPE_OK);
344 case 030: /* cursor right */
345 sprintf(outstr, "\033[C");
346 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
347 col++;
348 if (col > 80) {
349 col = 1;
350 row++;
351 if (row > 24) row = 1;
352 }
353 return (SCPE_OK);
354 case 031: /* Cursor left */
355 sprintf(outstr, "\033[D");
356 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
357 tto_unit.pos += 1;
358 col--;
359 if (col < 1) {
360 col = 80;
361 row--;
362 if (row < 1) row = 24;
363 }
364 return (SCPE_OK);
365 case 032: /* Cursor down */
366 sprintf(outstr, "\033[B");
367 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
368 row++;
369 if (row > 24) row = 1;
370 return (SCPE_OK);
371 case 034: /* Dim on */
372 sprintf(outstr, "\033[22m");
373 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
374 return (SCPE_OK);
375 case 035: /* Dim off */
376 sprintf(outstr, "\033[1m");
377 if ((temp = putseq(outstr)) != SCPE_OK) return temp;
378 return (SCPE_OK);
379 case 036: /* Special sequence */
380 spec200 = 1;
381 return SCPE_OK;
382 default: /* ..A character of data */
383 if ((temp = sim_putchar(c)) != SCPE_OK) return temp;
384 tto_unit.pos += 1;
385 col++;
386 if (col > 80) {
387 col = 1;
388 row++;
389 if (row > 24) row = 24;
390 }
391 return (SCPE_OK);
392 }
393 return SCPE_OK;
394 }
395
396 int32 putseq(char *seq)
397 {
398 int i, len, temp;
399
400 len = strlen(seq);
401 for (i = 0; i < len; i++) {
402 if ((temp = sim_putchar(seq[i])) != SCPE_OK)
403 return temp;
404 tto_unit.pos += 1;
405 }
406 return SCPE_OK;
407 }
408
409 /* -------------------- END INSERTION -----------------------*/
410
411 /* Reset routine */
412
413 t_stat tto_reset (DEVICE *dptr)
414 {
415 tto_unit.buf = 0;
416 dev_busy = dev_busy & ~INT_TTO; /* clear busy */
417 dev_done = dev_done & ~INT_TTO; /* clear done, int */
418 int_req = int_req & ~INT_TTO;
419 sim_cancel (&tto_unit); /* deactivate unit */
420 return SCPE_OK;
421 }
422
423 t_stat ttx_setmod (UNIT *uptr, int32 value, char *cptr, void *desc)
424 {
425 tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | value;
426 tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | value;
427 return SCPE_OK;
428 }