| 1 | /* pdp18b_lp.c: 18b PDP's line printer simulator\r |
| 2 | \r |
| 3 | Copyright (c) 1993-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 | lp62 (PDP-4) Type 62 line printer\r |
| 27 | lp647 (PDP-7,9) Type 647 line printer\r |
| 28 | lp09 (PDP-9,15) LP09 line printer\r |
| 29 | lp15 (PDP-15) LP15 line printer\r |
| 30 | \r |
| 31 | 19-Jan-07 RMS Added UNIT_TEXT flag\r |
| 32 | 11-Jun-06 RMS Made character translation table global scope\r |
| 33 | 14-Jan-04 RMS Revised IO device call interface\r |
| 34 | 23-Jul-03 RMS Fixed overprint bug in Type 62\r |
| 35 | 25-Apr-03 RMS Revised for extended file support\r |
| 36 | 05-Feb-03 RMS Added LP09, fixed conditionalization\r |
| 37 | 05-Oct-02 RMS Added DIB, device number support\r |
| 38 | 30-May-02 RMS Widened POS to 32b\r |
| 39 | 03-Feb-02 RMS Fixed typo (found by Robert Alan Byer)\r |
| 40 | 25-Nov-01 RMS Revised interrupt structure\r |
| 41 | 19-Sep-01 RMS Fixed bug in 647\r |
| 42 | 13-Feb-01 RMS Revised for register arrays\r |
| 43 | 15-Feb-01 RMS Fixed 3 cycle data break sequence\r |
| 44 | 30-Oct-00 RMS Standardized register naming\r |
| 45 | 20-Aug-98 RMS Fixed compilation problem in BeOS\r |
| 46 | 03-Jan-97 RMS Fixed bug in Type 62 state handling\r |
| 47 | */\r |
| 48 | \r |
| 49 | #include "pdp18b_defs.h"\r |
| 50 | extern int32 int_hwre[API_HLVL+1];\r |
| 51 | const char fio_to_asc[64] = {\r |
| 52 | ' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<',\r |
| 53 | '0','/','S','T','U','V','W','X','Y','Z','"',',','>','^','-','?',\r |
| 54 | 'o','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(',\r |
| 55 | '_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','['\r |
| 56 | };\r |
| 57 | \r |
| 58 | #if defined (TYPE62)\r |
| 59 | \r |
| 60 | /* Type 62 line printer */\r |
| 61 | \r |
| 62 | #define LP62_BSIZE 120 /* line size */\r |
| 63 | #define BPTR_MAX 40 /* pointer max */\r |
| 64 | #define BPTR_MASK 077 /* buf ptr max */\r |
| 65 | \r |
| 66 | int32 lp62_spc = 0; /* print vs spc */\r |
| 67 | int32 lp62_ovrpr = 0; /* overprint */\r |
| 68 | int32 lp62_stopioe = 0;\r |
| 69 | int32 lp62_bp = 0; /* buffer ptr */\r |
| 70 | char lp62_buf[LP62_BSIZE + 1] = { 0 };\r |
| 71 | static const char *lp62_cc[] = {\r |
| 72 | "\n",\r |
| 73 | "\n\n",\r |
| 74 | "\n\n\n",\r |
| 75 | "\n\n\n\n\n\n",\r |
| 76 | "\n\n\n\n\n\n\n\n\n\n\n",\r |
| 77 | "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",\r |
| 78 | "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",\r |
| 79 | "\f"\r |
| 80 | };\r |
| 81 | \r |
| 82 | DEVICE lp62_dev;\r |
| 83 | int32 lp62_65 (int32 dev, int32 pulse, int32 dat);\r |
| 84 | int32 lp62_66 (int32 dev, int32 pulse, int32 dat);\r |
| 85 | int32 lp62_iors (void);\r |
| 86 | t_stat lp62_svc (UNIT *uptr);\r |
| 87 | t_stat lp62_reset (DEVICE *dptr);\r |
| 88 | \r |
| 89 | /* Type 62 LPT data structures\r |
| 90 | \r |
| 91 | lp62_dev LPT device descriptor\r |
| 92 | lp62_unit LPT unit\r |
| 93 | lp62_reg LPT register list\r |
| 94 | */\r |
| 95 | \r |
| 96 | DIB lp62_dib = { DEV_LPT, 2, &lp62_iors, { &lp62_65, &lp62_66 } };\r |
| 97 | \r |
| 98 | UNIT lp62_unit = {\r |
| 99 | UDATA (&lp62_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r |
| 100 | };\r |
| 101 | \r |
| 102 | REG lp62_reg[] = {\r |
| 103 | { ORDATA (BUF, lp62_unit.buf, 8) },\r |
| 104 | { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },\r |
| 105 | { FLDATA (DONE, int_hwre[API_LPT], INT_V_LPT) },\r |
| 106 | { FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) },\r |
| 107 | { DRDATA (BPTR, lp62_bp, 6) },\r |
| 108 | { ORDATA (STATE, lp62_spc, 6), REG_HRO },\r |
| 109 | { FLDATA (OVRPR, lp62_ovrpr, 0), REG_HRO },\r |
| 110 | { DRDATA (POS, lp62_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 111 | { DRDATA (TIME, lp62_unit.wait, 24), PV_LEFT },\r |
| 112 | { FLDATA (STOP_IOE, lp62_stopioe, 0) },\r |
| 113 | { BRDATA (LBUF, lp62_buf, 8, 8, LP62_BSIZE) },\r |
| 114 | { ORDATA (DEVNO, lp62_dib.dev, 6), REG_HRO },\r |
| 115 | { NULL }\r |
| 116 | };\r |
| 117 | \r |
| 118 | MTAB lp62_mod[] = {\r |
| 119 | { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r |
| 120 | { 0 }\r |
| 121 | };\r |
| 122 | \r |
| 123 | DEVICE lp62_dev = {\r |
| 124 | "LPT", &lp62_unit, lp62_reg, lp62_mod,\r |
| 125 | 1, 10, 31, 1, 8, 8,\r |
| 126 | NULL, NULL, &lp62_reset,\r |
| 127 | NULL, NULL, NULL,\r |
| 128 | &lp62_dib, DEV_DISABLE\r |
| 129 | };\r |
| 130 | \r |
| 131 | /* IOT routines */\r |
| 132 | \r |
| 133 | int32 lp62_65 (int32 dev, int32 pulse, int32 dat)\r |
| 134 | {\r |
| 135 | int32 i;\r |
| 136 | \r |
| 137 | if ((pulse & 01) && TST_INT (LPT)) dat = IOT_SKP | dat; /* LPSF */\r |
| 138 | if (pulse & 02) {\r |
| 139 | int32 sb = pulse & 060; /* subopcode */\r |
| 140 | if (sb == 000) CLR_INT (LPT); /* LPCF */\r |
| 141 | if ((sb == 040) && (lp62_bp < BPTR_MAX)) { /* LPLD */\r |
| 142 | i = lp62_bp * 3; /* cvt to chr ptr */\r |
| 143 | lp62_buf[i] = fio_to_asc[(dat >> 12) & 077];\r |
| 144 | lp62_buf[i + 1] = fio_to_asc[(dat >> 6) & 077];\r |
| 145 | lp62_buf[i + 2] = fio_to_asc[dat & 077];\r |
| 146 | lp62_bp = (lp62_bp + 1) & BPTR_MASK;\r |
| 147 | }\r |
| 148 | }\r |
| 149 | if (pulse & 04) { /* LPSE */\r |
| 150 | lp62_spc = 0; /* print */\r |
| 151 | sim_activate (&lp62_unit, lp62_unit.wait); /* activate */\r |
| 152 | }\r |
| 153 | return dat;\r |
| 154 | }\r |
| 155 | \r |
| 156 | int32 lp62_66 (int32 dev, int32 pulse, int32 dat)\r |
| 157 | {\r |
| 158 | if ((pulse & 01) && TST_INT (LPTSPC)) /* LSSF */\r |
| 159 | dat = IOT_SKP | dat;\r |
| 160 | if (pulse & 02) CLR_INT (LPTSPC); /* LSCF */\r |
| 161 | if (pulse & 04) { /* LSPR */\r |
| 162 | lp62_spc = 020 | (dat & 07); /* space */\r |
| 163 | sim_activate (&lp62_unit, lp62_unit.wait); /* activate */\r |
| 164 | }\r |
| 165 | return dat;\r |
| 166 | }\r |
| 167 | \r |
| 168 | /* Unit service, action based on lp62_spc\r |
| 169 | \r |
| 170 | lp62_spc = 0 write buffer to file, set overprint\r |
| 171 | lp62_spc = 2x space command x, clear overprint\r |
| 172 | */\r |
| 173 | \r |
| 174 | t_stat lp62_svc (UNIT *uptr)\r |
| 175 | {\r |
| 176 | int32 i;\r |
| 177 | \r |
| 178 | if (lp62_spc) { /* space? */\r |
| 179 | SET_INT (LPTSPC); /* set flag */\r |
| 180 | if ((uptr->flags & UNIT_ATT) == 0) /* attached? */\r |
| 181 | return IORETURN (lp62_stopioe, SCPE_UNATT);\r |
| 182 | fputs (lp62_cc[lp62_spc & 07], uptr->fileref); /* print cctl */\r |
| 183 | uptr->pos = ftell (uptr->fileref); /* update position */\r |
| 184 | if (ferror (uptr->fileref)) { /* error? */\r |
| 185 | perror ("LPT I/O error");\r |
| 186 | clearerr (uptr->fileref);\r |
| 187 | return SCPE_IOERR;\r |
| 188 | }\r |
| 189 | lp62_ovrpr = 0; /* clear overprint */\r |
| 190 | }\r |
| 191 | else {\r |
| 192 | SET_INT (LPT); /* print */\r |
| 193 | if ((uptr->flags & UNIT_ATT) == 0) /* attached? */\r |
| 194 | return IORETURN (lp62_stopioe, SCPE_UNATT);\r |
| 195 | if (lp62_ovrpr) fputc ('\r', uptr->fileref); /* overprint? */\r |
| 196 | fputs (lp62_buf, uptr->fileref); /* print buffer */\r |
| 197 | uptr->pos = ftell (uptr->fileref); /* update position */\r |
| 198 | if (ferror (uptr->fileref)) { /* test error */\r |
| 199 | perror ("LPT I/O error");\r |
| 200 | clearerr (uptr->fileref);\r |
| 201 | return SCPE_IOERR;\r |
| 202 | }\r |
| 203 | lp62_bp = 0;\r |
| 204 | for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */\r |
| 205 | lp62_ovrpr = 1; /* set overprint */\r |
| 206 | }\r |
| 207 | return SCPE_OK;\r |
| 208 | }\r |
| 209 | \r |
| 210 | /* Reset routine */\r |
| 211 | \r |
| 212 | t_stat lp62_reset (DEVICE *dptr)\r |
| 213 | {\r |
| 214 | int32 i;\r |
| 215 | \r |
| 216 | CLR_INT (LPT); /* clear intrs */\r |
| 217 | CLR_INT (LPTSPC);\r |
| 218 | sim_cancel (&lp62_unit); /* deactivate unit */\r |
| 219 | lp62_bp = 0; /* clear buffer ptr */\r |
| 220 | for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */\r |
| 221 | lp62_spc = 0; /* clear state */\r |
| 222 | lp62_ovrpr = 0; /* clear overprint */\r |
| 223 | return SCPE_OK;\r |
| 224 | }\r |
| 225 | \r |
| 226 | /* IORS routine */\r |
| 227 | \r |
| 228 | int32 lp62_iors (void)\r |
| 229 | {\r |
| 230 | return (TST_INT (LPT)? IOS_LPT: 0) |\r |
| 231 | (TST_INT (LPTSPC)? IOS_LPT1: 0);\r |
| 232 | }\r |
| 233 | \r |
| 234 | #endif\r |
| 235 | \r |
| 236 | #if defined (TYPE647)\r |
| 237 | \r |
| 238 | /* Type 647 line printer */\r |
| 239 | \r |
| 240 | #define LP647_BSIZE 120 /* line size */\r |
| 241 | \r |
| 242 | int32 lp647_don = 0; /* ready */\r |
| 243 | int32 lp647_ie = 1; /* int enable */\r |
| 244 | int32 lp647_err = 0; /* error */\r |
| 245 | int32 lp647_iot = 0; /* saved state */\r |
| 246 | int32 lp647_stopioe = 0;\r |
| 247 | int32 lp647_bp = 0; /* buffer ptr */\r |
| 248 | char lp647_buf[LP647_BSIZE] = { 0 };\r |
| 249 | static const char *lp647_cc[] = {\r |
| 250 | "\n",\r |
| 251 | "\n\n",\r |
| 252 | "\n\n\n",\r |
| 253 | "\n\n\n\n\n\n",\r |
| 254 | "\n\n\n\n\n\n\n\n\n\n\n",\r |
| 255 | "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",\r |
| 256 | "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",\r |
| 257 | "\f"\r |
| 258 | };\r |
| 259 | \r |
| 260 | DEVICE lp647_dev;\r |
| 261 | int32 lp647_65 (int32 dev, int32 pulse, int32 dat);\r |
| 262 | int32 lp647_66 (int32 dev, int32 pulse, int32 dat);\r |
| 263 | int32 lp647_iors (void);\r |
| 264 | t_stat lp647_svc (UNIT *uptr);\r |
| 265 | t_stat lp647_reset (DEVICE *dptr);\r |
| 266 | t_stat lp647_attach (UNIT *uptr, char *cptr);\r |
| 267 | t_stat lp647_detach (UNIT *uptr);\r |
| 268 | \r |
| 269 | /* Type 647 LPT data structures\r |
| 270 | \r |
| 271 | lp647_dev LPT device descriptor\r |
| 272 | lp647_unit LPT unit\r |
| 273 | lp647_reg LPT register list\r |
| 274 | */\r |
| 275 | \r |
| 276 | DIB lp647_dib = { DEV_LPT, 2, &lp647_iors, { &lp647_65, &lp647_66 } };\r |
| 277 | \r |
| 278 | UNIT lp647_unit = {\r |
| 279 | UDATA (&lp647_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r |
| 280 | };\r |
| 281 | \r |
| 282 | REG lp647_reg[] = {\r |
| 283 | { ORDATA (BUF, lp647_unit.buf, 8) },\r |
| 284 | { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },\r |
| 285 | { FLDATA (DONE, lp647_don, 0) },\r |
| 286 | #if defined (PDP9)\r |
| 287 | { FLDATA (ENABLE, lp647_ie, 0) },\r |
| 288 | #endif\r |
| 289 | { FLDATA (ERR, lp647_err, 0) },\r |
| 290 | { DRDATA (BPTR, lp647_bp, 7) },\r |
| 291 | { ORDATA (SCMD, lp647_iot, 6), REG_HRO },\r |
| 292 | { DRDATA (POS, lp647_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 293 | { DRDATA (TIME, lp647_unit.wait, 24), PV_LEFT },\r |
| 294 | { FLDATA (STOP_IOE, lp647_stopioe, 0) },\r |
| 295 | { BRDATA (LBUF, lp647_buf, 8, 8, LP647_BSIZE) },\r |
| 296 | { ORDATA (DEVNO, lp647_dib.dev, 6), REG_HRO },\r |
| 297 | { NULL }\r |
| 298 | };\r |
| 299 | \r |
| 300 | MTAB lp647_mod[] = {\r |
| 301 | { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r |
| 302 | { 0 }\r |
| 303 | };\r |
| 304 | \r |
| 305 | DEVICE lp647_dev = {\r |
| 306 | "LPT", &lp647_unit, lp647_reg, lp647_mod,\r |
| 307 | 1, 10, 31, 1, 8, 8,\r |
| 308 | NULL, NULL, &lp647_reset,\r |
| 309 | NULL, &lp647_attach, &lp647_detach,\r |
| 310 | &lp647_dib, DEV_DISABLE\r |
| 311 | };\r |
| 312 | \r |
| 313 | /* IOT routines */\r |
| 314 | \r |
| 315 | int32 lp647_65 (int32 dev, int32 pulse, int32 dat)\r |
| 316 | {\r |
| 317 | int32 i, sb;\r |
| 318 | \r |
| 319 | sb = pulse & 060; /* subcode */\r |
| 320 | if ((pulse & 01) && lp647_don) dat = IOT_SKP | dat; /* LPSF */\r |
| 321 | if (pulse & 02) { /* pulse 02 */\r |
| 322 | lp647_don = 0; /* clear done */\r |
| 323 | CLR_INT (LPT); /* clear int req */\r |
| 324 | if (sb == 000) { /* LPCB */\r |
| 325 | for (i = 0; i < LP647_BSIZE; i++) lp647_buf[i] = 0;\r |
| 326 | lp647_bp = 0; /* reset buf ptr */\r |
| 327 | lp647_don = 1; /* set done */\r |
| 328 | if (lp647_ie) SET_INT (LPT); /* set int */\r |
| 329 | }\r |
| 330 | }\r |
| 331 | if (pulse & 004) { /* LPDI */\r |
| 332 | switch (sb) { /* case on subcode */\r |
| 333 | \r |
| 334 | case 000: /* LPDI */\r |
| 335 | #if defined (PDP9)\r |
| 336 | lp647_ie = 0; /* clear int enable */\r |
| 337 | CLR_INT (LPT); /* clear int req */\r |
| 338 | #endif\r |
| 339 | break;\r |
| 340 | \r |
| 341 | case 040: /* LPB3 */\r |
| 342 | if (lp647_bp < LP647_BSIZE) {\r |
| 343 | lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | ((dat >> 12) & 077);\r |
| 344 | lp647_bp = lp647_bp + 1;\r |
| 345 | }\r |
| 346 | \r |
| 347 | case 020: /* LPB2 */\r |
| 348 | if (lp647_bp < LP647_BSIZE) {\r |
| 349 | lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | ((dat >> 6) & 077);\r |
| 350 | lp647_bp = lp647_bp + 1;\r |
| 351 | }\r |
| 352 | \r |
| 353 | case 060: /* LPB1 */\r |
| 354 | if (lp647_bp < LP647_BSIZE) {\r |
| 355 | lp647_buf[lp647_bp] = lp647_buf[lp647_bp] | (dat & 077);\r |
| 356 | lp647_bp = lp647_bp + 1;\r |
| 357 | }\r |
| 358 | lp647_don = 1; /* set done */\r |
| 359 | if (lp647_ie) SET_INT (LPT); /* set int */\r |
| 360 | break;\r |
| 361 | } /* end case */\r |
| 362 | }\r |
| 363 | return dat;\r |
| 364 | }\r |
| 365 | \r |
| 366 | int32 lp647_66 (int32 dev, int32 pulse, int32 dat)\r |
| 367 | {\r |
| 368 | if ((pulse & 01) && lp647_err) dat = IOT_SKP | dat; /* LPSE */\r |
| 369 | if (pulse & 02) { /* LPCF */\r |
| 370 | lp647_don = 0; /* clear done, int */\r |
| 371 | CLR_INT (LPT);\r |
| 372 | }\r |
| 373 | if (pulse & 04) {\r |
| 374 | if ((pulse & 060) < 060) { /* LPLS, LPPB, LPPS */\r |
| 375 | lp647_iot = (pulse & 060) | (dat & 07); /* save parameters */\r |
| 376 | sim_activate (&lp647_unit, lp647_unit.wait); /* activate */\r |
| 377 | }\r |
| 378 | #if defined (PDP9)\r |
| 379 | else { /* LPEI */\r |
| 380 | lp647_ie = 1; /* set int enable */\r |
| 381 | if (lp647_don) SET_INT (LPT);\r |
| 382 | }\r |
| 383 | #endif\r |
| 384 | }\r |
| 385 | return dat;\r |
| 386 | }\r |
| 387 | \r |
| 388 | /* Unit service. lp647_iot specifies the action to be taken\r |
| 389 | \r |
| 390 | lp647_iot = 0x print only\r |
| 391 | lp647_iot = 2x space only, x is spacing command\r |
| 392 | lp647_iot = 4x print then space, x is spacing command\r |
| 393 | */\r |
| 394 | \r |
| 395 | t_stat lp647_svc (UNIT *uptr)\r |
| 396 | {\r |
| 397 | int32 i;\r |
| 398 | char pbuf[LP647_BSIZE + 2];\r |
| 399 | \r |
| 400 | lp647_don = 1;\r |
| 401 | if (lp647_ie) SET_INT (LPT); /* set flag */\r |
| 402 | if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r |
| 403 | lp647_err = 1; /* set error */\r |
| 404 | return IORETURN (lp647_stopioe, SCPE_UNATT);\r |
| 405 | }\r |
| 406 | if ((lp647_iot & 020) == 0) { /* print? */\r |
| 407 | for (i = 0; i < lp647_bp; i++) /* translate buffer */\r |
| 408 | pbuf[i] = lp647_buf[i] | ((lp647_buf[i] >= 040)? 0: 0100);\r |
| 409 | if ((lp647_iot & 060) == 0) pbuf[lp647_bp++] = '\r';\r |
| 410 | pbuf[lp647_bp++] = 0; /* append nul */\r |
| 411 | for (i = 0; i < LP647_BSIZE; i++) lp647_buf[i] = 0; /* clear buffer */\r |
| 412 | fputs (pbuf, uptr->fileref); /* print buffer */\r |
| 413 | uptr->pos = ftell (uptr->fileref); /* update position */\r |
| 414 | if (ferror (uptr->fileref)) { /* error? */\r |
| 415 | perror ("LPT I/O error");\r |
| 416 | clearerr (uptr->fileref);\r |
| 417 | lp647_bp = 0;\r |
| 418 | return SCPE_IOERR;\r |
| 419 | }\r |
| 420 | lp647_bp = 0; /* clear buffer ptr */\r |
| 421 | }\r |
| 422 | if (lp647_iot & 060) { /* space? */\r |
| 423 | fputs (lp647_cc[lp647_iot & 07], uptr->fileref); /* write cctl */\r |
| 424 | uptr->pos = ftell (uptr->fileref); /* update position */\r |
| 425 | if (ferror (uptr->fileref)) { /* error? */\r |
| 426 | perror ("LPT I/O error");\r |
| 427 | clearerr (uptr->fileref);\r |
| 428 | return SCPE_IOERR;\r |
| 429 | }\r |
| 430 | }\r |
| 431 | return SCPE_OK;\r |
| 432 | }\r |
| 433 | \r |
| 434 | /* Reset routine */\r |
| 435 | \r |
| 436 | t_stat lp647_reset (DEVICE *dptr)\r |
| 437 | {\r |
| 438 | int32 i;\r |
| 439 | \r |
| 440 | lp647_don = 0; /* clear done */\r |
| 441 | lp647_err = (lp647_unit.flags & UNIT_ATT)? 0: 1; /* clr/set error */\r |
| 442 | lp647_ie = 1; /* set enable */\r |
| 443 | CLR_INT (LPT); /* clear int */\r |
| 444 | sim_cancel (&lp647_unit); /* deactivate unit */\r |
| 445 | lp647_bp = 0; /* clear buffer ptr */\r |
| 446 | lp647_iot = 0; /* clear state */\r |
| 447 | for (i = 0; i < LP647_BSIZE; i++) lp647_buf[i] = 0; /* clear buffer */\r |
| 448 | return SCPE_OK;\r |
| 449 | }\r |
| 450 | \r |
| 451 | /* IORS routine */\r |
| 452 | \r |
| 453 | int32 lp647_iors (void)\r |
| 454 | {\r |
| 455 | return (lp647_don? IOS_LPT: 0) | (lp647_err? IOS_LPT1: 0);\r |
| 456 | }\r |
| 457 | \r |
| 458 | /* Attach routine */\r |
| 459 | \r |
| 460 | t_stat lp647_attach (UNIT *uptr, char *cptr)\r |
| 461 | {\r |
| 462 | t_stat reason;\r |
| 463 | \r |
| 464 | reason = attach_unit (uptr, cptr);\r |
| 465 | lp647_err = (lp647_unit.flags & UNIT_ATT)? 0: 1; /* clr/set error */\r |
| 466 | return reason;\r |
| 467 | }\r |
| 468 | \r |
| 469 | /* Detach routine */\r |
| 470 | \r |
| 471 | t_stat lp647_detach (UNIT *uptr)\r |
| 472 | {\r |
| 473 | lp647_err = 1;\r |
| 474 | return detach_unit (uptr);\r |
| 475 | }\r |
| 476 | \r |
| 477 | #endif\r |
| 478 | \r |
| 479 | #if defined (LP09)\r |
| 480 | \r |
| 481 | /* LP09 line printer */\r |
| 482 | \r |
| 483 | #define LP09_BSIZE 132 /* line size */\r |
| 484 | \r |
| 485 | int32 lp09_don = 0; /* ready */\r |
| 486 | int32 lp09_err = 0; /* error */\r |
| 487 | int32 lp09_ie = 1; /* int enable */\r |
| 488 | int32 lp09_stopioe = 0;\r |
| 489 | DEVICE lp09_dev;\r |
| 490 | \r |
| 491 | int32 lp09_66 (int32 dev, int32 pulse, int32 dat);\r |
| 492 | int32 lp09_iors (void);\r |
| 493 | t_stat lp09_svc (UNIT *uptr);\r |
| 494 | t_stat lp09_reset (DEVICE *dptr);\r |
| 495 | t_stat lp09_attach (UNIT *uptr, char *cptr);\r |
| 496 | t_stat lp09_detach (UNIT *uptr);\r |
| 497 | \r |
| 498 | /* LP09 LPT data structures\r |
| 499 | \r |
| 500 | lp09_dev LPT device descriptor\r |
| 501 | lp09_unit LPT unit\r |
| 502 | lp09_reg LPT register list\r |
| 503 | */\r |
| 504 | \r |
| 505 | DIB lp09_dib = { DEV_LPT, 2, &lp09_iors, { NULL, &lp09_66 } };\r |
| 506 | \r |
| 507 | UNIT lp09_unit = {\r |
| 508 | UDATA (&lp09_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r |
| 509 | };\r |
| 510 | \r |
| 511 | REG lp09_reg[] = {\r |
| 512 | { ORDATA (BUF, lp09_unit.buf, 7) },\r |
| 513 | { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },\r |
| 514 | { FLDATA (DONE, lp09_don, 0) },\r |
| 515 | { FLDATA (ENABLE, lp09_ie, 0) },\r |
| 516 | { FLDATA (ERR, lp09_err, 0) },\r |
| 517 | { DRDATA (POS, lp09_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 518 | { DRDATA (TIME, lp09_unit.wait, 24), PV_LEFT },\r |
| 519 | { FLDATA (STOP_IOE, lp09_stopioe, 0) },\r |
| 520 | { ORDATA (DEVNO, lp09_dib.dev, 6), REG_HRO },\r |
| 521 | { NULL }\r |
| 522 | };\r |
| 523 | \r |
| 524 | MTAB lp09_mod[] = {\r |
| 525 | { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r |
| 526 | { 0 }\r |
| 527 | };\r |
| 528 | \r |
| 529 | DEVICE lp09_dev = {\r |
| 530 | "LP9", &lp09_unit, lp09_reg, lp09_mod,\r |
| 531 | 1, 10, 31, 1, 8, 8,\r |
| 532 | NULL, NULL, &lp09_reset,\r |
| 533 | NULL, &lp09_attach, &lp09_detach,\r |
| 534 | &lp09_dib, DEV_DISABLE | DEV_DIS\r |
| 535 | };\r |
| 536 | \r |
| 537 | /* IOT routines */\r |
| 538 | \r |
| 539 | int32 lp09_66 (int32 dev, int32 pulse, int32 dat)\r |
| 540 | {\r |
| 541 | int32 sb = pulse & 060; /* subopcode */\r |
| 542 | \r |
| 543 | if (pulse & 001) {\r |
| 544 | if ((sb == 000) && lp09_don) dat = IOT_SKP | dat; /* LSDF */\r |
| 545 | if ((sb == 020) && lp09_err) dat = IOT_SKP | dat; /* LSEF */\r |
| 546 | }\r |
| 547 | if (pulse & 002) {\r |
| 548 | if (sb == 000) { /* LSCF */\r |
| 549 | lp09_don = 0; /* clear done, int */\r |
| 550 | CLR_INT (LPT);\r |
| 551 | }\r |
| 552 | else if (sb == 020) { /* LPLD */\r |
| 553 | lp09_don = 0; /* clear done, int */\r |
| 554 | CLR_INT (LPT);\r |
| 555 | lp09_unit.buf = dat & 0177; /* load char */\r |
| 556 | if ((lp09_unit.buf == 015) || (lp09_unit.buf == 014) ||\r |
| 557 | (lp09_unit.buf == 012))\r |
| 558 | sim_activate (&lp09_unit, lp09_unit.wait);\r |
| 559 | else dat = dat | (lp09_svc (&lp09_unit) << IOT_V_REASON);\r |
| 560 | }\r |
| 561 | }\r |
| 562 | if (pulse & 004) {\r |
| 563 | if (sb == 000) { /* LIOF */\r |
| 564 | lp09_ie = 0; /* clear int enab */\r |
| 565 | CLR_INT (LPT); /* clear int */\r |
| 566 | }\r |
| 567 | else if (sb == 040) { /* LION */\r |
| 568 | lp09_ie = 1; /* set int enab */\r |
| 569 | if (lp09_don) SET_INT (LPT); /* if done, set int */\r |
| 570 | }\r |
| 571 | }\r |
| 572 | return dat;\r |
| 573 | }\r |
| 574 | \r |
| 575 | /* Unit service */\r |
| 576 | \r |
| 577 | t_stat lp09_svc (UNIT *uptr)\r |
| 578 | {\r |
| 579 | int32 c;\r |
| 580 | \r |
| 581 | lp09_don = 1; /* set done */\r |
| 582 | if (lp09_ie) SET_INT (LPT); /* int enb? req int */\r |
| 583 | if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r |
| 584 | lp09_err = 1; /* set error */\r |
| 585 | return IORETURN (lp09_stopioe, SCPE_UNATT);\r |
| 586 | }\r |
| 587 | c = uptr->buf & 0177; /* get char */\r |
| 588 | if ((c == 0) || (c == 0177)) return SCPE_OK; /* skip NULL, DEL */\r |
| 589 | fputc (c, uptr->fileref); /* print char */\r |
| 590 | uptr->pos = ftell (uptr->fileref); /* update position */\r |
| 591 | if (ferror (uptr->fileref)) { /* error? */\r |
| 592 | perror ("LPT I/O error");\r |
| 593 | clearerr (uptr->fileref);\r |
| 594 | return SCPE_IOERR;\r |
| 595 | }\r |
| 596 | return SCPE_OK;\r |
| 597 | }\r |
| 598 | \r |
| 599 | /* Reset routine */\r |
| 600 | \r |
| 601 | t_stat lp09_reset (DEVICE *dptr)\r |
| 602 | {\r |
| 603 | lp09_don = 0; /* clear done */\r |
| 604 | lp09_err = (lp09_unit.flags & UNIT_ATT)? 0: 1; /* compute error */\r |
| 605 | lp09_ie = 1; /* set enable */\r |
| 606 | CLR_INT (LPT); /* clear int */\r |
| 607 | return SCPE_OK;\r |
| 608 | }\r |
| 609 | \r |
| 610 | /* IORS routine */\r |
| 611 | \r |
| 612 | int32 lp09_iors (void)\r |
| 613 | {\r |
| 614 | return (lp09_don? IOS_LPT: 0);\r |
| 615 | }\r |
| 616 | \r |
| 617 | /* Attach routine */\r |
| 618 | \r |
| 619 | t_stat lp09_attach (UNIT *uptr, char *cptr)\r |
| 620 | {\r |
| 621 | t_stat reason;\r |
| 622 | \r |
| 623 | reason = attach_unit (uptr, cptr);\r |
| 624 | lp09_err = (lp09_unit.flags & UNIT_ATT)? 0: 1; /* clr/set error */\r |
| 625 | return reason;\r |
| 626 | }\r |
| 627 | \r |
| 628 | /* Detach routine */\r |
| 629 | \r |
| 630 | t_stat lp09_detach (UNIT *uptr)\r |
| 631 | {\r |
| 632 | lp09_err = 1;\r |
| 633 | return detach_unit (uptr);\r |
| 634 | }\r |
| 635 | \r |
| 636 | #endif\r |
| 637 | \r |
| 638 | #if defined (LP15)\r |
| 639 | \r |
| 640 | /* LP15 line printer */\r |
| 641 | \r |
| 642 | #define LP15_BSIZE 132 /* line size */\r |
| 643 | #define LPT_WC 034 /* word count */\r |
| 644 | #define LPT_CA 035 /* current addr */\r |
| 645 | \r |
| 646 | /* Status register */\r |
| 647 | \r |
| 648 | #define STA_ERR 0400000 /* error */\r |
| 649 | #define STA_ALM 0200000 /* alarm */\r |
| 650 | #define STA_OVF 0100000 /* line overflow */\r |
| 651 | #define STA_IHT 0040000 /* illegal HT */\r |
| 652 | #define STA_BUSY 0020000 /* busy */\r |
| 653 | #define STA_DON 0010000 /* done */\r |
| 654 | #define STA_ILK 0004000 /* interlock */\r |
| 655 | #define STA_EFLGS (STA_ALM | STA_OVF | STA_IHT | STA_ILK)\r |
| 656 | #define STA_CLR 0003777 /* always clear */\r |
| 657 | \r |
| 658 | extern int32 M[];\r |
| 659 | int32 lp15_sta = 0;\r |
| 660 | int32 lp15_ie = 1;\r |
| 661 | int32 lp15_stopioe = 0;\r |
| 662 | int32 lp15_mode = 0;\r |
| 663 | int32 lp15_lc = 0;\r |
| 664 | int32 lp15_bp = 0;\r |
| 665 | char lp15_buf[LP15_BSIZE + 1] = { 0 };\r |
| 666 | \r |
| 667 | DEVICE lp15_dev;\r |
| 668 | int32 lp15_65 (int32 dev, int32 pulse, int32 dat);\r |
| 669 | int32 lp15_66 (int32 dev, int32 pulse, int32 dat);\r |
| 670 | int32 lp15_iors (void);\r |
| 671 | t_stat lp15_svc (UNIT *uptr);\r |
| 672 | t_stat lp15_reset (DEVICE *dptr);\r |
| 673 | \r |
| 674 | int32 lp15_updsta (int32 new);\r |
| 675 | \r |
| 676 | /* LP15 LPT data structures\r |
| 677 | \r |
| 678 | lp15_dev LPT device descriptor\r |
| 679 | lp15_unit LPT unit\r |
| 680 | lp15_reg LPT register list\r |
| 681 | */\r |
| 682 | \r |
| 683 | DIB lp15_dib = { DEV_LPT, 2, &lp15_iors, { &lp15_65, &lp15_66 } };\r |
| 684 | \r |
| 685 | UNIT lp15_unit = {\r |
| 686 | UDATA (&lp15_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r |
| 687 | };\r |
| 688 | \r |
| 689 | REG lp15_reg[] = {\r |
| 690 | { ORDATA (STA, lp15_sta, 18) },\r |
| 691 | { ORDATA (CA, M[LPT_CA], 18) },\r |
| 692 | { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },\r |
| 693 | { FLDATA (ENABLE, lp15_ie, 0) },\r |
| 694 | { DRDATA (LCNT, lp15_lc, 9) },\r |
| 695 | { DRDATA (BPTR, lp15_bp, 8) },\r |
| 696 | { FLDATA (MODE, lp15_mode, 0) },\r |
| 697 | { DRDATA (POS, lp15_unit.pos, T_ADDR_W), PV_LEFT },\r |
| 698 | { DRDATA (TIME, lp15_unit.wait, 24), PV_LEFT },\r |
| 699 | { FLDATA (STOP_IOE, lp15_stopioe, 0) },\r |
| 700 | { BRDATA (LBUF, lp15_buf, 8, 8, LP15_BSIZE) },\r |
| 701 | { ORDATA (DEVNO, lp15_dib.dev, 6), REG_HRO },\r |
| 702 | { NULL }\r |
| 703 | };\r |
| 704 | \r |
| 705 | MTAB lp15_mod[] = {\r |
| 706 | { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r |
| 707 | { 0 }\r |
| 708 | };\r |
| 709 | \r |
| 710 | DEVICE lp15_dev = {\r |
| 711 | "LPT", &lp15_unit, lp15_reg, lp15_mod,\r |
| 712 | 1, 10, 31, 1, 8, 8,\r |
| 713 | NULL, NULL, &lp15_reset,\r |
| 714 | NULL, NULL, NULL,\r |
| 715 | &lp15_dib, DEV_DISABLE\r |
| 716 | };\r |
| 717 | \r |
| 718 | /* IOT routines */\r |
| 719 | \r |
| 720 | int32 lp15_65 (int32 dev, int32 pulse, int32 dat)\r |
| 721 | {\r |
| 722 | int32 header, sb;\r |
| 723 | \r |
| 724 | sb = pulse & 060; /* subopcode */\r |
| 725 | if (pulse & 01) {\r |
| 726 | if ((sb == 000) && (lp15_sta & (STA_ERR | STA_DON))) /* LPSF */\r |
| 727 | dat = IOT_SKP | dat;\r |
| 728 | else if ((sb == 020) || (sb == 040)) { /* LPP1, LPPM */\r |
| 729 | sim_activate (&lp15_unit, lp15_unit.wait); /* activate */\r |
| 730 | header = M[(M[LPT_CA] + 1) & AMASK]; /* get first word */\r |
| 731 | M[LPT_CA] = (M[LPT_CA] + 2) & DMASK;\r |
| 732 | lp15_mode = header & 1; /* mode */\r |
| 733 | if (sb == 040) lp15_lc = 1; /* line count */\r |
| 734 | else lp15_lc = (header >> 9) & 0377;\r |
| 735 | if (lp15_lc == 0) lp15_lc = 256;\r |
| 736 | lp15_bp = 0; /* reset buf ptr */\r |
| 737 | }\r |
| 738 | else if (sb == 060) lp15_ie = 0; /* LPDI */\r |
| 739 | }\r |
| 740 | if ((pulse & 02) && (sb == 040)) dat = dat | lp15_updsta (0); /* LPOS, LPRS */\r |
| 741 | if ((pulse & 04) && (sb == 040)) lp15_ie = 1; /* LPEI */\r |
| 742 | lp15_updsta (0); /* update status */\r |
| 743 | return dat;\r |
| 744 | }\r |
| 745 | \r |
| 746 | int32 lp15_66 (int32 dev, int32 pulse, int32 dat)\r |
| 747 | {\r |
| 748 | if (pulse == 021) lp15_sta = lp15_sta & ~STA_DON; /* LPCD */\r |
| 749 | if (pulse == 041) lp15_sta = 0; /* LPCF */\r |
| 750 | lp15_updsta (0); /* update status */\r |
| 751 | return dat;\r |
| 752 | }\r |
| 753 | \r |
| 754 | /* Unit service */\r |
| 755 | \r |
| 756 | t_stat lp15_svc (UNIT *uptr)\r |
| 757 | {\r |
| 758 | int32 i, ccnt, more, w0, w1;\r |
| 759 | char c[5];\r |
| 760 | static const char *ctrl[040] = {\r |
| 761 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r |
| 762 | NULL, NULL, "\n", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",\r |
| 763 | "\f", "\r", NULL, NULL,\r |
| 764 | "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",\r |
| 765 | "\n\n", "\n\n\n", "\n",\r |
| 766 | "\n\n\n\n\n\n\n\n\n\n", NULL, NULL, NULL,\r |
| 767 | NULL, NULL, NULL, "\r", NULL, NULL, NULL, NULL\r |
| 768 | };\r |
| 769 | \r |
| 770 | if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r |
| 771 | lp15_updsta (STA_DON | STA_ALM); /* set done, err */\r |
| 772 | return IORETURN (lp15_stopioe, SCPE_UNATT);\r |
| 773 | }\r |
| 774 | \r |
| 775 | for (more = 1; more != 0; ) { /* loop until ctrl */\r |
| 776 | w0 = M[(M[LPT_CA] + 1) & AMASK]; /* get first word */\r |
| 777 | w1 = M[(M[LPT_CA] + 2) & AMASK]; /* get second word */\r |
| 778 | M[LPT_CA] = (M[LPT_CA] + 2) & DMASK; /* advance mem addr */\r |
| 779 | if (lp15_mode) { /* unpacked? */\r |
| 780 | c[0] = w0 & 0177;\r |
| 781 | c[1] = w1 & 0177;\r |
| 782 | ccnt = 2;\r |
| 783 | }\r |
| 784 | else { /* packed */\r |
| 785 | c[0] = (w0 >> 11) & 0177;\r |
| 786 | c[1] = (w0 >> 4) & 0177;\r |
| 787 | c[2] = (((w0 << 3) | (w1 >> 15))) & 0177;\r |
| 788 | c[3] = (w1 >> 8) & 0177;\r |
| 789 | c[4] = (w1 >> 1) & 0177;\r |
| 790 | ccnt = 5;\r |
| 791 | }\r |
| 792 | for (i = 0; i < ccnt; i++) { /* loop through */\r |
| 793 | if ((c[i] <= 037) && ctrl[c[i]]) { /* control char? */\r |
| 794 | lp15_buf[lp15_bp] = 0; /* append nul */\r |
| 795 | fputs (lp15_buf, uptr->fileref); /* print line */\r |
| 796 | fputs (ctrl[c[i]], uptr->fileref); /* space */\r |
| 797 | uptr->pos = ftell (uptr->fileref);\r |
| 798 | if (ferror (uptr->fileref)) { /* error? */\r |
| 799 | perror ("LPT I/O error");\r |
| 800 | clearerr (uptr->fileref);\r |
| 801 | lp15_bp = 0;\r |
| 802 | lp15_updsta (STA_DON | STA_ALM);\r |
| 803 | return SCPE_IOERR;\r |
| 804 | }\r |
| 805 | lp15_bp = more = 0;\r |
| 806 | }\r |
| 807 | else {\r |
| 808 | if (lp15_bp < LP15_BSIZE) lp15_buf[lp15_bp++] = c[i];\r |
| 809 | else lp15_sta = lp15_sta | STA_OVF;\r |
| 810 | }\r |
| 811 | }\r |
| 812 | }\r |
| 813 | \r |
| 814 | lp15_lc = lp15_lc - 1; /* decr line count */\r |
| 815 | if (lp15_lc) sim_activate (&lp15_unit, uptr->wait); /* more to do? */\r |
| 816 | else lp15_updsta (STA_DON); /* no, set done */\r |
| 817 | return SCPE_OK;\r |
| 818 | }\r |
| 819 | \r |
| 820 | /* Update status */\r |
| 821 | \r |
| 822 | int32 lp15_updsta (int32 new)\r |
| 823 | {\r |
| 824 | lp15_sta = (lp15_sta | new) & ~(STA_CLR | STA_ERR | STA_BUSY);\r |
| 825 | if (lp15_sta & STA_EFLGS) lp15_sta = lp15_sta | STA_ERR; /* update errors */\r |
| 826 | if (sim_is_active (&lp15_unit)) lp15_sta = lp15_sta | STA_BUSY;\r |
| 827 | if (lp15_ie && (lp15_sta & STA_DON)) SET_INT (LPT);\r |
| 828 | else CLR_INT (LPT); /* update int */\r |
| 829 | return lp15_sta;\r |
| 830 | }\r |
| 831 | \r |
| 832 | /* Reset routine */\r |
| 833 | \r |
| 834 | t_stat lp15_reset (DEVICE *dptr)\r |
| 835 | {\r |
| 836 | lp15_mode = lp15_lc = lp15_bp = 0; /* clear controls */\r |
| 837 | sim_cancel (&lp15_unit); /* deactivate unit */\r |
| 838 | lp15_sta = 0; /* clear status */\r |
| 839 | lp15_ie = 1; /* enable interrupts */\r |
| 840 | lp15_updsta (0); /* update status */\r |
| 841 | return SCPE_OK;\r |
| 842 | }\r |
| 843 | \r |
| 844 | /* IORS routine */\r |
| 845 | \r |
| 846 | int32 lp15_iors (void)\r |
| 847 | {\r |
| 848 | return ((lp15_sta & STA_DON)? IOS_LPT: 0);\r |
| 849 | }\r |
| 850 | \r |
| 851 | #endif\r |