First Commit of my working state
[simh.git] / I1401 / i1401_cd.c
CommitLineData
196ba1fc
PH
1/* i1401_cd.c: IBM 1402 card reader/punch\r
2\r
3 Copyright (c) 1993-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 cdr card reader\r
27 cdp card punch\r
28 stack stackers (5 units)\r
29 0 normal\r
30 1 1\r
31 2 2/8\r
32 3 unused\r
33 4 4\r
34\r
35 Cards are represented as ASCII text streams terminated by newlines.\r
36 This allows cards to be created and edited as normal files.\r
37\r
38 28-Jun-07 RMS Added support for SS overlap modifiers\r
39 19-Jan-07 RMS Added UNIT_TEXT flag\r
40 20-Sep-05 RMS Revised for new code tables, compatible colbinary treatment\r
41 30-Aug-05 RMS Fixed read, punch to ignore modifier on 1,4 char inst\r
42 (reported by Van Snyder)\r
43 14-Nov-04 WVS Added column binary support\r
44 25-Apr-03 RMS Revised for extended file support\r
45 30-May-02 RMS Widened POS to 32b\r
46 30-Jan-02 RMS New zero footprint card bootstrap from Van Snyder\r
47 29-Nov-01 RMS Added read only unit support\r
48 13-Apr-01 RMS Revised for register arrays\r
49*/\r
50\r
51#include "i1401_defs.h"\r
52#include <ctype.h>\r
53\r
54#define UNIT_V_PCH (UNIT_V_UF + 0) /* output conv */\r
55#define UNIT_PCH (1 << UNIT_V_PCH)\r
56\r
57extern uint8 M[];\r
58extern int32 ind[64], ssa, iochk;\r
59extern int32 conv_old;\r
60\r
61int32 s1sel, s2sel, s4sel, s8sel;\r
62char rbuf[2 * CBUFSIZE]; /* > CDR_WIDTH */\r
63t_stat cdr_svc (UNIT *uptr);\r
64t_stat cdr_boot (int32 unitno, DEVICE *dptr);\r
65t_stat cdr_attach (UNIT *uptr, char *cptr);\r
66t_stat cd_reset (DEVICE *dptr);\r
67int32 bcd2asc (int32 c, UNIT *uptr);\r
68char colbin_to_bcd (uint32 cb);\r
69\r
70/* Card reader data structures\r
71\r
72 cdr_dev CDR descriptor\r
73 cdr_unit CDR unit descriptor\r
74 cdr_reg CDR register list\r
75*/\r
76\r
77UNIT cdr_unit = {\r
78 UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0), 100\r
79 };\r
80\r
81REG cdr_reg[] = {\r
82 { FLDATA (LAST, ind[IN_LST], 0) },\r
83 { FLDATA (ERR, ind[IN_READ], 0) },\r
84 { FLDATA (S1, s1sel, 0) },\r
85 { FLDATA (S2, s2sel, 0) },\r
86 { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },\r
87 { DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT },\r
88 { BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) },\r
89 { NULL }\r
90 };\r
91\r
92DEVICE cdr_dev = {\r
93 "CDR", &cdr_unit, cdr_reg, NULL,\r
94 1, 10, 31, 1, 8, 7,\r
95 NULL, NULL, &cd_reset,\r
96 &cdr_boot, &cdr_attach, NULL\r
97 };\r
98\r
99/* CDP data structures\r
100\r
101 cdp_dev CDP device descriptor\r
102 cdp_unit CDP unit descriptor\r
103 cdp_reg CDP register list\r
104*/\r
105\r
106UNIT cdp_unit = {\r
107 UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0)\r
108 };\r
109\r
110REG cdp_reg[] = {\r
111 { FLDATA (ERR, ind[IN_PNCH], 0) },\r
112 { FLDATA (S4, s4sel, 0) },\r
113 { FLDATA (S8, s8sel, 0) },\r
114 { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },\r
115 { NULL }\r
116 };\r
117\r
118MTAB cdp_mod[] = {\r
119 { UNIT_PCH, 0, "business set", "BUSINESS" },\r
120 { UNIT_PCH, UNIT_PCH, "Fortran set", "FORTRAN" },\r
121 { 0 }\r
122 };\r
123\r
124DEVICE cdp_dev = {\r
125 "CDP", &cdp_unit, cdp_reg, cdp_mod,\r
126 1, 10, 31, 1, 8, 7,\r
127 NULL, NULL, &cd_reset,\r
128 NULL, NULL, NULL\r
129 };\r
130\r
131/* Stacker data structures\r
132\r
133 stack_dev STACK device descriptor\r
134 stack_unit STACK unit descriptors\r
135 stack_reg STACK register list\r
136*/\r
137\r
138UNIT stack_unit[] = {\r
139 { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) },\r
140 { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) },\r
141 { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) },\r
142 { UDATA (NULL, UNIT_DIS, 0) }, /* unused */\r
143 { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }\r
144 };\r
145\r
146REG stack_reg[] = {\r
147 { DRDATA (POS0, stack_unit[0].pos, T_ADDR_W), PV_LEFT },\r
148 { DRDATA (POS1, stack_unit[1].pos, T_ADDR_W), PV_LEFT },\r
149 { DRDATA (POS28, stack_unit[2].pos, T_ADDR_W), PV_LEFT },\r
150 { DRDATA (POS4, stack_unit[4].pos, T_ADDR_W), PV_LEFT },\r
151 { NULL }\r
152 };\r
153\r
154DEVICE stack_dev = {\r
155 "STKR", stack_unit, stack_reg, cdp_mod,\r
156 5, 10, 31, 1, 8, 7,\r
157 NULL, NULL, &cd_reset,\r
158 NULL, NULL, NULL\r
159 };\r
160\r
161/* Card read routine\r
162\r
163 Modifiers have been checked by the caller\r
164 C modifier is recognized (column binary is implemented)\r
165*/\r
166\r
167t_stat read_card (int32 ilnt, int32 mod)\r
168{\r
169int32 i, cbn, c1, c2;\r
170t_stat r;\r
171\r
172if (sim_is_active (&cdr_unit)) { /* busy? */\r
173 sim_cancel (&cdr_unit); /* cancel */\r
174 if (r = cdr_svc (&cdr_unit)) return r; /* process */\r
175 }\r
176if ((cdr_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */\r
177ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */\r
178cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */\r
179for (i = 0; i < 2 * CBUFSIZE; i++) rbuf[i] = 0; /* clear extended buf */\r
180fgets (rbuf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */\r
181 cdr_unit.fileref);\r
182if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */\r
183if (ferror (cdr_unit.fileref)) { /* error? */\r
184 ind[IN_READ] = 1; \r
185 perror ("Card reader I/O error");\r
186 clearerr (cdr_unit.fileref);\r
187 if (iochk) return SCPE_IOERR;\r
188 return SCPE_OK;\r
189 }\r
190cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */\r
191if (ssa) { /* if last cd on */\r
192 getc (cdr_unit.fileref); /* see if more */\r
193 if (feof (cdr_unit.fileref)) ind[IN_LST] = 1; /* eof? set flag */\r
194 fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET);\r
195 }\r
196if (cbn) { /* column binary */\r
197 for (i = 0; i < CDR_WIDTH; i++) {\r
198 if (conv_old) {\r
199 c1 = ascii2bcd (rbuf[i]);\r
200 c2 = ascii2bcd (rbuf[CDR_WIDTH + i]);\r
201 }\r
202 else {\r
203 c1 = ascii2bcd (rbuf[2 * i]);\r
204 c2 = ascii2bcd (rbuf[(2 * i) + 1]);\r
205 }\r
206 M[CD_CBUF1 + i] = (M[CD_CBUF1 + i] & WM) | c1;\r
207 M[CD_CBUF2 + i] = (M[CD_CBUF2 + i] & WM) | c2;\r
208 M[CDR_BUF + i] = colbin_to_bcd ((c1 << 6) | c2);\r
209 } /* end for i */\r
210 } /* end if col bin */\r
211else { /* normal read */\r
212 for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */\r
213 rbuf[i] = ascii2bcd (rbuf[i]);\r
214 M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | rbuf[i];\r
215 }\r
216 }\r
217M[CDR_BUF - 1] = 060; /* mem mark */\r
218sim_activate (&cdr_unit, cdr_unit.wait); /* activate */\r
219return SCPE_OK;\r
220}\r
221\r
222/* Card reader service. If a stacker select is active, copy to the\r
223 selected stacker. Otherwise, copy to the normal stacker. If the\r
224 unit is unattached, simply exit.\r
225*/\r
226\r
227t_stat cdr_svc (UNIT *uptr)\r
228{\r
229int32 i;\r
230\r
231if (s1sel) uptr = &stack_unit[1]; /* stacker 1? */\r
232else if (s2sel) uptr = &stack_unit[2]; /* stacker 2? */\r
233else uptr = &stack_unit[0]; /* then default */\r
234if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */\r
235for (i = 0; i < CDR_WIDTH; i++)\r
236 rbuf[i] = bcd2ascii (rbuf[i], uptr->flags & UNIT_PCH);\r
237for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) rbuf[i] = 0;\r
238rbuf[CDR_WIDTH] = 0; /* null at end */\r
239fputs (rbuf, uptr->fileref); /* write card */\r
240fputc ('\n', uptr->fileref); /* plus new line */\r
241uptr->pos = ftell (uptr->fileref); /* update position */\r
242if (ferror (uptr->fileref)) { /* error? */\r
243 perror ("Card stacker I/O error");\r
244 clearerr (uptr->fileref);\r
245 if (iochk) return SCPE_IOERR;\r
246 }\r
247return SCPE_OK;\r
248}\r
249\r
250/* Card punch routine\r
251\r
252 Modifiers have been checked by the caller\r
253 C modifier is recognized (column binary is implemented)\r
254*/\r
255\r
256t_stat punch_card (int32 ilnt, int32 mod)\r
257{\r
258int32 i, cbn, c1, c2;\r
259static char pbuf[(2 * CDP_WIDTH) + 1]; /* + null */\r
260t_bool use_h;\r
261UNIT *uptr;\r
262\r
263if (s8sel) uptr = &stack_unit[2]; /* stack 8? */\r
264else if (s4sel) uptr = &stack_unit[4]; /* stack 4? */\r
265else uptr = &cdp_unit; /* normal output */\r
266if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */\r
267use_h = uptr->flags & UNIT_PCH;\r
268ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */\r
269cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */\r
270\r
271M[CDP_BUF - 1] = 012; /* set prev loc */\r
272if (cbn) { /* column binary */\r
273 for (i = 0; i < CDP_WIDTH; i++) {\r
274 c1 = bcd2ascii (M[CD_CBUF1 + i] & CHAR, use_h);\r
275 c2 = bcd2ascii (M[CD_CBUF2 + i] & CHAR, use_h);\r
276 if (conv_old) {\r
277 pbuf[i] = c1;\r
278 pbuf[i + CDP_WIDTH] = c2;\r
279 }\r
280 else {\r
281 pbuf[2 * i] = c1;\r
282 pbuf[(2 * i) + 1] = c2;\r
283 }\r
284 }\r
285 for (i = 2 * CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--)\r
286 pbuf[i] = 0;\r
287 pbuf[2 * CDP_WIDTH] = 0; /* trailing null */\r
288 }\r
289else { /* normal */\r
290 for (i = 0; i < CDP_WIDTH; i++)\r
291 pbuf[i] = bcd2ascii (M[CDP_BUF + i] & CHAR, use_h);\r
292 for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--)\r
293 pbuf[i] = 0;\r
294 pbuf[CDP_WIDTH] = 0; /* trailing null */\r
295 }\r
296fputs (pbuf, uptr->fileref); /* output card */\r
297fputc ('\n', uptr->fileref); /* plus new line */\r
298uptr->pos = ftell (uptr->fileref); /* update position */\r
299if (ferror (uptr->fileref)) { /* error? */\r
300 perror ("Card punch I/O error");\r
301 clearerr (uptr->fileref);\r
302 if (iochk) return SCPE_IOERR;\r
303 ind[IN_PNCH] = 1;\r
304 }\r
305return SCPE_OK;\r
306}\r
307\r
308/* Select stack routine\r
309\r
310 Modifiers have been checked by the caller\r
311 Modifiers are 1, 2, 4, 8 for the respective stack,\r
312 or $, ., square for overlap control (ignored).\r
313*/\r
314\r
315t_stat select_stack (int32 ilnt, int32 mod)\r
316{\r
317if (mod == BCD_ONE) s1sel = 1;\r
318else if (mod == BCD_TWO) s2sel = 1;\r
319else if (mod == BCD_FOUR) s4sel = 1;\r
320else if (mod == BCD_EIGHT) s8sel = 1;\r
321return SCPE_OK;\r
322}\r
323\r
324/* Card reader/punch reset */\r
325\r
326t_stat cd_reset (DEVICE *dptr)\r
327{\r
328ind[IN_LST] = ind[IN_READ] = ind[IN_PNCH] = 0; /* clear indicators */\r
329s1sel = s2sel = s4sel = s8sel = 0; /* clear stacker sel */\r
330sim_cancel (&cdr_unit); /* clear reader event */\r
331return SCPE_OK;\r
332}\r
333\r
334/* Card reader attach */\r
335\r
336t_stat cdr_attach (UNIT *uptr, char *cptr)\r
337{\r
338ind[IN_LST] = ind[IN_READ] = 0; /* clear last card */\r
339return attach_unit (uptr, cptr);\r
340}\r
341\r
342/* Bootstrap routine */\r
343\r
344#define BOOT_START 0\r
345#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char))\r
346\r
347static const unsigned char boot_rom[] = {\r
348 OP_R + WM, OP_NOP + WM /* R, NOP */\r
349 };\r
350\r
351t_stat cdr_boot (int32 unitno, DEVICE *dptr)\r
352{\r
353int32 i;\r
354extern int32 saved_IS;\r
355\r
356for (i = 0; i < CDR_WIDTH; i++) M[CDR_BUF + i] = 0; /* clear buffer */\r
357for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];\r
358saved_IS = BOOT_START;\r
359return SCPE_OK;\r
360}\r
361\r
362/* Column binary to BCD\r
363\r
364 This is based on documentation in the IBM 1620 manual and may not be\r
365 accurate for the 7094. Each row (12,11,0,1..9) is interpreted as a bit\r
366 pattern, and the appropriate bits are set. (Double punches inclusive\r
367 OR, eg, 1,8,9 is 9.) On the 1620, double punch errors are detected;\r
368 since the 7094 only reads column binary, double punches are ignored.\r
369\r
370 Bit order, left to right, is 12, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.\r
371 The for loop works right to left, so the table is reversed. */\r
372\r
373static const char row_val[12] = {\r
374 011, 010, 007, 006, 005, 004,\r
375 003, 002, 001, 020, 040, 060\r
376 };\r
377\r
378char colbin_to_bcd (uint32 cb)\r
379{\r
380uint32 i;\r
381char bcd;\r
382\r
383for (i = 0, bcd = 0; i < 12; i++) { /* 'sum' rows */\r
384 if (cb & (1 << i)) bcd |= row_val[i];\r
385 }\r
386return bcd;\r
387}\r