First Commit of my working state
[simh.git] / PDP18B / pdp18b_lp.c
CommitLineData
196ba1fc
PH
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
50extern int32 int_hwre[API_HLVL+1];\r
51const 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
66int32 lp62_spc = 0; /* print vs spc */\r
67int32 lp62_ovrpr = 0; /* overprint */\r
68int32 lp62_stopioe = 0;\r
69int32 lp62_bp = 0; /* buffer ptr */\r
70char lp62_buf[LP62_BSIZE + 1] = { 0 };\r
71static 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
82DEVICE lp62_dev;\r
83int32 lp62_65 (int32 dev, int32 pulse, int32 dat);\r
84int32 lp62_66 (int32 dev, int32 pulse, int32 dat);\r
85int32 lp62_iors (void);\r
86t_stat lp62_svc (UNIT *uptr);\r
87t_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
96DIB lp62_dib = { DEV_LPT, 2, &lp62_iors, { &lp62_65, &lp62_66 } };\r
97\r
98UNIT lp62_unit = {\r
99 UDATA (&lp62_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r
100 };\r
101\r
102REG 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
118MTAB lp62_mod[] = {\r
119 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r
120 { 0 }\r
121 };\r
122\r
123DEVICE 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
133int32 lp62_65 (int32 dev, int32 pulse, int32 dat)\r
134{\r
135int32 i;\r
136\r
137if ((pulse & 01) && TST_INT (LPT)) dat = IOT_SKP | dat; /* LPSF */\r
138if (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
149if (pulse & 04) { /* LPSE */\r
150 lp62_spc = 0; /* print */\r
151 sim_activate (&lp62_unit, lp62_unit.wait); /* activate */\r
152 }\r
153return dat;\r
154}\r
155\r
156int32 lp62_66 (int32 dev, int32 pulse, int32 dat)\r
157{\r
158if ((pulse & 01) && TST_INT (LPTSPC)) /* LSSF */\r
159 dat = IOT_SKP | dat;\r
160if (pulse & 02) CLR_INT (LPTSPC); /* LSCF */\r
161if (pulse & 04) { /* LSPR */\r
162 lp62_spc = 020 | (dat & 07); /* space */\r
163 sim_activate (&lp62_unit, lp62_unit.wait); /* activate */\r
164 }\r
165return 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
174t_stat lp62_svc (UNIT *uptr)\r
175{\r
176int32 i;\r
177\r
178if (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
191else {\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
207return SCPE_OK;\r
208}\r
209\r
210/* Reset routine */\r
211\r
212t_stat lp62_reset (DEVICE *dptr)\r
213{\r
214int32 i;\r
215\r
216CLR_INT (LPT); /* clear intrs */\r
217CLR_INT (LPTSPC);\r
218sim_cancel (&lp62_unit); /* deactivate unit */\r
219lp62_bp = 0; /* clear buffer ptr */\r
220for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */\r
221lp62_spc = 0; /* clear state */\r
222lp62_ovrpr = 0; /* clear overprint */\r
223return SCPE_OK;\r
224}\r
225\r
226/* IORS routine */\r
227\r
228int32 lp62_iors (void)\r
229{\r
230return (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
242int32 lp647_don = 0; /* ready */\r
243int32 lp647_ie = 1; /* int enable */\r
244int32 lp647_err = 0; /* error */\r
245int32 lp647_iot = 0; /* saved state */\r
246int32 lp647_stopioe = 0;\r
247int32 lp647_bp = 0; /* buffer ptr */\r
248char lp647_buf[LP647_BSIZE] = { 0 };\r
249static 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
260DEVICE lp647_dev;\r
261int32 lp647_65 (int32 dev, int32 pulse, int32 dat);\r
262int32 lp647_66 (int32 dev, int32 pulse, int32 dat);\r
263int32 lp647_iors (void);\r
264t_stat lp647_svc (UNIT *uptr);\r
265t_stat lp647_reset (DEVICE *dptr);\r
266t_stat lp647_attach (UNIT *uptr, char *cptr);\r
267t_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
276DIB lp647_dib = { DEV_LPT, 2, &lp647_iors, { &lp647_65, &lp647_66 } };\r
277\r
278UNIT lp647_unit = {\r
279 UDATA (&lp647_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r
280 };\r
281\r
282REG 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
300MTAB lp647_mod[] = {\r
301 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r
302 { 0 }\r
303 };\r
304\r
305DEVICE 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
315int32 lp647_65 (int32 dev, int32 pulse, int32 dat)\r
316{\r
317int32 i, sb;\r
318\r
319sb = pulse & 060; /* subcode */\r
320if ((pulse & 01) && lp647_don) dat = IOT_SKP | dat; /* LPSF */\r
321if (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
331if (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
363return dat;\r
364}\r
365\r
366int32 lp647_66 (int32 dev, int32 pulse, int32 dat)\r
367{\r
368if ((pulse & 01) && lp647_err) dat = IOT_SKP | dat; /* LPSE */\r
369if (pulse & 02) { /* LPCF */\r
370 lp647_don = 0; /* clear done, int */\r
371 CLR_INT (LPT);\r
372 }\r
373if (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
385return 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
395t_stat lp647_svc (UNIT *uptr)\r
396{\r
397int32 i;\r
398char pbuf[LP647_BSIZE + 2];\r
399\r
400lp647_don = 1;\r
401if (lp647_ie) SET_INT (LPT); /* set flag */\r
402if ((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
406if ((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
422if (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
431return SCPE_OK;\r
432}\r
433\r
434/* Reset routine */\r
435\r
436t_stat lp647_reset (DEVICE *dptr)\r
437{\r
438int32 i;\r
439\r
440lp647_don = 0; /* clear done */\r
441lp647_err = (lp647_unit.flags & UNIT_ATT)? 0: 1; /* clr/set error */\r
442lp647_ie = 1; /* set enable */\r
443CLR_INT (LPT); /* clear int */\r
444sim_cancel (&lp647_unit); /* deactivate unit */\r
445lp647_bp = 0; /* clear buffer ptr */\r
446lp647_iot = 0; /* clear state */\r
447for (i = 0; i < LP647_BSIZE; i++) lp647_buf[i] = 0; /* clear buffer */\r
448return SCPE_OK;\r
449}\r
450\r
451/* IORS routine */\r
452\r
453int32 lp647_iors (void)\r
454{\r
455return (lp647_don? IOS_LPT: 0) | (lp647_err? IOS_LPT1: 0);\r
456}\r
457\r
458/* Attach routine */\r
459\r
460t_stat lp647_attach (UNIT *uptr, char *cptr)\r
461{\r
462t_stat reason;\r
463\r
464reason = attach_unit (uptr, cptr);\r
465lp647_err = (lp647_unit.flags & UNIT_ATT)? 0: 1; /* clr/set error */\r
466return reason;\r
467}\r
468\r
469/* Detach routine */\r
470\r
471t_stat lp647_detach (UNIT *uptr)\r
472{\r
473lp647_err = 1;\r
474return 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
485int32 lp09_don = 0; /* ready */\r
486int32 lp09_err = 0; /* error */\r
487int32 lp09_ie = 1; /* int enable */\r
488int32 lp09_stopioe = 0;\r
489DEVICE lp09_dev;\r
490\r
491int32 lp09_66 (int32 dev, int32 pulse, int32 dat);\r
492int32 lp09_iors (void);\r
493t_stat lp09_svc (UNIT *uptr);\r
494t_stat lp09_reset (DEVICE *dptr);\r
495t_stat lp09_attach (UNIT *uptr, char *cptr);\r
496t_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
505DIB lp09_dib = { DEV_LPT, 2, &lp09_iors, { NULL, &lp09_66 } };\r
506\r
507UNIT lp09_unit = {\r
508 UDATA (&lp09_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r
509 };\r
510\r
511REG 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
524MTAB lp09_mod[] = {\r
525 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r
526 { 0 }\r
527 };\r
528\r
529DEVICE 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
539int32 lp09_66 (int32 dev, int32 pulse, int32 dat)\r
540{\r
541int32 sb = pulse & 060; /* subopcode */\r
542\r
543if (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
547if (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
562if (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
572return dat;\r
573}\r
574\r
575/* Unit service */\r
576\r
577t_stat lp09_svc (UNIT *uptr)\r
578{\r
579int32 c;\r
580\r
581lp09_don = 1; /* set done */\r
582if (lp09_ie) SET_INT (LPT); /* int enb? req int */\r
583if ((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
587c = uptr->buf & 0177; /* get char */\r
588if ((c == 0) || (c == 0177)) return SCPE_OK; /* skip NULL, DEL */\r
589fputc (c, uptr->fileref); /* print char */\r
590uptr->pos = ftell (uptr->fileref); /* update position */\r
591if (ferror (uptr->fileref)) { /* error? */\r
592 perror ("LPT I/O error");\r
593 clearerr (uptr->fileref);\r
594 return SCPE_IOERR;\r
595 }\r
596return SCPE_OK;\r
597}\r
598\r
599/* Reset routine */\r
600\r
601t_stat lp09_reset (DEVICE *dptr)\r
602{\r
603lp09_don = 0; /* clear done */\r
604lp09_err = (lp09_unit.flags & UNIT_ATT)? 0: 1; /* compute error */\r
605lp09_ie = 1; /* set enable */\r
606CLR_INT (LPT); /* clear int */\r
607return SCPE_OK;\r
608}\r
609\r
610/* IORS routine */\r
611\r
612int32 lp09_iors (void)\r
613{\r
614return (lp09_don? IOS_LPT: 0);\r
615}\r
616\r
617/* Attach routine */\r
618\r
619t_stat lp09_attach (UNIT *uptr, char *cptr)\r
620{\r
621t_stat reason;\r
622\r
623reason = attach_unit (uptr, cptr);\r
624lp09_err = (lp09_unit.flags & UNIT_ATT)? 0: 1; /* clr/set error */\r
625return reason;\r
626}\r
627\r
628/* Detach routine */\r
629\r
630t_stat lp09_detach (UNIT *uptr)\r
631{\r
632lp09_err = 1;\r
633return 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
658extern int32 M[];\r
659int32 lp15_sta = 0;\r
660int32 lp15_ie = 1;\r
661int32 lp15_stopioe = 0;\r
662int32 lp15_mode = 0;\r
663int32 lp15_lc = 0;\r
664int32 lp15_bp = 0;\r
665char lp15_buf[LP15_BSIZE + 1] = { 0 };\r
666\r
667DEVICE lp15_dev;\r
668int32 lp15_65 (int32 dev, int32 pulse, int32 dat);\r
669int32 lp15_66 (int32 dev, int32 pulse, int32 dat);\r
670int32 lp15_iors (void);\r
671t_stat lp15_svc (UNIT *uptr);\r
672t_stat lp15_reset (DEVICE *dptr);\r
673\r
674int32 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
683DIB lp15_dib = { DEV_LPT, 2, &lp15_iors, { &lp15_65, &lp15_66 } };\r
684\r
685UNIT lp15_unit = {\r
686 UDATA (&lp15_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT\r
687 };\r
688\r
689REG 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
705MTAB lp15_mod[] = {\r
706 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },\r
707 { 0 }\r
708 };\r
709\r
710DEVICE 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
720int32 lp15_65 (int32 dev, int32 pulse, int32 dat)\r
721{\r
722int32 header, sb;\r
723\r
724sb = pulse & 060; /* subopcode */\r
725if (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
740if ((pulse & 02) && (sb == 040)) dat = dat | lp15_updsta (0); /* LPOS, LPRS */\r
741if ((pulse & 04) && (sb == 040)) lp15_ie = 1; /* LPEI */\r
742lp15_updsta (0); /* update status */\r
743return dat;\r
744}\r
745\r
746int32 lp15_66 (int32 dev, int32 pulse, int32 dat)\r
747{\r
748if (pulse == 021) lp15_sta = lp15_sta & ~STA_DON; /* LPCD */\r
749if (pulse == 041) lp15_sta = 0; /* LPCF */\r
750lp15_updsta (0); /* update status */\r
751return dat;\r
752}\r
753\r
754/* Unit service */\r
755\r
756t_stat lp15_svc (UNIT *uptr)\r
757{\r
758int32 i, ccnt, more, w0, w1;\r
759char c[5];\r
760static 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
770if ((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
775for (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
814lp15_lc = lp15_lc - 1; /* decr line count */\r
815if (lp15_lc) sim_activate (&lp15_unit, uptr->wait); /* more to do? */\r
816else lp15_updsta (STA_DON); /* no, set done */\r
817return SCPE_OK;\r
818}\r
819\r
820/* Update status */\r
821\r
822int32 lp15_updsta (int32 new)\r
823{\r
824lp15_sta = (lp15_sta | new) & ~(STA_CLR | STA_ERR | STA_BUSY);\r
825if (lp15_sta & STA_EFLGS) lp15_sta = lp15_sta | STA_ERR; /* update errors */\r
826if (sim_is_active (&lp15_unit)) lp15_sta = lp15_sta | STA_BUSY;\r
827if (lp15_ie && (lp15_sta & STA_DON)) SET_INT (LPT);\r
828else CLR_INT (LPT); /* update int */\r
829return lp15_sta;\r
830}\r
831\r
832/* Reset routine */\r
833\r
834t_stat lp15_reset (DEVICE *dptr)\r
835{\r
836lp15_mode = lp15_lc = lp15_bp = 0; /* clear controls */\r
837sim_cancel (&lp15_unit); /* deactivate unit */\r
838lp15_sta = 0; /* clear status */\r
839lp15_ie = 1; /* enable interrupts */\r
840lp15_updsta (0); /* update status */\r
841return SCPE_OK;\r
842}\r
843\r
844/* IORS routine */\r
845\r
846int32 lp15_iors (void)\r
847{\r
848return ((lp15_sta & STA_DON)? IOS_LPT: 0);\r
849}\r
850\r
851#endif\r