1 /* pdp18b_lp.c: 18b PDP's line printer simulator
3 Copyright (c) 1993-2007, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
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
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
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','*','.','+',']','|','['
60 /* Type 62 line printer */
62 #define LP62_BSIZE 120 /* line size */
63 #define BPTR_MAX 40 /* pointer max */
64 #define BPTR_MASK 077 /* buf ptr max */
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
[] = {
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",
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
);
89 /* Type 62 LPT data structures
91 lp62_dev LPT device descriptor
93 lp62_reg LPT register list
96 DIB lp62_dib
= { DEV_LPT
, 2, &lp62_iors
, { &lp62_65
, &lp62_66
} };
99 UDATA (&lp62_svc
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_TEXT
, 0), SERIAL_OUT_WAIT
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
},
119 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO", &set_devno
, &show_devno
},
124 "LPT", &lp62_unit
, lp62_reg
, lp62_mod
,
126 NULL
, NULL
, &lp62_reset
,
128 &lp62_dib
, DEV_DISABLE
133 int32
lp62_65 (int32 dev
, int32 pulse
, int32 dat
)
137 if ((pulse
& 01) && TST_INT (LPT
)) dat
= IOT_SKP
| dat
; /* LPSF */
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
;
149 if (pulse
& 04) { /* LPSE */
150 lp62_spc
= 0; /* print */
151 sim_activate (&lp62_unit
, lp62_unit
.wait
); /* activate */
156 int32
lp62_66 (int32 dev
, int32 pulse
, int32 dat
)
158 if ((pulse
& 01) && TST_INT (LPTSPC
)) /* LSSF */
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 */
168 /* Unit service, action based on lp62_spc
170 lp62_spc = 0 write buffer to file, set overprint
171 lp62_spc = 2x space command x, clear overprint
174 t_stat
lp62_svc (UNIT
*uptr
)
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
);
189 lp62_ovrpr
= 0; /* clear overprint */
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
);
204 for (i
= 0; i
<= LP62_BSIZE
; i
++) lp62_buf
[i
] = 0; /* clear buffer */
205 lp62_ovrpr
= 1; /* set overprint */
212 t_stat
lp62_reset (DEVICE
*dptr
)
216 CLR_INT (LPT
); /* clear intrs */
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 */
228 int32
lp62_iors (void)
230 return (TST_INT (LPT
)? IOS_LPT
: 0) |
231 (TST_INT (LPTSPC
)? IOS_LPT1
: 0);
236 #if defined (TYPE647)
238 /* Type 647 line printer */
240 #define LP647_BSIZE 120 /* line size */
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
[] = {
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",
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
);
269 /* Type 647 LPT data structures
271 lp647_dev LPT device descriptor
273 lp647_reg LPT register list
276 DIB lp647_dib
= { DEV_LPT
, 2, &lp647_iors
, { &lp647_65
, &lp647_66
} };
279 UDATA (&lp647_svc
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_TEXT
, 0), SERIAL_OUT_WAIT
283 { ORDATA (BUF
, lp647_unit
.buf
, 8) },
284 { FLDATA (INT
, int_hwre
[API_LPT
], INT_V_LPT
) },
285 { FLDATA (DONE
, lp647_don
, 0) },
287 { FLDATA (ENABLE
, lp647_ie
, 0) },
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
},
301 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO", &set_devno
, &show_devno
},
306 "LPT", &lp647_unit
, lp647_reg
, lp647_mod
,
308 NULL
, NULL
, &lp647_reset
,
309 NULL
, &lp647_attach
, &lp647_detach
,
310 &lp647_dib
, DEV_DISABLE
315 int32
lp647_65 (int32 dev
, int32 pulse
, int32 dat
)
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 */
331 if (pulse
& 004) { /* LPDI */
332 switch (sb
) { /* case on subcode */
336 lp647_ie
= 0; /* clear int enable */
337 CLR_INT (LPT
); /* clear int req */
342 if (lp647_bp
< LP647_BSIZE
) {
343 lp647_buf
[lp647_bp
] = lp647_buf
[lp647_bp
] | ((dat
>> 12) & 077);
344 lp647_bp
= lp647_bp
+ 1;
348 if (lp647_bp
< LP647_BSIZE
) {
349 lp647_buf
[lp647_bp
] = lp647_buf
[lp647_bp
] | ((dat
>> 6) & 077);
350 lp647_bp
= lp647_bp
+ 1;
354 if (lp647_bp
< LP647_BSIZE
) {
355 lp647_buf
[lp647_bp
] = lp647_buf
[lp647_bp
] | (dat
& 077);
356 lp647_bp
= lp647_bp
+ 1;
358 lp647_don
= 1; /* set done */
359 if (lp647_ie
) SET_INT (LPT
); /* set int */
366 int32
lp647_66 (int32 dev
, int32 pulse
, int32 dat
)
368 if ((pulse
& 01) && lp647_err
) dat
= IOT_SKP
| dat
; /* LPSE */
369 if (pulse
& 02) { /* LPCF */
370 lp647_don
= 0; /* clear done, int */
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 */
380 lp647_ie
= 1; /* set int enable */
381 if (lp647_don
) SET_INT (LPT
);
388 /* Unit service. lp647_iot specifies the action to be taken
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
395 t_stat
lp647_svc (UNIT
*uptr
)
398 char pbuf
[LP647_BSIZE
+ 2];
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
);
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
);
420 lp647_bp
= 0; /* clear buffer ptr */
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
);
436 t_stat
lp647_reset (DEVICE
*dptr
)
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 */
453 int32
lp647_iors (void)
455 return (lp647_don
? IOS_LPT
: 0) | (lp647_err
? IOS_LPT1
: 0);
460 t_stat
lp647_attach (UNIT
*uptr
, char *cptr
)
464 reason
= attach_unit (uptr
, cptr
);
465 lp647_err
= (lp647_unit
.flags
& UNIT_ATT
)? 0: 1; /* clr/set error */
471 t_stat
lp647_detach (UNIT
*uptr
)
474 return detach_unit (uptr
);
481 /* LP09 line printer */
483 #define LP09_BSIZE 132 /* line size */
485 int32 lp09_don
= 0; /* ready */
486 int32 lp09_err
= 0; /* error */
487 int32 lp09_ie
= 1; /* int enable */
488 int32 lp09_stopioe
= 0;
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
);
498 /* LP09 LPT data structures
500 lp09_dev LPT device descriptor
502 lp09_reg LPT register list
505 DIB lp09_dib
= { DEV_LPT
, 2, &lp09_iors
, { NULL
, &lp09_66
} };
508 UDATA (&lp09_svc
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_TEXT
, 0), SERIAL_OUT_WAIT
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
},
525 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO", &set_devno
, &show_devno
},
530 "LP9", &lp09_unit
, lp09_reg
, lp09_mod
,
532 NULL
, NULL
, &lp09_reset
,
533 NULL
, &lp09_attach
, &lp09_detach
,
534 &lp09_dib
, DEV_DISABLE
| DEV_DIS
539 int32
lp09_66 (int32 dev
, int32 pulse
, int32 dat
)
541 int32 sb
= pulse
& 060; /* subopcode */
544 if ((sb
== 000) && lp09_don
) dat
= IOT_SKP
| dat
; /* LSDF */
545 if ((sb
== 020) && lp09_err
) dat
= IOT_SKP
| dat
; /* LSEF */
548 if (sb
== 000) { /* LSCF */
549 lp09_don
= 0; /* clear done, int */
552 else if (sb
== 020) { /* LPLD */
553 lp09_don
= 0; /* clear done, int */
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
);
563 if (sb
== 000) { /* LIOF */
564 lp09_ie
= 0; /* clear int enab */
565 CLR_INT (LPT
); /* clear int */
567 else if (sb
== 040) { /* LION */
568 lp09_ie
= 1; /* set int enab */
569 if (lp09_don
) SET_INT (LPT
); /* if done, set int */
577 t_stat
lp09_svc (UNIT
*uptr
)
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
);
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
);
601 t_stat
lp09_reset (DEVICE
*dptr
)
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 */
612 int32
lp09_iors (void)
614 return (lp09_don
? IOS_LPT
: 0);
619 t_stat
lp09_attach (UNIT
*uptr
, char *cptr
)
623 reason
= attach_unit (uptr
, cptr
);
624 lp09_err
= (lp09_unit
.flags
& UNIT_ATT
)? 0: 1; /* clr/set error */
630 t_stat
lp09_detach (UNIT
*uptr
)
633 return detach_unit (uptr
);
640 /* LP15 line printer */
642 #define LP15_BSIZE 132 /* line size */
643 #define LPT_WC 034 /* word count */
644 #define LPT_CA 035 /* current addr */
646 /* Status register */
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 */
661 int32 lp15_stopioe
= 0;
665 char lp15_buf
[LP15_BSIZE
+ 1] = { 0 };
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
);
674 int32
lp15_updsta (int32
new);
676 /* LP15 LPT data structures
678 lp15_dev LPT device descriptor
680 lp15_reg LPT register list
683 DIB lp15_dib
= { DEV_LPT
, 2, &lp15_iors
, { &lp15_65
, &lp15_66
} };
686 UDATA (&lp15_svc
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_TEXT
, 0), SERIAL_OUT_WAIT
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
},
706 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO", &set_devno
, &show_devno
},
711 "LPT", &lp15_unit
, lp15_reg
, lp15_mod
,
713 NULL
, NULL
, &lp15_reset
,
715 &lp15_dib
, DEV_DISABLE
720 int32
lp15_65 (int32 dev
, int32 pulse
, int32 dat
)
724 sb
= pulse
& 060; /* subopcode */
726 if ((sb
== 000) && (lp15_sta
& (STA_ERR
| STA_DON
))) /* LPSF */
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 */
738 else if (sb
== 060) lp15_ie
= 0; /* LPDI */
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 */
746 int32
lp15_66 (int32 dev
, int32 pulse
, int32 dat
)
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 */
756 t_stat
lp15_svc (UNIT
*uptr
)
758 int32 i
, ccnt
, more
, w0
, w1
;
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
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
);
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? */
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;
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
);
802 lp15_updsta (STA_DON
| STA_ALM
);
808 if (lp15_bp
< LP15_BSIZE
) lp15_buf
[lp15_bp
++] = c
[i
];
809 else lp15_sta
= lp15_sta
| STA_OVF
;
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 */
822 int32
lp15_updsta (int32
new)
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 */
834 t_stat
lp15_reset (DEVICE
*dptr
)
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 */
846 int32
lp15_iors (void)
848 return ((lp15_sta
& STA_DON
)? IOS_LPT
: 0);