First Commit of my working state
[simh.git] / S3 / s3_cd.c
1 /* s3_cd.c: IBM 1442 card reader/punch
2
3 Copyright (c) 2001-2005, Charles E. Owen
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Charles E. Owen shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Charles E. Owen.
25
26 cdr card reader
27 cdp card punch
28 cdp2 card punch stacker 2
29
30 25-Apr-03 RMS Revised for extended file support
31 08-Oct-02 RMS Added impossible function catcher
32
33 Normally, cards are represented as ASCII text streams terminated by newlines.
34 This allows cards to be created and edited as normal files. Set the EBCDIC
35 flag on the card unit allows cards to be read or punched in EBCDIC format,
36 suitable for binary data.
37 */
38
39 #include "s3_defs.h"
40 #include <ctype.h>
41
42 extern uint8 M[];
43 extern char ebcdic_to_ascii[256];
44 extern char ascii_to_ebcdic[256];
45 int32 s1sel, s2sel;
46 char rbuf[CBUFSIZE]; /* > CDR_WIDTH */
47 t_stat cdr_svc (UNIT *uptr);
48 t_stat cdr_boot (int32 unitno, DEVICE *dptr);
49 t_stat cdr_attach (UNIT *uptr, char *cptr);
50 t_stat cd_reset (DEVICE *dptr);
51 t_stat read_card (int32 ilnt, int32 mod);
52 t_stat punch_card (int32 ilnt, int32 mod);
53
54 int32 DAR; /* Data address register */
55 int32 LCR; /* Length Count Register */
56 int32 lastcard = 0; /* Last card switch */
57 int32 carderr = 0; /* Error switch */
58 int32 pcherror = 0; /* Punch error */
59 int32 notready = 0; /* Not ready error */
60 int32 cdr_ebcdic = 0; /* EBCDIC mode on reader */
61 int32 cdp_ebcdic = 0; /* EBCDIC mode on punch */
62
63 extern int32 GetMem(int32 addr);
64 extern int32 PutMem(int32 addr, int32 data);
65
66 /* Card reader data structures
67
68 cdr_dev CDR descriptor
69 cdr_unit CDR unit descriptor
70 cdr_reg CDR register list
71 */
72
73 UNIT cdr_unit = { UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 100 };
74
75 REG cdr_reg[] = {
76 { FLDATA (LAST, lastcard, 0) },
77 { FLDATA (ERR, carderr, 0) },
78 { FLDATA (NOTRDY, notready, 0) },
79 { HRDATA (DAR, DAR, 16) },
80 { HRDATA (LCR, LCR, 16) },
81 { FLDATA (EBCDIC, cdr_ebcdic, 0) },
82 { FLDATA (S2, s2sel, 0) },
83 { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },
84 { DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT },
85 { BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) },
86 { NULL }
87 };
88
89 DEVICE cdr_dev = {
90 "CDR", &cdr_unit, cdr_reg, NULL,
91 1, 10, 31, 1, 8, 7,
92 NULL, NULL, &cd_reset,
93 &cdr_boot, &cdr_attach, NULL
94 };
95
96 /* CDP data structures
97
98 cdp_dev CDP device descriptor
99 cdp_unit CDP unit descriptor
100 cdp_reg CDP register list
101 */
102
103 UNIT cdp_unit = { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
104
105 REG cdp_reg[] = {
106 { FLDATA (ERR, pcherror, 0) },
107 { FLDATA (EBCDIC, cdp_ebcdic, 0) },
108 { FLDATA (S2, s2sel, 0) },
109 { FLDATA (NOTRDY, notready, 0) },
110 { HRDATA (DAR, DAR, 16) },
111 { HRDATA (LCR, LCR, 16) },
112 { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },
113 { NULL }
114 };
115
116 DEVICE cdp_dev = {
117 "CDP", &cdp_unit, cdp_reg, NULL,
118 1, 10, 31, 1, 8, 7,
119 NULL, NULL, &cd_reset,
120 NULL, NULL, NULL
121 };
122
123 /* Stacker data structures
124
125 stack_dev STACK device descriptor
126 stack_unit STACK unit descriptors
127 stack_reg STACK register list
128 */
129
130 UNIT stack_unit[] = {
131 { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }
132 };
133
134 REG stack_reg[] = {
135 { DRDATA (POS0, stack_unit[0].pos, 32), PV_LEFT },
136 { NULL }
137 };
138
139 DEVICE stack_dev = {
140 "CDP2", stack_unit, stack_reg, NULL,
141 1, 10, 31, 1, 8, 7,
142 NULL, NULL, &cd_reset,
143 NULL, NULL, NULL
144 };
145
146
147 /* -------------------------------------------------------------------- */
148
149 /* 1442: master routine */
150
151 int32 crd (int32 op, int32 m, int32 n, int32 data)
152 {
153 int32 iodata;
154 switch (op) {
155 case 0: /* SIO 1442 */
156 /* if (n == 1)
157 return STOP_IBKPT; */
158 switch (data) { /* Select stacker */
159 case 0x00:
160 break;
161 case 0x01:
162 s2sel = 1;
163 break;
164 default:
165 break;
166 }
167 switch (n) {
168 case 0x00: /* Feed */
169 iodata = SCPE_OK;
170 break;
171 case 0x01: /* Read only */
172 if (cdr_ebcdic)
173 iodata = read_card(0, 1);
174 else
175 iodata = read_card(0, 0);
176 break;
177 case 0x02: /* Punch and feed */
178 iodata = punch_card(0, 0);
179 break;
180 case 0x03: /* Read Col Binary */
181 iodata = read_card(0, 1);
182 break;
183 case 0x04: /* Punch no feed */
184 iodata = punch_card(0, 1);
185 break;
186 default:
187 return STOP_INVDEV;
188 }
189 return iodata;
190 case 1: /* LIO 1442 */
191 switch (n) {
192 case 0x00: /* Load LCR */
193 LCR = data & 0xffff;
194 break;
195 case 0x04:
196 DAR = data & 0xffff;
197 break;
198 default:
199 return STOP_INVDEV;
200 }
201 return SCPE_OK;
202 case 2: /* TIO 1442 */
203 iodata = 0;
204 switch (n) {
205 case 0x00: /* Error */
206 if (carderr || pcherror || notready)
207 iodata = 1;
208 if ((cdr_unit.flags & UNIT_ATT) == 0)
209 iodata = 1; /* attached? */
210 break;
211 case 0x02: /* Busy */
212 if (sim_is_active (&cdr_unit))
213 iodata = 1;
214 break;
215 default:
216 return (STOP_INVDEV << 16);
217 }
218 return ((SCPE_OK << 16) | iodata);
219 case 3: /* SNS 1442 */
220 iodata = 0;
221 switch (n) {
222 case 0x01:
223 break;
224 case 0x02:
225 break;
226 case 0x03:
227 if (carderr)
228 iodata |= 0x80;
229 if (lastcard)
230 iodata |= 0x40;
231 if (pcherror)
232 iodata |= 0x20;
233 if ((cdr_unit.flags & UNIT_ATT) == 0)
234 iodata |= 0x08;
235 if (notready)
236 iodata |= 0x08;
237 break;
238 case 0x04:
239 iodata = DAR;
240 break;
241 default:
242 return (STOP_INVDEV << 16);
243 }
244 iodata |= ((SCPE_OK << 16) & 0xffff0000);
245 return (iodata);
246 case 4: /* APL 1442 */
247 iodata = 0;
248 switch (n) {
249 case 0x00: /* Error */
250 if (carderr || pcherror || notready)
251 iodata = 1;
252 if ((cdr_unit.flags & UNIT_ATT) == 0)
253 iodata = 1; /* attached? */
254 break;
255 case 0x02: /* Busy */
256 if (sim_is_active (&cdr_unit))
257 iodata = 1;
258 break;
259 default:
260 return (STOP_INVDEV << 16);
261 }
262 return ((SCPE_OK << 16) | iodata);
263 default:
264 break;
265 }
266 printf (">>CRD non-existent function %d\n", op);
267 return SCPE_OK;
268 }
269
270 /* Card read routine
271 mod 0 = ASCII read
272 mod 1 = EBCDIC read
273 */
274
275 t_stat read_card (int32 ilnt, int32 mod)
276 {
277 int32 i;
278 t_stat r;
279
280 if (sim_is_active (&cdr_unit)) { /* busy? */
281 sim_cancel (&cdr_unit); /* cancel */
282 if (r = cdr_svc (&cdr_unit)) return r; /* process */
283 }
284
285 if (((cdp_unit.flags & UNIT_ATT) != 0 ||
286 (stack_unit[0].flags & UNIT_ATT) != 0) && /* Punch is attached and */
287 (cdr_unit.flags & UNIT_ATT) == 0) { /* reader is not --- */
288 for (i = 0; i < 80; i++) { /* Assume blank cards in hopper */
289 PutMem(DAR, 0x40);
290 DAR++;
291 }
292 sim_activate (&cdr_unit, cdr_unit.wait); /* activate */
293 return SCPE_OK;
294 }
295
296 if ((cdr_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
297
298 lastcard = carderr = notready = s1sel = s2sel = 0; /* default stacker */
299
300 for (i = 0; i < CBUFSIZE; i++) rbuf[i] = 0x20; /* clear buffer */
301 if (mod) {
302 for (i = 0; i < 80; i++) {
303 rbuf[i] = fgetc(cdr_unit.fileref); /* Read EBCDIC */
304 }
305 } else {
306 fgets (rbuf, CBUFSIZE, cdr_unit.fileref); /* read Ascii */
307 }
308 if (feof (cdr_unit.fileref)) { /* eof? */
309 notready = 1;
310 return STOP_NOCD;
311 }
312 if (ferror (cdr_unit.fileref)) { /* error? */
313 perror ("Card reader I/O error");
314 clearerr (cdr_unit.fileref);
315 carderr = 1;
316 return SCPE_OK; }
317 cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */
318 i = getc (cdr_unit.fileref); /* see if more */
319 if (feof (cdr_unit.fileref)) lastcard = 1; /* eof? set flag */
320 fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET);
321 for (i = 0; i < 80; i++) {
322 if (mod == 0) { /* If ASCII mode... */
323 if (rbuf[i] == '\n' || /* remove ASCII CR/LF */
324 rbuf[i] == '\r' ||
325 rbuf[i] == 0x00)
326 rbuf[i] = ' ';
327 rbuf[i] = ascii_to_ebcdic[rbuf[i]]; /* convert to EBCDIC */
328 }
329 PutMem(DAR, rbuf[i]); /* Copy to main memory */
330 DAR++;
331 }
332 sim_activate (&cdr_unit, cdr_unit.wait); /* activate */
333 return SCPE_OK;
334 }
335
336 /* Card reader service. If a stacker select is active, copy to the
337 selected stacker. Otherwise, copy to the normal stacker. If the
338 unit is unattached, simply exit.
339 */
340
341 t_stat cdr_svc (UNIT *uptr)
342 {
343 int32 i;
344
345 if (s2sel) uptr = &stack_unit[0]; /* stacker 1? */
346 else uptr = &stack_unit[0]; /* then default */
347 if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
348 for (i = 0; i < CDR_WIDTH; i++) rbuf[i] = ebcdic_to_ascii[rbuf[i]];
349 for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) rbuf[i] = 0;
350 rbuf[CDR_WIDTH] = 0; /* null at end */
351 fputs (rbuf, uptr -> fileref); /* write card */
352 fputc ('\n', uptr -> fileref); /* plus new line */
353 if (ferror (uptr -> fileref)) { /* error? */
354 perror ("Card stacker I/O error");
355 clearerr (uptr -> fileref);
356 }
357 uptr -> pos = ftell (uptr -> fileref); /* update position */
358 return SCPE_OK;
359 }
360
361 /* Card punch routine
362
363 mod: not used
364 */
365
366 t_stat punch_card (int32 ilnt, int32 mod)
367 {
368 int32 i, colcount;
369 static char pbuf[CDP_WIDTH + 1]; /* + null */
370 UNIT *uptr;
371
372 if (s2sel) uptr = &stack_unit[0]; /* stack 2? */
373 else uptr = &cdp_unit; /* normal output */
374 if ((uptr -> flags & UNIT_ATT) == 0) { /* Attached? */
375 notready = 1;
376 return SCPE_OK;
377 }
378 pcherror = s1sel = notready = 0; /* clear flags */
379
380 colcount = 128 - LCR;
381 for (i = 0; i < colcount; i++) { /* Fetch data */
382 if (cdp_ebcdic)
383 pbuf[i] = GetMem(DAR) & 0xff;
384 else
385 pbuf[i] = ebcdic_to_ascii[GetMem(DAR)];
386 DAR++;
387 }
388 for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) pbuf[i] = 0;
389 pbuf[CDP_WIDTH] = 0; /* trailing null */
390 if (!cdp_ebcdic) {
391 fputs (pbuf, uptr -> fileref); /* output card */
392 fputc ('\n', uptr -> fileref); /* plus new line */
393 } else {
394 for (i = 0; i < 80; i++) {
395 fputc(pbuf[i], uptr -> fileref);
396 }
397 }
398 if (ferror (uptr -> fileref)) { /* error? */
399 perror ("Card punch I/O error");
400 clearerr (uptr -> fileref);
401 pcherror = 1;
402 }
403 uptr -> pos = ftell (uptr -> fileref); /* update position */
404 return SCPE_OK;
405 }
406
407 /* Select stack routine
408
409 Modifiers have been checked by the caller
410 Modifiers are 1, 2, for the respective stack
411 */
412
413 t_stat select_stack (int32 ilnt, int32 mod)
414 {
415 if (mod == 1) s1sel = 1;
416 else if (mod == 2) s2sel = 1;
417 return SCPE_OK;
418 }
419
420 /* Card reader/punch reset */
421
422 t_stat cd_reset (DEVICE *dptr)
423 {
424 lastcard = carderr = notready = pcherror = 0; /* clear indicators */
425 s1sel = s2sel = 0; /* clear stacker sel */
426 sim_cancel (&cdr_unit); /* clear reader event */
427 return SCPE_OK;
428 }
429
430 /* Card reader attach */
431
432 t_stat cdr_attach (UNIT *uptr, char *cptr)
433 {
434 carderr = lastcard = notready = 0; /* clear last card */
435 return attach_unit (uptr, cptr);
436 }
437
438 /* Bootstrap routine */
439
440 t_stat cdr_boot (int32 unitno, DEVICE *dptr)
441 {
442 cdr_ebcdic = 1;
443 DAR = 0;
444 LCR = 80;
445 read_card(0, 1);
446 return SCPE_OK;
447 }