First Commit of my working state
[simh.git] / S3 / s3_lp.c
CommitLineData
196ba1fc
PH
1/* s3_lp.c: IBM 1403 line printer simulator\r
2\r
3 Copyright (c) 2001-2005, Charles E. Owen\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 Charles E. Owen 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 Charles E. Owen.\r
25\r
26 lpt 1403 line printer\r
27\r
28 25-Apr-03 RMS Revised for extended file support\r
29 08-Oct-02 RMS Added impossible function catcher\r
30*/\r
31\r
32#include "s3_defs.h"\r
33\r
34extern uint8 M[];\r
35extern char bcd_to_ascii[64];\r
36extern int32 iochk, ind[64];\r
37int32 cct[CCT_LNT] = { 03 };\r
38int32 cctlnt = 66, cctptr = 0, lines = 0, lflag = 0;\r
39t_stat lpt_reset (DEVICE *dptr);\r
40t_stat lpt_attach (UNIT *uptr, char *cptr);\r
41t_stat write_line (int32 ilnt, int32 mod);\r
42t_stat space (int32 lines, int32 lflag);\r
43t_stat carriage_control (int32 action, int32 mod);\r
44extern unsigned char ebcdic_to_ascii[256];\r
45\r
46#define UNIT_V_PCHAIN (UNIT_V_UF + 0)\r
47#define UNIT_M_PCHAIN 03\r
48#define M_UCS 00 /* Universal */\r
49#define M_PCF 00 /* full */\r
50#define M_PCA 01 /* business */\r
51#define M_PCH 02 /* Fortran */\r
52#define UNIT_PCHAIN (UNIT_M_PCHAIN << UNIT_V_PCHAIN)\r
53#define UCS (M_UCS << UNIT_V_PCHAIN)\r
54#define PCF (M_PCF << UNIT_V_PCHAIN)\r
55#define PCA (M_PCA << UNIT_V_PCHAIN)\r
56#define PCH (M_PCH << UNIT_V_PCHAIN)\r
57#define GET_PCHAIN(x) (((x) >> UNIT_V_PCHAIN) & UNIT_M_PCHAIN)\r
58#define CHP(ch,val) ((val) & (1 << (ch)))\r
59\r
60int32 LPDAR; /* Data Address */\r
61int32 LPFLR; /* Forms Length */\r
62int32 LPIAR; /* Image address */\r
63int32 linectr; /* current line # */\r
64int32 lpterror = 0;\r
65int32 CC9 = 0;\r
66int32 CC12 = 0;\r
67\r
68/* LPT data structures\r
69\r
70 lpt_dev LPT device descriptor\r
71 lpt_unit LPT unit descriptor\r
72 lpt_reg LPT register list\r
73*/\r
74\r
75UNIT lpt_unit = { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };\r
76\r
77REG lpt_reg[] = {\r
78 { FLDATA (ERR, lpterror, 0) },\r
79 { HRDATA (LPDAR, LPDAR, 16) },\r
80 { HRDATA (LPFLR, LPFLR, 8) },\r
81 { HRDATA (LPIAR, LPIAR, 16) },\r
82 { DRDATA (LINECT, linectr, 8) },\r
83 { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },\r
84 { BRDATA (CCT, cct, 8, 32, CCT_LNT) },\r
85 { DRDATA (LINES, lines, 8), PV_LEFT },\r
86 { DRDATA (CCTP, cctptr, 8), PV_LEFT },\r
87 { DRDATA (CCTL, cctlnt, 8), REG_RO + PV_LEFT },\r
88 { GRDATA (CHAIN, lpt_unit.flags, 10, 2, UNIT_V_PCHAIN), REG_HRO },\r
89 { NULL }\r
90};\r
91\r
92MTAB lpt_mod[] = {\r
93 { UNIT_PCHAIN, UCS, "UCS", "UCS", NULL },\r
94 { UNIT_PCHAIN, PCA, "A chain", "PCA", NULL },\r
95 { UNIT_PCHAIN, PCH, "H chain", "PCH", NULL },\r
96 { 0 }\r
97};\r
98\r
99DEVICE lpt_dev = {\r
100 "LPT", &lpt_unit, lpt_reg, lpt_mod,\r
101 1, 10, 31, 1, 8, 7,\r
102 NULL, NULL, &lpt_reset,\r
103 NULL, NULL, NULL\r
104};\r
105\r
106\r
107/* -------------------------------------------------------------------- */\r
108\r
109/* Printer: master routine */\r
110\r
111int32 lpt (int32 op, int32 m, int32 n, int32 data)\r
112{\r
113 int32 iodata;\r
114 switch (op) {\r
115 case 0: /* SIO 1403 */\r
116 iodata = 0;\r
117 printf("\0");\r
118 switch (n) {\r
119 case 0x00: /* Spacing only */\r
120 if (data > 0 && data < 4)\r
121 iodata = carriage_control(2, data);\r
122 break;\r
123 case 0x02: /* Print & space */\r
124 iodata = write_line(0, 0);\r
125 if (data > 3) data = 0;\r
126 if (iodata == SCPE_OK)\r
127 iodata = carriage_control(2, data);\r
128 break;\r
129 case 0x04: /* Skip only */\r
130 iodata = carriage_control(4, data);\r
131 break;\r
132 case 0x06: /* Print and skip */\r
133 iodata = write_line(0, 0);\r
134 if (iodata == SCPE_OK)\r
135 iodata = carriage_control(4, data);\r
136 break;\r
137 default: \r
138 return STOP_INVDEV;\r
139 } \r
140 return iodata;\r
141 case 1: /* LIO 1403 */\r
142 switch (n) {\r
143 case 0x00: /* LPFLR */\r
144 LPFLR = (data >> 8) & 0xff;\r
145 break;\r
146 case 0x04:\r
147 LPIAR = data & 0xffff;\r
148 break;\r
149 case 0x06:\r
150 LPDAR = data & 0xffff;\r
151 break;\r
152 default:\r
153 return STOP_INVDEV;\r
154 } \r
155 return SCPE_OK;\r
156 case 2: /* TIO 1403 */\r
157 iodata = 0;\r
158 switch (n) {\r
159 case 0x00: /* Not ready/check */\r
160 if (lpterror)\r
161 iodata = 1;\r
162 if ((lpt_unit.flags & UNIT_ATT) == 0) \r
163 iodata = 1; \r
164 break;\r
165 case 0x02: /* Buffer Busy */\r
166 iodata = 0;\r
167 break;\r
168 case 0x04: /* Carriage Busy */\r
169 iodata = 0;\r
170 break;\r
171 case 0x06: /* Printer busy */\r
172 iodata = 0;\r
173 break;\r
174 default:\r
175 return (STOP_INVDEV << 16); \r
176 } \r
177 return ((SCPE_OK << 16) | iodata); \r
178 case 3: /* SNS 1403 */\r
179 switch (n) {\r
180 case 0x00: /* Line count */\r
181 iodata = (linectr << 8);\r
182 break;\r
183 case 0x02: /* Timing data */\r
184 iodata = 0;\r
185 break;\r
186 case 0x03: /* Check data */\r
187 iodata = 0;\r
188 break;\r
189 case 0x04: /* LPIAR */\r
190 iodata = LPIAR;\r
191 break;\r
192 case 0x06: /* LPDAR */\r
193 iodata = LPDAR; \r
194 break;\r
195 default:\r
196 return (STOP_INVDEV << 16);\r
197 } \r
198 return ((SCPE_OK << 16) | iodata); \r
199 case 4: /* APL 1403 */\r
200 iodata = 0;\r
201 return ((SCPE_OK << 16) | iodata); \r
202 default:\r
203 break;\r
204 } \r
205 printf (">>LPT non-existent function %d\n", op);\r
206 return SCPE_OK; \r
207}\r
208\r
209\r
210/* Print routine\r
211\r
212 Modifiers have been checked by the caller\r
213 S = suppress automatic newline\r
214*/\r
215\r
216t_stat write_line (int32 ilnt, int32 mod)\r
217{\r
218int32 i, t, lc;\r
219static char lbuf[LPT_WIDTH + 1]; /* + null */\r
220\r
221if ((lpt_unit.flags & UNIT_ATT) == 0)\r
222 return SCPE_UNATT; \r
223\r
224lpterror = 0;\r
225lc = LPDAR; /* clear error */\r
226for (i = 0; i < LPT_WIDTH; i++) { /* convert print buf */\r
227 t = M[lc];\r
228 lbuf[i] = ebcdic_to_ascii[t & 0xff];\r
229 M[lc] = 0x40; /* HJS MOD */\r
230 lc++;\r
231}\r
232for (i = LPT_WIDTH - 1; (i >= 0) && (lbuf[i] == ' '); i--) lbuf[i] = 0;\r
233fputs (lbuf, lpt_unit.fileref); /* write line */\r
234if (lines) space (lines, lflag); /* cc action? do it */\r
235else if (mod == 0) space (1, FALSE); /* default? 1 line */\r
236else {\r
237 fputc ('\r', lpt_unit.fileref); /* sup -> overprint */\r
238 lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */\r
239}\r
240lines = lflag = 0; /* clear cc action */\r
241if (ferror (lpt_unit.fileref)) { /* error? */\r
242 perror ("Line printer I/O error");\r
243 clearerr (lpt_unit.fileref);\r
244 lpterror = 1;\r
245}\r
246return SCPE_OK;\r
247}\r
248\r
249/* Carriage control routine\r
250\r
251 Parameters:\r
252 action = 00, skip to channel now\r
253 = 01, space lines after\r
254 = 02, space lines now\r
255 = 03, skip to channel after\r
256 = 04, skip to line number\r
257 mod = number of lines or channel number or line number\r
258*/\r
259\r
260t_stat carriage_control (int32 action, int32 mod)\r
261{\r
262int32 i;\r
263\r
264if ((lpt_unit.flags & UNIT_ATT) == 0)\r
265 return SCPE_UNATT; \r
266\r
267switch (action) {\r
268case 0: /* to channel now */\r
269 if ((mod == 0) || (mod > 12) || CHP (mod, cct[cctptr])) return SCPE_OK;\r
270 for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */\r
271 if (CHP (mod, cct[(cctptr + i) % cctlnt]))\r
272 return space (i, TRUE);\r
273 }\r
274 return STOP_INVDEV; /* runaway channel */\r
275case 1: /* space after */\r
276 if (mod <= 3) {\r
277 lines = mod; /* save # lines */\r
278 lflag = FALSE; /* flag spacing */\r
279 CC9 = CC12 = 0;\r
280 }\r
281 return SCPE_OK;\r
282case 2: /* space now */\r
283 if (mod <= 3) return space (mod, FALSE);\r
284 return SCPE_OK;\r
285case 3: /* to channel after */\r
286 if ((mod == 0) || (mod > 12)) return SCPE_OK; /* check channel */\r
287 CC9 = CC12 = 0;\r
288 for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */\r
289 if (CHP (mod, cct[(cctptr + i) % cctlnt])) {\r
290 lines = i; /* save # lines */\r
291 lflag = TRUE; /* flag skipping */\r
292 return SCPE_OK;\r
293 }\r
294 }\r
295 return STOP_INVDEV; \r
296case 4: /* To line # */\r
297 if (mod < 2) {\r
298 fputs ("\n\f", lpt_unit.fileref); /* nl, ff */\r
299 linectr = 1;\r
300 } else {\r
301 if (mod <= linectr) {\r
302 fputs ("\n\f", lpt_unit.fileref);\r
303 linectr = 1;\r
304 } \r
305 while (1) {\r
306 if (linectr == mod)\r
307 break;\r
308 space(1, 0);\r
309 } \r
310 } \r
311 return SCPE_OK;\r
312} \r
313return SCPE_OK;\r
314}\r
315\r
316/* Space routine - space or skip n lines\r
317 \r
318 Inputs:\r
319 count = number of lines to space or skip\r
320 sflag = skip (TRUE) or space (FALSE)\r
321*/\r
322\r
323t_stat space (int32 count, int32 sflag)\r
324{\r
325int32 i;\r
326\r
327if ((lpt_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT;\r
328cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */\r
329if (sflag && CHP (0, cct[cctptr])) { /* skip, top of form? */\r
330 fputs ("\n\f", lpt_unit.fileref); /* nl, ff */\r
331 linectr = 1;\r
332} else {\r
333 for (i = 0; i < count; i++) fputc ('\n', lpt_unit.fileref);\r
334}\r
335lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */\r
336CC9 = CHP (9, cct[cctptr]) != 0; /* set indicators */\r
337CC12 = CHP (12, cct[cctptr]) != 0;\r
338linectr += count;\r
339if (linectr > LPFLR) \r
340 linectr -= LPFLR;\r
341return SCPE_OK;\r
342}\r
343\r
344/* Reset routine */\r
345\r
346t_stat lpt_reset (DEVICE *dptr)\r
347{\r
348cctptr = 0; /* clear cct ptr */\r
349lines = linectr = lflag = 0; /* no cc action */\r
350lpterror = 0;\r
351return SCPE_OK;\r
352}\r
353\r
354/* Attach routine */\r
355\r
356t_stat lpt_attach (UNIT *uptr, char *cptr)\r
357{\r
358cctptr = 0; /* clear cct ptr */\r
359lines = 0; /* no cc action */\r
360lpterror = 0;\r
361linectr = 0;\r
362return attach_unit (uptr, cptr);\r
363}\r