First Commit of my working state
[simh.git] / SDS / sds_lp.c
CommitLineData
196ba1fc
PH
1/* sds_lp.c: SDS 940 line printer simulator\r
2\r
3 Copyright (c) 2001-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 lpt line printer\r
27\r
28 19-Jan-07 RMS Added UNIT_TEXT flag\r
29 25-Apr-03 RMS Revised for extended file support\r
30*/\r
31\r
32#include "sds_defs.h"\r
33\r
34#define LPT_V_LN 9\r
35#define LPT_M_LN 07\r
36#define LPT_GETLN(x) (((x) >> LPT_V_LN) & LPT_M_LN)\r
37#define CHP(ch,val) ((val) & (1 << (ch))) /* CCL chan test */\r
38#define SET_XFR 1 /* set xfr */\r
39#define SET_EOR 2 /* print, set eor */\r
40#define SET_SPC 4 /* space */\r
41\r
42extern char sds_to_ascii[64];\r
43extern uint32 xfr_req;\r
44extern int32 stop_invins, stop_invdev, stop_inviop;\r
45int32 lpt_spc = 0; /* space instr */\r
46int32 lpt_sta = 0; /* timeout state */\r
47int32 lpt_bptr = 0; /* line buf ptr */\r
48int32 lpt_err = 0; /* error */\r
49int32 lpt_ccl = 1, lpt_ccp = 0; /* cctl lnt, ptr */\r
50int32 lpt_ctime = 10; /* char time */\r
51int32 lpt_ptime = 1000; /* print time */\r
52int32 lpt_stime = 10000; /* space time */\r
53int32 lpt_stopioe = 1; /* stop on err */\r
54char lpt_buf[LPT_WIDTH + 1] = { 0 }; /* line buffer */\r
55uint8 lpt_cct[CCT_LNT] = { 0377 }; /* car ctl tape */\r
56DSPT lpt_tplt[] = { /* template */\r
57 { 1, 0 },\r
58 { 0, 0 }\r
59 };\r
60\r
61DEVICE lpt_dev;\r
62t_stat lpt_svc (UNIT *uptr);\r
63t_stat lpt_reset (DEVICE *dptr);\r
64t_stat lpt_attach (UNIT *uptr, char *cptr);\r
65t_stat lpt_crctl (int32 ch);\r
66t_stat lpt_status (UNIT *uptr);\r
67t_stat lpt_bufout (UNIT *uptr);\r
68void lpt_end_op (int32 fl);\r
69t_stat lpt (uint32 fnc, uint32 inst, uint32 *dat);\r
70\r
71/* LPT data structures\r
72\r
73 lpt_dev LPT device descriptor\r
74 lpt_unit LPT unit descriptor\r
75 lpt_reg LPT register list\r
76*/\r
77\r
78DIB lpt_dib = { CHAN_W, DEV_LPT, XFR_LPT, lpt_tplt, &lpt };\r
79\r
80UNIT lpt_unit = {\r
81 UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0)\r
82 };\r
83\r
84REG lpt_reg[] = {\r
85 { BRDATA (BUF, lpt_buf, 8, 8, LPT_WIDTH) },\r
86 { DRDATA (BPTR, lpt_bptr, 8), PV_LEFT },\r
87 { FLDATA (XFR, xfr_req, XFR_V_LPT) },\r
88 { FLDATA (ERR, lpt_err, 0) },\r
89 { ORDATA (STA, lpt_sta, 3) },\r
90 { BRDATA (CCT, lpt_cct, 8, 8, CCT_LNT) },\r
91 { DRDATA (CCTP, lpt_ccp, 8), PV_LEFT },\r
92 { DRDATA (CCTL, lpt_ccl, 8), REG_RO + PV_LEFT },\r
93 { ORDATA (SPCINST, lpt_spc, 24) },\r
94 { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },\r
95 { DRDATA (CTIME, lpt_ctime, 24), REG_NZ + PV_LEFT },\r
96 { DRDATA (PTIME, lpt_ptime, 24), REG_NZ + PV_LEFT },\r
97 { DRDATA (STIME, lpt_stime, 24), REG_NZ + PV_LEFT },\r
98 { FLDATA (STOP_IOE, lpt_stopioe, 0) },\r
99 { NULL }\r
100 };\r
101\r
102MTAB lpt_mod[] = {\r
103 { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", "CHANNEL",\r
104 &set_chan, &show_chan, NULL },\r
105 { 0 }\r
106 };\r
107\r
108DEVICE lpt_dev = {\r
109 "LPT", &lpt_unit, lpt_reg, lpt_mod,\r
110 1, 10, 31, 1, 8, 7,\r
111 NULL, NULL, &lpt_reset,\r
112 NULL, &lpt_attach, NULL,\r
113 &lpt_dib, DEV_DISABLE\r
114 };\r
115\r
116/* Line printer routine\r
117\r
118 conn - inst = EOM0, dat = NULL\r
119 eom1 - inst = EOM1, dat = NULL\r
120 sks - inst = SKS, dat = ptr to result\r
121 disc - inst = device number, dat = NULL\r
122 wreor - inst = device number, dat = NULL\r
123 read - inst = device number, dat = ptr to data\r
124 write - inst = device number, dat = ptr to result\r
125\r
126 The line printer is an asynchronous output device, that is, it\r
127 can never set the channel rate error flag.\r
128*/\r
129\r
130t_stat lpt (uint32 fnc, uint32 inst, uint32 *dat)\r
131{\r
132int32 i, t, new_ch;\r
133char asc;\r
134\r
135switch (fnc) { /* case function */\r
136\r
137 case IO_CONN: /* connect */\r
138 new_ch = I_GETEOCH (inst); /* get new chan */\r
139 if (new_ch != lpt_dib.chan) return SCPE_IERR; /* wrong chan? */\r
140 for (i = 0; i < LPT_WIDTH; i++) lpt_buf[i] = 0; /* clr buffer */\r
141 lpt_bptr = 0; /* clr buf ptr */\r
142 lpt_err = 0; /* err = 0 */\r
143 xfr_req = xfr_req & ~XFR_LPT; /* clr xfr flag */\r
144 lpt_sta = lpt_sta | SET_XFR; /* need xfr */\r
145 sim_activate (&lpt_unit, lpt_ctime); /* start timer */\r
146 break;\r
147\r
148 case IO_EOM1: /* EOM mode 1 */\r
149 new_ch = I_GETEOCH (inst); /* get new chan */\r
150 if (new_ch != lpt_dib.chan) CRETIOP; /* wrong chan? */\r
151 if (inst & 0400) { /* space? */\r
152 lpt_spc = inst; /* save instr */\r
153 lpt_sta = lpt_sta | SET_SPC; /* need space */\r
154 sim_cancel (&lpt_unit); /* cancel timer */\r
155 sim_activate (&lpt_unit, lpt_stime); /* start timer */\r
156 }\r
157 break;\r
158\r
159 case IO_DISC: /* disconnect */\r
160 lpt_end_op (0); /* normal term */\r
161 return lpt_bufout (&lpt_unit); /* dump output */\r
162\r
163 case IO_WREOR: /* write eor */\r
164 lpt_sta = (lpt_sta | SET_EOR) & ~SET_XFR; /* need eor */\r
165 sim_activate (&lpt_unit, lpt_ptime); /* start timer */\r
166 break;\r
167\r
168 case IO_SKS: /* SKS */\r
169 new_ch = I_GETSKCH (inst); /* sks chan */\r
170 if (new_ch != lpt_dib.chan) return SCPE_IERR; /* wrong chan? */\r
171 t = I_GETSKCND (inst); /* sks cond */\r
172 if (((t == 020) && (!CHP (7, lpt_cct[lpt_ccp]))) || /* 14062: !ch 7 */\r
173 ((t == 010) && (lpt_unit.flags & UNIT_ATT)) || /* 12062: !online */\r
174 (t == 004) && !lpt_err) *dat = 1; /* 11062: !err */\r
175 break;\r
176\r
177 case IO_WRITE: /* write */\r
178 asc = sds_to_ascii[(*dat) & 077]; /* convert data */\r
179 xfr_req = xfr_req & ~XFR_LPT; /* clr xfr flag */\r
180 if (lpt_bptr < LPT_WIDTH) lpt_buf[lpt_bptr++] = asc;/* store data */\r
181 lpt_sta = lpt_sta | SET_XFR; /* need xfr */\r
182 sim_activate (&lpt_unit, lpt_ctime); /* start ch timer */\r
183 break;\r
184\r
185 default:\r
186 CRETINS;\r
187 }\r
188\r
189return SCPE_OK;\r
190}\r
191\r
192/* Unit service and write */\r
193\r
194t_stat lpt_svc (UNIT *uptr)\r
195{\r
196t_stat r = SCPE_OK;\r
197static const char *lpt_stabl[] = {\r
198 "\r", "\n", "\n\n", "\n\n\n",\r
199 "\n\n\n\n", "\n\n\n\n\n",\r
200 "\n\n\n\n\n\n", "\n\n\n\n\n\n\n"\r
201 };\r
202\r
203if (lpt_sta & SET_XFR) chan_set_ordy (lpt_dib.chan); /* need lpt xfr? */\r
204if (lpt_sta & SET_EOR) { /* printing? */\r
205 chan_set_flag (lpt_dib.chan, CHF_EOR); /* set eor flg */\r
206 r = lpt_bufout (uptr); /* output buf */\r
207 }\r
208if (lpt_sta & SET_SPC) { /* spacing? */\r
209 if (uptr->flags & UNIT_ATT) { /* attached? */\r
210 int32 ln = LPT_GETLN (lpt_spc); /* get lines, ch */\r
211 if (lpt_spc & 0200) /* n lines? */\r
212 fputs (lpt_stabl[ln], uptr->fileref); /* upspace */\r
213 else lpt_crctl (ln); /* carriage ctl */\r
214 }\r
215 r = lpt_status (uptr); /* update status */\r
216 }\r
217lpt_sta = 0; /* clear state */\r
218return r;\r
219}\r
220\r
221/* Trim and output buffer */\r
222\r
223t_stat lpt_bufout (UNIT *uptr)\r
224{\r
225int32 i;\r
226\r
227if ((uptr->flags & UNIT_ATT) && lpt_bptr) { /* attached? */\r
228 for (i = LPT_WIDTH - 1; (i >= 0) && (lpt_buf[i] == ' '); i--)\r
229 lpt_buf[i] = 0; /* trim line */\r
230 fputs (lpt_buf, uptr->fileref); /* write line */\r
231 lpt_bptr = 0;\r
232 }\r
233return lpt_status (uptr); /* return status */\r
234}\r
235\r
236/* Status update after I/O */\r
237\r
238t_stat lpt_status (UNIT *uptr)\r
239{\r
240if (uptr->flags & UNIT_ATT) { /* attached? */\r
241 uptr->pos = ftell (uptr->fileref); /* update position */\r
242 if (ferror (uptr->fileref)) { /* I/O error? */\r
243 lpt_end_op (CHF_EOR | CHF_ERR); /* set err, disc */\r
244 perror ("LPT I/O error"); /* print msg */\r
245 clearerr (uptr->fileref);\r
246 return SCPE_IOERR; /* ret error */\r
247 }\r
248 }\r
249else {\r
250 lpt_end_op (CHF_EOR | CHF_ERR); /* set err, disc */\r
251 CRETIOE (lpt_stopioe, SCPE_UNATT); /* ret error */\r
252 }\r
253return SCPE_OK;\r
254}\r
255\r
256/* Terminate LPT operation */\r
257\r
258void lpt_end_op (int32 fl)\r
259{\r
260if (fl) chan_set_flag (lpt_dib.chan, fl); /* set flags */\r
261xfr_req = xfr_req & ~XFR_LPT; /* clear xfr */\r
262sim_cancel (&lpt_unit); /* stop */\r
263if (fl & CHF_ERR) { /* error? */\r
264 chan_disc (lpt_dib.chan); /* disconnect */\r
265 lpt_err = 1; /* set lpt err */\r
266 }\r
267return;\r
268}\r
269\r
270/* Carriage control */\r
271\r
272t_stat lpt_crctl (int32 ch)\r
273{\r
274int32 i, j;\r
275\r
276if ((ch == 1) && CHP (ch, lpt_cct[0])) { /* top of form? */\r
277 fputs ("\f\n", lpt_unit.fileref); /* ff + nl */\r
278 lpt_ccp = 0; /* top of page */\r
279 return SCPE_OK;\r
280 }\r
281for (i = 1; i < lpt_ccl + 1; i++) { /* sweep thru cct */\r
282 lpt_ccp = (lpt_ccp + 1) %lpt_ccl; /* adv pointer */\r
283 if (CHP (ch, lpt_cct[lpt_ccp])) { /* chan punched? */\r
284 for (j = 0; j < i; j++) fputc ('\n', lpt_unit.fileref);\r
285 return SCPE_OK;\r
286 }\r
287 }\r
288return STOP_CCT; /* runaway channel */\r
289}\r
290\r
291/* Reset routine */\r
292\r
293t_stat lpt_reset (DEVICE *dptr)\r
294{\r
295chan_disc (lpt_dib.chan); /* disconnect */\r
296lpt_spc = 0; /* clr state */\r
297lpt_sta = 0;\r
298xfr_req = xfr_req & ~XFR_LPT; /* clr xfr flag */\r
299sim_cancel (&lpt_unit); /* deactivate */\r
300return SCPE_OK;\r
301}\r
302\r
303/* Attach routine */\r
304\r
305t_stat lpt_attach (UNIT *uptr, char *cptr)\r
306{\r
307lpt_ccp = 0; /* top of form */\r
308return attach_unit (uptr, cptr);\r
309}\r