1 /* vax_stddev.c: VAX 3900 standard I/O devices
2
3 Copyright (c) 1998-2012, 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 clk 100Hz and TODR clock
29
30 18-Apr-12 RMS Revised TTI to use clock coscheduling and
31 remove IORESET bug
32 17-Aug-08 RMS Resync TODR on any clock reset
33 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
34 17-Oct-06 RMS Synced keyboard poll to real-time clock for idling
35 22-Nov-05 RMS Revised for new terminal processing routines
36 09-Sep-04 RMS Integrated powerup into RESET (with -p)
37 28-May-04 RMS Removed SET TTI CTRL-C
38 29-Dec-03 RMS Added console backpressure support
39 25-Apr-03 RMS Revised for extended file support
40 02-Mar-02 RMS Added SET TTI CTRL-C
41 22-Dec-02 RMS Added console halt capability
42 01-Nov-02 RMS Added 7B/8B capability to terminal
43 12-Sep-02 RMS Removed paper tape, added variable vector support
44 30-May-02 RMS Widened POS to 32b
45 30-Apr-02 RMS Automatically set TODR to VMS-correct value during boot
46 */
47
48 #include "vax_defs.h"
49 #include <time.h>
50
51 #define TTICSR_IMP (CSR_DONE + CSR_IE) /* terminal input */
52 #define TTICSR_RW (CSR_IE)
53 #define TTIBUF_ERR 0x8000 /* error */
54 #define TTIBUF_OVR 0x4000 /* overrun */
55 #define TTIBUF_FRM 0x2000 /* framing error */
56 #define TTIBUF_RBR 0x0400 /* receive break */
57 #define TTOCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */
58 #define TTOCSR_RW (CSR_IE)
59 #define CLKCSR_IMP (CSR_IE) /* real-time clock */
60 #define CLKCSR_RW (CSR_IE)
61 #define CLK_DELAY 5000 /* 100 Hz */
62 #define TMXR_MULT 1 /* 100 Hz */
63
64 extern int32 int_req[IPL_HLVL];
65 extern int32 hlt_pin;
66 extern int32 sim_switches, sim_is_running;
67
68 int32 tti_csr = 0; /* control/status */
69 int32 tto_csr = 0; /* control/status */
70 int32 clk_csr = 0; /* control/status */
71 int32 clk_tps = 100; /* ticks/second */
72 int32 todr_reg = 0; /* TODR register */
73 int32 todr_blow = 1; /* TODR battery low */
74 int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
75 int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
76
77 t_stat tti_svc (UNIT *uptr);
78 t_stat tto_svc (UNIT *uptr);
79 t_stat clk_svc (UNIT *uptr);
80 t_stat tti_reset (DEVICE *dptr);
81 t_stat tto_reset (DEVICE *dptr);
82 t_stat clk_reset (DEVICE *dptr);
83 t_stat todr_resync (void);
84
85 extern int32 sysd_hlt_enb (void);
86
87 /* TTI data structures
88
89 tti_dev TTI device descriptor
90 tti_unit TTI unit descriptor
91 tti_reg TTI register list
92 */
93
94 DIB tti_dib = { 0, 0, NULL, NULL, 1, IVCL (TTI), SCB_TTI, { NULL } };
95
96 UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_8B, 0), 0 };
97
98 REG tti_reg[] = {
99 { HRDATA (BUF, tti_unit.buf, 16) },
100 { HRDATA (CSR, tti_csr, 16) },
101 { FLDATA (INT, int_req[IPL_TTI], INT_V_TTI) },
102 { FLDATA (DONE, tti_csr, CSR_V_DONE) },
103 { FLDATA (IE, tti_csr, CSR_V_IE) },
104 { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
105 { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT },
106 { NULL }
107 };
108
109 MTAB tti_mod[] = {
110 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
111 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
112 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
113 NULL, &show_vec, NULL },
114 { 0 }
115 };
116
117 DEVICE tti_dev = {
118 "TTI", &tti_unit, tti_reg, tti_mod,
119 1, 10, 31, 1, 16, 8,
120 NULL, NULL, &tti_reset,
121 NULL, NULL, NULL,
122 &tti_dib, 0
123 };
124
125 /* TTO data structures
126
127 tto_dev TTO device descriptor
128 tto_unit TTO unit descriptor
129 tto_reg TTO register list
130 */
131
132 DIB tto_dib = { 0, 0, NULL, NULL, 1, IVCL (TTO), SCB_TTO, { NULL } };
133
134 UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_8B, 0), SERIAL_OUT_WAIT };
135
136 REG tto_reg[] = {
137 { HRDATA (BUF, tto_unit.buf, 8) },
138 { HRDATA (CSR, tto_csr, 16) },
139 { FLDATA (INT, int_req[IPL_TTO], INT_V_TTO) },
140 { FLDATA (DONE, tto_csr, CSR_V_DONE) },
141 { FLDATA (IE, tto_csr, CSR_V_IE) },
142 { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
143 { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
144 { NULL }
145 };
146
147 MTAB tto_mod[] = {
148 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
149 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
150 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
151 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec },
152 { 0 }
153 };
154
155 DEVICE tto_dev = {
156 "TTO", &tto_unit, tto_reg, tto_mod,
157 1, 10, 31, 1, 16, 8,
158 NULL, NULL, &tto_reset,
159 NULL, NULL, NULL,
160 &tto_dib, 0
161 };
162
163 /* CLK data structures
164
165 clk_dev CLK device descriptor
166 clk_unit CLK unit descriptor
167 clk_reg CLK register list
168 */
169
170 DIB clk_dib = { 0, 0, NULL, NULL, 1, IVCL (CLK), SCB_INTTIM, { NULL } };
171
172 UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY };
173
174 REG clk_reg[] = {
175 { HRDATA (CSR, clk_csr, 16) },
176 { FLDATA (INT, int_req[IPL_CLK], INT_V_CLK) },
177 { FLDATA (IE, clk_csr, CSR_V_IE) },
178 { DRDATA (TODR, todr_reg, 32), PV_LEFT },
179 { FLDATA (BLOW, todr_blow, 0) },
180 { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
181 { DRDATA (POLL, tmr_poll, 24), REG_NZ + PV_LEFT + REG_HRO },
182 { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
183 { NULL }
184 };
185
186 MTAB clk_mod[] = {
187 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec },
188 { 0 }
189 };
190
191 DEVICE clk_dev = {
192 "CLK", &clk_unit, clk_reg, clk_mod,
193 1, 0, 0, 0, 0, 0,
194 NULL, NULL, &clk_reset,
195 NULL, NULL, NULL,
196 &clk_dib, 0
197 };
198
199 /* Clock and terminal MxPR routines
200
201 iccs_rd/wr interval timer
202 todr_rd/wr time of year clock
203 rxcs_rd/wr input control/status
204 rxdb_rd input buffer
205 txcs_rd/wr output control/status
206 txdb_wr output buffer
207 */
208
iccs_rd(void)209 int32 iccs_rd (void)
210 {
211 return (clk_csr & CLKCSR_IMP);
212 }
213
todr_rd(void)214 int32 todr_rd (void)
215 {
216 return todr_reg;
217 }
218
rxcs_rd(void)219 int32 rxcs_rd (void)
220 {
221 return (tti_csr & TTICSR_IMP);
222 }
223
rxdb_rd(void)224 int32 rxdb_rd (void)
225 {
226 int32 t = tti_unit.buf; /* char + error */
227
228 tti_csr = tti_csr & ~CSR_DONE; /* clr done */
229 tti_unit.buf = tti_unit.buf & 0377; /* clr errors */
230 CLR_INT (TTI);
231 return t;
232 }
233
txcs_rd(void)234 int32 txcs_rd (void)
235 {
236 return (tto_csr & TTOCSR_IMP);
237 }
238
iccs_wr(int32 data)239 void iccs_wr (int32 data)
240 {
241 if ((data & CSR_IE) == 0)
242 CLR_INT (CLK);
243 clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW);
244 return;
245 }
246
todr_wr(int32 data)247 void todr_wr (int32 data)
248 {
249 todr_reg = data;
250 if (data)
251 todr_blow = 0;
252 return;
253 }
254
rxcs_wr(int32 data)255 void rxcs_wr (int32 data)
256 {
257 if ((data & CSR_IE) == 0)
258 CLR_INT (TTI);
259 else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
260 SET_INT (TTI);
261 tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW);
262 return;
263 }
264
txcs_wr(int32 data)265 void txcs_wr (int32 data)
266 {
267 if ((data & CSR_IE) == 0)
268 CLR_INT (TTO);
269 else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
270 SET_INT (TTO);
271 tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW);
272 return;
273 }
274
txdb_wr(int32 data)275 void txdb_wr (int32 data)
276 {
277 tto_unit.buf = data & 0377;
278 tto_csr = tto_csr & ~CSR_DONE;
279 CLR_INT (TTO);
280 sim_activate (&tto_unit, tto_unit.wait);
281 return;
282 }
283
284 /* Terminal input routines
285
286 tti_svc process event (character ready)
287 tti_reset process reset
288 */
289
tti_svc(UNIT * uptr)290 t_stat tti_svc (UNIT *uptr)
291 {
292 int32 c;
293
294 sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmr_poll)));
295 /* continue poll */
296 if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
297 return c;
298 if (c & SCPE_BREAK) { /* break? */
299 if (sysd_hlt_enb ()) /* if enabled, halt */
300 hlt_pin = 1;
301 tti_unit.buf = TTIBUF_ERR | TTIBUF_FRM | TTIBUF_RBR;
302 }
303 else tti_unit.buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
304 uptr->pos = uptr->pos + 1;
305 tti_csr = tti_csr | CSR_DONE;
306 if (tti_csr & CSR_IE)
307 SET_INT (TTI);
308 return SCPE_OK;
309 }
310
tti_reset(DEVICE * dptr)311 t_stat tti_reset (DEVICE *dptr)
312 {
313 tti_unit.buf = 0;
314 tti_csr = 0;
315 CLR_INT (TTI);
316 sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll));
317 return SCPE_OK;
318 }
319
320 /* Terminal output routines
321
322 tto_svc process event (character typed)
323 tto_reset process reset
324 */
325
tto_svc(UNIT * uptr)326 t_stat tto_svc (UNIT *uptr)
327 {
328 int32 c;
329 t_stat r;
330
331 c = sim_tt_outcvt (tto_unit.buf, TT_GET_MODE (uptr->flags));
332 if (c >= 0) {
333 if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
334 sim_activate (uptr, uptr->wait); /* retry */
335 return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
336 }
337 }
338 tto_csr = tto_csr | CSR_DONE;
339 if (tto_csr & CSR_IE)
340 SET_INT (TTO);
341 uptr->pos = uptr->pos + 1;
342 return SCPE_OK;
343 }
344
tto_reset(DEVICE * dptr)345 t_stat tto_reset (DEVICE *dptr)
346 {
347 tto_unit.buf = 0;
348 tto_csr = CSR_DONE;
349 CLR_INT (TTO);
350 sim_cancel (&tto_unit); /* deactivate unit */
351 return SCPE_OK;
352 }
353
354 /* Clock routines
355
356 clk_svc process event (clock tick)
357 clk_reset process reset
358 todr_powerup powerup for TODR (get date from system)
359 */
360
clk_svc(UNIT * uptr)361 t_stat clk_svc (UNIT *uptr)
362 {
363 int32 t;
364
365 if (clk_csr & CSR_IE)
366 SET_INT (CLK);
367 t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
368 sim_activate (&clk_unit, t); /* reactivate unit */
369 tmr_poll = t; /* set tmr poll */
370 tmxr_poll = t * TMXR_MULT; /* set mux poll */
371 if (!todr_blow) /* incr TODR */
372 todr_reg = todr_reg + 1;
373 return SCPE_OK;
374 }
375
376 /* Clock coscheduling routine */
377
clk_cosched(int32 wait)378 int32 clk_cosched (int32 wait)
379 {
380 int32 t;
381
382 t = sim_is_active (&clk_unit);
383 return (t? t - 1: wait);
384 }
385
386 /* TODR resync routine */
387
todr_resync(void)388 t_stat todr_resync (void)
389 {
390 uint32 base;
391 time_t curr;
392 struct tm *ctm;
393
394 curr = time (NULL); /* get curr time */
395 if (curr == (time_t) -1) /* error? */
396 return SCPE_NOFNC;
397 ctm = localtime (&curr); /* decompose */
398 if (ctm == NULL) /* error? */
399 return SCPE_NOFNC;
400 base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
401 ctm->tm_hour) * 60) +
402 ctm->tm_min) * 60) +
403 ctm->tm_sec;
404 todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */
405 todr_blow = 0;
406 return SCPE_OK;
407 }
408
409 /* Reset routine */
410
clk_reset(DEVICE * dptr)411 t_stat clk_reset (DEVICE *dptr)
412 {
413 int32 t;
414
415 todr_resync (); /* resync clock */
416 clk_csr = 0;
417 CLR_INT (CLK);
418 if (!sim_is_running) { /* RESET (not IORESET)? */
419 t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */
420 sim_activate (&clk_unit, t); /* activate unit */
421 tmr_poll = t; /* set tmr poll */
422 tmxr_poll = t * TMXR_MULT; /* set mux poll */
423 }
424 return SCPE_OK;
425 }
426
427