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