First Commit of my working state
[simh.git] / I1620 / i1620_cd.c
CommitLineData
196ba1fc
PH
1/* i1620_cd.c: IBM 1622 card reader/punch\r
2\r
3 Copyright (c) 2002-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 1622 card reader\r
27 cdp 1622 card punch\r
28\r
29 19-Jan-07 RMS Set UNIT_TEXT flag\r
30 13-Jul-06 RMS Fixed card reader fgets call (from Tom McBride)\r
31 Fixed card reader boot sequence (from Tom McBride)\r
32 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility\r
33 25-Apr-03 RMS Revised for extended file support\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\r
39#include "i1620_defs.h"\r
40\r
41#define CD_LEN 80\r
42\r
43extern uint8 M[MAXMEMSIZE];\r
44extern uint8 ind[NUM_IND];\r
45extern UNIT cpu_unit;\r
46extern int32 io_stop;\r
47\r
48char cdr_buf[CD_LEN + 2];\r
49char cdp_buf[CD_LEN + 2];\r
50\r
51t_stat cdr_reset (DEVICE *dptr);\r
52t_stat cdr_attach (UNIT *uptr, char *cptr);\r
53t_stat cdr_boot (int32 unitno, DEVICE *dptr);\r
54t_stat cdr_read (void);\r
55t_stat cdp_reset (DEVICE *dptr);\r
56t_stat cdp_write (uint32 len);\r
57t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump);\r
58\r
59/* Card reader data structures\r
60\r
61 cdr_dev CDR descriptor\r
62 cdr_unit CDR unit descriptor\r
63 cdr_reg CDR register list\r
64*/\r
65\r
66UNIT cdr_unit = {\r
67 UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0)\r
68 };\r
69\r
70REG cdr_reg[] = {\r
71 { FLDATA (LAST, ind[IN_LAST], 0) },\r
72 { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },\r
73 { NULL }\r
74 };\r
75\r
76DEVICE cdr_dev = {\r
77 "CDR", &cdr_unit, cdr_reg, NULL,\r
78 1, 10, 31, 1, 8, 7,\r
79 NULL, NULL, &cdr_reset,\r
80 &cdr_boot, &cdr_attach, NULL\r
81 };\r
82\r
83/* CDP data structures\r
84\r
85 cdp_dev CDP device descriptor\r
86 cdp_unit CDP unit descriptor\r
87 cdp_reg CDP register list\r
88*/\r
89\r
90UNIT cdp_unit = {\r
91 UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0)\r
92 };\r
93\r
94REG cdp_reg[] = {\r
95 { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },\r
96 { NULL }\r
97 };\r
98\r
99DEVICE cdp_dev = {\r
100 "CDP", &cdp_unit, cdp_reg, NULL,\r
101 1, 10, 31, 1, 8, 7,\r
102 NULL, NULL, &cdp_reset,\r
103 NULL, NULL, NULL\r
104 };\r
105\r
106/* Data tables. The card reader presents unusual problems.\r
107 - Unique codes needed for 11-2-8 (uses !) and 12-7-8 (uses ") .\r
108 - Can punch both 11 (-) and 11-0 (uses ]).\r
109 On input, the nul and nl generated by C are converted to\r
110 spaces; tabs and line feeds are also converted to spaces.\r
111\r
112/* Card reader (ASCII) to numeric (one digit) */\r
113\r
114const char cdr_to_num[128] = {\r
115 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */\r
116 -1, 0x00, 0x00, -1, -1, 0x00, -1, -1,\r
117 -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */\r
118 -1, -1, -1, -1, -1, -1, -1, -1,\r
119 0x00, 0x1A, 0x0F, 0x0B, 0x1B, 0x0C, 0x00, 0x0C, /* !"#$%&' */\r
120 0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x1B, 0x01, /* ()*+,-./ */\r
121 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */\r
122 0x08, 0x09, 0x00, 0x1E, 0x1E, 0x0B, 0x0E, 0x1A, /* 89:;<=>? */\r
123 0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* @ABCDEFG */\r
124 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* HIJKLMNO */\r
125 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* PQRSTUVW */\r
126 0x07, 0x08, 0x09, 0x00, 0x0E, 0x10, 0x0A, 0x1F, /* XYZ[\]^_ */\r
127 -1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* `abcdefg */\r
128 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* hijklmno */\r
129 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* pqrstuvw */\r
130 0x07, 0x08, 0x09, 0x0F, 0x0A, 0x1F, 0x00, -1 /* xyz{|}~ */\r
131 };\r
132\r
133/* Numeric (flag + digit) to card punch (ASCII) */\r
134\r
135const char num_to_cdp[32] = {\r
136 '0', '1', '2', '3', '4', '5', '6', '7', /* 0 */\r
137 '8', '9', '|', ',', ' ', '"', ' ', '"',\r
138 ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* F + 0 */\r
139 'Q', 'R', '!', '$', -1, -1, -1, '"'\r
140 };\r
141\r
142/* Card reader (ASCII) to alphameric (two digits)\r
143\r
144 11-2-8 (!) reads as 5A\r
145 11-7-8 (_) reads as 5F\r
146 12-2-8 (?) reads inconsistently (here 02)\r
147 12-6-8 (<) reads inconsistently (here 5E)\r
148 12-7-8 (}) reads as 5F\r
149*/\r
150\r
151const char cdr_to_alp[128] = {\r
152 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */\r
153 -1, 0x00, 0x00, -1, -1, 0x00, -1, -1,\r
154 -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */\r
155 -1, -1, -1, -1, -1, -1, -1, -1,\r
156 0x00, 0x5A, 0x0F, 0x33, 0x13, 0x24, 0x10, 0x34, /* !"#$%&' */\r
157 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */\r
158 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */\r
159 0x78, 0x79, 0x70, 0x5E, 0x5E, 0x33, 0x0E, 0x02, /* 89:;<=>? */\r
160 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */\r
161 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */\r
162 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */\r
163 0x67, 0x68, 0x69, 0x40, 0x0E, 0x50, 0x0A, 0x5F, /* XYZ[\]^_ */\r
164 0x50, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */\r
165 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */\r
166 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */\r
167 0x67, 0x68, 0x69, 0x0F, 0x0A, 0x5F, 0x60, -1 /* xyz{|}~ */\r
168 };\r
169\r
170/* Alphameric (two digits) to card punch (ASCII). Oddities:\r
171\r
172 02 -> 12-2-8 (?), symmetric\r
173 07 -> 12-7-8 (}), reads as 5F\r
174 12 -> 11-2-8 (!), reads as 5A\r
175 15 -> 11,0 (`), reads as 50\r
176 22 -> 0-2-8 (|), reads as 0A\r
177 32 -> 2-8 (^), reads as 0A\r
178 5B -> 11-3-8 (=), reads as 13\r
179 6A -> 0-2-8 (|), reads as 0A\r
180 6B -> 0-3-8 (,), reads as 23\r
181 AA -> 0-2-8 (|), reads as 0A\r
182\r
183 There is no way to punch 0-5-8 (~), 0-6-8 (\),\r
184 11-5-8 (]), 11-6-8 (;), 11-7-8 (_),\r
185 12-5-8 ([), or 12-6-8 (<)\r
186*/\r
187\r
188const char alp_to_cdp[256] = {\r
189 ' ', -1, '?', '.', ')', -1, -1, '}', /* 00 */\r
190 -1, -1, '\'', -1, -1, -1, -1, '"',\r
191 '+', -1, '!', '$', '*', ']', -1, -1, /* 10 */ \r
192 -1, -1, -1, -1, -1, -1, -1, -1,\r
193 '-', '/', '|', ',', '(', -1, -1, -1, /* 20 */\r
194 -1, -1, -1, -1, -1, -1, -1, -1,\r
195 -1, -1, '^', '=', '@', ':', ' ', -1, /* 30 */\r
196 -1, -1, '|', -1, -1, -1, -1, '"',\r
197 -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */\r
198 'H', 'I', -1, -1, -1, -1, -1, -1,\r
199 '_', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */\r
200 'Q', 'R', '?', '=', -1, -1, -1, '}',\r
201 -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */\r
202 'Y', 'Z', '|', ',', -1, -1, -1, -1,\r
203 '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */\r
204 '8', '9', -1, -1, -1, -1, -1, -1,\r
205 -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */\r
206 -1, -1, -1, -1, -1, -1, -1, -1,\r
207 -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */\r
208 -1, -1, -1, -1, -1, -1, -1, -1,\r
209 -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */\r
210 -1, -1, '|', -1, -1, -1, -1, -1,\r
211 -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */\r
212 -1, -1, -1, -1, -1, -1, -1, -1,\r
213 -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */\r
214 -1, -1, -1, -1, -1, -1, -1, -1,\r
215 -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */\r
216 -1, -1, -1, -1, -1, -1, -1, -1,\r
217 -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */\r
218 -1, -1, -1, -1, -1, -1, -1, -1,\r
219 -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */\r
220 -1, -1, -1, -1, -1, -1, -1, -1\r
221 }; \r
222\r
223/* Card reader IO routine\r
224 \r
225 - Hard errors stop the operation and halt the system.\r
226 - Invalid characters place a blank in memory and set RDCHK.\r
227 If IO stop is set, the system halts at the end of the operation.\r
228*/\r
229\r
230t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1)\r
231{\r
232int32 i;\r
233int8 cdc;\r
234t_stat r, sta;\r
235\r
236sta = SCPE_OK; /* assume ok */\r
237switch (op) { /* case on op */\r
238\r
239 case OP_RN: /* read numeric */\r
240 r = cdr_read (); /* fill reader buf */\r
241 if (r != SCPE_OK) return r; /* error? */\r
242 for (i = 0; i < CD_LEN; i++) { /* transfer to mem */\r
243 cdc = cdr_to_num[cdr_buf[i]]; /* translate */\r
244 if (cdc < 0) { /* invalid? */\r
245 ind[IN_RDCHK] = 1; /* set read check */\r
246 if (io_stop) sta = STOP_INVCHR; /* set return status */\r
247 cdc = 0;\r
248 }\r
249 M[pa] = cdc; /* store digit */\r
250 PP (pa); /* incr mem addr */\r
251 }\r
252 break;\r
253\r
254 case OP_RA: /* read alphameric */\r
255 r = cdr_read (); /* fill reader buf */\r
256 if (r != SCPE_OK) return r; /* error? */\r
257 for (i = 0; i < CD_LEN; i++) { /* transfer to mem */\r
258 cdc = cdr_to_alp[cdr_buf[i]]; /* translate */\r
259 if (cdc < 0) { /* invalid? */\r
260 ind[IN_RDCHK] = 1; /* set read check */\r
261 if (io_stop) sta = STOP_INVCHR; /* set return status */\r
262 cdc = 0;\r
263 };\r
264 M[pa] = (M[pa] & FLAG) | (cdc & DIGIT); /* store 2 digits */\r
265 M[pa - 1] = (M[pa - 1] & FLAG) | ((cdc >> 4) & DIGIT);\r
266 pa = ADDR_A (pa, 2); /* incr mem addr */\r
267 }\r
268 break; \r
269\r
270 default: /* invalid function */\r
271 return STOP_INVFNC;\r
272 }\r
273\r
274return sta;\r
275}\r
276\r
277/* Fill card reader buffer - all errors are hard errors */\r
278\r
279t_stat cdr_read (void)\r
280{\r
281int32 i;\r
282\r
283ind[IN_LAST] = 0; /* clear last card */\r
284if ((cdr_unit.flags & UNIT_ATT) == 0) { /* attached? */\r
285 ind[IN_RDCHK] = 1; /* no, error */\r
286 return SCPE_UNATT;\r
287 }\r
288\r
289for (i = 0; i < CD_LEN + 2; i++) cdr_buf[i] = ' '; /* clear buffer */\r
290fgets (cdr_buf, CD_LEN + 2, cdr_unit.fileref); /* read card */\r
291if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */\r
292if (ferror (cdr_unit.fileref)) { /* error? */\r
293 ind[IN_RDCHK] = 1; /* set read check */\r
294 perror ("CDR I/O error");\r
295 clearerr (cdr_unit.fileref);\r
296 return SCPE_IOERR;\r
297 }\r
298cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */\r
299getc (cdr_unit.fileref); /* see if more */\r
300if (feof (cdr_unit.fileref)) ind[IN_LAST] = 1; /* eof? set last */\r
301fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); /* "backspace" */\r
302return SCPE_OK;\r
303}\r
304\r
305/* Card reader attach */\r
306\r
307t_stat cdr_attach (UNIT *uptr, char *cptr)\r
308{\r
309ind[IN_LAST] = 0; /* clear last card */\r
310return attach_unit (uptr, cptr);\r
311}\r
312\r
313/* Card reader reset */\r
314\r
315t_stat cdr_reset (DEVICE *dptr)\r
316{\r
317ind[IN_LAST] = 0; /* clear last card */\r
318return SCPE_OK;\r
319}\r
320\r
321/* Bootstrap routine */\r
322\r
323#define BOOT_START 0\r
324\r
325t_stat cdr_boot (int32 unitno, DEVICE *dptr)\r
326{\r
327t_stat r;\r
328int32 old_io_stop;\r
329extern int32 saved_PC;\r
330\r
331old_io_stop = io_stop;\r
332io_stop = 1;\r
333r = cdr (OP_RN, 0, 0, 0); /* read card @ 0 */\r
334io_stop = old_io_stop;\r
335if (r != SCPE_OK) return r; /* error? */\r
336saved_PC = BOOT_START;\r
337return SCPE_OK;\r
338}\r
339\r
340/* Card punch IO routine \r
341\r
342 - Hard errors stop the operation and halt the system.\r
343 - Invalid characters stop the operation and set WRCHK.\r
344 If IO stop is set, the system halts.\r
345*/\r
346\r
347t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1)\r
348{\r
349int32 i;\r
350int8 cdc;\r
351uint8 z, d;\r
352\r
353switch (op) { /* decode op */\r
354\r
355 case OP_DN:\r
356 return cdp_num (pa, 20000 - (pa % 20000), TRUE); /* dump numeric */\r
357\r
358 case OP_WN:\r
359 return cdp_num (pa, CD_LEN, FALSE); /* write numeric */\r
360\r
361 case OP_WA:\r
362 for (i = 0; i < CD_LEN; i++) { /* one card */\r
363 d = M[pa] & DIGIT; /* get digit pair */\r
364 z = M[pa - 1] & DIGIT;\r
365 cdc = alp_to_cdp[(z << 4) | d]; /* translate */\r
366 if (cdc < 0) { /* bad char? */\r
367 ind[IN_WRCHK] = 1; /* set write check */\r
368 CRETIOE (io_stop, STOP_INVCHR);\r
369 }\r
370 cdp_buf[i] = cdc; /* store in buf */\r
371 pa = ADDR_A (pa, 2); /* incr mem addr */\r
372 }\r
373 return cdp_write (CD_LEN); /* punch buffer */\r
374\r
375 default: /* invalid function */\r
376 break;\r
377 }\r
378\r
379return STOP_INVFNC;\r
380}\r
381\r
382/* Punch card numeric */\r
383\r
384t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump)\r
385{\r
386int32 i, ncd, len;\r
387uint8 d;\r
388int8 cdc;\r
389t_stat r;\r
390\r
391ncd = ndig / CD_LEN; /* number of cards */\r
392while (ncd-- >= 0) { /* until done */\r
393 len = (ncd >= 0)? CD_LEN: (ndig % CD_LEN); /* card length */\r
394 if (len == 0) break;\r
395 for (i = 0; i < len; i++) { /* one card */\r
396 d = M[pa] & (FLAG | DIGIT); /* get char */\r
397 if (dump && (d == FLAG)) cdc = '-'; /* dump? F+0 is diff */\r
398 else cdc = num_to_cdp[d]; /* translate */\r
399 if (cdc < 0) { /* bad char? */\r
400 ind[IN_WRCHK] = 1; /* set write check */\r
401 CRETIOE (io_stop, STOP_INVCHR); /* stop */\r
402 }\r
403 cdp_buf[i] = cdc; /* store in buf */\r
404 PP (pa); /* incr mem addr */\r
405 }\r
406 r = cdp_write (len); /* punch card */\r
407 if (r != SCPE_OK) return r; /* error? */\r
408 }\r
409return SCPE_OK;\r
410}\r
411\r
412/* Write punch card buffer - all errors are hard errors */\r
413\r
414t_stat cdp_write (uint32 len)\r
415{\r
416if ((cdp_unit.flags & UNIT_ATT) == 0) { /* attached? */\r
417 ind[IN_WRCHK] = 1; /* no, error */\r
418 return SCPE_UNATT;\r
419 }\r
420\r
421while ((len > 0) && (cdp_buf[len - 1] == ' ')) --len; /* trim spaces */\r
422cdp_buf[len] = '\n'; /* newline, null */\r
423cdp_buf[len + 1] = 0;\r
424\r
425fputs (cdp_buf, cdp_unit.fileref); /* write card */\r
426cdp_unit.pos = ftell (cdp_unit.fileref); /* count char */\r
427if (ferror (cdp_unit.fileref)) { /* error? */\r
428 ind[IN_WRCHK] = 1;\r
429 perror ("CDP I/O error");\r
430 clearerr (cdp_unit.fileref);\r
431 return SCPE_IOERR;\r
432 }\r
433return SCPE_OK;\r
434}\r
435\r
436/* Reset card punch */\r
437\r
438t_stat cdp_reset (DEVICE *dptr)\r
439{\r
440return SCPE_OK;\r
441}\r