| 1 | /* ibm1130_prt.c: IBM 1130 line printer emulation\r |
| 2 | \r |
| 3 | Based on the SIMH simulator package written by Robert M Supnik\r |
| 4 | \r |
| 5 | Brian Knittel\r |
| 6 | Revision History\r |
| 7 | \r |
| 8 | 2006.12.06 - Moved CGI stuff out of this routine into cgi1130 main() module.\r |
| 9 | \r |
| 10 | 2006.07.06 - Made 1403 printer 132 columns wide, was 120 previously\r |
| 11 | \r |
| 12 | 2006.01.03 - Fixed bug in prt_attach, found and fixed by Carl Claunch. Detach followed\r |
| 13 | by reattach of 1403-mode printer left device permanently not-ready.\r |
| 14 | \r |
| 15 | 2004.11.08 - HACK for demo mode: in physical (-p) mode, multiple consecutive formfeeds are suppressed.\r |
| 16 | This lets us do a formfeed at the end of a job to kick the last page out\r |
| 17 | without getting another blank page at the beginning of the next job.\r |
| 18 | \r |
| 19 | 2003.12.02 - Added -p option for physical line printer output (flushes\r |
| 20 | output buffer after each line). When using a physical printer on\r |
| 21 | Windows, be sure to set printer to "send output directly to printer"\r |
| 22 | to disable spooling, otherwise nothing appears until printer is\r |
| 23 | detatched.\r |
| 24 | \r |
| 25 | 2003.11.25 - Changed magic filename for standard output to "(stdout)".\r |
| 26 | \r |
| 27 | 2002.09.13 - Added 1403 support. New file, taken from part of ibm1130_stddev.c\r |
| 28 | \r |
| 29 | Note: The 1403 is much faster, even in emulation, because it takes much\r |
| 30 | less CPU power to run it. DMS doesn't use the WAIT command when waiting for\r |
| 31 | printer operations to complete, so it ends up burning LOTS of cpu cycles.\r |
| 32 | The 1403 printer doesn't require as many. HOWEVER: DMS must be loaded for the 1403,\r |
| 33 | and Fortran IOCS control cards must specify it.\r |
| 34 | \r |
| 35 | The 1132 is still the default printer.\r |
| 36 | \r |
| 37 | As written, we can't have two printers.\r |
| 38 | \r |
| 39 | * (C) Copyright 2002, Brian Knittel.\r |
| 40 | * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r |
| 41 | * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r |
| 42 | * usual yada-yada. Please keep this notice and the copyright in any distributions\r |
| 43 | * or modifications.\r |
| 44 | *\r |
| 45 | * This is not a supported product, but I welcome bug reports and fixes.\r |
| 46 | * Mail to simh@ibm1130.org\r |
| 47 | */\r |
| 48 | \r |
| 49 | #include "ibm1130_defs.h"\r |
| 50 | #include <stdlib.h> /* needed for atexit, for cgi mode */\r |
| 51 | \r |
| 52 | /***************************************************************************************\r |
| 53 | * 1132 PRINTER \r |
| 54 | ***************************************************************************************/\r |
| 55 | \r |
| 56 | #define PRT1132_DSW_READ_EMITTER_RESPONSE 0x8000\r |
| 57 | #define PRT1132_DSW_SKIP_RESPONSE 0x4000\r |
| 58 | #define PRT1132_DSW_SPACE_RESPONSE 0x2000\r |
| 59 | #define PRT1132_DSW_CARRIAGE_BUSY 0x1000\r |
| 60 | #define PRT1132_DSW_PRINT_SCAN_CHECK 0x0800\r |
| 61 | #define PRT1132_DSW_NOT_READY 0x0400\r |
| 62 | #define PRT1132_DSW_PRINTER_BUSY 0x0200\r |
| 63 | \r |
| 64 | #define PRT1132_DSW_CHANNEL_MASK 0x00FF /* 1132 printer DSW bits */\r |
| 65 | #define PRT1132_DSW_CHANNEL_1 0x0080\r |
| 66 | #define PRT1132_DSW_CHANNEL_2 0x0040\r |
| 67 | #define PRT1132_DSW_CHANNEL_3 0x0020\r |
| 68 | #define PRT1132_DSW_CHANNEL_4 0x0010\r |
| 69 | #define PRT1132_DSW_CHANNEL_5 0x0008\r |
| 70 | #define PRT1132_DSW_CHANNEL_6 0x0004\r |
| 71 | #define PRT1132_DSW_CHANNEL_9 0x0002\r |
| 72 | #define PRT1132_DSW_CHANNEL_12 0x0001\r |
| 73 | \r |
| 74 | #define PRT1403_DSW_PARITY_CHECK 0x8000 /* 1403 printer DSW bits */\r |
| 75 | #define PRT1403_DSW_TRANSFER_COMPLETE 0x4000\r |
| 76 | #define PRT1403_DSW_PRINT_COMPLETE 0x2000\r |
| 77 | #define PRT1403_DSW_CARRIAGE_COMPLETE 0x1000\r |
| 78 | #define PRT1403_DSW_RING_CHECK 0x0400\r |
| 79 | #define PRT1403_DSW_SYNC_CHECK 0x0200\r |
| 80 | #define PRT1403_DSW_CH9 0x0010\r |
| 81 | #define PRT1403_DSW_CH12 0x0008\r |
| 82 | #define PRT1403_DSW_CARRIAGE_BUSY 0x0004\r |
| 83 | #define PRT1403_DSW_PRINTER_BUSY 0x0002\r |
| 84 | #define PRT1403_DSW_NOT_READY 0x0001\r |
| 85 | \r |
| 86 | #define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)\r |
| 87 | \r |
| 88 | static t_stat prt1132_svc(UNIT *uptr);\r |
| 89 | static t_stat prt1403_svc(UNIT *uptr);\r |
| 90 | static t_stat prt_svc (UNIT *uptr);\r |
| 91 | static t_stat prt_reset (DEVICE *dptr);\r |
| 92 | static t_stat prt_attach (UNIT *uptr, char *cptr);\r |
| 93 | static t_stat prt_detach (UNIT *uptr);\r |
| 94 | \r |
| 95 | static int16 PRT_DSW = 0; /* device status word */\r |
| 96 | static int32 prt_swait = 500; /* line skip wait */\r |
| 97 | static int32 prt_cwait = 1250; /* character rotation wait */\r |
| 98 | static int32 prt_fwait = 100; /* fast wait, for 1403 operations */\r |
| 99 | static int32 prt_twait = 50; /* transfer wait, for 1403 operations */\r |
| 100 | #define SKIPTARGET (uptr->u4) /* target for skip operation */\r |
| 101 | \r |
| 102 | static t_bool formfed = FALSE; /* last line printed was a formfeed */\r |
| 103 | \r |
| 104 | #define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */\r |
| 105 | #define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */\r |
| 106 | #define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */\r |
| 107 | #define UNIT_V_SPACING (UNIT_V_UF + 3) /* printer is spacing */\r |
| 108 | #define UNIT_V_PRINTING (UNIT_V_UF + 4) /* printer printing */\r |
| 109 | #define UNIT_V_TRANSFERRING (UNIT_V_UF + 5) /* unit is transferring print buffer (1403 only) */\r |
| 110 | #define UNIT_V_1403 (UNIT_V_UF + 6) /* printer model is 1403 rather than 1132 */\r |
| 111 | #define UNIT_V_PARITYCHECK (UNIT_V_UF + 7) /* error flags for 1403 */\r |
| 112 | #define UNIT_V_RINGCHECK (UNIT_V_UF + 8)\r |
| 113 | #define UNIT_V_SYNCCHECK (UNIT_V_UF + 9)\r |
| 114 | #define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* this appears in ibm1130_gui as well */\r |
| 115 | \r |
| 116 | #define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK)\r |
| 117 | #define UNIT_DATACHECK (1u << UNIT_V_DATACHECK)\r |
| 118 | #define UNIT_SKIPPING (1u << UNIT_V_SKIPPING)\r |
| 119 | #define UNIT_SPACING (1u << UNIT_V_SPACING)\r |
| 120 | #define UNIT_PRINTING (1u << UNIT_V_PRINTING)\r |
| 121 | #define UNIT_TRANSFERRING (1u << UNIT_V_TRANSFERRING)\r |
| 122 | #define UNIT_1403 (1u << UNIT_V_1403)\r |
| 123 | #define UNIT_PARITYCHECK (1u << UNIT_V_PARITYCHECK) \r |
| 124 | #define UNIT_RINGCHECK (1u << UNIT_V_RINGCHECK)\r |
| 125 | #define UNIT_SYNCCHECK (1u << UNIT_V_SYNCCHECK)\r |
| 126 | #define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)\r |
| 127 | \r |
| 128 | UNIT prt_unit[] = {\r |
| 129 | { UDATA (&prt_svc, UNIT_ATTABLE, 0) },\r |
| 130 | };\r |
| 131 | \r |
| 132 | #define IS_1403(uptr) (uptr->flags & UNIT_1403) /* model test */\r |
| 133 | #define IS_1132(uptr) ((uptr->flags & UNIT_1403) == 0) /* model test */\r |
| 134 | #define IS_PHYSICAL(uptr) (uptr->flags & UNIT_PHYSICAL_PTR)\r |
| 135 | \r |
| 136 | /* Parameter in the unit descriptor (1132 printer) */\r |
| 137 | \r |
| 138 | #define CMD_NONE 0\r |
| 139 | #define CMD_SPACE 1\r |
| 140 | #define CMD_SKIP 2\r |
| 141 | #define CMD_PRINT 3\r |
| 142 | \r |
| 143 | REG prt_reg[] = {\r |
| 144 | { HRDATA (PRTDSW, PRT_DSW, 16) }, /* device status word */\r |
| 145 | { DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */\r |
| 146 | { DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */\r |
| 147 | { DRDATA (FTIME, prt_fwait, 24), PV_LEFT }, /* 1403 fast wait */\r |
| 148 | { DRDATA (TTIME, prt_twait, 24), PV_LEFT }, /* 1403 transfer wait */\r |
| 149 | { NULL } };\r |
| 150 | \r |
| 151 | MTAB prt_mod[] = {\r |
| 152 | { UNIT_1403, 0, "1132", "1132", NULL }, /* model option */\r |
| 153 | { UNIT_1403, UNIT_1403, "1403", "1403", NULL },\r |
| 154 | { 0 } };\r |
| 155 | \r |
| 156 | DEVICE prt_dev = {\r |
| 157 | "PRT", prt_unit, prt_reg, prt_mod,\r |
| 158 | 1, 16, 16, 1, 16, 16,\r |
| 159 | NULL, NULL, &prt_reset,\r |
| 160 | NULL, prt_attach, prt_detach};\r |
| 161 | \r |
| 162 | #define MAX_COLUMNS 120 \r |
| 163 | #define MAX_OVPRINT 20\r |
| 164 | #define PRT1132_COLUMNS 120\r |
| 165 | #define PRT1403_COLUMNS 120 /* the 1130's version of the 1403 printed in 120 columns only (see Functional Characteristics) */\r |
| 166 | \r |
| 167 | static char prtbuf[MAX_COLUMNS*MAX_OVPRINT];\r |
| 168 | static int nprint[MAX_COLUMNS], ncol[MAX_OVPRINT], maxnp;\r |
| 169 | static int prt_nchar, prt_row; /* current printwheel position, current page row */\r |
| 170 | static int prt_nnl; /* number of queued newlines */\r |
| 171 | \r |
| 172 | #define CC_CHANNEL_1 0x0800 /* carriage control tape punch values */\r |
| 173 | #define CC_CHANNEL_2 0x0400\r |
| 174 | #define CC_CHANNEL_3 0x0200\r |
| 175 | #define CC_CHANNEL_4 0x0100\r |
| 176 | #define CC_CHANNEL_5 0x0080\r |
| 177 | #define CC_CHANNEL_6 0x0040 /* 7, 8, 10 and 11 are not used on 1132 printer */\r |
| 178 | #define CC_CHANNEL_7 0x0020\r |
| 179 | #define CC_CHANNEL_8 0x0010\r |
| 180 | #define CC_CHANNEL_9 0x0008\r |
| 181 | #define CC_CHANNEL_10 0x0004\r |
| 182 | #define CC_CHANNEL_11 0x0002\r |
| 183 | #define CC_CHANNEL_12 0x0001\r |
| 184 | \r |
| 185 | #define CC_1403_BITS 0x0FFF /* all bits for 1403, most for 1132 */\r |
| 186 | #define CC_1132_BITS (CC_1403_BITS & ~(CC_CHANNEL_7|CC_CHANNEL_8|CC_CHANNEL_10|CC_CHANNEL_11))\r |
| 187 | \r |
| 188 | #define PRT_PAGELENGTH 66\r |
| 189 | \r |
| 190 | static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */\r |
| 191 | \r |
| 192 | static struct tag_ccpunches { /* list of rows and punches on tape */\r |
| 193 | int row, channels;\r |
| 194 | }\r |
| 195 | ccpunches[] = {\r |
| 196 | 2, CC_CHANNEL_1, /* channel 1 = top of form */\r |
| 197 | 62, CC_CHANNEL_12 /* channel 12 = bottom of form */\r |
| 198 | },\r |
| 199 | cccgi[] = {\r |
| 200 | 2, CC_CHANNEL_1 /* channel 1 = top of form; no bottom of form */\r |
| 201 | };\r |
| 202 | \r |
| 203 | #include "ibm1130_prtwheel.h"\r |
| 204 | \r |
| 205 | extern int32 sim_switches;\r |
| 206 | \r |
| 207 | /* cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read */\r |
| 208 | \r |
| 209 | static int cc_format_1132 (int bits)\r |
| 210 | {\r |
| 211 | return ((bits & (CC_CHANNEL_1|CC_CHANNEL_2|CC_CHANNEL_3|CC_CHANNEL_4|CC_CHANNEL_5|CC_CHANNEL_6)) >> 4) |\r |
| 212 | ((bits & CC_CHANNEL_9) >> 3) |\r |
| 213 | (bits & CC_CHANNEL_12);\r |
| 214 | }\r |
| 215 | \r |
| 216 | #define cc_format_1403(bits) (bits)\r |
| 217 | \r |
| 218 | /* reset_prt_line - clear the print line following paper advancement */\r |
| 219 | \r |
| 220 | static void reset_prt_line (void)\r |
| 221 | {\r |
| 222 | memset(nprint, 0, sizeof(nprint));\r |
| 223 | memset(ncol, 0, sizeof(ncol));\r |
| 224 | maxnp = 0;\r |
| 225 | }\r |
| 226 | \r |
| 227 | /* save_1132_prt_line - fire hammers for character 'ch' */\r |
| 228 | \r |
| 229 | static t_bool save_1132_prt_line (int ch)\r |
| 230 | {\r |
| 231 | int i, r, addr = 32;\r |
| 232 | int32 mask = 0, wd = 0;\r |
| 233 | \r |
| 234 | for (i = 0; i < PRT1132_COLUMNS; i++) {\r |
| 235 | if (mask == 0) { /* fetch next word from memory */\r |
| 236 | mask = 0x8000;\r |
| 237 | wd = M[addr++];\r |
| 238 | }\r |
| 239 | \r |
| 240 | if (wd & mask) { /* hammer is to fire in this column */\r |
| 241 | if ((r = nprint[i]) < MAX_OVPRINT) {\r |
| 242 | if (ncol[r] <= i) { /* we haven't moved this far yet */\r |
| 243 | if (ncol[r] == 0) /* first char in this row? */\r |
| 244 | memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1132_COLUMNS); /* blank out the new row */\r |
| 245 | ncol[r] = i+1; /* remember new row length */\r |
| 246 | }\r |
| 247 | prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */\r |
| 248 | \r |
| 249 | nprint[i]++; /* remember max overprintings for this column */\r |
| 250 | maxnp = MAX(maxnp, nprint[i]);\r |
| 251 | }\r |
| 252 | }\r |
| 253 | \r |
| 254 | mask >>= 1; /* prepare to examine next bit */\r |
| 255 | }\r |
| 256 | \r |
| 257 | return wd & 1; /* return TRUE if the last word has lsb set, which means all bits had been set */\r |
| 258 | }\r |
| 259 | \r |
| 260 | /* write_line - write collected line to output file. No need to trim spaces as the hammers\r |
| 261 | * are never fired for them, so ncol[r] is the last printed position on each line.\r |
| 262 | */\r |
| 263 | \r |
| 264 | static void newpage (FILE *fd, t_bool physical_printer)\r |
| 265 | {\r |
| 266 | if (cgi)\r |
| 267 | fputs("<HR>\n", fd);\r |
| 268 | else if (! formfed) {\r |
| 269 | putc('\f', fd);\r |
| 270 | if (physical_printer) {\r |
| 271 | fflush(fd); /* send the ff out to the printer immediately */\r |
| 272 | formfed = TRUE; /* hack: inhibit consecutive ff's */\r |
| 273 | }\r |
| 274 | }\r |
| 275 | }\r |
| 276 | \r |
| 277 | static void flush_prt_line (FILE *fd, int spacemode, t_bool physical_printer)\r |
| 278 | {\r |
| 279 | int r;\r |
| 280 | \r |
| 281 | if (! (spacemode || maxnp)) /* nothing to do */\r |
| 282 | return;\r |
| 283 | \r |
| 284 | prt_row = (prt_row+1) % PRT_PAGELENGTH; /* NEXT line */\r |
| 285 | \r |
| 286 | if (spacemode && ! maxnp) { /* spacing only */\r |
| 287 | if (prt_row == 0 && prt_nnl) {\r |
| 288 | #ifdef _WIN32\r |
| 289 | if (! cgi)\r |
| 290 | putc('\r', fd); /* DOS/Windows: end with cr/lf */\r |
| 291 | #endif\r |
| 292 | putc('\n', fd); /* otherwise end with lf */\r |
| 293 | if (spacemode & UNIT_SKIPPING) /* add formfeed if we crossed page boundary while skipping */\r |
| 294 | newpage(fd, physical_printer);\r |
| 295 | \r |
| 296 | prt_nnl = 0;\r |
| 297 | }\r |
| 298 | else {\r |
| 299 | prt_nnl++;\r |
| 300 | formfed = FALSE;\r |
| 301 | }\r |
| 302 | \r |
| 303 | prt_unit->pos++; /* note something written */\r |
| 304 | return;\r |
| 305 | }\r |
| 306 | \r |
| 307 | if (prt_nnl) { /* there are queued newlines */\r |
| 308 | while (prt_nnl > 0) { /* spit out queued newlines */\r |
| 309 | #ifdef _WIN32\r |
| 310 | if (! cgi)\r |
| 311 | putc('\r', fd); /* DOS/Windows: end with cr/lf */\r |
| 312 | #endif\r |
| 313 | putc('\n', fd); /* otherwise end with lf */\r |
| 314 | prt_nnl--;\r |
| 315 | }\r |
| 316 | }\r |
| 317 | \r |
| 318 | for (r = 0; r < maxnp; r++) {\r |
| 319 | if (r > 0)\r |
| 320 | putc('\r', fd); /* carriage return between overprinted lines */\r |
| 321 | \r |
| 322 | fxwrite(&prtbuf[r*MAX_COLUMNS], 1, ncol[r], fd);\r |
| 323 | }\r |
| 324 | \r |
| 325 | reset_prt_line();\r |
| 326 | \r |
| 327 | prt_unit->pos++; /* note something written */\r |
| 328 | prt_nnl++; /* queue a newline */\r |
| 329 | \r |
| 330 | if (physical_printer) /* if physical printer, send buffered output to device */\r |
| 331 | fflush(fd);\r |
| 332 | \r |
| 333 | formfed = FALSE; /* note that something is now on the page */\r |
| 334 | }\r |
| 335 | \r |
| 336 | /* 1132 printer commands */\r |
| 337 | \r |
| 338 | #define PRT_CMD_START_PRINTER 0x0080\r |
| 339 | #define PRT_CMD_STOP_PRINTER 0x0040\r |
| 340 | #define PRT_CMD_START_CARRIAGE 0x0004\r |
| 341 | #define PRT_CMD_STOP_CARRIAGE 0x0002\r |
| 342 | #define PRT_CMD_SPACE 0x0001\r |
| 343 | \r |
| 344 | #define PRT_CMD_MASK 0x00C7\r |
| 345 | \r |
| 346 | extern char * saywhere (int addr);\r |
| 347 | \r |
| 348 | static void mytrace (int start, char *what)\r |
| 349 | {\r |
| 350 | char *where;\r |
| 351 | \r |
| 352 | if ((where = saywhere(prev_IAR)) == NULL) where = "?";\r |
| 353 | trace_io("%s %s at %04x: %s\n", start ? "start" : "stop", what, prev_IAR, where);\r |
| 354 | }\r |
| 355 | \r |
| 356 | /* xio_1132_printer - XIO command interpreter for the 1132 printer */\r |
| 357 | \r |
| 358 | void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)\r |
| 359 | {\r |
| 360 | char msg[80];\r |
| 361 | UNIT *uptr = &prt_unit[0];\r |
| 362 | \r |
| 363 | switch (func) {\r |
| 364 | case XIO_READ:\r |
| 365 | M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8;\r |
| 366 | \r |
| 367 | if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */\r |
| 368 | prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132;\r |
| 369 | break;\r |
| 370 | \r |
| 371 | case XIO_SENSE_DEV:\r |
| 372 | ACC = PRT_DSW;\r |
| 373 | if (modify & 0x01) { /* reset interrupts */\r |
| 374 | CLRBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE | PRT1132_DSW_SKIP_RESPONSE | PRT1132_DSW_SPACE_RESPONSE);\r |
| 375 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r |
| 376 | }\r |
| 377 | break;\r |
| 378 | \r |
| 379 | case XIO_CONTROL:\r |
| 380 | if (modify & PRT_CMD_START_PRINTER) {\r |
| 381 | SETBIT(uptr->flags, UNIT_PRINTING);\r |
| 382 | /* mytrace(1, "printing"); */\r |
| 383 | }\r |
| 384 | \r |
| 385 | if (modify & PRT_CMD_STOP_PRINTER) {\r |
| 386 | CLRBIT(uptr->flags, UNIT_PRINTING);\r |
| 387 | /* mytrace(0, "printing"); */\r |
| 388 | }\r |
| 389 | \r |
| 390 | if (modify & PRT_CMD_START_CARRIAGE) {\r |
| 391 | SETBIT(uptr->flags, UNIT_SKIPPING);\r |
| 392 | /* mytrace(1, "skipping"); */\r |
| 393 | }\r |
| 394 | \r |
| 395 | if (modify & PRT_CMD_STOP_CARRIAGE) {\r |
| 396 | CLRBIT(uptr->flags, UNIT_SKIPPING);\r |
| 397 | /* mytrace(0, "skipping"); */\r |
| 398 | }\r |
| 399 | \r |
| 400 | if (modify & PRT_CMD_SPACE) {\r |
| 401 | SETBIT(uptr->flags, UNIT_SPACING);\r |
| 402 | /* mytrace(1, "space"); */\r |
| 403 | }\r |
| 404 | \r |
| 405 | sim_cancel(uptr);\r |
| 406 | if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { /* busy bits = doing something */\r |
| 407 | SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r |
| 408 | sim_activate(uptr, prt_cwait);\r |
| 409 | }\r |
| 410 | else\r |
| 411 | CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r |
| 412 | \r |
| 413 | if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING))\r |
| 414 | SETBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY);\r |
| 415 | else\r |
| 416 | CLRBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY);\r |
| 417 | \r |
| 418 | if ((uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) == (UNIT_SKIPPING|UNIT_SPACING)) {\r |
| 419 | sprintf(msg, "1132 printer skip and space at same time?");\r |
| 420 | xio_error(msg);\r |
| 421 | }\r |
| 422 | break;\r |
| 423 | \r |
| 424 | default:\r |
| 425 | sprintf(msg, "Invalid 1132 printer XIO function %x", func);\r |
| 426 | xio_error(msg);\r |
| 427 | }\r |
| 428 | }\r |
| 429 | \r |
| 430 | #define SET_ACTION(u,a) {(u)->flags &= ~(UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING|UNIT_TRANSFERRING); (u)->flags |= a;}\r |
| 431 | \r |
| 432 | static t_stat prt_svc (UNIT *uptr)\r |
| 433 | {\r |
| 434 | return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr);\r |
| 435 | }\r |
| 436 | \r |
| 437 | /* prt1132_svc - emulated timeout for 1132 operation */\r |
| 438 | \r |
| 439 | static t_stat prt1132_svc (UNIT *uptr)\r |
| 440 | {\r |
| 441 | if (PRT_DSW & PRT1132_DSW_NOT_READY) { /* cancel operation if printer went offline */\r |
| 442 | SETBIT(uptr->flags, UNIT_FORMCHECK);\r |
| 443 | SET_ACTION(uptr, 0);\r |
| 444 | forms_check(TRUE); /* and turn on forms check lamp */\r |
| 445 | return SCPE_OK;\r |
| 446 | }\r |
| 447 | \r |
| 448 | if (uptr->flags & UNIT_SPACING) {\r |
| 449 | flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));\r |
| 450 | \r |
| 451 | CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY);\r |
| 452 | SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE);\r |
| 453 | SETBIT(ILSW[1], ILSW_1_1132_PRINTER);\r |
| 454 | CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */\r |
| 455 | calc_ints();\r |
| 456 | }\r |
| 457 | \r |
| 458 | if (uptr->flags & UNIT_SKIPPING) {\r |
| 459 | do {\r |
| 460 | flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));\r |
| 461 | CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK);\r |
| 462 | SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]));\r |
| 463 | } while ((cctape[prt_row] & CC_1132_BITS) == 0); /* slew directly to a cc tape punch */\r |
| 464 | \r |
| 465 | SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE);\r |
| 466 | SETBIT(ILSW[1], ILSW_1_1132_PRINTER);\r |
| 467 | calc_ints();\r |
| 468 | }\r |
| 469 | \r |
| 470 | if (uptr->flags & UNIT_PRINTING) {\r |
| 471 | if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { /* save previous printed line */\r |
| 472 | SETBIT(uptr->flags, UNIT_DATACHECK); /* buffer wasn't set in time */\r |
| 473 | SET_ACTION(uptr, 0);\r |
| 474 | print_check(TRUE); /* and turn on forms check lamp */\r |
| 475 | return SCPE_OK;\r |
| 476 | }\r |
| 477 | \r |
| 478 | prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; /* advance print drum */\r |
| 479 | \r |
| 480 | SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); /* issue interrupt to tell printer to set buffer */\r |
| 481 | SETBIT(ILSW[1], ILSW_1_1132_PRINTER); /* we'll save the printed stuff just before next emitter response (later than on real 1130) */\r |
| 482 | calc_ints();\r |
| 483 | }\r |
| 484 | \r |
| 485 | if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { /* still doing something */\r |
| 486 | SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r |
| 487 | sim_activate(uptr, prt_cwait);\r |
| 488 | }\r |
| 489 | else\r |
| 490 | CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r |
| 491 | \r |
| 492 | return SCPE_OK;\r |
| 493 | }\r |
| 494 | \r |
| 495 | void save_1403_prt_line (int32 addr)\r |
| 496 | {\r |
| 497 | int i, j, r, ch, even = TRUE;\r |
| 498 | unsigned char ebcdic;\r |
| 499 | int32 wd;\r |
| 500 | \r |
| 501 | for (i = 0; i < PRT1403_COLUMNS; i++) {\r |
| 502 | if (even) { /* fetch next word from memory */\r |
| 503 | wd = M[addr++];\r |
| 504 | ebcdic = (unsigned char) ((wd >> 8) & 0x7F);\r |
| 505 | even = FALSE;\r |
| 506 | }\r |
| 507 | else {\r |
| 508 | ebcdic = (unsigned char) (wd & 0x7F); /* use low byte of previously fetched word */\r |
| 509 | even = TRUE;\r |
| 510 | }\r |
| 511 | \r |
| 512 | ch = ' '; /* translate ebcdic to ascii. Don't bother checking for parity errors */\r |
| 513 | for (j = 0; j < WHEELCHARS_1403; j++) {\r |
| 514 | if (codewheel1403[j].ebcdic == ebcdic) {\r |
| 515 | ch = codewheel1403[j].ascii;\r |
| 516 | break;\r |
| 517 | }\r |
| 518 | }\r |
| 519 | \r |
| 520 | if (ch > ' ') {\r |
| 521 | if ((r = nprint[i]) < MAX_OVPRINT) {\r |
| 522 | if (ncol[r] <= i) { /* we haven't moved this far yet */\r |
| 523 | if (ncol[r] == 0) /* first char in this row? */\r |
| 524 | memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1403_COLUMNS); /* blank out the new row */\r |
| 525 | ncol[r] = i+1; /* remember new row length */\r |
| 526 | }\r |
| 527 | prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */\r |
| 528 | \r |
| 529 | nprint[i]++; /* remember max overprintings for this column */\r |
| 530 | maxnp = MAX(maxnp, nprint[i]);\r |
| 531 | }\r |
| 532 | }\r |
| 533 | }\r |
| 534 | }\r |
| 535 | \r |
| 536 | void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify)\r |
| 537 | {\r |
| 538 | UNIT *uptr = &prt_unit[0];\r |
| 539 | \r |
| 540 | switch (func) {\r |
| 541 | case XIO_INITW: /* print a line */\r |
| 542 | save_1403_prt_line(iocc_addr); /* put formatted line into our print buffer */\r |
| 543 | \r |
| 544 | SETBIT(uptr->flags, UNIT_TRANSFERRING); /* schedule transfer complete interrupt */\r |
| 545 | SETBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);\r |
| 546 | sim_activate(uptr, prt_twait);\r |
| 547 | break;\r |
| 548 | \r |
| 549 | case XIO_CONTROL: /* initiate single space */\r |
| 550 | if (uptr->flags & UNIT_SKIPPING) {\r |
| 551 | xio_error("1403 printer skip and space at same time?");\r |
| 552 | }\r |
| 553 | else {\r |
| 554 | SETBIT(uptr->flags, UNIT_SPACING);\r |
| 555 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r |
| 556 | sim_activate(uptr, prt_fwait);\r |
| 557 | }\r |
| 558 | break;\r |
| 559 | \r |
| 560 | case XIO_WRITE: /* initiate skip */\r |
| 561 | if (uptr->flags & UNIT_SPACING) {\r |
| 562 | xio_error("1403 printer skip and space at same time?");\r |
| 563 | }\r |
| 564 | else {\r |
| 565 | SETBIT(uptr->flags, UNIT_SKIPPING);\r |
| 566 | SKIPTARGET = ReadW(iocc_addr) & CC_1403_BITS; /* get CC bits that we're to match */\r |
| 567 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r |
| 568 | sim_activate(uptr, prt_fwait);\r |
| 569 | }\r |
| 570 | break;\r |
| 571 | \r |
| 572 | case XIO_SENSE_DEV: /* get device status word */\r |
| 573 | ACC = PRT_DSW;\r |
| 574 | if (modify & 0x01) { /* reset interrupts */\r |
| 575 | CLRBIT(PRT_DSW, PRT1403_DSW_PARITY_CHECK | PRT1403_DSW_TRANSFER_COMPLETE |\r |
| 576 | PRT1403_DSW_PRINT_COMPLETE | PRT1403_DSW_CARRIAGE_COMPLETE | \r |
| 577 | PRT1403_DSW_RING_CHECK | PRT1403_DSW_SYNC_CHECK);\r |
| 578 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r |
| 579 | }\r |
| 580 | break;\r |
| 581 | }\r |
| 582 | }\r |
| 583 | \r |
| 584 | static t_stat prt1403_svc(UNIT *uptr)\r |
| 585 | {\r |
| 586 | if (PRT_DSW & PRT1403_DSW_NOT_READY) { /* cancel operation if printer went offline */\r |
| 587 | SET_ACTION(uptr, 0);\r |
| 588 | forms_check(TRUE); /* and turn on forms check lamp */\r |
| 589 | }\r |
| 590 | else if (uptr->flags & UNIT_TRANSFERRING) { /* end of transfer */\r |
| 591 | CLRBIT(uptr->flags, UNIT_TRANSFERRING);\r |
| 592 | SETBIT(uptr->flags, UNIT_PRINTING); /* schedule "print complete" */\r |
| 593 | \r |
| 594 | SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); /* issue transfer complete interrupt */\r |
| 595 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER);\r |
| 596 | }\r |
| 597 | else if (uptr->flags & UNIT_PRINTING) {\r |
| 598 | CLRBIT(uptr->flags, UNIT_PRINTING);\r |
| 599 | CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);\r |
| 600 | \r |
| 601 | SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE);\r |
| 602 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER); /* issue print complete interrupt */\r |
| 603 | }\r |
| 604 | else if (uptr->flags & UNIT_SKIPPING) {\r |
| 605 | do { /* find line with exact match of tape punches */\r |
| 606 | flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));\r |
| 607 | } while (cctape[prt_row] != SKIPTARGET); /* slew directly to requested cc tape punch */\r |
| 608 | \r |
| 609 | CLRBIT(uptr->flags, UNIT_SKIPPING); /* done with this */\r |
| 610 | CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r |
| 611 | \r |
| 612 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);\r |
| 613 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER);\r |
| 614 | }\r |
| 615 | else if (uptr->flags & UNIT_SPACING) {\r |
| 616 | flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));\r |
| 617 | \r |
| 618 | CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */\r |
| 619 | CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r |
| 620 | \r |
| 621 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);\r |
| 622 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER);\r |
| 623 | }\r |
| 624 | \r |
| 625 | if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING))\r |
| 626 | sim_activate(uptr, prt_fwait);\r |
| 627 | \r |
| 628 | CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); /* set the two CC bits in the DSW */\r |
| 629 | if (cctape[prt_row] & CC_CHANNEL_9)\r |
| 630 | SETBIT(PRT_DSW, PRT1403_DSW_CH9);\r |
| 631 | if (cctape[prt_row] & CC_CHANNEL_12)\r |
| 632 | SETBIT(PRT_DSW, PRT1403_DSW_CH12);\r |
| 633 | \r |
| 634 | calc_ints();\r |
| 635 | return SCPE_OK;\r |
| 636 | }\r |
| 637 | \r |
| 638 | /* delete_cmd - SCP command to delete a file */\r |
| 639 | \r |
| 640 | static t_stat delete_cmd (int flag, char *cptr)\r |
| 641 | {\r |
| 642 | char gbuf[CBUFSIZE];\r |
| 643 | int status;\r |
| 644 | \r |
| 645 | cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r |
| 646 | if (*gbuf == 0) return SCPE_2FARG;\r |
| 647 | if (*cptr != 0) return SCPE_2MARG; /* now eol? */\r |
| 648 | \r |
| 649 | status = remove(gbuf); /* delete the file */\r |
| 650 | \r |
| 651 | if (status != 0 && errno != ENOENT) /* print message if failed and file exists */\r |
| 652 | perror(gbuf);\r |
| 653 | \r |
| 654 | return SCPE_OK;\r |
| 655 | }\r |
| 656 | \r |
| 657 | /* prt_reset - reset emulated printer */\r |
| 658 | \r |
| 659 | static t_stat prt_reset (DEVICE *dptr)\r |
| 660 | {\r |
| 661 | UNIT *uptr = &prt_unit[0];\r |
| 662 | int i;\r |
| 663 | \r |
| 664 | /* add a DELETE filename command so we can be sure to have clean listings */\r |
| 665 | register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n");\r |
| 666 | \r |
| 667 | sim_cancel(uptr);\r |
| 668 | \r |
| 669 | memset(cctape, 0, sizeof(cctape)); /* copy punch list into carriage control tape image */\r |
| 670 | \r |
| 671 | if (cgi) {\r |
| 672 | for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++)\r |
| 673 | cctape[cccgi[i].row-1] |= cccgi[i].channels;\r |
| 674 | }\r |
| 675 | else\r |
| 676 | for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++)\r |
| 677 | cctape[ccpunches[i].row-1] |= ccpunches[i].channels;\r |
| 678 | \r |
| 679 | prt_nchar = 0;\r |
| 680 | prt_row = 0;\r |
| 681 | prt_nnl = 0;\r |
| 682 | \r |
| 683 | CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK|UNIT_PRINTING|UNIT_SPACING|UNIT_SKIPPING|\r |
| 684 | UNIT_TRANSFERRING|UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);\r |
| 685 | \r |
| 686 | if (IS_1132(uptr)) {\r |
| 687 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r |
| 688 | PRT_DSW = cc_format_1132(cctape[prt_row]);\r |
| 689 | if (! IS_ONLINE(uptr))\r |
| 690 | SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);\r |
| 691 | }\r |
| 692 | else {\r |
| 693 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r |
| 694 | PRT_DSW = 0;\r |
| 695 | if (cctape[prt_row] & CC_CHANNEL_9)\r |
| 696 | SETBIT(PRT_DSW, PRT1403_DSW_CH9);\r |
| 697 | if (cctape[prt_row] & CC_CHANNEL_12)\r |
| 698 | SETBIT(PRT_DSW, PRT1403_DSW_CH12);\r |
| 699 | if (! IS_ONLINE(uptr))\r |
| 700 | SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);\r |
| 701 | }\r |
| 702 | \r |
| 703 | SET_ACTION(uptr, 0);\r |
| 704 | calc_ints();\r |
| 705 | reset_prt_line();\r |
| 706 | \r |
| 707 | forms_check(FALSE);\r |
| 708 | return SCPE_OK;\r |
| 709 | }\r |
| 710 | \r |
| 711 | static t_stat prt_attach (UNIT *uptr, char *cptr)\r |
| 712 | {\r |
| 713 | t_stat rval;\r |
| 714 | /* assume failure */\r |
| 715 | SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY);\r |
| 716 | formfed = FALSE;\r |
| 717 | \r |
| 718 | if (uptr->flags & UNIT_ATT) {\r |
| 719 | if ((rval = prt_detach(uptr)) != SCPE_OK) {\r |
| 720 | return rval;\r |
| 721 | }\r |
| 722 | }\r |
| 723 | \r |
| 724 | if (sim_switches & SWMASK('P')) /* set physical (unbuffered) printer flag */\r |
| 725 | SETBIT(uptr->flags, UNIT_PHYSICAL_PTR);\r |
| 726 | else\r |
| 727 | CLRBIT(uptr->flags, UNIT_PHYSICAL_PTR);\r |
| 728 | \r |
| 729 | sim_cancel(uptr);\r |
| 730 | \r |
| 731 | if (strcmp(cptr, "(stdout)") == 0) { /* connect printer to stdout */\r |
| 732 | if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */\r |
| 733 | uptr->filename = calloc(CBUFSIZE, sizeof(char));\r |
| 734 | strcpy(uptr->filename, "(stdout)");\r |
| 735 | uptr->fileref = stdout;\r |
| 736 | SETBIT(uptr->flags, UNIT_ATT);\r |
| 737 | uptr->pos = 0;\r |
| 738 | }\r |
| 739 | else {\r |
| 740 | if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK)\r |
| 741 | return rval;\r |
| 742 | }\r |
| 743 | \r |
| 744 | fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */\r |
| 745 | uptr->pos = ftell(uptr->fileref);\r |
| 746 | \r |
| 747 | if (IS_1132(uptr)) {\r |
| 748 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r |
| 749 | CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);\r |
| 750 | }\r |
| 751 | else {\r |
| 752 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r |
| 753 | CLRBIT(uptr->flags, UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);\r |
| 754 | }\r |
| 755 | \r |
| 756 | SET_ACTION(uptr, 0);\r |
| 757 | calc_ints();\r |
| 758 | \r |
| 759 | prt_nchar = 0;\r |
| 760 | prt_nnl = 0;\r |
| 761 | prt_row = 0;\r |
| 762 | reset_prt_line();\r |
| 763 | \r |
| 764 | if (IS_1132(uptr)) {\r |
| 765 | PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]);\r |
| 766 | \r |
| 767 | if (IS_ONLINE(uptr))\r |
| 768 | CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);\r |
| 769 | }\r |
| 770 | else {\r |
| 771 | CLRBIT(PRT_DSW, PRT1403_DSW_CH9 | PRT1403_DSW_CH12);\r |
| 772 | if (cctape[prt_row] & CC_CHANNEL_9)\r |
| 773 | SETBIT(PRT_DSW, PRT1403_DSW_CH9);\r |
| 774 | if (cctape[prt_row] & CC_CHANNEL_12)\r |
| 775 | SETBIT(PRT_DSW, PRT1403_DSW_CH12);\r |
| 776 | \r |
| 777 | if (IS_ONLINE(uptr))\r |
| 778 | CLRBIT(PRT_DSW, PRT1403_DSW_NOT_READY); /* fixed by Carl Claunch */\r |
| 779 | }\r |
| 780 | \r |
| 781 | forms_check(FALSE);\r |
| 782 | \r |
| 783 | return SCPE_OK;\r |
| 784 | }\r |
| 785 | \r |
| 786 | static t_stat prt_detach (UNIT *uptr)\r |
| 787 | {\r |
| 788 | t_stat rval;\r |
| 789 | \r |
| 790 | if (uptr->flags & UNIT_ATT)\r |
| 791 | flush_prt_line(uptr->fileref, TRUE, TRUE);\r |
| 792 | \r |
| 793 | if (uptr->fileref == stdout) {\r |
| 794 | CLRBIT(uptr->flags, UNIT_ATT);\r |
| 795 | free(uptr->filename);\r |
| 796 | uptr->filename = NULL;\r |
| 797 | }\r |
| 798 | else if ((rval = detach_unit(uptr)) != SCPE_OK)\r |
| 799 | return rval;\r |
| 800 | \r |
| 801 | sim_cancel(uptr);\r |
| 802 | \r |
| 803 | if (IS_1132(uptr)) {\r |
| 804 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r |
| 805 | CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);\r |
| 806 | SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);\r |
| 807 | }\r |
| 808 | else {\r |
| 809 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r |
| 810 | SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);\r |
| 811 | }\r |
| 812 | SET_ACTION(uptr, 0);\r |
| 813 | \r |
| 814 | calc_ints();\r |
| 815 | \r |
| 816 | forms_check(FALSE);\r |
| 817 | return SCPE_OK;\r |
| 818 | }\r |
| 819 | \r |