First Commit of my working state
[simh.git] / Interdata / id_tt.c
CommitLineData
196ba1fc
PH
1/* id_tt.c: Interdata teletype\r
2\r
3 Copyright (c) 2000-2007, Robert M. Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 tt console\r
27\r
28 18-Jun-07 RMS Added UNIT_IDLE flag to console input\r
29 18-Oct-06 RMS Sync keyboard to LFC clock\r
30 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode\r
31 22-Nov-05 RMS Revised for new terminal processing routines\r
32 29-Dec-03 RMS Added support for console backpressure\r
33 25-Apr-03 RMS Revised for extended file support\r
34 11-Jan-03 RMS Added TTP support\r
35 22-Dec-02 RMS Added break support\r
36*/\r
37\r
38#include "id_defs.h"\r
39#include <ctype.h>\r
40\r
41/* Device definitions */\r
42\r
43#define TTI 0\r
44#define TTO 1\r
45\r
46#define STA_OVR 0x80 /* overrun */\r
47#define STA_BRK 0x20 /* break */\r
48#define STA_MASK (STA_OVR | STA_BRK | STA_BSY) /* status mask */\r
49#define SET_EX (STA_OVR | STA_BRK) /* set EX */\r
50\r
51#define CMD_V_FDPX 4 /* full/half duplex */\r
52#define CMD_V_RD 2 /* read/write */\r
53\r
54extern uint32 int_req[INTSZ], int_enb[INTSZ];\r
55extern int32 lfc_poll;\r
56\r
57uint32 tt_sta = STA_BSY; /* status */\r
58uint32 tt_fdpx = 1; /* tt mode */\r
59uint32 tt_rd = 1, tt_chp = 0; /* tt state */\r
60uint32 tt_arm = 0; /* int arm */\r
61\r
62uint32 tt (uint32 dev, uint32 op, uint32 dat);\r
63t_stat tti_svc (UNIT *uptr);\r
64t_stat tto_svc (UNIT *uptr);\r
65t_stat tt_reset (DEVICE *dptr);\r
66t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);\r
67t_stat tt_set_break (UNIT *uptr, int32 val, char *cptr, void *desc);\r
68t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc);\r
69\r
70/* TT data structures\r
71\r
72 tt_dev TT device descriptor\r
73 tt_unit TT unit descriptors\r
74 tt_reg TT register list\r
75 tt_mod TT modifiers list\r
76*/\r
77\r
78DIB tt_dib = { d_TT, -1, v_TT, NULL, &tt, NULL };\r
79\r
80UNIT tt_unit[] = {\r
81 { UDATA (&tti_svc, TT_MODE_KSR|UNIT_IDLE, 0), 0 },\r
82 { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT }\r
83 };\r
84\r
85REG tt_reg[] = {\r
86 { HRDATA (STA, tt_sta, 8) },\r
87 { HRDATA (KBUF, tt_unit[TTI].buf, 8) },\r
88 { DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT },\r
89 { DRDATA (KTIME, tt_unit[TTI].wait, 24), PV_LEFT },\r
90 { HRDATA (TBUF, tt_unit[TTO].buf, 8) },\r
91 { DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT },\r
92 { DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT },\r
93 { FLDATA (IREQ, int_req[l_TT], i_TT) },\r
94 { FLDATA (IENB, int_enb[l_TT], i_TT) },\r
95 { FLDATA (IARM, tt_arm, 0) },\r
96 { FLDATA (RD, tt_rd, 0) },\r
97 { FLDATA (FDPX, tt_fdpx, 0) },\r
98 { FLDATA (CHP, tt_chp, 0) },\r
99 { HRDATA (DEVNO, tt_dib.dno, 8), REG_HRO },\r
100 { NULL }\r
101 };\r
102\r
103MTAB tt_mod[] = {\r
104 { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tt_set_mode },\r
105 { TT_MODE, TT_MODE_7B, "7b", "7B", &tt_set_mode },\r
106 { TT_MODE, TT_MODE_8B, "8b", "8B", &tt_set_mode },\r
107 { TT_MODE, TT_MODE_7P, "7p", "7P", &tt_set_mode },\r
108 { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ENABLED",\r
109 &tt_set_enbdis, NULL, NULL },\r
110 { MTAB_XTD|MTAB_VDV|MTAB_NMO, DEV_DIS, NULL, "DISABLED",\r
111 &tt_set_enbdis, NULL, NULL },\r
112 { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "BREAK",\r
113 &tt_set_break, NULL, NULL },\r
114 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r
115 &set_dev, &show_dev, &tt_dib },\r
116 { 0 }\r
117 };\r
118\r
119DEVICE tt_dev = {\r
120 "TT", tt_unit, tt_reg, tt_mod,\r
121 2, 10, 31, 1, 16, 8,\r
122 NULL, NULL, &tt_reset,\r
123 NULL, NULL, NULL,\r
124 &tt_dib, 0\r
125 };\r
126\r
127/* Terminal: IO routine */\r
128\r
129uint32 tt (uint32 dev, uint32 op, uint32 dat)\r
130{\r
131uint32 old_rd, t;\r
132\r
133switch (op) { /* case IO op */\r
134\r
135 case IO_ADR: /* select */\r
136 return BY; /* byte only */\r
137\r
138 case IO_OC: /* command */\r
139 old_rd = tt_rd;\r
140 tt_arm = int_chg (v_TT, dat, tt_arm); /* upd int ctrl */\r
141 tt_fdpx = io_2b (dat, CMD_V_FDPX, tt_fdpx); /* upd full/half */\r
142 tt_rd = io_2b (dat, CMD_V_RD, tt_rd); /* upd rd/write */\r
143 if (tt_rd != old_rd) { /* rw change? */\r
144 if (tt_rd? tt_chp: !sim_is_active (&tt_unit[TTO])) {\r
145 tt_sta = 0; /* busy = 0 */\r
146 if (tt_arm) SET_INT (v_TT); /* req intr */\r
147 }\r
148 else {\r
149 tt_sta = STA_BSY; /* busy = 1 */\r
150 CLR_INT (v_TT); /* clr int */\r
151 }\r
152 }\r
153 else tt_sta = tt_sta & ~STA_OVR; /* clr ovflo */\r
154 break;\r
155\r
156 case IO_RD: /* read */\r
157 tt_chp = 0; /* clear pend */\r
158 if (tt_rd) tt_sta = (tt_sta | STA_BSY) & ~STA_OVR;\r
159 return (tt_unit[TTI].buf & 0xFF);\r
160\r
161 case IO_WD: /* write */\r
162 tt_unit[TTO].buf = dat & 0xFF; /* save char */\r
163 if (!tt_rd) tt_sta = tt_sta | STA_BSY; /* set busy */\r
164 sim_activate (&tt_unit[TTO], tt_unit[TTO].wait);\r
165 break;\r
166\r
167 case IO_SS: /* status */\r
168 t = tt_sta & STA_MASK; /* get status */\r
169 if (t & SET_EX) t = t | STA_EX; /* test for EX */\r
170 return t;\r
171 }\r
172\r
173return 0;\r
174}\r
175\r
176/* Unit service routines */\r
177\r
178t_stat tti_svc (UNIT *uptr)\r
179{\r
180int32 out, temp;\r
181\r
182sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_poll)); /* continue poll */\r
183tt_sta = tt_sta & ~STA_BRK; /* clear break */\r
184if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */\r
185if (tt_rd) { /* read mode? */\r
186 tt_sta = tt_sta & ~STA_BSY; /* clear busy */\r
187 if (tt_arm) SET_INT (v_TT); /* if armed, intr */\r
188 if (tt_chp) tt_sta = tt_sta | STA_OVR; /* got char? overrun */\r
189 }\r
190tt_chp = 1; /* char pending */\r
191out = temp & 0x7F; /* echo is 7B */\r
192if (temp & SCPE_BREAK) { /* break? */\r
193 tt_sta = tt_sta | STA_BRK; /* set status */\r
194 uptr->buf = 0; /* no character */\r
195 }\r
196else uptr->buf = sim_tt_inpcvt (temp, TT_GET_MODE (uptr->flags) | TTUF_KSR);\r
197uptr->pos = uptr->pos + 1; /* incr count */\r
198if (!tt_fdpx) { /* half duplex? */\r
199 out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags) | TTUF_KSR);\r
200 if (out >= 0) { /* valid echo? */\r
201 sim_putchar (out); /* write char */\r
202 tt_unit[TTO].pos = tt_unit[TTO].pos + 1;\r
203 }\r
204 }\r
205return SCPE_OK;\r
206}\r
207\r
208t_stat tto_svc (UNIT *uptr)\r
209{\r
210int32 ch;\r
211t_stat r;\r
212\r
213ch = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR);\r
214if (ch >= 0) {\r
215 if ((r = sim_putchar_s (ch)) != SCPE_OK) { /* output; error? */\r
216 sim_activate (uptr, uptr->wait); /* try again */\r
217 return ((r == SCPE_STALL)? SCPE_OK: r);\r
218 }\r
219 }\r
220if (!tt_rd) { /* write mode? */\r
221 tt_sta = tt_sta & ~STA_BSY; /* clear busy */\r
222 if (tt_arm) SET_INT (v_TT); /* if armed, intr */\r
223 }\r
224uptr->pos = uptr->pos + 1; /* incr count */\r
225return SCPE_OK;\r
226}\r
227\r
228/* Reset routine */\r
229\r
230t_stat tt_reset (DEVICE *dptr)\r
231{\r
232if (dptr->flags & DEV_DIS) sim_cancel (&tt_unit[TTI]); /* dis? cancel poll */\r
233else sim_activate_abs (&tt_unit[TTI], KBD_WAIT (tt_unit[TTI].wait, lfc_poll));\r
234sim_cancel (&tt_unit[TTO]); /* cancel output */\r
235tt_rd = tt_fdpx = 1; /* read, full duplex */\r
236tt_chp = 0; /* no char */\r
237tt_sta = STA_BSY; /* buffer empty */\r
238CLR_INT (v_TT); /* clear int */\r
239CLR_ENB (v_TT); /* disable int */\r
240tt_arm = 0; /* disarm int */\r
241return SCPE_OK;\r
242}\r
243\r
244/* Make mode flags uniform */\r
245\r
246t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)\r
247{\r
248tt_unit[TTO].flags = (tt_unit[TTO].flags & ~TT_MODE) | val;\r
249if (val == TT_MODE_7P) val = TT_MODE_7B;\r
250tt_unit[TTI].flags = (tt_unit[TTI].flags & ~TT_MODE) | val;\r
251return SCPE_OK;\r
252}\r
253\r
254/* Set input break */\r
255\r
256t_stat tt_set_break (UNIT *uptr, int32 val, char *cptr, void *desc)\r
257{\r
258if (tt_dev.flags & DEV_DIS) return SCPE_NOFNC;\r
259tt_sta = tt_sta | STA_BRK;\r
260if (tt_rd) { /* read mode? */\r
261 tt_sta = tt_sta & ~STA_BSY; /* clear busy */\r
262 if (tt_arm) SET_INT (v_TT); /* if armed, intr */\r
263 }\r
264sim_cancel (&tt_unit[TTI]); /* restart TT poll */\r
265sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* so brk is seen */\r
266return SCPE_OK;\r
267}\r
268\r
269/* Set enabled/disabled */\r
270\r
271t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc)\r
272{\r
273extern DEVICE ttp_dev;\r
274extern t_stat ttp_reset (DEVICE *dptr);\r
275\r
276tt_dev.flags = (tt_dev.flags & ~DEV_DIS) | val;\r
277ttp_dev.flags = (ttp_dev.flags & ~DEV_DIS) | (val ^ DEV_DIS);\r
278tt_reset (&tt_dev);\r
279ttp_reset (&ttp_dev);\r
280return SCPE_OK;\r
281}\r