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