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