Commit | Line | Data |
---|---|---|
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 | |
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 |