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