First Commit of my working state
[simh.git] / Interdata / id_lp.c
CommitLineData
196ba1fc
PH
1/* id_lp.c: Interdata line printer\r
2\r
3 Copyright (c) 2001-2008, 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 lpt M46-206 line printer\r
27\r
28 27-May-08 RMS Fixed bug in printing test (from Davis Johnson)\r
29 19-Jan-07 RMS Added UNIT_TEXT flag\r
30 25-Apr-03 RMS Revised for extended file support\r
31*/\r
32\r
33#include "id_defs.h"\r
34#include <ctype.h>\r
35\r
36/* Device definitions */\r
37\r
38#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */\r
39#define UNIT_UC (1 << UNIT_V_UC)\r
40#define SPC_BASE 0x40 /* spacing base */\r
41#define VFU_BASE 0x78 /* VFU base */\r
42#define VFU_WIDTH 0x8 /* VFU width */\r
43#define LF 0xA\r
44#define VT 0xB\r
45#define VT_VFU 4 /* VFU chan for VT */\r
46#define FF 0xC\r
47#define FF_VFU 8 /* VFU chan for FF */\r
48#define CR 0xD\r
49#define VFUP(ch,val) ((val) & (1 << (ch))) /* VFU chan test */\r
50\r
51/* Status byte, * = dynamic */\r
52\r
53#define STA_PAPE 0x40 /* *paper empty */\r
54#define STA_MASK (STA_BSY) /* static status */\r
55\r
56uint32 lpt_sta = STA_BSY; /* status */\r
57char lpxb[LPT_WIDTH + 1]; /* line buffer */\r
58uint32 lpt_bptr = 0; /* buf ptr */\r
59uint32 lpt_spnd = 0; /* space pending */\r
60uint32 lpt_vfup = 0; /* VFU ptr */\r
61uint32 lpt_vful = 1; /* VFU lnt */\r
62uint8 lpt_vfut[VFU_LNT] = { 0xFF }; /* VFU tape */\r
63uint32 lpt_arm = 0; /* int armed */\r
64int32 lpt_ctime = 10; /* char time */\r
65int32 lpt_stime = 1000; /* space time */\r
66int32 lpt_stopioe = 0; /* stop on err */\r
67\r
68extern uint32 int_req[INTSZ], int_enb[INTSZ];\r
69\r
70DEVICE lpt_dev;\r
71uint32 lpt (uint32 dev, uint32 op, uint32 dat);\r
72t_stat lpt_svc (UNIT *uptr);\r
73t_stat lpt_reset (DEVICE *dptr);\r
74t_stat lpt_attach (UNIT *uptr, char *cptr);\r
75t_stat lpt_bufout (UNIT *uptr);\r
76t_stat lpt_vfu (UNIT *uptr, int32 ch);\r
77t_stat lpt_spc (UNIT *uptr, int32 cnt);\r
78\r
79/* LPT data structures\r
80\r
81 lpt_dev LPT device descriptor\r
82 lpt_unit LPT unit descriptors\r
83 lpt_reg LPT register list\r
84*/\r
85\r
86DIB lpt_dib = { d_LPT, -1, v_LPT, NULL, &lpt, NULL };\r
87\r
88UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_UC+UNIT_TEXT, 0) };\r
89\r
90REG lpt_reg[] = {\r
91 { HRDATA (STA, lpt_sta, 8) },\r
92 { HRDATA (BUF, lpt_unit.buf, 7) },\r
93 { BRDATA (DBUF, lpxb, 16, 7, LPT_WIDTH) },\r
94 { HRDATA (DBPTR, lpt_bptr, 8) },\r
95 { HRDATA (VFUP, lpt_vfup, 8) },\r
96 { HRDATA (VFUL, lpt_vful, 8) },\r
97 { BRDATA (VFUT, lpt_vfut, 16, 8, VFU_LNT) },\r
98 { FLDATA (IREQ, int_req[l_LPT], i_LPT) },\r
99 { FLDATA (IENB, int_enb[l_LPT], i_LPT) },\r
100 { FLDATA (IARM, lpt_arm, 0) },\r
101 { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },\r
102 { DRDATA (CTIME, lpt_ctime, 24), PV_LEFT },\r
103 { DRDATA (STIME, lpt_stime, 24), PV_LEFT },\r
104 { FLDATA (STOP_IOE, lpt_stopioe, 0) },\r
105 { HRDATA (DEVNO, lpt_dib.dno, 8), REG_HRO },\r
106 { NULL }\r
107 };\r
108\r
109MTAB lpt_mod[] = {\r
110 { UNIT_UC, 0, "lower case", "LC", NULL },\r
111 { UNIT_UC, UNIT_UC, "upper case", "UC", NULL },\r
112 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r
113 &set_dev, &show_dev, NULL },\r
114 { 0 }\r
115 };\r
116\r
117DEVICE lpt_dev = {\r
118 "LPT", &lpt_unit, lpt_reg, lpt_mod,\r
119 1, 10, 31, 1, 16, 7,\r
120 NULL, NULL, &lpt_reset,\r
121 NULL, &lpt_attach, NULL,\r
122 &lpt_dib, DEV_DISABLE\r
123 };\r
124\r
125/* Line printer: IO routine */\r
126\r
127uint32 lpt (uint32 dev, uint32 op, uint32 dat)\r
128{\r
129int32 t;\r
130\r
131switch (op) { /* case IO op */\r
132\r
133 case IO_ADR: /* select */\r
134 return BY; /* byte only */\r
135\r
136 case IO_OC: /* command */\r
137 lpt_arm = int_chg (v_LPT, dat, lpt_arm); /* upd int ctrl */\r
138 break;\r
139\r
140 case IO_WD: /* write */\r
141 t = lpt_unit.buf = dat & 0x7F; /* mask char */\r
142 lpt_sta = STA_BSY; /* set busy */\r
143 if (lpt_spnd || ((t >= LF) && (t <= CR))) /* space op? */\r
144 sim_activate (&lpt_unit, lpt_stime);\r
145 else sim_activate (&lpt_unit, lpt_ctime); /* normal char */\r
146 break;\r
147\r
148 case IO_SS: /* status */\r
149 t = lpt_sta & STA_MASK; /* status byte */\r
150 if ((lpt_unit.flags & UNIT_ATT) == 0) /* test paper out */\r
151 t = t | STA_EX | STA_PAPE | STA_BSY;\r
152 return t;\r
153 }\r
154\r
155return 0;\r
156}\r
157\r
158/* Unit service */\r
159\r
160t_stat lpt_svc (UNIT *uptr)\r
161{\r
162int32 t;\r
163t_stat r = SCPE_OK;\r
164\r
165lpt_sta = 0; /* clear busy */\r
166if (lpt_arm) SET_INT (v_LPT); /* armed? intr */\r
167if ((uptr->flags & UNIT_ATT) == 0) /* attached? */\r
168 return IORETURN (lpt_stopioe, SCPE_UNATT);\r
169t = uptr->buf; /* get character */\r
170if (lpt_spnd || ((t >= LF) && (t < CR))) { /* spc pend or spc op? */\r
171 lpt_spnd = 0;\r
172 if (lpt_bufout (uptr) != SCPE_OK) /* print */\r
173 return SCPE_IOERR;\r
174 if ((t == 1) || (t == LF)) lpt_spc (uptr, 1); /* single space */\r
175 else if (t == VT) r = lpt_vfu (uptr, VT_VFU - 1); /* VT->VFU */\r
176 else if (t == 0xC) r = lpt_vfu (uptr, FF_VFU - 1); /* FF->VFU */\r
177 else if ((t >= SPC_BASE) && (t < VFU_BASE))\r
178 lpt_spc (uptr, t - SPC_BASE); /* space */\r
179 else if ((t >= VFU_BASE) && (t < VFU_BASE + VFU_WIDTH))\r
180 r = lpt_vfu (uptr, t - VFU_BASE); /* VFU */\r
181 else fputs ("\r", uptr->fileref); /* overprint */\r
182 uptr->pos = ftell (uptr->fileref); /* update position */\r
183 if (ferror (lpt_unit.fileref)) {\r
184 perror ("LPT I/O error");\r
185 clearerr (uptr->fileref);\r
186 return SCPE_IOERR;\r
187 }\r
188 }\r
189else if (t == CR) { /* CR? */\r
190 lpt_spnd = 1; /* set spc pend */\r
191 return lpt_bufout (uptr); /* print line */\r
192 }\r
193else if (t >= 0x20) { /* printable? */\r
194 if ((uptr->flags & UNIT_UC) && islower (t)) /* UC only? */\r
195 t = toupper (t);\r
196 if (lpt_bptr < LPT_WIDTH) lpxb[lpt_bptr++] = t;\r
197 }\r
198return r;\r
199}\r
200\r
201/* Printing and spacing routines */\r
202\r
203t_stat lpt_bufout (UNIT *uptr)\r
204{\r
205int32 i;\r
206t_stat r = SCPE_OK;\r
207\r
208if (lpt_bptr == 0) return SCPE_OK; /* any char in buf? */\r
209for (i = LPT_WIDTH - 1; (i >= 0) && (lpxb[i] == ' '); i--)\r
210 lpxb[i] = 0; /* backscan line */\r
211if (lpxb[0]) { /* any char left? */\r
212 fputs (lpxb, uptr->fileref); /* write line */\r
213 lpt_unit.pos = ftell (uptr->fileref); /* update position */\r
214 if (ferror (uptr->fileref)) {\r
215 perror ("LPT I/O error");\r
216 clearerr (uptr->fileref);\r
217 r = SCPE_IOERR;\r
218 }\r
219 } \r
220lpt_bptr = 0; /* reset buffer */\r
221for (i = 0; i < LPT_WIDTH; i++) lpxb[i] = ' ';\r
222lpxb[LPT_WIDTH] = 0;\r
223return r;\r
224}\r
225\r
226t_stat lpt_vfu (UNIT *uptr, int32 ch)\r
227{\r
228uint32 i, j;\r
229\r
230if ((ch == (FF_VFU - 1)) && VFUP (ch, lpt_vfut[0])) { /* top of form? */\r
231 fputs ("\n\f", uptr->fileref); /* nl + ff */\r
232 lpt_vfup = 0; /* top of page */\r
233 return SCPE_OK;\r
234 }\r
235for (i = 1; i < lpt_vful + 1; i++) { /* sweep thru cct */\r
236 lpt_vfup = (lpt_vfup + 1) % lpt_vful; /* adv pointer */\r
237 if (VFUP (ch, lpt_vfut[lpt_vfup])) { /* chan punched? */\r
238 for (j = 0; j < i; j++) fputc ('\n', uptr->fileref);\r
239 return SCPE_OK;\r
240 }\r
241 }\r
242return STOP_VFU; /* runaway channel */\r
243}\r
244\r
245t_stat lpt_spc (UNIT *uptr, int32 cnt)\r
246{\r
247int32 i;\r
248\r
249if (cnt == 0) fputc ('\r', uptr->fileref);\r
250else {\r
251 for (i = 0; i < cnt; i++) fputc ('\n', uptr->fileref);\r
252 lpt_vfup = (lpt_vfup + cnt) % lpt_vful;\r
253 }\r
254return SCPE_OK;\r
255}\r
256\r
257/* Reset routine */\r
258\r
259t_stat lpt_reset (DEVICE *dptr)\r
260{\r
261int32 i;\r
262\r
263sim_cancel (&lpt_unit); /* deactivate */\r
264lpt_sta = 0; /* clr busy */\r
265lpt_bptr = 0; /* clr buf ptr */\r
266for (i = 0; i < LPT_WIDTH; i++) lpxb[i] = ' '; /* clr buf */\r
267lpxb[LPT_WIDTH] = 0;\r
268CLR_INT (v_LPT); /* clearr int */\r
269CLR_ENB (v_LPT); /* disable int */\r
270lpt_arm = 0; /* disarm int */\r
271return SCPE_OK;\r
272}\r
273\r
274/* Attach routine */\r
275\r
276t_stat lpt_attach (UNIT *uptr, char *cptr)\r
277{\r
278lpt_vfup = 0; /* top of form */\r
279return attach_unit (uptr, cptr);\r
280}\r
281\r
282/* Carriage control load routine */\r
283\r
284t_stat lp_load (FILE *fileref, char *cptr, char *fnam)\r
285{\r
286int32 col, ptr, mask, vfubuf[VFU_LNT];\r
287uint32 rpt;\r
288t_stat r;\r
289char cbuf[CBUFSIZE], gbuf[CBUFSIZE];\r
290\r
291if (*cptr != 0) return SCPE_ARG;\r
292ptr = 0;\r
293for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */\r
294 mask = 0;\r
295 if (*cptr == '(') { /* repeat count? */\r
296 cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */\r
297 rpt = get_uint (gbuf, 10, VFU_LNT, &r); /* repeat count */\r
298 if (r != SCPE_OK) return SCPE_FMT;\r
299 }\r
300 else rpt = 1;\r
301 while (*cptr != 0) { /* get col no's */\r
302 cptr = get_glyph (cptr, gbuf, ','); /* get next field */\r
303 col = get_uint (gbuf, 10, 7, &r); /* column number */\r
304 if (r != SCPE_OK) return SCPE_FMT;\r
305 mask = mask | (1 << col); /* set bit */\r
306 }\r
307 for ( ; rpt > 0; rpt--) { /* store vals */\r
308 if (ptr >= VFU_LNT) return SCPE_FMT;\r
309 vfubuf[ptr++] = mask;\r
310 }\r
311 }\r
312if (ptr == 0) return SCPE_FMT;\r
313lpt_vful = ptr;\r
314lpt_vfup = 0;\r
315for (rpt = 0; rpt < lpt_vful; rpt++) lpt_vfut[rpt] = vfubuf[rpt];\r
316return SCPE_OK;\r
317}\r