1 /* i1401_cd.c: IBM 1402 card reader/punch
3 Copyright (c) 1993-2007, Robert M. Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
28 stack stackers (5 units)
35 Cards are represented as ASCII text streams terminated by newlines.
36 This allows cards to be created and edited as normal files.
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
51 #include "i1401_defs.h"
54 #define UNIT_V_PCH (UNIT_V_UF + 0) /* output conv */
55 #define UNIT_PCH (1 << UNIT_V_PCH)
58 extern int32 ind
[64], ssa
, iochk
;
59 extern int32 conv_old
;
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
);
70 /* Card reader data structures
72 cdr_dev CDR descriptor
73 cdr_unit CDR unit descriptor
74 cdr_reg CDR register list
78 UDATA (&cdr_svc
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_ROABLE
+UNIT_TEXT
, 0), 100
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
) },
93 "CDR", &cdr_unit
, cdr_reg
, NULL
,
95 NULL
, NULL
, &cd_reset
,
96 &cdr_boot
, &cdr_attach
, NULL
99 /* CDP data structures
101 cdp_dev CDP device descriptor
102 cdp_unit CDP unit descriptor
103 cdp_reg CDP register list
107 UDATA (NULL
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_TEXT
, 0)
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
},
119 { UNIT_PCH
, 0, "business set", "BUSINESS" },
120 { UNIT_PCH
, UNIT_PCH
, "Fortran set", "FORTRAN" },
125 "CDP", &cdp_unit
, cdp_reg
, cdp_mod
,
127 NULL
, NULL
, &cd_reset
,
131 /* Stacker data structures
133 stack_dev STACK device descriptor
134 stack_unit STACK unit descriptors
135 stack_reg STACK register list
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) }
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
},
155 "STKR", stack_unit
, stack_reg
, cdp_mod
,
157 NULL
, NULL
, &cd_reset
,
163 Modifiers have been checked by the caller
164 C modifier is recognized (column binary is implemented)
167 t_stat
read_card (int32 ilnt
, int32 mod
)
169 int32 i
, cbn
, c1
, c2
;
172 if (sim_is_active (&cdr_unit
)) { /* busy? */
173 sim_cancel (&cdr_unit
); /* cancel */
174 if (r
= cdr_svc (&cdr_unit
)) return r
; /* process */
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 */
182 if (feof (cdr_unit
.fileref
)) return STOP_NOCD
; /* eof? */
183 if (ferror (cdr_unit
.fileref
)) { /* error? */
185 perror ("Card reader I/O error");
186 clearerr (cdr_unit
.fileref
);
187 if (iochk
) return SCPE_IOERR
;
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
);
196 if (cbn
) { /* column binary */
197 for (i
= 0; i
< CDR_WIDTH
; i
++) {
199 c1
= ascii2bcd (rbuf
[i
]);
200 c2
= ascii2bcd (rbuf
[CDR_WIDTH
+ i
]);
203 c1
= ascii2bcd (rbuf
[2 * i
]);
204 c2
= ascii2bcd (rbuf
[(2 * i
) + 1]);
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
);
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
];
217 M
[CDR_BUF
- 1] = 060; /* mem mark */
218 sim_activate (&cdr_unit
, cdr_unit
.wait
); /* activate */
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.
227 t_stat
cdr_svc (UNIT
*uptr
)
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
;
250 /* Card punch routine
252 Modifiers have been checked by the caller
253 C modifier is recognized (column binary is implemented)
256 t_stat
punch_card (int32 ilnt
, int32 mod
)
258 int32 i
, cbn
, c1
, c2
;
259 static char pbuf
[(2 * CDP_WIDTH
) + 1]; /* + null */
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? */
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
);
278 pbuf
[i
+ CDP_WIDTH
] = c2
;
282 pbuf
[(2 * i
) + 1] = c2
;
285 for (i
= 2 * CDP_WIDTH
- 1; (i
>= 0) && (pbuf
[i
] == ' '); i
--)
287 pbuf
[2 * CDP_WIDTH
] = 0; /* trailing null */
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
--)
294 pbuf
[CDP_WIDTH
] = 0; /* trailing null */
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
;
308 /* Select stack routine
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).
315 t_stat
select_stack (int32 ilnt
, int32 mod
)
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;
324 /* Card reader/punch reset */
326 t_stat
cd_reset (DEVICE
*dptr
)
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 */
334 /* Card reader attach */
336 t_stat
cdr_attach (UNIT
*uptr
, char *cptr
)
338 ind
[IN_LST
] = ind
[IN_READ
] = 0; /* clear last card */
339 return attach_unit (uptr
, cptr
);
342 /* Bootstrap routine */
345 #define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char))
347 static const unsigned char boot_rom
[] = {
348 OP_R
+ WM
, OP_NOP
+ WM
/* R, NOP */
351 t_stat
cdr_boot (int32 unitno
, DEVICE
*dptr
)
354 extern int32 saved_IS
;
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
;
362 /* Column binary to BCD
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.
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. */
373 static const char row_val
[12] = {
374 011, 010, 007, 006, 005, 004,
375 003, 002, 001, 020, 040, 060
378 char colbin_to_bcd (uint32 cb
)
383 for (i
= 0, bcd
= 0; i
< 12; i
++) { /* 'sum' rows */
384 if (cb
& (1 << i
)) bcd
|= row_val
[i
];