First Commit of my working state
[simh.git] / I7094 / i7094_cd.c
CommitLineData
196ba1fc
PH
1/* i7094_cd.c: IBM 711/721 card reader/punch\r
2\r
3 Copyright (c) 2003-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 711 card reader\r
27 cdp 721 card punch\r
28\r
29 19-Jan-07 RMS Added UNIT_TEXT\r
30 13-Jul-06 RMS Fixed problem with 80 column full cards\r
31\r
32 Cards are represented as ASCII text streams terminated by newlines.\r
33 This allows cards to be created and edited as normal files. Two\r
34 formats are supported:\r
35\r
36 column binary each character represents 6b of a 12b column\r
37 text each character represents all 12b of a column\r
38\r
39 Internally, the 7094 works only with column binary and is limited\r
40 to 72 columns of data. Each row of the card is represented by 72b\r
41 of data (two 36b words). A complete card image consists of 12 rows\r
42 (24 36b words).\r
43*/\r
44\r
45#include "i7094_defs.h"\r
46\r
47#define CD_BINLNT 24 /* bin buf length */\r
48#define CD_CHRLNT 80 /* char buf length */\r
49\r
50#define CDS_INIT 0 /* card in motion */\r
51#define CDS_DATA 1 /* data transfer */\r
52#define CDS_END 2 /* card complete */\r
53\r
54#define UNIT_V_CBN (UNIT_V_UF + 0) /* column binary file */\r
55#define UNIT_V_PCA (UNIT_V_UF + 1) /* A vs H punch flag */\r
56#define UNIT_CBN (1 << UNIT_V_CBN)\r
57#define UNIT_PCA (1 << UNIT_V_PCA)\r
58\r
59uint32 cdr_sta = 0; /* state */\r
60uint32 cdr_bptr = 0; /* buffer ptr */\r
61uint32 cdr_tstart = 27500; /* timing */\r
62uint32 cdr_tstop = 27500;\r
63uint32 cdr_tleft = 150;\r
64uint32 cdr_tright = 4000;\r
65t_uint64 cdr_bbuf[CD_BINLNT]; /* col binary buf */\r
66\r
67uint32 cdp_sta = 0; /* state */\r
68uint32 cdp_bptr = 0; /* buffer ptr */\r
69uint32 cdp_tstart = 35000; /* timing */\r
70uint32 cdp_tstop = 35000;\r
71uint32 cdp_tleft = 150;\r
72uint32 cdp_tright = 15500;\r
73t_uint64 cdp_chob = 0;\r
74uint32 cdp_chob_v = 0;\r
75t_uint64 cdp_bbuf[CD_BINLNT]; /* col binary buf */\r
76\r
77t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit);\r
78t_stat cdr_reset (DEVICE *dptr);\r
79t_stat cdr_svc (UNIT *uptr);\r
80t_stat cdr_boot (int32 unitno, DEVICE *dptr);\r
81t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit);\r
82t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 flags);\r
83t_stat cdp_reset (DEVICE *dptr);\r
84t_stat cdp_svc (UNIT *uptr);\r
85t_stat cdp_card_end (UNIT *uptr);\r
86t_stat cd_attach (UNIT *uptr, char *cptr);\r
87t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);\r
88char colbin_to_bcd (uint32 cb);\r
89\r
90extern uint32 sim_switches;\r
91extern uint32 PC;\r
92extern uint32 ind_ioc;\r
93extern char bcd_to_ascii_a[64];\r
94extern char bcd_to_ascii_h[64];\r
95extern uint32 bcd_to_colbin[64];\r
96extern char ascii_to_bcd[128];\r
97extern t_uint64 bit_masks[36];\r
98extern uint32 col_masks[12];\r
99\r
100/* Card reader data structures\r
101\r
102 cdr_dev CDR descriptor\r
103 cdr_unit CDR unit descriptor\r
104 cdr_reg CDR register list\r
105*/\r
106\r
107DIB cdr_dib = { &cdr_chsel, NULL };\r
108\r
109UNIT cdr_unit = {\r
110 UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0)\r
111 };\r
112\r
113REG cdr_reg[] = {\r
114 { ORDATA (STATE, cdr_sta, 2) },\r
115 { DRDATA (BPTR, cdr_bptr, 5), PV_LEFT },\r
116 { BRDATA (BUF, cdr_bbuf, 8, 36, CD_BINLNT) },\r
117 { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },\r
118 { DRDATA (TSTART, cdr_tstart, 24), PV_LEFT + REG_NZ },\r
119 { DRDATA (TSTOP, cdr_tstop, 24), PV_LEFT + REG_NZ },\r
120 { DRDATA (TLEFT, cdr_tleft, 24), PV_LEFT + REG_NZ },\r
121 { DRDATA (TRIGHT, cdr_tright, 24), PV_LEFT + REG_NZ },\r
122 { NULL } };\r
123\r
124MTAB cdr_mod[] = {\r
125 { UNIT_CBN, UNIT_CBN, "column binary", "BINARY", &cd_set_mode },\r
126 { UNIT_CBN, UNIT_CBN, "text", "TEXT", &cd_set_mode },\r
127 { 0 }\r
128 };\r
129\r
130DEVICE cdr_dev = {\r
131 "CDR", &cdr_unit, cdr_reg, cdr_mod,\r
132 1, 10, 31, 1, 8, 7,\r
133 NULL, NULL, &cdr_reset,\r
134 &cdr_boot, &cd_attach, NULL,\r
135 &cdr_dib, DEV_DISABLE\r
136 };\r
137\r
138/* CDP data structures\r
139\r
140 cdp_dev CDP device descriptor\r
141 cdp_unit CDP unit descriptor\r
142 cdp_reg CDP register list\r
143*/\r
144\r
145DIB cdp_dib = { &cdp_chsel, &cdp_chwr };\r
146\r
147UNIT cdp_unit = {\r
148 UDATA (&cdp_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0)\r
149 };\r
150\r
151REG cdp_reg[] = {\r
152 { ORDATA (STATE, cdp_sta, 2) },\r
153 { ORDATA (CHOB, cdp_chob, 36) },\r
154 { FLDATA (CHOBV, cdp_chob_v, 0) },\r
155 { DRDATA (BPTR, cdp_bptr, 5), PV_LEFT },\r
156 { BRDATA (BUF, cdp_bbuf, 8, 36, CD_BINLNT) },\r
157 { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },\r
158 { DRDATA (TSTART, cdp_tstart, 24), PV_LEFT + REG_NZ },\r
159 { DRDATA (TSTOP, cdp_tstop, 24), PV_LEFT + REG_NZ },\r
160 { DRDATA (TLEFT, cdp_tleft, 24), PV_LEFT + REG_NZ },\r
161 { DRDATA (TRIGHT, cdp_tright, 24), PV_LEFT + REG_NZ },\r
162 { NULL }\r
163 };\r
164\r
165MTAB cdp_mod[] = {\r
166 { UNIT_CBN, UNIT_CBN, "column binary", "BINARY", &cd_set_mode },\r
167 { UNIT_CBN, UNIT_CBN, "text", "TEXT", &cd_set_mode },\r
168 { UNIT_PCA, UNIT_PCA, "business set", "BUSINESS", NULL },\r
169 { UNIT_PCA, 0, "Fortran set", "FORTRAN", NULL },\r
170 { 0 }\r
171 };\r
172\r
173DEVICE cdp_dev = {\r
174 "CDP", &cdp_unit, cdp_reg, cdp_mod,\r
175 1, 10, 31, 1, 8, 7,\r
176 NULL, NULL, &cdp_reset,\r
177 NULL, &cd_attach, NULL,\r
178 &cdp_dib, DEV_DISABLE\r
179 };\r
180\r
181/* Card reader select */\r
182\r
183t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit)\r
184{\r
185if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */\r
186\r
187switch (sel) { /* case on data sel */\r
188\r
189 case CHSL_RDS: /* read */\r
190 if ((cdr_unit.flags & UNIT_ATT) == 0) /* not attached? */\r
191 return SCPE_UNATT;\r
192 if (sim_is_active (&cdr_unit)) /* busy? */\r
193 return ERR_STALL;\r
194 cdr_sta = CDS_INIT; /* initial state */\r
195 sim_activate (&cdr_unit, cdp_tstart); /* start reader */\r
196 break;\r
197\r
198 default: /* other */\r
199 return STOP_ILLIOP; /* not allowed */\r
200 }\r
201\r
202return SCPE_OK;\r
203}\r
204\r
205/* Unit timeout */\r
206\r
207t_stat cdr_svc (UNIT *uptr)\r
208{\r
209uint32 i, col, row, bufw, colbin;\r
210char cdr_cbuf[(2 * CD_CHRLNT) + 2];\r
211t_uint64 dat = 0;\r
212\r
213if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* not attached? */\r
214switch (cdr_sta) { /* case on state */\r
215\r
216 case CDS_INIT: /* initial state */\r
217 for (i = 0; i < CD_BINLNT; i++) /* clear bin buf */ \r
218 cdr_bbuf[i] = 0;\r
219 for (i = 0; i < ((2 * CD_CHRLNT) + 2); i++) /* clear char buf */\r
220 cdr_cbuf[i] = ' ';\r
221 cdr_sta = CDS_DATA; /* data state */\r
222 cdr_bptr = 0; /* init buf ptr */\r
223 fgets (cdr_cbuf, (uptr->flags & UNIT_CBN)? (2 * CD_CHRLNT) + 2: CD_CHRLNT + 2,\r
224 uptr->fileref); /* read card */\r
225 if (feof (uptr->fileref)) /* eof? */\r
226 return ch6_err_disc (CH_A, U_CDR, CHF_EOF); /* set EOF, disc */\r
227 if (ferror (uptr->fileref)) { /* error? */\r
228 perror ("CDR I/O error");\r
229 clearerr (uptr->fileref);\r
230 return SCPE_IOERR; /* stop */\r
231 }\r
232 uptr->pos = ftell (uptr->fileref); /* update position */\r
233 for (i = 0; i < (2 * CD_CHRLNT); i++) /* convert to BCD */\r
234 cdr_cbuf[i] = ascii_to_bcd[cdr_cbuf[i] & 0177] & 077;\r
235 for (col = 0; col < 72; col++) { /* process 72 columns */\r
236 if (uptr->flags & UNIT_CBN) /* column binary? */\r
237 colbin = (((uint32) cdr_cbuf[2 * col]) << 6) |\r
238 ((uint32) cdr_cbuf[(2 * col) + 1]); /* 2 chars -> col bin */\r
239 else colbin = bcd_to_colbin[cdr_cbuf[col]]; /* cvt to col binary */\r
240 dat = bit_masks[35 - (col % 36)]; /* mask for column */\r
241 for (row = 0; row < 12; row++) { /* rows 9..0, 11, 12 */\r
242 bufw = (row * 2) + (col / 36); /* index to buffer */\r
243 if (colbin & col_masks[row]) /* row bit set? */\r
244 cdr_bbuf[bufw] |= dat;\r
245 }\r
246 }\r
247\r
248 case CDS_DATA: /* data state */\r
249 dat = cdr_bbuf[cdr_bptr++]; /* get next word */\r
250 if (cdr_bptr >= CD_BINLNT) { /* last word? */\r
251 cdr_sta = CDS_END; /* end state */\r
252 ch6_req_rd (CH_A, U_CDR, dat, CH6DF_EOR); /* req chan, dat, EOR */\r
253 sim_activate (uptr, cdr_tstop);\r
254 }\r
255 else {\r
256 ch6_req_rd (CH_A, U_CDR, dat, 0); /* req chan, dat */\r
257 sim_activate (uptr, (cdr_bptr & 1)? cdr_tleft: cdr_tright);\r
258 }\r
259 break;\r
260\r
261 case CDS_END: /* end state */\r
262 if (ch6_qconn (CH_A, U_CDR)) { /* if cdr still conn */\r
263 cdr_sta = CDS_INIT; /* return to init */\r
264 sim_activate (uptr, 1); /* next card */\r
265 }\r
266 break;\r
267 }\r
268\r
269return SCPE_OK;\r
270}\r
271\r
272/* Card reader reset */\r
273\r
274t_stat cdr_reset (DEVICE *dptr)\r
275{\r
276uint32 i;\r
277\r
278for (i = 0; i < CD_BINLNT; i++) cdr_bbuf[i] = 0; /* clear buffer */\r
279cdr_sta = 0; /* clear state */\r
280cdr_bptr = 0; /* clear buf ptr */\r
281sim_cancel (&cdr_unit); /* stop reader */\r
282return SCPE_OK;\r
283}\r
284\r
285/* Card reader bootstrap */\r
286\r
287#define BOOT_START 01000\r
288#define BOOT_SIZE (sizeof (boot_rom) / sizeof (t_uint64))\r
289\r
290static const t_uint64 boot_rom[] = {\r
291 00762000001000 + U_CDR, /* RDSA CDR */\r
292 00544000000000 + BOOT_START + 4, /* LCHA *+3 */\r
293 00544000000000, /* LCHA 0 */\r
294 00021000000001, /* TTR 1 */\r
295 05000030000000, /* IOCT 3,,0 */\r
296 };\r
297\r
298t_stat cdr_boot (int32 unitno, DEVICE *dptr)\r
299{\r
300uint32 i;\r
301extern t_uint64 *M;\r
302\r
303for (i = 0; i < BOOT_SIZE; i++)\r
304 WriteP (BOOT_START + i, boot_rom[i]);\r
305PC = BOOT_START;\r
306return SCPE_OK;\r
307}\r
308\r
309/* Reader/punch attach */\r
310\r
311t_stat cd_attach (UNIT *uptr, char *cptr)\r
312{\r
313t_stat r = attach_unit (uptr, cptr);\r
314\r
315if (r != SCPE_OK) return r; /* attach */\r
316if (sim_switches & SWMASK ('T')) /* text? */\r
317 uptr->flags = uptr->flags & ~UNIT_CBN;\r
318else if (sim_switches & SWMASK ('C')) /* column binary? */\r
319 uptr->flags = uptr->flags | UNIT_CBN;\r
320else if (match_ext (cptr, "TXT")) /* .txt? */\r
321 uptr->flags = uptr->flags & ~UNIT_CBN;\r
322else if (match_ext (cptr, "CBN")) /* .cbn? */\r
323 uptr->flags = uptr->flags | UNIT_CBN;\r
324return SCPE_OK;\r
325}\r
326\r
327/* Reader/punch set mode - valid only if not attached */\r
328\r
329t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)\r
330{\r
331return (uptr->flags & UNIT_ATT)? SCPE_NOFNC: SCPE_OK;\r
332}\r
333\r
334/* Card punch select */\r
335\r
336t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit)\r
337{\r
338if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */\r
339\r
340switch (sel) { /* case on cmd */\r
341\r
342 case CHSL_WRS: /* write */\r
343 if ((cdp_unit.flags & UNIT_ATT) == 0) /* not attached? */\r
344 return SCPE_UNATT;\r
345 if (sim_is_active (&cdp_unit)) /* busy? */\r
346 return ERR_STALL;\r
347 cdp_sta = CDS_INIT; /* initial state */\r
348 sim_activate (&cdp_unit, cdp_tstart); /* start punch */\r
349 break;\r
350\r
351 default: /* other */\r
352 return STOP_ILLIOP; /* not allowed */\r
353 }\r
354return SCPE_OK;\r
355}\r
356\r
357/* Channel write routine - write word to buffer, write card when full */\r
358\r
359t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 eorfl)\r
360{\r
361cdp_chob = val & DMASK; /* store data */\r
362cdp_chob_v = 1; /* buffer valid */\r
363if (cdp_sta == CDS_DATA) {\r
364 cdp_bbuf[cdp_bptr++] = cdp_chob; /* store data */\r
365 if ((cdp_bptr >= CD_BINLNT) || eorfl) { /* end card or end rec? */\r
366 ch6_set_flags (CH_A, U_CDP, CHF_EOR); /* set eor */\r
367 return cdp_card_end (&cdp_unit); /* write card */\r
368 }\r
369 return SCPE_OK;\r
370 }\r
371return SCPE_IERR;\r
372}\r
373\r
374/* Unit timeout */\r
375\r
376t_stat cdp_svc (UNIT *uptr)\r
377{\r
378uint32 i;\r
379\r
380switch (cdp_sta) { /* case on state */\r
381\r
382 case CDS_INIT: /* initial state */\r
383 for (i = 0; i < CD_BINLNT; i++) /* clear bin buffer */\r
384 cdp_bbuf[i] = 0;\r
385 cdp_sta = CDS_DATA; /* data state */\r
386 cdp_bptr = 0; /* init pointer */\r
387 ch6_req_wr (CH_A, U_CDP); /* request channel */\r
388 cdp_chob = 0; /* clr, inval buffer */\r
389 cdp_chob_v = 0;\r
390 sim_activate (uptr, cdp_tleft); /* go again */\r
391 break;\r
392\r
393 case CDS_DATA: /* data state */\r
394 if (!ch6_qconn (CH_A, U_CDP)) /* chan disconnect? */\r
395 return cdp_card_end (uptr); /* write card */\r
396 if (cdp_chob_v) cdp_chob_v = 0; /* valid? clear */\r
397 else ind_ioc = 1; /* no, io check */\r
398 ch6_req_wr (CH_A, U_CDP); /* req channel */\r
399 sim_activate (uptr, (cdp_bptr & 1)? cdp_tleft: cdp_tright);\r
400 break;\r
401\r
402 case CDS_END: /* end state */\r
403 if (ch6_qconn (CH_A, U_CDP)) { /* if cdp still conn */\r
404 cdp_sta = CDS_INIT; /* return to init */\r
405 sim_activate (uptr, 1); /* next card */\r
406 }\r
407 break;\r
408 }\r
409\r
410return SCPE_OK;\r
411}\r
412\r
413/* Card end - write card image to file, transition to end state */\r
414\r
415t_stat cdp_card_end (UNIT *uptr)\r
416{\r
417uint32 i, col, row, bufw, colbin;\r
418char *pch, bcd, cdp_cbuf[(2 * CD_CHRLNT) + 2];\r
419t_uint64 dat;\r
420\r
421if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* not attached? */\r
422if (uptr->flags & UNIT_PCA) pch = bcd_to_ascii_a;\r
423else pch = bcd_to_ascii_h;\r
424for (col = 0; col < ((2 * CD_CHRLNT) + 1); col++)\r
425 cdp_cbuf[col] = ' '; /* clear char buf */\r
426for (col = 0; col < 72; col++) { /* process 72 columns */\r
427 colbin = 0;\r
428 dat = bit_masks[35 - (col % 36)]; /* mask for column */\r
429 for (row = 0; row < 12; row++) { /* proc 12 rows */\r
430 bufw = (row * 2) + (col / 36); /* index to buffer */\r
431 if (cdp_bbuf[bufw] & dat) colbin |= col_masks[row];\r
432 }\r
433 if (cdp_unit.flags & UNIT_CBN) { /* column binary? */\r
434 cdp_cbuf[2 * col] = pch[(colbin >> 6) & 077];\r
435 cdp_cbuf[(2 * col) + 1] = pch[colbin & 077];\r
436 }\r
437 else { /* text */\r
438 bcd = colbin_to_bcd (colbin); /* column bin -> BCD */\r
439 cdp_cbuf[col] = pch[bcd]; /* -> ASCII */\r
440 }\r
441 }\r
442for (i = ((2 * CD_CHRLNT) + 1); (i > 0) &&\r
443 (cdp_cbuf[i - 1] == ' '); --i) ; /* trim spaces */\r
444cdp_cbuf[i++] = '\n'; /* append nl */\r
445cdp_cbuf[i++] = 0; /* append nul */\r
446fputs (cdp_cbuf, uptr->fileref); /* write card */\r
447uptr->pos = ftell (uptr->fileref); /* update position */\r
448if (ferror (uptr->fileref)) { /* error? */\r
449 perror ("CDP I/O error");\r
450 clearerr (uptr->fileref);\r
451 return SCPE_IOERR;\r
452 }\r
453cdp_sta = CDS_END; /* end state */\r
454sim_cancel (uptr); /* cancel current */\r
455sim_activate (uptr, cdp_tstop); /* long timer */\r
456return SCPE_OK;\r
457}\r
458\r
459/* Card punch reset */\r
460\r
461t_stat cdp_reset (DEVICE *dptr)\r
462{\r
463uint32 i;\r
464\r
465for (i = 0; i < 24; i++) cdp_bbuf[i] = 0; /* clear buffer */\r
466cdp_sta = 0; /* clear state */\r
467cdp_bptr = 0; /* clear buf ptr */\r
468cdp_chob = 0;\r
469cdp_chob_v = 0;\r
470sim_cancel (&cdp_unit); /* stop punch */\r
471return SCPE_OK;\r
472}\r
473\r
474/* Column binary to BCD\r
475\r
476 This is based on documentation in the IBM 1620 manual and may not be\r
477 accurate for the 7094. Each row (12,11,0,1..9) is interpreted as a bit\r
478 pattern, and the appropriate bits are set. (Double punches inclusive\r
479 OR, eg, 1,8,9 is 9.) On the 1620, double punch errors are detected;\r
480 since the 7094 only reads column binary, double punches are ignored.\r
481\r
482 Bit order, left to right, is 12, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.\r
483 The for loop works right to left, so the table is reversed. */\r
484\r
485static const char row_val[12] = {\r
486 011, 010, 007, 006, 005, 004,\r
487 003, 002, 001, 020, 040, 060\r
488 };\r
489\r
490char colbin_to_bcd (uint32 cb)\r
491{\r
492uint32 i;\r
493char bcd;\r
494\r
495for (i = 0, bcd = 0; i < 12; i++) { /* 'sum' rows */\r
496 if (cb & (1 << i)) bcd |= row_val[i];\r
497 }\r
498return bcd;\r
499}\r