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