1 /* i1620_cd.c: IBM 1622 card reader/punch
3 Copyright (c) 2002-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.
29 19-Jan-07 RMS Set UNIT_TEXT flag
30 13-Jul-06 RMS Fixed card reader fgets call (from Tom McBride)
31 Fixed card reader boot sequence (from Tom McBride)
32 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility
33 25-Apr-03 RMS Revised for extended file support
35 Cards are represented as ASCII text streams terminated by newlines.
36 This allows cards to be created and edited as normal files.
39 #include "i1620_defs.h"
43 extern uint8 M
[MAXMEMSIZE
];
44 extern uint8 ind
[NUM_IND
];
48 char cdr_buf
[CD_LEN
+ 2];
49 char cdp_buf
[CD_LEN
+ 2];
51 t_stat
cdr_reset (DEVICE
*dptr
);
52 t_stat
cdr_attach (UNIT
*uptr
, char *cptr
);
53 t_stat
cdr_boot (int32 unitno
, DEVICE
*dptr
);
54 t_stat
cdr_read (void);
55 t_stat
cdp_reset (DEVICE
*dptr
);
56 t_stat
cdp_write (uint32 len
);
57 t_stat
cdp_num (uint32 pa
, uint32 ndig
, t_bool dump
);
59 /* Card reader data structures
61 cdr_dev CDR descriptor
62 cdr_unit CDR unit descriptor
63 cdr_reg CDR register list
67 UDATA (NULL
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_ROABLE
+UNIT_TEXT
, 0)
71 { FLDATA (LAST
, ind
[IN_LAST
], 0) },
72 { DRDATA (POS
, cdr_unit
.pos
, T_ADDR_W
), PV_LEFT
},
77 "CDR", &cdr_unit
, cdr_reg
, NULL
,
79 NULL
, NULL
, &cdr_reset
,
80 &cdr_boot
, &cdr_attach
, NULL
83 /* CDP data structures
85 cdp_dev CDP device descriptor
86 cdp_unit CDP unit descriptor
87 cdp_reg CDP register list
91 UDATA (NULL
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_TEXT
, 0)
95 { DRDATA (POS
, cdp_unit
.pos
, T_ADDR_W
), PV_LEFT
},
100 "CDP", &cdp_unit
, cdp_reg
, NULL
,
102 NULL
, NULL
, &cdp_reset
,
106 /* Data tables. The card reader presents unusual problems.
107 - Unique codes needed for 11-2-8 (uses !) and 12-7-8 (uses ") .
108 - Can punch both 11 (-) and 11-0 (uses ]).
109 On input, the nul and nl generated by C are converted to
110 spaces; tabs and line feeds are also converted to spaces.
112 /* Card reader (ASCII) to numeric (one digit) */
114 const char cdr_to_num
[128] = {
115 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */
116 -1, 0x00, 0x00, -1, -1, 0x00, -1, -1,
117 -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
118 -1, -1, -1, -1, -1, -1, -1, -1,
119 0x00, 0x1A, 0x0F, 0x0B, 0x1B, 0x0C, 0x00, 0x0C, /* !"#$%&' */
120 0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x1B, 0x01, /* ()*+,-./ */
121 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */
122 0x08, 0x09, 0x00, 0x1E, 0x1E, 0x0B, 0x0E, 0x1A, /* 89:;<=>? */
123 0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* @ABCDEFG */
124 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* HIJKLMNO */
125 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* PQRSTUVW */
126 0x07, 0x08, 0x09, 0x00, 0x0E, 0x10, 0x0A, 0x1F, /* XYZ[\]^_ */
127 -1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* `abcdefg */
128 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* hijklmno */
129 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* pqrstuvw */
130 0x07, 0x08, 0x09, 0x0F, 0x0A, 0x1F, 0x00, -1 /* xyz{|}~ */
133 /* Numeric (flag + digit) to card punch (ASCII) */
135 const char num_to_cdp
[32] = {
136 '0', '1', '2', '3', '4', '5', '6', '7', /* 0 */
137 '8', '9', '|', ',', ' ', '"', ' ', '"',
138 ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* F + 0 */
139 'Q', 'R', '!', '$', -1, -1, -1, '"'
142 /* Card reader (ASCII) to alphameric (two digits)
144 11-2-8 (!) reads as 5A
145 11-7-8 (_) reads as 5F
146 12-2-8 (?) reads inconsistently (here 02)
147 12-6-8 (<) reads inconsistently (here 5E)
148 12-7-8 (}) reads as 5F
151 const char cdr_to_alp
[128] = {
152 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */
153 -1, 0x00, 0x00, -1, -1, 0x00, -1, -1,
154 -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
155 -1, -1, -1, -1, -1, -1, -1, -1,
156 0x00, 0x5A, 0x0F, 0x33, 0x13, 0x24, 0x10, 0x34, /* !"#$%&' */
157 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */
158 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */
159 0x78, 0x79, 0x70, 0x5E, 0x5E, 0x33, 0x0E, 0x02, /* 89:;<=>? */
160 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
161 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */
162 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */
163 0x67, 0x68, 0x69, 0x40, 0x0E, 0x50, 0x0A, 0x5F, /* XYZ[\]^_ */
164 0x50, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */
165 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */
166 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */
167 0x67, 0x68, 0x69, 0x0F, 0x0A, 0x5F, 0x60, -1 /* xyz{|}~ */
170 /* Alphameric (two digits) to card punch (ASCII). Oddities:
172 02 -> 12-2-8 (?), symmetric
173 07 -> 12-7-8 (}), reads as 5F
174 12 -> 11-2-8 (!), reads as 5A
175 15 -> 11,0 (`), reads as 50
176 22 -> 0-2-8 (|), reads as 0A
177 32 -> 2-8 (^), reads as 0A
178 5B -> 11-3-8 (=), reads as 13
179 6A -> 0-2-8 (|), reads as 0A
180 6B -> 0-3-8 (,), reads as 23
181 AA -> 0-2-8 (|), reads as 0A
183 There is no way to punch 0-5-8 (~), 0-6-8 (\),
184 11-5-8 (]), 11-6-8 (;), 11-7-8 (_),
185 12-5-8 ([), or 12-6-8 (<)
188 const char alp_to_cdp
[256] = {
189 ' ', -1, '?', '.', ')', -1, -1, '}', /* 00 */
190 -1, -1, '\'', -1, -1, -1, -1, '"',
191 '+', -1, '!', '$', '*', ']', -1, -1, /* 10 */
192 -1, -1, -1, -1, -1, -1, -1, -1,
193 '-', '/', '|', ',', '(', -1, -1, -1, /* 20 */
194 -1, -1, -1, -1, -1, -1, -1, -1,
195 -1, -1, '^', '=', '@', ':', ' ', -1, /* 30 */
196 -1, -1, '|', -1, -1, -1, -1, '"',
197 -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
198 'H', 'I', -1, -1, -1, -1, -1, -1,
199 '_', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
200 'Q', 'R', '?', '=', -1, -1, -1, '}',
201 -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
202 'Y', 'Z', '|', ',', -1, -1, -1, -1,
203 '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
204 '8', '9', -1, -1, -1, -1, -1, -1,
205 -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
206 -1, -1, -1, -1, -1, -1, -1, -1,
207 -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
208 -1, -1, -1, -1, -1, -1, -1, -1,
209 -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
210 -1, -1, '|', -1, -1, -1, -1, -1,
211 -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
212 -1, -1, -1, -1, -1, -1, -1, -1,
213 -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
214 -1, -1, -1, -1, -1, -1, -1, -1,
215 -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
216 -1, -1, -1, -1, -1, -1, -1, -1,
217 -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
218 -1, -1, -1, -1, -1, -1, -1, -1,
219 -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
220 -1, -1, -1, -1, -1, -1, -1, -1
223 /* Card reader IO routine
225 - Hard errors stop the operation and halt the system.
226 - Invalid characters place a blank in memory and set RDCHK.
227 If IO stop is set, the system halts at the end of the operation.
230 t_stat
cdr (uint32 op
, uint32 pa
, uint32 f0
, uint32 f1
)
236 sta
= SCPE_OK
; /* assume ok */
237 switch (op
) { /* case on op */
239 case OP_RN
: /* read numeric */
240 r
= cdr_read (); /* fill reader buf */
241 if (r
!= SCPE_OK
) return r
; /* error? */
242 for (i
= 0; i
< CD_LEN
; i
++) { /* transfer to mem */
243 cdc
= cdr_to_num
[cdr_buf
[i
]]; /* translate */
244 if (cdc
< 0) { /* invalid? */
245 ind
[IN_RDCHK
] = 1; /* set read check */
246 if (io_stop
) sta
= STOP_INVCHR
; /* set return status */
249 M
[pa
] = cdc
; /* store digit */
250 PP (pa
); /* incr mem addr */
254 case OP_RA
: /* read alphameric */
255 r
= cdr_read (); /* fill reader buf */
256 if (r
!= SCPE_OK
) return r
; /* error? */
257 for (i
= 0; i
< CD_LEN
; i
++) { /* transfer to mem */
258 cdc
= cdr_to_alp
[cdr_buf
[i
]]; /* translate */
259 if (cdc
< 0) { /* invalid? */
260 ind
[IN_RDCHK
] = 1; /* set read check */
261 if (io_stop
) sta
= STOP_INVCHR
; /* set return status */
264 M
[pa
] = (M
[pa
] & FLAG
) | (cdc
& DIGIT
); /* store 2 digits */
265 M
[pa
- 1] = (M
[pa
- 1] & FLAG
) | ((cdc
>> 4) & DIGIT
);
266 pa
= ADDR_A (pa
, 2); /* incr mem addr */
270 default: /* invalid function */
277 /* Fill card reader buffer - all errors are hard errors */
279 t_stat
cdr_read (void)
283 ind
[IN_LAST
] = 0; /* clear last card */
284 if ((cdr_unit
.flags
& UNIT_ATT
) == 0) { /* attached? */
285 ind
[IN_RDCHK
] = 1; /* no, error */
289 for (i
= 0; i
< CD_LEN
+ 2; i
++) cdr_buf
[i
] = ' '; /* clear buffer */
290 fgets (cdr_buf
, CD_LEN
+ 2, cdr_unit
.fileref
); /* read card */
291 if (feof (cdr_unit
.fileref
)) return STOP_NOCD
; /* eof? */
292 if (ferror (cdr_unit
.fileref
)) { /* error? */
293 ind
[IN_RDCHK
] = 1; /* set read check */
294 perror ("CDR I/O error");
295 clearerr (cdr_unit
.fileref
);
298 cdr_unit
.pos
= ftell (cdr_unit
.fileref
); /* update position */
299 getc (cdr_unit
.fileref
); /* see if more */
300 if (feof (cdr_unit
.fileref
)) ind
[IN_LAST
] = 1; /* eof? set last */
301 fseek (cdr_unit
.fileref
, cdr_unit
.pos
, SEEK_SET
); /* "backspace" */
305 /* Card reader attach */
307 t_stat
cdr_attach (UNIT
*uptr
, char *cptr
)
309 ind
[IN_LAST
] = 0; /* clear last card */
310 return attach_unit (uptr
, cptr
);
313 /* Card reader reset */
315 t_stat
cdr_reset (DEVICE
*dptr
)
317 ind
[IN_LAST
] = 0; /* clear last card */
321 /* Bootstrap routine */
325 t_stat
cdr_boot (int32 unitno
, DEVICE
*dptr
)
329 extern int32 saved_PC
;
331 old_io_stop
= io_stop
;
333 r
= cdr (OP_RN
, 0, 0, 0); /* read card @ 0 */
334 io_stop
= old_io_stop
;
335 if (r
!= SCPE_OK
) return r
; /* error? */
336 saved_PC
= BOOT_START
;
340 /* Card punch IO routine
342 - Hard errors stop the operation and halt the system.
343 - Invalid characters stop the operation and set WRCHK.
344 If IO stop is set, the system halts.
347 t_stat
cdp (uint32 op
, uint32 pa
, uint32 f0
, uint32 f1
)
353 switch (op
) { /* decode op */
356 return cdp_num (pa
, 20000 - (pa
% 20000), TRUE
); /* dump numeric */
359 return cdp_num (pa
, CD_LEN
, FALSE
); /* write numeric */
362 for (i
= 0; i
< CD_LEN
; i
++) { /* one card */
363 d
= M
[pa
] & DIGIT
; /* get digit pair */
364 z
= M
[pa
- 1] & DIGIT
;
365 cdc
= alp_to_cdp
[(z
<< 4) | d
]; /* translate */
366 if (cdc
< 0) { /* bad char? */
367 ind
[IN_WRCHK
] = 1; /* set write check */
368 CRETIOE (io_stop
, STOP_INVCHR
);
370 cdp_buf
[i
] = cdc
; /* store in buf */
371 pa
= ADDR_A (pa
, 2); /* incr mem addr */
373 return cdp_write (CD_LEN
); /* punch buffer */
375 default: /* invalid function */
382 /* Punch card numeric */
384 t_stat
cdp_num (uint32 pa
, uint32 ndig
, t_bool dump
)
391 ncd
= ndig
/ CD_LEN
; /* number of cards */
392 while (ncd
-- >= 0) { /* until done */
393 len
= (ncd
>= 0)? CD_LEN
: (ndig
% CD_LEN
); /* card length */
395 for (i
= 0; i
< len
; i
++) { /* one card */
396 d
= M
[pa
] & (FLAG
| DIGIT
); /* get char */
397 if (dump
&& (d
== FLAG
)) cdc
= '-'; /* dump? F+0 is diff */
398 else cdc
= num_to_cdp
[d
]; /* translate */
399 if (cdc
< 0) { /* bad char? */
400 ind
[IN_WRCHK
] = 1; /* set write check */
401 CRETIOE (io_stop
, STOP_INVCHR
); /* stop */
403 cdp_buf
[i
] = cdc
; /* store in buf */
404 PP (pa
); /* incr mem addr */
406 r
= cdp_write (len
); /* punch card */
407 if (r
!= SCPE_OK
) return r
; /* error? */
412 /* Write punch card buffer - all errors are hard errors */
414 t_stat
cdp_write (uint32 len
)
416 if ((cdp_unit
.flags
& UNIT_ATT
) == 0) { /* attached? */
417 ind
[IN_WRCHK
] = 1; /* no, error */
421 while ((len
> 0) && (cdp_buf
[len
- 1] == ' ')) --len
; /* trim spaces */
422 cdp_buf
[len
] = '\n'; /* newline, null */
423 cdp_buf
[len
+ 1] = 0;
425 fputs (cdp_buf
, cdp_unit
.fileref
); /* write card */
426 cdp_unit
.pos
= ftell (cdp_unit
.fileref
); /* count char */
427 if (ferror (cdp_unit
.fileref
)) { /* error? */
429 perror ("CDP I/O error");
430 clearerr (cdp_unit
.fileref
);
436 /* Reset card punch */
438 t_stat
cdp_reset (DEVICE
*dptr
)