Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* ibm1130_prt.c: IBM 1130 line printer emulation\r |
2 | \r | |
3 | Based on the SIMH simulator package written by Robert M Supnik\r | |
4 | \r | |
5 | Brian Knittel\r | |
6 | Revision History\r | |
7 | \r | |
8 | 2006.12.06 - Moved CGI stuff out of this routine into cgi1130 main() module.\r | |
9 | \r | |
10 | 2006.07.06 - Made 1403 printer 132 columns wide, was 120 previously\r | |
11 | \r | |
12 | 2006.01.03 - Fixed bug in prt_attach, found and fixed by Carl Claunch. Detach followed\r | |
13 | by reattach of 1403-mode printer left device permanently not-ready.\r | |
14 | \r | |
15 | 2004.11.08 - HACK for demo mode: in physical (-p) mode, multiple consecutive formfeeds are suppressed.\r | |
16 | This lets us do a formfeed at the end of a job to kick the last page out\r | |
17 | without getting another blank page at the beginning of the next job.\r | |
18 | \r | |
19 | 2003.12.02 - Added -p option for physical line printer output (flushes\r | |
20 | output buffer after each line). When using a physical printer on\r | |
21 | Windows, be sure to set printer to "send output directly to printer"\r | |
22 | to disable spooling, otherwise nothing appears until printer is\r | |
23 | detatched.\r | |
24 | \r | |
25 | 2003.11.25 - Changed magic filename for standard output to "(stdout)".\r | |
26 | \r | |
27 | 2002.09.13 - Added 1403 support. New file, taken from part of ibm1130_stddev.c\r | |
28 | \r | |
29 | Note: The 1403 is much faster, even in emulation, because it takes much\r | |
30 | less CPU power to run it. DMS doesn't use the WAIT command when waiting for\r | |
31 | printer operations to complete, so it ends up burning LOTS of cpu cycles.\r | |
32 | The 1403 printer doesn't require as many. HOWEVER: DMS must be loaded for the 1403,\r | |
33 | and Fortran IOCS control cards must specify it.\r | |
34 | \r | |
35 | The 1132 is still the default printer.\r | |
36 | \r | |
37 | As written, we can't have two printers.\r | |
38 | \r | |
39 | * (C) Copyright 2002, Brian Knittel.\r | |
40 | * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r | |
41 | * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r | |
42 | * usual yada-yada. Please keep this notice and the copyright in any distributions\r | |
43 | * or modifications.\r | |
44 | *\r | |
45 | * This is not a supported product, but I welcome bug reports and fixes.\r | |
46 | * Mail to simh@ibm1130.org\r | |
47 | */\r | |
48 | \r | |
49 | #include "ibm1130_defs.h"\r | |
50 | #include <stdlib.h> /* needed for atexit, for cgi mode */\r | |
51 | \r | |
52 | /***************************************************************************************\r | |
53 | * 1132 PRINTER \r | |
54 | ***************************************************************************************/\r | |
55 | \r | |
56 | #define PRT1132_DSW_READ_EMITTER_RESPONSE 0x8000\r | |
57 | #define PRT1132_DSW_SKIP_RESPONSE 0x4000\r | |
58 | #define PRT1132_DSW_SPACE_RESPONSE 0x2000\r | |
59 | #define PRT1132_DSW_CARRIAGE_BUSY 0x1000\r | |
60 | #define PRT1132_DSW_PRINT_SCAN_CHECK 0x0800\r | |
61 | #define PRT1132_DSW_NOT_READY 0x0400\r | |
62 | #define PRT1132_DSW_PRINTER_BUSY 0x0200\r | |
63 | \r | |
64 | #define PRT1132_DSW_CHANNEL_MASK 0x00FF /* 1132 printer DSW bits */\r | |
65 | #define PRT1132_DSW_CHANNEL_1 0x0080\r | |
66 | #define PRT1132_DSW_CHANNEL_2 0x0040\r | |
67 | #define PRT1132_DSW_CHANNEL_3 0x0020\r | |
68 | #define PRT1132_DSW_CHANNEL_4 0x0010\r | |
69 | #define PRT1132_DSW_CHANNEL_5 0x0008\r | |
70 | #define PRT1132_DSW_CHANNEL_6 0x0004\r | |
71 | #define PRT1132_DSW_CHANNEL_9 0x0002\r | |
72 | #define PRT1132_DSW_CHANNEL_12 0x0001\r | |
73 | \r | |
74 | #define PRT1403_DSW_PARITY_CHECK 0x8000 /* 1403 printer DSW bits */\r | |
75 | #define PRT1403_DSW_TRANSFER_COMPLETE 0x4000\r | |
76 | #define PRT1403_DSW_PRINT_COMPLETE 0x2000\r | |
77 | #define PRT1403_DSW_CARRIAGE_COMPLETE 0x1000\r | |
78 | #define PRT1403_DSW_RING_CHECK 0x0400\r | |
79 | #define PRT1403_DSW_SYNC_CHECK 0x0200\r | |
80 | #define PRT1403_DSW_CH9 0x0010\r | |
81 | #define PRT1403_DSW_CH12 0x0008\r | |
82 | #define PRT1403_DSW_CARRIAGE_BUSY 0x0004\r | |
83 | #define PRT1403_DSW_PRINTER_BUSY 0x0002\r | |
84 | #define PRT1403_DSW_NOT_READY 0x0001\r | |
85 | \r | |
86 | #define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)\r | |
87 | \r | |
88 | static t_stat prt1132_svc(UNIT *uptr);\r | |
89 | static t_stat prt1403_svc(UNIT *uptr);\r | |
90 | static t_stat prt_svc (UNIT *uptr);\r | |
91 | static t_stat prt_reset (DEVICE *dptr);\r | |
92 | static t_stat prt_attach (UNIT *uptr, char *cptr);\r | |
93 | static t_stat prt_detach (UNIT *uptr);\r | |
94 | \r | |
95 | static int16 PRT_DSW = 0; /* device status word */\r | |
96 | static int32 prt_swait = 500; /* line skip wait */\r | |
97 | static int32 prt_cwait = 1250; /* character rotation wait */\r | |
98 | static int32 prt_fwait = 100; /* fast wait, for 1403 operations */\r | |
99 | static int32 prt_twait = 50; /* transfer wait, for 1403 operations */\r | |
100 | #define SKIPTARGET (uptr->u4) /* target for skip operation */\r | |
101 | \r | |
102 | static t_bool formfed = FALSE; /* last line printed was a formfeed */\r | |
103 | \r | |
104 | #define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */\r | |
105 | #define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */\r | |
106 | #define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */\r | |
107 | #define UNIT_V_SPACING (UNIT_V_UF + 3) /* printer is spacing */\r | |
108 | #define UNIT_V_PRINTING (UNIT_V_UF + 4) /* printer printing */\r | |
109 | #define UNIT_V_TRANSFERRING (UNIT_V_UF + 5) /* unit is transferring print buffer (1403 only) */\r | |
110 | #define UNIT_V_1403 (UNIT_V_UF + 6) /* printer model is 1403 rather than 1132 */\r | |
111 | #define UNIT_V_PARITYCHECK (UNIT_V_UF + 7) /* error flags for 1403 */\r | |
112 | #define UNIT_V_RINGCHECK (UNIT_V_UF + 8)\r | |
113 | #define UNIT_V_SYNCCHECK (UNIT_V_UF + 9)\r | |
114 | #define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* this appears in ibm1130_gui as well */\r | |
115 | \r | |
116 | #define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK)\r | |
117 | #define UNIT_DATACHECK (1u << UNIT_V_DATACHECK)\r | |
118 | #define UNIT_SKIPPING (1u << UNIT_V_SKIPPING)\r | |
119 | #define UNIT_SPACING (1u << UNIT_V_SPACING)\r | |
120 | #define UNIT_PRINTING (1u << UNIT_V_PRINTING)\r | |
121 | #define UNIT_TRANSFERRING (1u << UNIT_V_TRANSFERRING)\r | |
122 | #define UNIT_1403 (1u << UNIT_V_1403)\r | |
123 | #define UNIT_PARITYCHECK (1u << UNIT_V_PARITYCHECK) \r | |
124 | #define UNIT_RINGCHECK (1u << UNIT_V_RINGCHECK)\r | |
125 | #define UNIT_SYNCCHECK (1u << UNIT_V_SYNCCHECK)\r | |
126 | #define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)\r | |
127 | \r | |
128 | UNIT prt_unit[] = {\r | |
129 | { UDATA (&prt_svc, UNIT_ATTABLE, 0) },\r | |
130 | };\r | |
131 | \r | |
132 | #define IS_1403(uptr) (uptr->flags & UNIT_1403) /* model test */\r | |
133 | #define IS_1132(uptr) ((uptr->flags & UNIT_1403) == 0) /* model test */\r | |
134 | #define IS_PHYSICAL(uptr) (uptr->flags & UNIT_PHYSICAL_PTR)\r | |
135 | \r | |
136 | /* Parameter in the unit descriptor (1132 printer) */\r | |
137 | \r | |
138 | #define CMD_NONE 0\r | |
139 | #define CMD_SPACE 1\r | |
140 | #define CMD_SKIP 2\r | |
141 | #define CMD_PRINT 3\r | |
142 | \r | |
143 | REG prt_reg[] = {\r | |
144 | { HRDATA (PRTDSW, PRT_DSW, 16) }, /* device status word */\r | |
145 | { DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */\r | |
146 | { DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */\r | |
147 | { DRDATA (FTIME, prt_fwait, 24), PV_LEFT }, /* 1403 fast wait */\r | |
148 | { DRDATA (TTIME, prt_twait, 24), PV_LEFT }, /* 1403 transfer wait */\r | |
149 | { NULL } };\r | |
150 | \r | |
151 | MTAB prt_mod[] = {\r | |
152 | { UNIT_1403, 0, "1132", "1132", NULL }, /* model option */\r | |
153 | { UNIT_1403, UNIT_1403, "1403", "1403", NULL },\r | |
154 | { 0 } };\r | |
155 | \r | |
156 | DEVICE prt_dev = {\r | |
157 | "PRT", prt_unit, prt_reg, prt_mod,\r | |
158 | 1, 16, 16, 1, 16, 16,\r | |
159 | NULL, NULL, &prt_reset,\r | |
160 | NULL, prt_attach, prt_detach};\r | |
161 | \r | |
162 | #define MAX_COLUMNS 120 \r | |
163 | #define MAX_OVPRINT 20\r | |
164 | #define PRT1132_COLUMNS 120\r | |
165 | #define PRT1403_COLUMNS 120 /* the 1130's version of the 1403 printed in 120 columns only (see Functional Characteristics) */\r | |
166 | \r | |
167 | static char prtbuf[MAX_COLUMNS*MAX_OVPRINT];\r | |
168 | static int nprint[MAX_COLUMNS], ncol[MAX_OVPRINT], maxnp;\r | |
169 | static int prt_nchar, prt_row; /* current printwheel position, current page row */\r | |
170 | static int prt_nnl; /* number of queued newlines */\r | |
171 | \r | |
172 | #define CC_CHANNEL_1 0x0800 /* carriage control tape punch values */\r | |
173 | #define CC_CHANNEL_2 0x0400\r | |
174 | #define CC_CHANNEL_3 0x0200\r | |
175 | #define CC_CHANNEL_4 0x0100\r | |
176 | #define CC_CHANNEL_5 0x0080\r | |
177 | #define CC_CHANNEL_6 0x0040 /* 7, 8, 10 and 11 are not used on 1132 printer */\r | |
178 | #define CC_CHANNEL_7 0x0020\r | |
179 | #define CC_CHANNEL_8 0x0010\r | |
180 | #define CC_CHANNEL_9 0x0008\r | |
181 | #define CC_CHANNEL_10 0x0004\r | |
182 | #define CC_CHANNEL_11 0x0002\r | |
183 | #define CC_CHANNEL_12 0x0001\r | |
184 | \r | |
185 | #define CC_1403_BITS 0x0FFF /* all bits for 1403, most for 1132 */\r | |
186 | #define CC_1132_BITS (CC_1403_BITS & ~(CC_CHANNEL_7|CC_CHANNEL_8|CC_CHANNEL_10|CC_CHANNEL_11))\r | |
187 | \r | |
188 | #define PRT_PAGELENGTH 66\r | |
189 | \r | |
190 | static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */\r | |
191 | \r | |
192 | static struct tag_ccpunches { /* list of rows and punches on tape */\r | |
193 | int row, channels;\r | |
194 | }\r | |
195 | ccpunches[] = {\r | |
196 | 2, CC_CHANNEL_1, /* channel 1 = top of form */\r | |
197 | 62, CC_CHANNEL_12 /* channel 12 = bottom of form */\r | |
198 | },\r | |
199 | cccgi[] = {\r | |
200 | 2, CC_CHANNEL_1 /* channel 1 = top of form; no bottom of form */\r | |
201 | };\r | |
202 | \r | |
203 | #include "ibm1130_prtwheel.h"\r | |
204 | \r | |
205 | extern int32 sim_switches;\r | |
206 | \r | |
207 | /* cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read */\r | |
208 | \r | |
209 | static int cc_format_1132 (int bits)\r | |
210 | {\r | |
211 | return ((bits & (CC_CHANNEL_1|CC_CHANNEL_2|CC_CHANNEL_3|CC_CHANNEL_4|CC_CHANNEL_5|CC_CHANNEL_6)) >> 4) |\r | |
212 | ((bits & CC_CHANNEL_9) >> 3) |\r | |
213 | (bits & CC_CHANNEL_12);\r | |
214 | }\r | |
215 | \r | |
216 | #define cc_format_1403(bits) (bits)\r | |
217 | \r | |
218 | /* reset_prt_line - clear the print line following paper advancement */\r | |
219 | \r | |
220 | static void reset_prt_line (void)\r | |
221 | {\r | |
222 | memset(nprint, 0, sizeof(nprint));\r | |
223 | memset(ncol, 0, sizeof(ncol));\r | |
224 | maxnp = 0;\r | |
225 | }\r | |
226 | \r | |
227 | /* save_1132_prt_line - fire hammers for character 'ch' */\r | |
228 | \r | |
229 | static t_bool save_1132_prt_line (int ch)\r | |
230 | {\r | |
231 | int i, r, addr = 32;\r | |
232 | int32 mask = 0, wd = 0;\r | |
233 | \r | |
234 | for (i = 0; i < PRT1132_COLUMNS; i++) {\r | |
235 | if (mask == 0) { /* fetch next word from memory */\r | |
236 | mask = 0x8000;\r | |
237 | wd = M[addr++];\r | |
238 | }\r | |
239 | \r | |
240 | if (wd & mask) { /* hammer is to fire in this column */\r | |
241 | if ((r = nprint[i]) < MAX_OVPRINT) {\r | |
242 | if (ncol[r] <= i) { /* we haven't moved this far yet */\r | |
243 | if (ncol[r] == 0) /* first char in this row? */\r | |
244 | memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1132_COLUMNS); /* blank out the new row */\r | |
245 | ncol[r] = i+1; /* remember new row length */\r | |
246 | }\r | |
247 | prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */\r | |
248 | \r | |
249 | nprint[i]++; /* remember max overprintings for this column */\r | |
250 | maxnp = MAX(maxnp, nprint[i]);\r | |
251 | }\r | |
252 | }\r | |
253 | \r | |
254 | mask >>= 1; /* prepare to examine next bit */\r | |
255 | }\r | |
256 | \r | |
257 | return wd & 1; /* return TRUE if the last word has lsb set, which means all bits had been set */\r | |
258 | }\r | |
259 | \r | |
260 | /* write_line - write collected line to output file. No need to trim spaces as the hammers\r | |
261 | * are never fired for them, so ncol[r] is the last printed position on each line.\r | |
262 | */\r | |
263 | \r | |
264 | static void newpage (FILE *fd, t_bool physical_printer)\r | |
265 | {\r | |
266 | if (cgi)\r | |
267 | fputs("<HR>\n", fd);\r | |
268 | else if (! formfed) {\r | |
269 | putc('\f', fd);\r | |
270 | if (physical_printer) {\r | |
271 | fflush(fd); /* send the ff out to the printer immediately */\r | |
272 | formfed = TRUE; /* hack: inhibit consecutive ff's */\r | |
273 | }\r | |
274 | }\r | |
275 | }\r | |
276 | \r | |
277 | static void flush_prt_line (FILE *fd, int spacemode, t_bool physical_printer)\r | |
278 | {\r | |
279 | int r;\r | |
280 | \r | |
281 | if (! (spacemode || maxnp)) /* nothing to do */\r | |
282 | return;\r | |
283 | \r | |
284 | prt_row = (prt_row+1) % PRT_PAGELENGTH; /* NEXT line */\r | |
285 | \r | |
286 | if (spacemode && ! maxnp) { /* spacing only */\r | |
287 | if (prt_row == 0 && prt_nnl) {\r | |
288 | #ifdef _WIN32\r | |
289 | if (! cgi)\r | |
290 | putc('\r', fd); /* DOS/Windows: end with cr/lf */\r | |
291 | #endif\r | |
292 | putc('\n', fd); /* otherwise end with lf */\r | |
293 | if (spacemode & UNIT_SKIPPING) /* add formfeed if we crossed page boundary while skipping */\r | |
294 | newpage(fd, physical_printer);\r | |
295 | \r | |
296 | prt_nnl = 0;\r | |
297 | }\r | |
298 | else {\r | |
299 | prt_nnl++;\r | |
300 | formfed = FALSE;\r | |
301 | }\r | |
302 | \r | |
303 | prt_unit->pos++; /* note something written */\r | |
304 | return;\r | |
305 | }\r | |
306 | \r | |
307 | if (prt_nnl) { /* there are queued newlines */\r | |
308 | while (prt_nnl > 0) { /* spit out queued newlines */\r | |
309 | #ifdef _WIN32\r | |
310 | if (! cgi)\r | |
311 | putc('\r', fd); /* DOS/Windows: end with cr/lf */\r | |
312 | #endif\r | |
313 | putc('\n', fd); /* otherwise end with lf */\r | |
314 | prt_nnl--;\r | |
315 | }\r | |
316 | }\r | |
317 | \r | |
318 | for (r = 0; r < maxnp; r++) {\r | |
319 | if (r > 0)\r | |
320 | putc('\r', fd); /* carriage return between overprinted lines */\r | |
321 | \r | |
322 | fxwrite(&prtbuf[r*MAX_COLUMNS], 1, ncol[r], fd);\r | |
323 | }\r | |
324 | \r | |
325 | reset_prt_line();\r | |
326 | \r | |
327 | prt_unit->pos++; /* note something written */\r | |
328 | prt_nnl++; /* queue a newline */\r | |
329 | \r | |
330 | if (physical_printer) /* if physical printer, send buffered output to device */\r | |
331 | fflush(fd);\r | |
332 | \r | |
333 | formfed = FALSE; /* note that something is now on the page */\r | |
334 | }\r | |
335 | \r | |
336 | /* 1132 printer commands */\r | |
337 | \r | |
338 | #define PRT_CMD_START_PRINTER 0x0080\r | |
339 | #define PRT_CMD_STOP_PRINTER 0x0040\r | |
340 | #define PRT_CMD_START_CARRIAGE 0x0004\r | |
341 | #define PRT_CMD_STOP_CARRIAGE 0x0002\r | |
342 | #define PRT_CMD_SPACE 0x0001\r | |
343 | \r | |
344 | #define PRT_CMD_MASK 0x00C7\r | |
345 | \r | |
346 | extern char * saywhere (int addr);\r | |
347 | \r | |
348 | static void mytrace (int start, char *what)\r | |
349 | {\r | |
350 | char *where;\r | |
351 | \r | |
352 | if ((where = saywhere(prev_IAR)) == NULL) where = "?";\r | |
353 | trace_io("%s %s at %04x: %s\n", start ? "start" : "stop", what, prev_IAR, where);\r | |
354 | }\r | |
355 | \r | |
356 | /* xio_1132_printer - XIO command interpreter for the 1132 printer */\r | |
357 | \r | |
358 | void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)\r | |
359 | {\r | |
360 | char msg[80];\r | |
361 | UNIT *uptr = &prt_unit[0];\r | |
362 | \r | |
363 | switch (func) {\r | |
364 | case XIO_READ:\r | |
365 | M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8;\r | |
366 | \r | |
367 | if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */\r | |
368 | prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132;\r | |
369 | break;\r | |
370 | \r | |
371 | case XIO_SENSE_DEV:\r | |
372 | ACC = PRT_DSW;\r | |
373 | if (modify & 0x01) { /* reset interrupts */\r | |
374 | CLRBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE | PRT1132_DSW_SKIP_RESPONSE | PRT1132_DSW_SPACE_RESPONSE);\r | |
375 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r | |
376 | }\r | |
377 | break;\r | |
378 | \r | |
379 | case XIO_CONTROL:\r | |
380 | if (modify & PRT_CMD_START_PRINTER) {\r | |
381 | SETBIT(uptr->flags, UNIT_PRINTING);\r | |
382 | /* mytrace(1, "printing"); */\r | |
383 | }\r | |
384 | \r | |
385 | if (modify & PRT_CMD_STOP_PRINTER) {\r | |
386 | CLRBIT(uptr->flags, UNIT_PRINTING);\r | |
387 | /* mytrace(0, "printing"); */\r | |
388 | }\r | |
389 | \r | |
390 | if (modify & PRT_CMD_START_CARRIAGE) {\r | |
391 | SETBIT(uptr->flags, UNIT_SKIPPING);\r | |
392 | /* mytrace(1, "skipping"); */\r | |
393 | }\r | |
394 | \r | |
395 | if (modify & PRT_CMD_STOP_CARRIAGE) {\r | |
396 | CLRBIT(uptr->flags, UNIT_SKIPPING);\r | |
397 | /* mytrace(0, "skipping"); */\r | |
398 | }\r | |
399 | \r | |
400 | if (modify & PRT_CMD_SPACE) {\r | |
401 | SETBIT(uptr->flags, UNIT_SPACING);\r | |
402 | /* mytrace(1, "space"); */\r | |
403 | }\r | |
404 | \r | |
405 | sim_cancel(uptr);\r | |
406 | if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { /* busy bits = doing something */\r | |
407 | SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r | |
408 | sim_activate(uptr, prt_cwait);\r | |
409 | }\r | |
410 | else\r | |
411 | CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r | |
412 | \r | |
413 | if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING))\r | |
414 | SETBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY);\r | |
415 | else\r | |
416 | CLRBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY);\r | |
417 | \r | |
418 | if ((uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) == (UNIT_SKIPPING|UNIT_SPACING)) {\r | |
419 | sprintf(msg, "1132 printer skip and space at same time?");\r | |
420 | xio_error(msg);\r | |
421 | }\r | |
422 | break;\r | |
423 | \r | |
424 | default:\r | |
425 | sprintf(msg, "Invalid 1132 printer XIO function %x", func);\r | |
426 | xio_error(msg);\r | |
427 | }\r | |
428 | }\r | |
429 | \r | |
430 | #define SET_ACTION(u,a) {(u)->flags &= ~(UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING|UNIT_TRANSFERRING); (u)->flags |= a;}\r | |
431 | \r | |
432 | static t_stat prt_svc (UNIT *uptr)\r | |
433 | {\r | |
434 | return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr);\r | |
435 | }\r | |
436 | \r | |
437 | /* prt1132_svc - emulated timeout for 1132 operation */\r | |
438 | \r | |
439 | static t_stat prt1132_svc (UNIT *uptr)\r | |
440 | {\r | |
441 | if (PRT_DSW & PRT1132_DSW_NOT_READY) { /* cancel operation if printer went offline */\r | |
442 | SETBIT(uptr->flags, UNIT_FORMCHECK);\r | |
443 | SET_ACTION(uptr, 0);\r | |
444 | forms_check(TRUE); /* and turn on forms check lamp */\r | |
445 | return SCPE_OK;\r | |
446 | }\r | |
447 | \r | |
448 | if (uptr->flags & UNIT_SPACING) {\r | |
449 | flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));\r | |
450 | \r | |
451 | CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY);\r | |
452 | SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE);\r | |
453 | SETBIT(ILSW[1], ILSW_1_1132_PRINTER);\r | |
454 | CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */\r | |
455 | calc_ints();\r | |
456 | }\r | |
457 | \r | |
458 | if (uptr->flags & UNIT_SKIPPING) {\r | |
459 | do {\r | |
460 | flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));\r | |
461 | CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK);\r | |
462 | SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]));\r | |
463 | } while ((cctape[prt_row] & CC_1132_BITS) == 0); /* slew directly to a cc tape punch */\r | |
464 | \r | |
465 | SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE);\r | |
466 | SETBIT(ILSW[1], ILSW_1_1132_PRINTER);\r | |
467 | calc_ints();\r | |
468 | }\r | |
469 | \r | |
470 | if (uptr->flags & UNIT_PRINTING) {\r | |
471 | if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { /* save previous printed line */\r | |
472 | SETBIT(uptr->flags, UNIT_DATACHECK); /* buffer wasn't set in time */\r | |
473 | SET_ACTION(uptr, 0);\r | |
474 | print_check(TRUE); /* and turn on forms check lamp */\r | |
475 | return SCPE_OK;\r | |
476 | }\r | |
477 | \r | |
478 | prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; /* advance print drum */\r | |
479 | \r | |
480 | SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); /* issue interrupt to tell printer to set buffer */\r | |
481 | SETBIT(ILSW[1], ILSW_1_1132_PRINTER); /* we'll save the printed stuff just before next emitter response (later than on real 1130) */\r | |
482 | calc_ints();\r | |
483 | }\r | |
484 | \r | |
485 | if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { /* still doing something */\r | |
486 | SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r | |
487 | sim_activate(uptr, prt_cwait);\r | |
488 | }\r | |
489 | else\r | |
490 | CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);\r | |
491 | \r | |
492 | return SCPE_OK;\r | |
493 | }\r | |
494 | \r | |
495 | void save_1403_prt_line (int32 addr)\r | |
496 | {\r | |
497 | int i, j, r, ch, even = TRUE;\r | |
498 | unsigned char ebcdic;\r | |
499 | int32 wd;\r | |
500 | \r | |
501 | for (i = 0; i < PRT1403_COLUMNS; i++) {\r | |
502 | if (even) { /* fetch next word from memory */\r | |
503 | wd = M[addr++];\r | |
504 | ebcdic = (unsigned char) ((wd >> 8) & 0x7F);\r | |
505 | even = FALSE;\r | |
506 | }\r | |
507 | else {\r | |
508 | ebcdic = (unsigned char) (wd & 0x7F); /* use low byte of previously fetched word */\r | |
509 | even = TRUE;\r | |
510 | }\r | |
511 | \r | |
512 | ch = ' '; /* translate ebcdic to ascii. Don't bother checking for parity errors */\r | |
513 | for (j = 0; j < WHEELCHARS_1403; j++) {\r | |
514 | if (codewheel1403[j].ebcdic == ebcdic) {\r | |
515 | ch = codewheel1403[j].ascii;\r | |
516 | break;\r | |
517 | }\r | |
518 | }\r | |
519 | \r | |
520 | if (ch > ' ') {\r | |
521 | if ((r = nprint[i]) < MAX_OVPRINT) {\r | |
522 | if (ncol[r] <= i) { /* we haven't moved this far yet */\r | |
523 | if (ncol[r] == 0) /* first char in this row? */\r | |
524 | memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1403_COLUMNS); /* blank out the new row */\r | |
525 | ncol[r] = i+1; /* remember new row length */\r | |
526 | }\r | |
527 | prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */\r | |
528 | \r | |
529 | nprint[i]++; /* remember max overprintings for this column */\r | |
530 | maxnp = MAX(maxnp, nprint[i]);\r | |
531 | }\r | |
532 | }\r | |
533 | }\r | |
534 | }\r | |
535 | \r | |
536 | void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify)\r | |
537 | {\r | |
538 | UNIT *uptr = &prt_unit[0];\r | |
539 | \r | |
540 | switch (func) {\r | |
541 | case XIO_INITW: /* print a line */\r | |
542 | save_1403_prt_line(iocc_addr); /* put formatted line into our print buffer */\r | |
543 | \r | |
544 | SETBIT(uptr->flags, UNIT_TRANSFERRING); /* schedule transfer complete interrupt */\r | |
545 | SETBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);\r | |
546 | sim_activate(uptr, prt_twait);\r | |
547 | break;\r | |
548 | \r | |
549 | case XIO_CONTROL: /* initiate single space */\r | |
550 | if (uptr->flags & UNIT_SKIPPING) {\r | |
551 | xio_error("1403 printer skip and space at same time?");\r | |
552 | }\r | |
553 | else {\r | |
554 | SETBIT(uptr->flags, UNIT_SPACING);\r | |
555 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r | |
556 | sim_activate(uptr, prt_fwait);\r | |
557 | }\r | |
558 | break;\r | |
559 | \r | |
560 | case XIO_WRITE: /* initiate skip */\r | |
561 | if (uptr->flags & UNIT_SPACING) {\r | |
562 | xio_error("1403 printer skip and space at same time?");\r | |
563 | }\r | |
564 | else {\r | |
565 | SETBIT(uptr->flags, UNIT_SKIPPING);\r | |
566 | SKIPTARGET = ReadW(iocc_addr) & CC_1403_BITS; /* get CC bits that we're to match */\r | |
567 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r | |
568 | sim_activate(uptr, prt_fwait);\r | |
569 | }\r | |
570 | break;\r | |
571 | \r | |
572 | case XIO_SENSE_DEV: /* get device status word */\r | |
573 | ACC = PRT_DSW;\r | |
574 | if (modify & 0x01) { /* reset interrupts */\r | |
575 | CLRBIT(PRT_DSW, PRT1403_DSW_PARITY_CHECK | PRT1403_DSW_TRANSFER_COMPLETE |\r | |
576 | PRT1403_DSW_PRINT_COMPLETE | PRT1403_DSW_CARRIAGE_COMPLETE | \r | |
577 | PRT1403_DSW_RING_CHECK | PRT1403_DSW_SYNC_CHECK);\r | |
578 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r | |
579 | }\r | |
580 | break;\r | |
581 | }\r | |
582 | }\r | |
583 | \r | |
584 | static t_stat prt1403_svc(UNIT *uptr)\r | |
585 | {\r | |
586 | if (PRT_DSW & PRT1403_DSW_NOT_READY) { /* cancel operation if printer went offline */\r | |
587 | SET_ACTION(uptr, 0);\r | |
588 | forms_check(TRUE); /* and turn on forms check lamp */\r | |
589 | }\r | |
590 | else if (uptr->flags & UNIT_TRANSFERRING) { /* end of transfer */\r | |
591 | CLRBIT(uptr->flags, UNIT_TRANSFERRING);\r | |
592 | SETBIT(uptr->flags, UNIT_PRINTING); /* schedule "print complete" */\r | |
593 | \r | |
594 | SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); /* issue transfer complete interrupt */\r | |
595 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER);\r | |
596 | }\r | |
597 | else if (uptr->flags & UNIT_PRINTING) {\r | |
598 | CLRBIT(uptr->flags, UNIT_PRINTING);\r | |
599 | CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);\r | |
600 | \r | |
601 | SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE);\r | |
602 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER); /* issue print complete interrupt */\r | |
603 | }\r | |
604 | else if (uptr->flags & UNIT_SKIPPING) {\r | |
605 | do { /* find line with exact match of tape punches */\r | |
606 | flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));\r | |
607 | } while (cctape[prt_row] != SKIPTARGET); /* slew directly to requested cc tape punch */\r | |
608 | \r | |
609 | CLRBIT(uptr->flags, UNIT_SKIPPING); /* done with this */\r | |
610 | CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r | |
611 | \r | |
612 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);\r | |
613 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER);\r | |
614 | }\r | |
615 | else if (uptr->flags & UNIT_SPACING) {\r | |
616 | flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));\r | |
617 | \r | |
618 | CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */\r | |
619 | CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);\r | |
620 | \r | |
621 | SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);\r | |
622 | SETBIT(ILSW[4], ILSW_4_1403_PRINTER);\r | |
623 | }\r | |
624 | \r | |
625 | if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING))\r | |
626 | sim_activate(uptr, prt_fwait);\r | |
627 | \r | |
628 | CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); /* set the two CC bits in the DSW */\r | |
629 | if (cctape[prt_row] & CC_CHANNEL_9)\r | |
630 | SETBIT(PRT_DSW, PRT1403_DSW_CH9);\r | |
631 | if (cctape[prt_row] & CC_CHANNEL_12)\r | |
632 | SETBIT(PRT_DSW, PRT1403_DSW_CH12);\r | |
633 | \r | |
634 | calc_ints();\r | |
635 | return SCPE_OK;\r | |
636 | }\r | |
637 | \r | |
638 | /* delete_cmd - SCP command to delete a file */\r | |
639 | \r | |
640 | static t_stat delete_cmd (int flag, char *cptr)\r | |
641 | {\r | |
642 | char gbuf[CBUFSIZE];\r | |
643 | int status;\r | |
644 | \r | |
645 | cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */\r | |
646 | if (*gbuf == 0) return SCPE_2FARG;\r | |
647 | if (*cptr != 0) return SCPE_2MARG; /* now eol? */\r | |
648 | \r | |
649 | status = remove(gbuf); /* delete the file */\r | |
650 | \r | |
651 | if (status != 0 && errno != ENOENT) /* print message if failed and file exists */\r | |
652 | perror(gbuf);\r | |
653 | \r | |
654 | return SCPE_OK;\r | |
655 | }\r | |
656 | \r | |
657 | /* prt_reset - reset emulated printer */\r | |
658 | \r | |
659 | static t_stat prt_reset (DEVICE *dptr)\r | |
660 | {\r | |
661 | UNIT *uptr = &prt_unit[0];\r | |
662 | int i;\r | |
663 | \r | |
664 | /* add a DELETE filename command so we can be sure to have clean listings */\r | |
665 | register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n");\r | |
666 | \r | |
667 | sim_cancel(uptr);\r | |
668 | \r | |
669 | memset(cctape, 0, sizeof(cctape)); /* copy punch list into carriage control tape image */\r | |
670 | \r | |
671 | if (cgi) {\r | |
672 | for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++)\r | |
673 | cctape[cccgi[i].row-1] |= cccgi[i].channels;\r | |
674 | }\r | |
675 | else\r | |
676 | for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++)\r | |
677 | cctape[ccpunches[i].row-1] |= ccpunches[i].channels;\r | |
678 | \r | |
679 | prt_nchar = 0;\r | |
680 | prt_row = 0;\r | |
681 | prt_nnl = 0;\r | |
682 | \r | |
683 | CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK|UNIT_PRINTING|UNIT_SPACING|UNIT_SKIPPING|\r | |
684 | UNIT_TRANSFERRING|UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);\r | |
685 | \r | |
686 | if (IS_1132(uptr)) {\r | |
687 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r | |
688 | PRT_DSW = cc_format_1132(cctape[prt_row]);\r | |
689 | if (! IS_ONLINE(uptr))\r | |
690 | SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);\r | |
691 | }\r | |
692 | else {\r | |
693 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r | |
694 | PRT_DSW = 0;\r | |
695 | if (cctape[prt_row] & CC_CHANNEL_9)\r | |
696 | SETBIT(PRT_DSW, PRT1403_DSW_CH9);\r | |
697 | if (cctape[prt_row] & CC_CHANNEL_12)\r | |
698 | SETBIT(PRT_DSW, PRT1403_DSW_CH12);\r | |
699 | if (! IS_ONLINE(uptr))\r | |
700 | SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);\r | |
701 | }\r | |
702 | \r | |
703 | SET_ACTION(uptr, 0);\r | |
704 | calc_ints();\r | |
705 | reset_prt_line();\r | |
706 | \r | |
707 | forms_check(FALSE);\r | |
708 | return SCPE_OK;\r | |
709 | }\r | |
710 | \r | |
711 | static t_stat prt_attach (UNIT *uptr, char *cptr)\r | |
712 | {\r | |
713 | t_stat rval;\r | |
714 | /* assume failure */\r | |
715 | SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY);\r | |
716 | formfed = FALSE;\r | |
717 | \r | |
718 | if (uptr->flags & UNIT_ATT) {\r | |
719 | if ((rval = prt_detach(uptr)) != SCPE_OK) {\r | |
720 | return rval;\r | |
721 | }\r | |
722 | }\r | |
723 | \r | |
724 | if (sim_switches & SWMASK('P')) /* set physical (unbuffered) printer flag */\r | |
725 | SETBIT(uptr->flags, UNIT_PHYSICAL_PTR);\r | |
726 | else\r | |
727 | CLRBIT(uptr->flags, UNIT_PHYSICAL_PTR);\r | |
728 | \r | |
729 | sim_cancel(uptr);\r | |
730 | \r | |
731 | if (strcmp(cptr, "(stdout)") == 0) { /* connect printer to stdout */\r | |
732 | if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */\r | |
733 | uptr->filename = calloc(CBUFSIZE, sizeof(char));\r | |
734 | strcpy(uptr->filename, "(stdout)");\r | |
735 | uptr->fileref = stdout;\r | |
736 | SETBIT(uptr->flags, UNIT_ATT);\r | |
737 | uptr->pos = 0;\r | |
738 | }\r | |
739 | else {\r | |
740 | if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK)\r | |
741 | return rval;\r | |
742 | }\r | |
743 | \r | |
744 | fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */\r | |
745 | uptr->pos = ftell(uptr->fileref);\r | |
746 | \r | |
747 | if (IS_1132(uptr)) {\r | |
748 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r | |
749 | CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);\r | |
750 | }\r | |
751 | else {\r | |
752 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r | |
753 | CLRBIT(uptr->flags, UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);\r | |
754 | }\r | |
755 | \r | |
756 | SET_ACTION(uptr, 0);\r | |
757 | calc_ints();\r | |
758 | \r | |
759 | prt_nchar = 0;\r | |
760 | prt_nnl = 0;\r | |
761 | prt_row = 0;\r | |
762 | reset_prt_line();\r | |
763 | \r | |
764 | if (IS_1132(uptr)) {\r | |
765 | PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]);\r | |
766 | \r | |
767 | if (IS_ONLINE(uptr))\r | |
768 | CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);\r | |
769 | }\r | |
770 | else {\r | |
771 | CLRBIT(PRT_DSW, PRT1403_DSW_CH9 | PRT1403_DSW_CH12);\r | |
772 | if (cctape[prt_row] & CC_CHANNEL_9)\r | |
773 | SETBIT(PRT_DSW, PRT1403_DSW_CH9);\r | |
774 | if (cctape[prt_row] & CC_CHANNEL_12)\r | |
775 | SETBIT(PRT_DSW, PRT1403_DSW_CH12);\r | |
776 | \r | |
777 | if (IS_ONLINE(uptr))\r | |
778 | CLRBIT(PRT_DSW, PRT1403_DSW_NOT_READY); /* fixed by Carl Claunch */\r | |
779 | }\r | |
780 | \r | |
781 | forms_check(FALSE);\r | |
782 | \r | |
783 | return SCPE_OK;\r | |
784 | }\r | |
785 | \r | |
786 | static t_stat prt_detach (UNIT *uptr)\r | |
787 | {\r | |
788 | t_stat rval;\r | |
789 | \r | |
790 | if (uptr->flags & UNIT_ATT)\r | |
791 | flush_prt_line(uptr->fileref, TRUE, TRUE);\r | |
792 | \r | |
793 | if (uptr->fileref == stdout) {\r | |
794 | CLRBIT(uptr->flags, UNIT_ATT);\r | |
795 | free(uptr->filename);\r | |
796 | uptr->filename = NULL;\r | |
797 | }\r | |
798 | else if ((rval = detach_unit(uptr)) != SCPE_OK)\r | |
799 | return rval;\r | |
800 | \r | |
801 | sim_cancel(uptr);\r | |
802 | \r | |
803 | if (IS_1132(uptr)) {\r | |
804 | CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);\r | |
805 | CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);\r | |
806 | SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);\r | |
807 | }\r | |
808 | else {\r | |
809 | CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);\r | |
810 | SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);\r | |
811 | }\r | |
812 | SET_ACTION(uptr, 0);\r | |
813 | \r | |
814 | calc_ints();\r | |
815 | \r | |
816 | forms_check(FALSE);\r | |
817 | return SCPE_OK;\r | |
818 | }\r | |
819 | \r |