Commit | Line | Data |
---|---|---|
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 | |
59 | uint32 cdr_sta = 0; /* state */\r | |
60 | uint32 cdr_bptr = 0; /* buffer ptr */\r | |
61 | uint32 cdr_tstart = 27500; /* timing */\r | |
62 | uint32 cdr_tstop = 27500;\r | |
63 | uint32 cdr_tleft = 150;\r | |
64 | uint32 cdr_tright = 4000;\r | |
65 | t_uint64 cdr_bbuf[CD_BINLNT]; /* col binary buf */\r | |
66 | \r | |
67 | uint32 cdp_sta = 0; /* state */\r | |
68 | uint32 cdp_bptr = 0; /* buffer ptr */\r | |
69 | uint32 cdp_tstart = 35000; /* timing */\r | |
70 | uint32 cdp_tstop = 35000;\r | |
71 | uint32 cdp_tleft = 150;\r | |
72 | uint32 cdp_tright = 15500;\r | |
73 | t_uint64 cdp_chob = 0;\r | |
74 | uint32 cdp_chob_v = 0;\r | |
75 | t_uint64 cdp_bbuf[CD_BINLNT]; /* col binary buf */\r | |
76 | \r | |
77 | t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit);\r | |
78 | t_stat cdr_reset (DEVICE *dptr);\r | |
79 | t_stat cdr_svc (UNIT *uptr);\r | |
80 | t_stat cdr_boot (int32 unitno, DEVICE *dptr);\r | |
81 | t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit);\r | |
82 | t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 flags);\r | |
83 | t_stat cdp_reset (DEVICE *dptr);\r | |
84 | t_stat cdp_svc (UNIT *uptr);\r | |
85 | t_stat cdp_card_end (UNIT *uptr);\r | |
86 | t_stat cd_attach (UNIT *uptr, char *cptr);\r | |
87 | t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
88 | char colbin_to_bcd (uint32 cb);\r | |
89 | \r | |
90 | extern uint32 sim_switches;\r | |
91 | extern uint32 PC;\r | |
92 | extern uint32 ind_ioc;\r | |
93 | extern char bcd_to_ascii_a[64];\r | |
94 | extern char bcd_to_ascii_h[64];\r | |
95 | extern uint32 bcd_to_colbin[64];\r | |
96 | extern char ascii_to_bcd[128];\r | |
97 | extern t_uint64 bit_masks[36];\r | |
98 | extern 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 | |
107 | DIB cdr_dib = { &cdr_chsel, NULL };\r | |
108 | \r | |
109 | UNIT cdr_unit = {\r | |
110 | UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0)\r | |
111 | };\r | |
112 | \r | |
113 | REG 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 | |
124 | MTAB 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 | |
130 | DEVICE 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 | |
145 | DIB cdp_dib = { &cdp_chsel, &cdp_chwr };\r | |
146 | \r | |
147 | UNIT cdp_unit = {\r | |
148 | UDATA (&cdp_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0)\r | |
149 | };\r | |
150 | \r | |
151 | REG 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 | |
165 | MTAB 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 | |
173 | DEVICE 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 | |
183 | t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit)\r | |
184 | {\r | |
185 | if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */\r | |
186 | \r | |
187 | switch (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 | |
202 | return SCPE_OK;\r | |
203 | }\r | |
204 | \r | |
205 | /* Unit timeout */\r | |
206 | \r | |
207 | t_stat cdr_svc (UNIT *uptr)\r | |
208 | {\r | |
209 | uint32 i, col, row, bufw, colbin;\r | |
210 | char cdr_cbuf[(2 * CD_CHRLNT) + 2];\r | |
211 | t_uint64 dat = 0;\r | |
212 | \r | |
213 | if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* not attached? */\r | |
214 | switch (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 | |
269 | return SCPE_OK;\r | |
270 | }\r | |
271 | \r | |
272 | /* Card reader reset */\r | |
273 | \r | |
274 | t_stat cdr_reset (DEVICE *dptr)\r | |
275 | {\r | |
276 | uint32 i;\r | |
277 | \r | |
278 | for (i = 0; i < CD_BINLNT; i++) cdr_bbuf[i] = 0; /* clear buffer */\r | |
279 | cdr_sta = 0; /* clear state */\r | |
280 | cdr_bptr = 0; /* clear buf ptr */\r | |
281 | sim_cancel (&cdr_unit); /* stop reader */\r | |
282 | return 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 | |
290 | static 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 | |
298 | t_stat cdr_boot (int32 unitno, DEVICE *dptr)\r | |
299 | {\r | |
300 | uint32 i;\r | |
301 | extern t_uint64 *M;\r | |
302 | \r | |
303 | for (i = 0; i < BOOT_SIZE; i++)\r | |
304 | WriteP (BOOT_START + i, boot_rom[i]);\r | |
305 | PC = BOOT_START;\r | |
306 | return SCPE_OK;\r | |
307 | }\r | |
308 | \r | |
309 | /* Reader/punch attach */\r | |
310 | \r | |
311 | t_stat cd_attach (UNIT *uptr, char *cptr)\r | |
312 | {\r | |
313 | t_stat r = attach_unit (uptr, cptr);\r | |
314 | \r | |
315 | if (r != SCPE_OK) return r; /* attach */\r | |
316 | if (sim_switches & SWMASK ('T')) /* text? */\r | |
317 | uptr->flags = uptr->flags & ~UNIT_CBN;\r | |
318 | else if (sim_switches & SWMASK ('C')) /* column binary? */\r | |
319 | uptr->flags = uptr->flags | UNIT_CBN;\r | |
320 | else if (match_ext (cptr, "TXT")) /* .txt? */\r | |
321 | uptr->flags = uptr->flags & ~UNIT_CBN;\r | |
322 | else if (match_ext (cptr, "CBN")) /* .cbn? */\r | |
323 | uptr->flags = uptr->flags | UNIT_CBN;\r | |
324 | return SCPE_OK;\r | |
325 | }\r | |
326 | \r | |
327 | /* Reader/punch set mode - valid only if not attached */\r | |
328 | \r | |
329 | t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
330 | {\r | |
331 | return (uptr->flags & UNIT_ATT)? SCPE_NOFNC: SCPE_OK;\r | |
332 | }\r | |
333 | \r | |
334 | /* Card punch select */\r | |
335 | \r | |
336 | t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit)\r | |
337 | {\r | |
338 | if (sel & CHSL_NDS) return ch6_end_nds (ch); /* nds? nop */\r | |
339 | \r | |
340 | switch (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 | |
354 | return SCPE_OK;\r | |
355 | }\r | |
356 | \r | |
357 | /* Channel write routine - write word to buffer, write card when full */\r | |
358 | \r | |
359 | t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 eorfl)\r | |
360 | {\r | |
361 | cdp_chob = val & DMASK; /* store data */\r | |
362 | cdp_chob_v = 1; /* buffer valid */\r | |
363 | if (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 | |
371 | return SCPE_IERR;\r | |
372 | }\r | |
373 | \r | |
374 | /* Unit timeout */\r | |
375 | \r | |
376 | t_stat cdp_svc (UNIT *uptr)\r | |
377 | {\r | |
378 | uint32 i;\r | |
379 | \r | |
380 | switch (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 | |
410 | return SCPE_OK;\r | |
411 | }\r | |
412 | \r | |
413 | /* Card end - write card image to file, transition to end state */\r | |
414 | \r | |
415 | t_stat cdp_card_end (UNIT *uptr)\r | |
416 | {\r | |
417 | uint32 i, col, row, bufw, colbin;\r | |
418 | char *pch, bcd, cdp_cbuf[(2 * CD_CHRLNT) + 2];\r | |
419 | t_uint64 dat;\r | |
420 | \r | |
421 | if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* not attached? */\r | |
422 | if (uptr->flags & UNIT_PCA) pch = bcd_to_ascii_a;\r | |
423 | else pch = bcd_to_ascii_h;\r | |
424 | for (col = 0; col < ((2 * CD_CHRLNT) + 1); col++)\r | |
425 | cdp_cbuf[col] = ' '; /* clear char buf */\r | |
426 | for (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 | |
442 | for (i = ((2 * CD_CHRLNT) + 1); (i > 0) &&\r | |
443 | (cdp_cbuf[i - 1] == ' '); --i) ; /* trim spaces */\r | |
444 | cdp_cbuf[i++] = '\n'; /* append nl */\r | |
445 | cdp_cbuf[i++] = 0; /* append nul */\r | |
446 | fputs (cdp_cbuf, uptr->fileref); /* write card */\r | |
447 | uptr->pos = ftell (uptr->fileref); /* update position */\r | |
448 | if (ferror (uptr->fileref)) { /* error? */\r | |
449 | perror ("CDP I/O error");\r | |
450 | clearerr (uptr->fileref);\r | |
451 | return SCPE_IOERR;\r | |
452 | }\r | |
453 | cdp_sta = CDS_END; /* end state */\r | |
454 | sim_cancel (uptr); /* cancel current */\r | |
455 | sim_activate (uptr, cdp_tstop); /* long timer */\r | |
456 | return SCPE_OK;\r | |
457 | }\r | |
458 | \r | |
459 | /* Card punch reset */\r | |
460 | \r | |
461 | t_stat cdp_reset (DEVICE *dptr)\r | |
462 | {\r | |
463 | uint32 i;\r | |
464 | \r | |
465 | for (i = 0; i < 24; i++) cdp_bbuf[i] = 0; /* clear buffer */\r | |
466 | cdp_sta = 0; /* clear state */\r | |
467 | cdp_bptr = 0; /* clear buf ptr */\r | |
468 | cdp_chob = 0;\r | |
469 | cdp_chob_v = 0;\r | |
470 | sim_cancel (&cdp_unit); /* stop punch */\r | |
471 | return 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 | |
485 | static 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 | |
490 | char colbin_to_bcd (uint32 cb)\r | |
491 | {\r | |
492 | uint32 i;\r | |
493 | char bcd;\r | |
494 | \r | |
495 | for (i = 0, bcd = 0; i < 12; i++) { /* 'sum' rows */\r | |
496 | if (cb & (1 << i)) bcd |= row_val[i];\r | |
497 | }\r | |
498 | return bcd;\r | |
499 | }\r |