First Commit of my working state
[simh.git] / PDP11 / pdp11_cr.c
1 /* pdp11_cr.c: CR/CM/CD-11 card reader simulator
2
3 Copyright (c) 2005-2007, John A. Dundas III
4 Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu
5 Portions derived from work by Robert M Supnik
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 and/or sell copies of the Software, and to permit persons to whom the
12 Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 Except as contained in this notice, the name of the Author shall
25 not be used in advertising or otherwise to promote the sale, use
26 or other dealings in this Software without prior written
27 authorization from the Author.
28
29 ------------------------------------------------------------------------------
30
31 cr CR11/CD11 punched and mark sense card reader for SIMH
32 The CR11 controller is also compatible with the CM11-F, CME11, and CMS11.
33
34 Information necessary to create this simulation was gathered from
35 a number of sources including:
36
37 CR11 Card Reader System Manual, DEC-11-HCRB-D
38 http://www.bitsavers.org/pdf/dec/unibus/DEC-11-HCRB-D_CR11_Mar72.pdf
39 Various editions of the Peripherals Handbook
40 OpenVMS VAX Card Reader, Line Printer, and LPA11-K I/O User's
41 Reference Manual, AA-PVXGA-TE
42 http://h71000.www7.hp.com/DOC/73final/documentation/pdf/OVMS_VAX_CARD_LP_REF.pdf
43 OpenVMS System Manager's Manual, Volume 1: Essentials
44 http://h71000.www7.hp.com/DOC/732FINAL/aa-pv5mh-tk/aa-pv5mh-tk.PDF
45 CRDRIVER.LIS - CR11 Card Reader Driver, X-9, graciously made available
46 by HP
47 Various RSTS manuals
48 RT-11 Software Support Manual
49 RT-11 System Reference Manual, DEC-11-ORUGA-C-D
50 Professor Douglas W. Jones's web site:
51 http://www.cs.uiowa.edu/~jones/cards/
52 Paul Mattes' x026 keypunch simulator
53 http://x3270.bgp.nu/x026.html
54 CD2SER.MAC - TOPS card reader driver source
55 http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cd2ser.mac
56
57 The Card Image format code and documentation is adapted from Prof.
58 Jones's site, with his permission. Please see his site for additional
59 documentation as well as the card image utilities referenced in
60 his documentation (cardmake, cardlist, etc.).
61 http://www.cs.uiowa.edu/~jones/cards/format.html
62
63 Known limitations:
64 1. Need a copy of the CR bootstrap (and some way to test it)
65 2. Need a copy of the XXDP+ test deck
66 3. No testing under RSX; volunteers needed
67 4. No testing under Ultrix or Unix for PDP-11; volunteers needed
68 5. No testing under Ultrix or Unix for VAX; volunteers needed
69 6. The simulator implements a single controller/reader combination
70
71 Operating System Notes
72
73 RT-11 (and CTS-300) support one CR11 or CM11, but no CD11.
74
75 VMS supports multiple CR11 controllers, but no CD11.
76
77 RSTS/E supports either the CR11/CM11 or CD11 but not both in
78 the same SIL. It appears to support only one unit.
79
80 For RSX there exists a CR/CM task handler. Is there a CD
81 handler?
82
83 Don't have any information about Unix or Ultrix-11 yet. Same
84 for VAX Unices.
85
86 TOPS: only the CD11 is supported, under the name CD20.
87
88 Revision History:
89
90 01-Feb-07 RMS Added PDP-10 support
91 12-May-06 JAD Modify the DEBUG code to use the SIMH DEBUG_x
92 macros. Modify the UNIT structure to include
93 the DEBUG bit.
94 Mark the trans[] array contents constant.
95 Make device data structures static and constant
96 as appropriate.
97 18-Mar-05 JAD Slight optimization for blank punches recognizing
98 that blank is 0 in all character encodings.
99 17-Mar-05 JAD Completely initialize ascii_code correctly.
100 Define the end of deck punch code separately from
101 the cardcode.i file.
102 Make initTranslation() set a pointer to the correct
103 punch code table to use. Modify card read functions
104 to use this table pointer.
105 16-Mar-05 JAD Make certain switches passed to the ATTACH command
106 are valid; return error on any others.
107 Make default unit wait time compatible with default
108 device specification.
109 Implement SET TRANSLATION=value. Still need to
110 modify the H2ASCII table used for text files;
111 currently hard-coded to 029.
112 24-Feb-05 JAD Allow the maintenance bits in CRM to clear as
113 well as set status bits. Not sure this is the
114 correct behavior, though, without more documentation.
115 Catch three more places to spin down the blower
116 correctly.
117 Zero the CDDB and CRM at INIT.
118 17-Feb-05 JAD When the hopper empties, a pick check should
119 be generated 300ms later. They are simultaneous
120 for now.
121 Make sure readColumnBinary() generates a complete
122 EOF card.
123 08-Feb-05 JAD Replace blowerWait with different times for blower
124 spin up and down.
125 06-Feb-05 JAD After DETACH: mark CD offline, set appropriate
126 blower state.
127 Make sure unit wait time is recalculated every
128 time cpm is set.
129 04-Feb-05 JAD Better tracking of blower state throughout driver.
130 Make sure IE gets cleared for CR at INIT.
131 Normalize error response in read routines.
132 Finish condition handling for column binary.
133 02-Feb-05 JAD Remove Qbus support; Unibus only.
134 Support ATTACH switches:
135 A - ASCII, B - column binary, I - Card Image
136 If none given, check for .TXT or .CBN; if none,
137 examine file for magic header.
138 Finer granularity to blower state. Expose this
139 variable to examine/deposit from SIMH.
140 Preliminary implementation of support for
141 column binary format.
142 24-Jan-05 JAD Make AUTOEOF work as a surrogate for the EOF
143 button of a CD11 reader. May need to separate
144 this later, though.
145 Partial implementation of DATAERR for CD11.
146 Implement the Rev. J mods (as best I understand
147 them) to the CD11 affecting the CDDB used as a
148 second status register.
149 23-Jan-05 JAD Preliminary clean-up of CD state transitions.
150 Tested with RSTS/E (V9.1-05).
151 22-Jan-05 JAD Finish CR state transitions; should be close now.
152 Tested with RSTS/E (V9.1-05), RT-11 (V5.3), and
153 VAX/VMS (V7.2).
154 19-Jan-05 JAD Add bounds to the RATE command; also default and
155 help a la the XQ driver.
156 Improved handling of empty files.
157 17-Jan-05 JAD Add the CR maintenance register.
158 16-Jan-05 JAD Add preliminary CD11 support.
159 Simulate the STOP and RESET switches.
160 14-Jan-05 JAD Add the ability to automatically generate an 'EOF'
161 card recognized by DEC operating systems when
162 reading ASCII files.
163 08-Jan-05 JAD Original creation and testing
164 */
165
166 #if defined (VM_PDP10) /* PDP10 version */
167 #include "pdp10_defs.h"
168 extern int32 int_req;
169 #define DFLT_DIS (DEV_DIS)
170 #define DFLT_CR11 (0) /* CD11 only */
171 #define DFLT_CPM 1000
172
173 #elif defined (VM_VAX) /* VAX version */
174 #include "vax_defs.h"
175 extern int32 int_req[IPL_HLVL];
176 #define DFLT_DIS (0)
177 #define DFLT_CR11 (UNIT_CR11)
178 #define DFLT_CPM 285
179
180 #else /* PDP-11 version */
181 #include "pdp11_defs.h"
182 extern int32 int_req[IPL_HLVL];
183 #define DFLT_DIS (0)
184 #define DFLT_CR11 (UNIT_CR11)
185 #define DFLT_CPM 285
186 #endif
187
188 extern FILE *sim_deb; /* sim_console.c */
189
190 /* create a int32 constant from four characters */
191 #define I4C(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
192 #define I4C_CBN I4C ('C','B','N',' ')
193 #define I4C_H80 I4C ('H','8','0',' ')
194 #define I4C_H82 I4C ('H','8','2',' ')
195 #define I4C_H40 I4C ('H','4','0',' ')
196
197 #define UNIT_V_CR11 (UNIT_V_UF + 0)
198 #define UNIT_CR11 (1u << UNIT_V_CR11)
199 #define UNIT_V_AUTOEOF (UNIT_V_UF + 1)
200 #define UNIT_AUTOEOF (1u << UNIT_V_AUTOEOF)
201
202 #include <assert.h>
203 #define ERROR (00404)
204 #include "pdp11_cr_dat.h"
205 #define PUNCH_EOD (07417)
206 #define PUNCH_SPACE (0) /* same for all encodings */
207
208 /* CR */
209 /* also use CSR_ERR, CSR_IE, and CSR_GO */
210 #define CRCSR_V_CRDDONE 14 /* card done */
211 #define CRCSR_V_SUPPLY 13 /* supply error */
212 #define CRCSR_V_RDCHK 12 /* reader check */
213 #define CRCSR_V_TIMERR 11 /* timing error */
214 #define CRCSR_V_ONLINE 10 /* on line */
215 #define CRCSR_V_BUSY 9 /* busy reading */
216 #define CRCSR_V_OFFLINE 8 /* off line AKA READY? */
217 #define CRCSR_V_COLRDY 7 /* column ready */
218 #define CRCSR_V_EJECT 1 /* ignore card */
219
220 #define CRCSR_CRDDONE (1u << CRCSR_V_CRDDONE)
221 #define CRCSR_SUPPLY (1u << CRCSR_V_SUPPLY)
222 #define CRCSR_RDCHK (1u << CRCSR_V_RDCHK)
223 #define CRCSR_TIMERR (1u << CRCSR_V_TIMERR)
224 #define CRCSR_ONLINE (1u << CRCSR_V_ONLINE)
225 #define CRCSR_BUSY (1u << CRCSR_V_BUSY)
226 #define CRCSR_OFFLINE (1u << CRCSR_V_OFFLINE)
227 #define CRCSR_COLRDY (1u << CRCSR_V_COLRDY)
228 #define CRCSR_EJECT (1u << CRCSR_V_EJECT)
229
230 #define CRCSR_IMP (CSR_ERR | CRCSR_CRDDONE | CRCSR_SUPPLY | \
231 CRCSR_RDCHK | CRCSR_TIMERR | CRCSR_ONLINE | \
232 CRCSR_BUSY | CRCSR_OFFLINE | CRCSR_COLRDY | \
233 CSR_IE | CRCSR_EJECT)
234 #define CRCSR_RW (CSR_IE | CRCSR_EJECT | CSR_GO) /* read/write */
235
236 #define CRM_V_MAINT 15 /* enable maint funct */
237 #define CRM_V_BUSY 14
238 #define CRM_V_READY 13
239 #define CRM_V_HOPPER 12
240
241 #define CRM_MAINT (1u << CRM_V_MAINT)
242 #define CRM_BUSY (1u << CRM_V_BUSY)
243 #define CRM_READY (1u << CRM_V_READY)
244 #define CRM_HOPPER (1u << CRM_V_HOPPER)
245
246 /* CD */
247 /* also use CSR_ERR, CSR_IE, and CSR_GO */
248 #define CDCSR_V_RDRCHK 14 /* reader check */
249 #define CDCSR_V_EOF 13 /* CD11-E EOF button */
250 #define CDCSR_V_OFFLINE 12 /* off line */
251 #define CDCSR_V_DATAERR 11 /* data error */
252 #define CDCSR_V_LATE 10 /* data late */
253 #define CDCSR_V_NXM 9 /* non-existent memory */
254 #define CDCSR_V_PWRCLR 8 /* power clear */
255 #define CDCSR_V_RDY 7 /* ready */
256 #define CDCSR_V_XBA17 5
257 #define CDCSR_V_XBA16 4
258 #define CDCSR_V_ONLINE 3 /* on line transition */
259 #define CDCSR_V_HOPPER 2 /* hopper check */
260 #define CDCSR_V_PACK 1 /* data packing */
261
262 #define CDCSR_RDRCHK (1u << CDCSR_V_RDRCHK)
263 #define CDCSR_EOF (1u << CDCSR_V_EOF)
264 #define CDCSR_OFFLINE (1u << CDCSR_V_OFFLINE)
265 #define CDCSR_DATAERR (1u << CDCSR_V_DATAERR)
266 #define CDCSR_LATE (1u << CDCSR_V_LATE)
267 #define CDCSR_NXM (1u << CDCSR_V_NXM)
268 #define CDCSR_PWRCLR (1u << CDCSR_V_PWRCLR)
269 #define CDCSR_RDY (1u << CDCSR_V_RDY)
270 #define CDCSR_XBA17 (1u << CDCSR_V_XBA17)
271 #define CDCSR_XBA16 (1u << CDCSR_V_XBA16)
272 #define CDCSR_ONLINE (1u << CDCSR_V_ONLINE)
273 #define CDCSR_HOPPER (1u << CDCSR_V_HOPPER)
274 #define CDCSR_PACK (1u << CDCSR_V_PACK)
275
276 #define CDCSR_IMP (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | \
277 CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | \
278 CDCSR_PWRCLR | CDCSR_RDY | CSR_IE | \
279 CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | \
280 CDCSR_HOPPER | CDCSR_PACK | CSR_GO)
281
282 #define CDCSR_RW (CDCSR_PWRCLR | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | \
283 CDCSR_PACK | CSR_GO)
284
285 /* Blower state values */
286 #define BLOW_OFF (0) /* steady state off */
287 #define BLOW_START (1) /* starting up */
288 #define BLOW_ON (2) /* steady state on */
289 #define BLOW_STOP (3) /* shutting down */
290
291 /* Card Reader state */
292 static char *cardFormat = "unknown";
293 static t_bool (*readRtn)(FILE *, int16 *, char *, char *);
294 static char ascii_code[4096]; /* 2^12 possible values */
295 static int currCol; /* current column when reading */
296 static int colStart; /* starting column */
297 static int colEnd; /* ending column */
298 static int table = 3; /* character translation table */
299 static const int *codeTbl = o29_code; /* punch translation table */
300 static int32 blowerState = BLOW_OFF; /* reader vacuum/blower motor */
301 static int32 spinUp = 3000; /* blower spin-up time: 3 seconds */
302 static int32 spinDown = 2000; /* blower spin-down time: 2 seconds */
303 static t_bool EOFcard = FALSE; /* played special card yet? */
304 static int32 cpm = DFLT_CPM; /* reader rate: cards per minute */
305 /* card image in various formats */
306 static int16 hcard[82]; /* Hollerith format */
307 static char ccard[82]; /* DEC compressed format */
308 static char acard[82]; /* ASCII format */
309 /* CR/CM registers */
310 static int32 crs = 0; /* control/status */
311 static int32 crb1 = 0; /* 12-bit Hollerith characters */
312 static int32 crb2 = 0; /* 8-bit compressed characters */
313 static int32 crm = 0; /* CMS maintenance register */
314 /* CD registers */
315 static int32 cdst = 0; /* control/status */
316 static int32 cdcc = 0; /* column count */
317 static int32 cdba = 0; /* current address, low 16 bits */
318 static int32 cddb = 0; /* data, 2nd status */
319
320 /* forward references */
321 DEVICE cr_dev;
322 static void setupCardFile (UNIT *, int32);
323 t_stat cr_rd (int32 *, int32, int32);
324 t_stat cr_wr (int32, int32, int32);
325 t_stat cr_svc (UNIT *);
326 t_stat cr_reset (DEVICE *);
327 t_stat cr_attach (UNIT *, char *);
328 t_stat cr_detach (UNIT *);
329 t_stat cr_set_type (UNIT *, int32, char *, void *);
330 t_stat cr_show_format (FILE *, UNIT *, int32, void *);
331 t_stat cr_set_rate (UNIT *, int32, char *, void *);
332 t_stat cr_show_rate (FILE *, UNIT *, int32, void *);
333 t_stat cr_set_reset (UNIT *, int32, char *, void *);
334 t_stat cr_set_stop (UNIT *, int32, char *, void *);
335 t_stat cr_set_trans (UNIT *, int32, char*, void *);
336 t_stat cr_show_trans (FILE *, UNIT *, int32, void *);
337
338 /* CR data structures
339
340 cr_dib CR device information block
341 cr_unit CR unit descriptor
342 cr_reg CR register list
343 cr_mod CR modifier table
344 cr_dev CR device descriptor
345 */
346
347 static DIB cr_dib = { IOBA_CR, IOLN_CR, &cr_rd, &cr_wr,
348 1, IVCL (CR), VEC_CR, { NULL } };
349
350 static UNIT cr_unit = {
351 UDATA (&cr_svc,
352 UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE+UNIT_DISABLE+
353 DFLT_CR11+UNIT_AUTOEOF, 0),
354 (60 * 1000) / DFLT_CPM };
355
356 static const REG cr_reg[] = {
357 { GRDATA (BUF, cr_unit.buf, DEV_RDX, 8, 0) },
358 { GRDATA (CRS, crs, DEV_RDX, 16, 0) },
359 { GRDATA (CRB1, crb1, DEV_RDX, 16, 0) },
360 { GRDATA (CRB2, crb2, DEV_RDX, 16, 0) },
361 { GRDATA (CRM, crm, DEV_RDX, 16, 0) },
362 { GRDATA (CDST, cdst, DEV_RDX, 16, 0) },
363 { GRDATA (CDCC, cdcc, DEV_RDX, 16, 0) },
364 { GRDATA (CDBA, cdba, DEV_RDX, 16, 0) },
365 { GRDATA (CDDB, cddb, DEV_RDX, 16, 0) },
366 { GRDATA (BLOWER, blowerState, DEV_RDX, 2, 0) },
367 { FLDATA (INT, IREQ (CR), INT_V_CR) },
368 { FLDATA (ERR, crs, CSR_V_ERR) },
369 { FLDATA (IE, crs, CSR_V_IE) },
370 { DRDATA (POS, cr_unit.pos, T_ADDR_W), PV_LEFT },
371 { DRDATA (TIME, cr_unit.wait, 24), PV_LEFT },
372 { GRDATA (DEVADDR, cr_dib.ba, DEV_RDX, 32, 0), REG_HRO },
373 { GRDATA (DEVVEC, cr_dib.vec, DEV_RDX, 16, 0), REG_HRO },
374 { NULL } };
375
376 static const MTAB cr_mod[] = {
377 #if defined (VM_PDP11)
378 { UNIT_CR11, UNIT_CR11, "CR11", "CR11", &cr_set_type },
379 { UNIT_CR11, 0, "CD11", "CD11", &cr_set_type },
380 #else
381 { UNIT_CR11, UNIT_CR11, "CR11", NULL },
382 { UNIT_CR11, 0, "CD11", NULL },
383 #endif
384 { UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", NULL },
385 { UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", NULL },
386 /* card reader RESET switch */
387 { MTAB_XTD|MTAB_VDV, 0, NULL, "RESET",
388 &cr_set_reset, NULL, NULL },
389 /* card reader STOP switch */
390 { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP",
391 &cr_set_stop, NULL, NULL },
392 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", NULL,
393 NULL, &cr_show_format, NULL },
394 { MTAB_XTD|MTAB_VDV, 006, "ADDRESS", "ADDRESS",
395 &set_addr, &show_addr, NULL },
396 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
397 &set_vec, &show_vec, NULL },
398 { MTAB_XTD|MTAB_VDV, 0, "RATE", "RATE={DEFAULT|200..1200}",
399 &cr_set_rate, &cr_show_rate, NULL },
400 { MTAB_XTD|MTAB_VDV, 0, "TRANSLATION",
401 "TRANSLATION={DEFAULT|026|026FTN|029|EBCDIC}",
402 &cr_set_trans, &cr_show_trans, NULL },
403 { 0 } };
404
405 DEVICE cr_dev = {
406 "CR", &cr_unit, (REG *) &cr_reg, (MTAB *) &cr_mod,
407 1, 10, 31, 1, DEV_RDX, 8,
408 NULL, NULL, &cr_reset,
409 NULL, &cr_attach, &cr_detach,
410 &cr_dib, DEV_DISABLE | DFLT_DIS | DEV_UBUS | DEV_DEBUG };
411
412 /* Utility routines */
413
414 /*
415 These functions read a "card" from a virtual deck file (passed in
416 fp) and fill in three arrays. The first array 'hcard' contains the
417 12-bit binary image of the punch in each column; the second array
418 'ccard' contains the 8-bit DEC encoded representation of the
419 corresponding column; the third array 'acard' contains the ASCII
420 representation (if possible) of the character. The routines return
421 TRUE if a card was read (possibly with errors) and FALSE if the
422 "hopper is empty" (EOF) or fatal file errors prevented any portion
423 of a card from being read.
424
425 Errors other than EOF are signaled out of band in the controller
426 state variables. Possible errors are data in columns 0 or 81
427 (signalled as read check; currently these columns are ignored), or
428 any file errors (signalled as motion check).
429
430 Might rethink this. Should probably treat file errors as "pick
431 check". Retry 3 times. After that, give up with error.
432
433 */
434
435 static t_bool readCardImage ( FILE *fp,
436 int16 *hcard,
437 char *ccard,
438 char *acard )
439 {
440 int c1, c2, c3, col;
441
442 if (DEBUG_PRS (cr_dev))
443 fprintf (sim_deb, "readCardImage pos %d\n", ftell (fp));
444 /* get card header bytes */
445 c1 = fgetc (fp);
446 c2 = fgetc (fp);
447 c3 = fgetc (fp);
448 cr_unit.pos = ftell (fp);
449 /* check for EOF */
450 if (c1 == EOF) {
451 if (DEBUG_PRS (cr_dev))
452 fprintf (sim_deb, "hopper empty\n");
453 if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) {
454 EOFcard = TRUE;
455 for (col = 1; col <= 8; col++) {
456 hcard[col] = PUNCH_EOD;
457 ccard[col] = h2c_code[PUNCH_EOD];
458 acard[col] = ' ';
459 }
460 while (col <= colEnd) {
461 hcard[col] = PUNCH_SPACE;
462 ccard[col] = PUNCH_SPACE;
463 acard[col] = ' ';
464 col++;
465 }
466 return (TRUE);
467 }
468 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE;
469 crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE);
470 cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER;
471 if (cr_unit.flags & UNIT_AUTOEOF)
472 cdst |= CDCSR_EOF;
473 blowerState = BLOW_STOP;
474 return (FALSE);
475 }
476 /* check for valid header */
477 if ((c2 == EOF) || (c3 == EOF) || ((c1 & 0x80) == 0) ||
478 ((c2 & 0x80) == 0) || ((c3 & 0x80) == 0)) {
479 if (DEBUG_PRS (cr_dev))
480 fprintf (sim_deb, "header error\n");
481 /* unexpected EOF or format problems */
482 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE;
483 crs &= ~CRCSR_ONLINE;
484 cdst |= CSR_ERR | CDCSR_RDRCHK;
485 blowerState = BLOW_STOP;
486 return (FALSE);
487 }
488 assert (colStart < colEnd);
489 assert (colStart >= 0);
490 assert (colEnd <= 81);
491 for (col = colStart; col < colEnd; ) {
492 int16 i;
493 /* get 3 bytes */
494 c1 = fgetc (fp);
495 c2 = fgetc (fp);
496 c3 = fgetc (fp);
497 cr_unit.pos = ftell (fp);
498 if (ferror (fp) || feof (fp)) {
499 if (DEBUG_PRS (cr_dev))
500 fprintf (sim_deb, "file error\n");
501 /* signal error; unexpected EOF, format problems, or file error(s) */
502 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE;
503 crs &= ~CRCSR_ONLINE;
504 cdst |= CSR_ERR | CDCSR_RDRCHK;
505 blowerState = BLOW_STOP;
506 return (FALSE);
507 }
508 /* convert to 2 columns */
509 i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF;
510 hcard[col] = i;
511 ccard[col] = h2c_code[i];
512 acard[col] = ascii_code[i];
513 col++;
514
515 i = (((c2 & 017) << 8) | c3) & 0xFFF;
516 hcard[col] = i;
517 ccard[col] = h2c_code[i];
518 acard[col] = ascii_code[i];
519 col++;
520 }
521 if (DEBUG_PRS (cr_dev))
522 fprintf (sim_deb, "successfully loaded card\n");
523 return (TRUE);
524 }
525
526 static t_bool readColumnBinary ( FILE *fp,
527 int16 *hcard,
528 char *ccard,
529 char *acard )
530 {
531 int col;
532
533 for (col = colStart; col <= colEnd; col++) {
534 int16 i;
535 i = fgetc (fp) & 077;
536 i |= ((fgetc (fp) & 077) << 6);
537 cr_unit.pos = ftell (fp);
538 if (feof (fp)) {
539 if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) {
540 EOFcard = TRUE;
541 for (col = 1; col <= 8; col++) {
542 hcard[col] = PUNCH_EOD;
543 ccard[col] = h2c_code[PUNCH_EOD];
544 acard[col] = ' ';
545 }
546 while (col <= colEnd) {
547 hcard[col] = PUNCH_SPACE;
548 ccard[col] = PUNCH_SPACE;
549 acard[col] = ' ';
550 col++;
551 }
552 return (TRUE);
553 }
554 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY |
555 CRCSR_OFFLINE;
556 crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE);
557 cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER;
558 if (cr_unit.flags & UNIT_AUTOEOF)
559 cdst |= CDCSR_EOF;
560 blowerState = BLOW_STOP;
561 return (FALSE);
562 }
563 if (ferror (fp)) {
564 /* signal error */
565 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE;
566 crs &= ~CRCSR_ONLINE;
567 cdst |= CSR_ERR | CDCSR_RDRCHK;
568 blowerState = BLOW_STOP;
569 return (FALSE);
570 }
571 hcard[col] = i;
572 ccard[col] = h2c_code[i];
573 acard[col] = ascii_code[i];
574 }
575 return (TRUE);
576 }
577
578 /*
579
580 Should this routine perform special handling of non-printable,
581 (e.g., control) characters or characters that have no encoded
582 representation?
583
584 */
585
586 static t_bool readCardASCII ( FILE *fp,
587 int16 *hcard,
588 char *ccard,
589 char *acard )
590 {
591 int c, col;
592
593 assert (colStart < colEnd);
594 assert (colStart >= 1);
595 assert (colEnd <= 80);
596
597 if (DEBUG_PRS (cr_dev))
598 fprintf (sim_deb, "readCardASCII\n");
599 for (col = colStart; col <= colEnd; ) {
600 switch (c = fgetc (fp)) {
601 case EOF:
602 if (ferror (fp)) {
603 /* signal error */
604 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE;
605 crs &= ~CRCSR_ONLINE;
606 cdst |= CSR_ERR | CDCSR_RDRCHK;
607 blowerState = BLOW_STOP;
608 cr_unit.pos = ftell (fp);
609 return (FALSE);
610 }
611 if (col == colStart) {
612 if (DEBUG_PRS (cr_dev))
613 fprintf (sim_deb, "hopper empty\n");
614 if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) {
615 EOFcard = TRUE;
616 for (col = 1; col <= 8; col++) {
617 hcard[col] = PUNCH_EOD;
618 ccard[col] = h2c_code[PUNCH_EOD];
619 acard[col] = ' ';
620 }
621 c = '\n';
622 goto fill_card;
623 }
624 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE;
625 crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE);
626 cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER;
627 if (cr_unit.flags & UNIT_AUTOEOF)
628 cdst |= CDCSR_EOF;
629 blowerState = BLOW_STOP;
630 cr_unit.pos = ftell (fp);
631 return (FALSE);
632 }
633 /* fall through */
634 case '\r':
635 case '\n':
636 fill_card:
637 while (col <= colEnd) {
638 hcard[col] = PUNCH_SPACE;
639 ccard[col] = PUNCH_SPACE;
640 acard[col] = ' ';
641 col++;
642 }
643 break;
644 case '\t':
645 do {
646 hcard[col] = PUNCH_SPACE;
647 ccard[col] = PUNCH_SPACE;
648 acard[col] = ' ';
649 col++;
650 } while (((col & 07) != 1) && (col <= colEnd));
651 break;
652 default:
653 hcard[col] = codeTbl[c & 0177];
654 /* check for unrepresentable ASCII characters */
655 if (hcard[col] == ERROR) {
656 cdst |= CDCSR_DATAERR;
657 if (DEBUG_PRS (cr_dev))
658 fprintf (sim_deb,
659 "error character at column %d\n",
660 col);
661 }
662 ccard[col] = h2c_code[hcard[col]];
663 acard[col] = c;
664 col++;
665 break;
666 }
667 }
668 /* silently truncate/flush long lines, or flag over-length card? */
669 if (c != '\n') {
670 if (DEBUG_PRS (cr_dev))
671 fprintf (sim_deb, "truncating card\n");
672 do c = fgetc (fp);
673 while ((c != EOF) && (c != '\n') && (c != '\r'));
674 }
675 if (DEBUG_PRS (cr_dev))
676 fprintf (sim_deb, "successfully loaded card\n");
677 cr_unit.pos = ftell (fp);
678 return (TRUE);
679 }
680
681 /*
682
683 Initialize the binary translation table. Generally called when a
684 new deck is attached but could be set manually as well.
685
686 */
687
688 static void initTranslation (void)
689 {
690 int32 i;
691
692 memset (ascii_code, '~', sizeof (ascii_code));
693 switch (table) {
694 case 1:
695 codeTbl = o26_comm_code;
696 for (i = ' '; i < '`'; i++)
697 ascii_code[o26_comm_code[i]] = i;
698 break;
699 case 2:
700 codeTbl = o26_ftn_code;
701 for (i = ' '; i < '`'; i++)
702 ascii_code[o26_ftn_code[i]] = i;
703 break;
704 case 3:
705 codeTbl = o29_code;
706 for (i = ' '; i < '`'; i++)
707 ascii_code[o29_code[i]] = i;
708 break;
709 case 4:
710 codeTbl = EBCDIC_code;
711 for (i = 0; i < 0177; i++)
712 ascii_code[EBCDIC_code[i]] = i;
713 break;
714 default:
715 /* can't happen */
716 if (DEBUG_PRS (cr_dev))
717 fprintf (sim_deb,
718 "bad CR translation initialization value\n");
719 break;
720 }
721 }
722
723 /*
724
725 Examine the command switches, file extension, and virtual card deck
726 file to determine the format. Set up the global variables
727 appropriately. Rewind ASCII files to the beginning
728
729 */
730
731 static void setupCardFile ( UNIT *uptr,
732 int32 switches )
733 {
734 int32 i;
735
736 if (switches & SWMASK ('A'))
737 i = 0;
738 else if (switches & SWMASK ('B'))
739 i = I4C_CBN;
740 else if (switches & SWMASK ('I'))
741 goto read_header;
742 else if (match_ext (uptr->filename, "TXT"))
743 i = 0;
744 else if (match_ext (uptr->filename, "CBN"))
745 i = I4C_CBN;
746 else {
747 read_header:
748 /* look for card image magic file number */
749 i = fgetc (uptr->fileref);
750 i = (i << 8) | fgetc (uptr->fileref);
751 i = (i << 8) | fgetc (uptr->fileref);
752 i = (i << 8) | ' ';
753 }
754 switch (i) {
755 case I4C_H80:
756 colStart = 1;
757 colEnd = 80;
758 cardFormat = "card image";
759 readRtn = readCardImage;
760 break;
761 case I4C_H82:
762 colStart = 0;
763 colEnd = 81;
764 cardFormat = "card image";
765 readRtn = readCardImage;
766 break;
767 case I4C_H40:
768 colStart = 1;
769 colEnd = 40;
770 cardFormat = "card image";
771 readRtn = readCardImage;
772 break;
773 case I4C_CBN:
774 colStart = 1;
775 colEnd = 80;
776 cardFormat = "column binary";
777 readRtn = readColumnBinary;
778 break;
779 default:
780 colStart = 1;
781 colEnd = 80;
782 cardFormat = "ASCII";
783 readRtn = readCardASCII;
784 fseek (uptr->fileref, 0L, SEEK_SET);
785 break;
786 }
787 initTranslation ();
788 if (DEBUG_PRS (cr_dev))
789 fprintf (sim_deb, "colStart = %d, colEnd = %d\n",
790 colStart, colEnd);
791 cr_unit.pos = ftell (uptr->fileref);
792 }
793
794 /* Card reader routines
795
796 cr_rd I/O page read
797 cr_wr I/O page write
798 cr_svc process event (reader ready)
799 cr_reset process reset
800 cr_attach process attach
801 cr_detach process detach
802 */
803
804 t_stat cr_rd ( int32 *data,
805 int32 PA,
806 int32 access )
807 {
808 switch ((PA >> 1) & 03) {
809 case 0: /* CSR */
810 if (cdst & (077000))
811 cdst |= CSR_ERR;
812 else
813 cdst &= ~CSR_ERR;
814 *data = (cr_unit.flags & UNIT_CR11) ?
815 crs & CRCSR_IMP : cdst & CDCSR_IMP;
816 /* CR: if error removed, clear 15, 14, 11, 10 */
817 if (DEBUG_PRS (cr_dev))
818 fprintf (sim_deb, "cr_rd crs %06o cdst %06o\n",
819 crs, cdst);
820 break;
821 case 1:
822 *data = (cr_unit.flags & UNIT_CR11) ? crb1 : cdcc;
823 /* Does crb1 clear after read? Implied by VMS driver. */
824 crb1 = 0;
825 crs &= ~CRCSR_COLRDY;
826 if (DEBUG_PRS (cr_dev)) {
827 if (cr_unit.flags & UNIT_CR11)
828 fprintf (sim_deb, "cr_rd crb1 %06o '%c' %d\n",
829 crb1, cr_unit.buf, cr_unit.buf);
830 else
831 fprintf (sim_deb, "cr_rd cdcc %06o\n", cdcc);
832 }
833 break;
834 case 2:
835 *data = (cr_unit.flags & UNIT_CR11) ? crb2 : cdba;
836 crb2 = 0; /* see note for crb1 */
837 crs &= ~CRCSR_COLRDY;
838 if (DEBUG_PRS (cr_dev)) {
839 if (cr_unit.flags & UNIT_CR11)
840 fprintf (sim_deb, "cr_rd crb2 %06o\n", crb2);
841 else
842 fprintf (sim_deb, "\r\ncr_rd cdba %06o\n", cdba);
843 }
844 break;
845 case 3:
846 default:
847 if (cr_unit.flags & UNIT_CR11)
848 *data = crm;
849 else
850 *data = 0100000 | (cdst & CDCSR_RDRCHK) |
851 (cdst & CDCSR_OFFLINE) ?
852 cddb & 0777 : 0777;
853 if (DEBUG_PRS (cr_dev))
854 fprintf (sim_deb, "cr_rd crm %06o cddb %06o data %06o\n",
855 crm, cddb, *data);
856 break;
857 }
858 return (SCPE_OK);
859 }
860
861 t_stat cr_wr ( int32 data,
862 int32 PA,
863 int32 access )
864 {
865 switch ((PA >> 1) & 03) {
866 case 0:
867 if (cr_unit.flags & UNIT_CR11) {
868 /* ignore high-byte writes */
869 if (PA & 1)
870 break;
871 /* fixup data for low byte write */
872 if (access == WRITEB)
873 data = (crs & ~0377) | (data & 0377);
874 if (!(data & CSR_IE))
875 CLR_INT (CR);
876 crs = (crs & ~CRCSR_RW) | (data & CRCSR_RW);
877 crs &= ~(CSR_ERR | CRCSR_CRDDONE | CRCSR_TIMERR);
878 if (DEBUG_PRS (cr_dev))
879 fprintf (sim_deb, "cr_wr data %06o crs %06o\n",
880 data, crs);
881 if (data & CSR_GO) {
882 if (blowerState != BLOW_ON) {
883 sim_activate (&cr_unit, spinUp);
884 blowerState = BLOW_START;
885 } else
886 sim_activate (&cr_unit, cr_unit.wait);
887 }
888 } else {
889 if (data & CDCSR_PWRCLR) {
890 CLR_INT (CR);
891 sim_cancel (&cr_unit);
892 cdst &= ~(CDCSR_RDRCHK |CDCSR_OFFLINE |
893 CDCSR_RDY | CDCSR_HOPPER);
894 cdst |= CDCSR_RDY;
895 cdcc = 0;
896 cdba = 0;
897 break;
898 }
899 if (!(data & CSR_IE))
900 CLR_INT (CR);
901 cdst = (cdst & ~CDCSR_RW) | (data & CDCSR_RW);
902 if (DEBUG_PRS (cr_dev))
903 fprintf (sim_deb, "cr_wr data %06o cdst %06o\n",
904 data, cdst);
905 if (data & CSR_GO) {
906 if (blowerState != BLOW_ON) {
907 sim_activate (&cr_unit, spinUp);
908 blowerState = BLOW_START;
909 } else
910 sim_activate (&cr_unit, cr_unit.wait);
911 }
912 }
913 break;
914 case 1:
915 if (DEBUG_PRS (cr_dev))
916 fprintf (sim_deb, "cr_wr cdcc %06o\n", data);
917 if (cr_unit.flags & UNIT_CR11)
918 break;
919 cdcc = data & 0177777;
920 break;
921 case 2:
922 if (DEBUG_PRS (cr_dev))
923 fprintf (sim_deb, "cr_wr crba %06o\n", data);
924 if (cr_unit.flags & UNIT_CR11)
925 break;
926 cdba = data & 0177777;
927 break;
928 case 3:
929 if (DEBUG_PRS (cr_dev))
930 fprintf (sim_deb, "cr_wr cddb/crm %06o\n", data);
931 /* ignore writes to cddb */
932 if (!(cr_unit.flags & UNIT_CR11))
933 break;
934 /* fixup data for byte writes and read-modify-write */
935 if (access == WRITEB)
936 data = (PA & 1) ?
937 (crm & 0377) | (data << 8) :
938 (crm & ~0377) | (data & 0377);
939 crm = data & 0177777;
940 /* not 100% certain how these work */
941 if (!(crm & CRM_MAINT))
942 break;
943 crs = (crm & CRM_BUSY) ?
944 (crs | CRCSR_BUSY) : (crs & ~CRCSR_BUSY);
945 crs = (crm & CRM_READY) ?
946 (crs | CRCSR_OFFLINE) : (crs & ~CRCSR_OFFLINE);
947 crs = (crm & CRM_HOPPER) ?
948 (crs | CRCSR_SUPPLY | CRCSR_RDCHK) :
949 (crs & ~(CRCSR_SUPPLY | CRCSR_RDCHK));
950 crb1 = crm & 07777; /* load low 12 bits */
951 break;
952 default:
953 /* can't happen */
954 break;
955 }
956 return (SCPE_OK);
957 }
958
959 /*
960 Enter the service routine once for each column read from the card.
961 CR state bits drive this primarily (see _BUSY and _CRDDONE). However,
962 when in CD mode, also execute one column of DMA input.
963
964 */
965
966 t_stat cr_svc ( UNIT *uptr )
967 {
968 uint32 pa;
969 uint8 c;
970 uint16 w;
971
972 if (blowerState == BLOW_STOP) {
973 blowerState = BLOW_OFF;
974 return (SCPE_OK);
975 }
976 if (blowerState == BLOW_START)
977 blowerState = BLOW_ON;
978 /* (almost) anything we do now will cause a CR interrupt */
979 if (crs & CSR_IE)
980 SET_INT (CR);
981 if (!(uptr->flags & UNIT_ATT) || (crs & CSR_ERR) || (cdst & CSR_ERR))
982 return (SCPE_OK);
983 if ((crs & CRCSR_BUSY) && (currCol > colEnd)) {
984 crs &= ~(CRCSR_BUSY | CSR_GO | CRCSR_COLRDY);
985 crs |= CRCSR_CRDDONE;
986 if (cdst & (CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM))
987 cdst |= CSR_ERR;
988 if (cdst & CSR_IE)
989 SET_INT (CR);
990 if (DEBUG_PRS (cr_dev))
991 fprintf (sim_deb, "cr_svc card done\n");
992 return (SCPE_OK);
993 }
994 if (!(crs & CRCSR_BUSY)) {
995 /* try to read a card */
996 /* crs &= ~CRCSR_CRDDONE; */
997 if (!readRtn (uptr->fileref, hcard, ccard, acard)) {
998 sim_activate (uptr, spinDown);
999 return (SCPE_OK);
1000 }
1001 currCol = colStart;
1002 crs |= CRCSR_BUSY; /* indicate reader busy */
1003 }
1004 /* check for overrun (timing error) */
1005 if ((uptr->flags & UNIT_CR11) && (crs & CRCSR_COLRDY))
1006 crs |= CSR_ERR | CRCSR_TIMERR;
1007 crb1 = hcard[currCol] & 07777;
1008 crb2 = ccard[currCol] & 0377;
1009 uptr->buf = acard[currCol] & 0377; /* helpful for debugging */
1010 if (!(uptr->flags & UNIT_CR11)) {
1011 pa = cdba | ((cdst & 060) << 12);
1012 /*
1013 The implementation of _NXM here is not quite the same as I interpret
1014 the (limited) documentaiton I have to indicate. However the effect
1015 should be similar. Documentation indicates that once _NXM is set,
1016 further NPR requests are inhibited though the card is allowed to
1017 read until completion. This implies that CDBA and the XBA bits are
1018 incremented accordingly, even though no data transfer occurs. This
1019 code detects and flags the NXM condition but allows attempts at
1020 subsequent memory writes, thus insuring the address registers are
1021 incremented properly. If this causes problems, I'll fix it.
1022 */
1023 if (cdst & CDCSR_PACK) {
1024 c = cddb = ccard[currCol] & 0377;
1025 if (Map_WriteB (pa, 1, &c))
1026 cdst |= CDCSR_NXM;
1027 pa = (pa + 1) & 0777777;
1028 } else {
1029 w = cddb = hcard[currCol] & 07777;
1030 if (Map_WriteW (pa, 2, &w))
1031 cdst |= CDCSR_NXM;
1032 pa = (pa + 2) & 0777777;
1033 }
1034 cdba = pa & 0177777;
1035 cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) |
1036 ((pa & 0600000) >> 12);
1037 cdcc = (cdcc + 1) & 0177777;
1038 #if 0
1039 if (!(cdst & CSR_IE) && !(crs & CRCSR_CRDDONE))
1040 CLR_INT (CR);
1041 #endif
1042 }
1043 currCol++; /* advance the column counter */
1044 if (!(crs & CRCSR_EJECT))
1045 crs |= CRCSR_COLRDY;
1046 else
1047 CLR_INT (CR);
1048 sim_activate (uptr, uptr->wait);
1049 return (SCPE_OK);
1050 }
1051
1052 t_stat cr_reset ( DEVICE *dptr )
1053 {
1054 if (DEBUG_PRS (cr_dev))
1055 fprintf (sim_deb, "cr_reset\n");
1056 cr_unit.buf = 0;
1057 currCol = 1;
1058 crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_TIMERR|CRCSR_ONLINE|CRCSR_BUSY|
1059 CRCSR_COLRDY|CSR_IE|CRCSR_EJECT|CSR_GO);
1060 crb1 = 0;
1061 crb2 = 0;
1062 crm = 0;
1063 cdst &= ~(CSR_ERR|CDCSR_RDRCHK|CDCSR_EOF|CDCSR_DATAERR|CDCSR_LATE|
1064 CDCSR_NXM|CSR_IE|CDCSR_XBA17|CDCSR_XBA16|CDCSR_ONLINE|
1065 CDCSR_PACK|CSR_GO);
1066 cdst |= CDCSR_RDY;
1067 cdcc = 0;
1068 cdba = 0;
1069 cddb = 0;
1070 if ((cr_unit.flags & UNIT_ATT) && !feof (cr_unit.fileref)) {
1071 crs |= CRCSR_ONLINE; /* non-standard */
1072 crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE);
1073 cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER);
1074 } else {
1075 cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER;
1076 crs = CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE;
1077 }
1078 sim_cancel (&cr_unit); /* deactivate unit */
1079 if (blowerState != BLOW_OFF) {
1080 blowerState = BLOW_STOP;
1081 sim_activate (&cr_unit, spinDown);
1082 }
1083 EOFcard = FALSE;
1084 CLR_INT (CR);
1085 /* TBD: flush current card */
1086 /* init uptr->wait ? */
1087 return (SCPE_OK);
1088 }
1089
1090 /*
1091 Handle the interface status and SIMH portion of the ATTACH. Another
1092 routine is used to evaluate the file and initialize other state
1093 globals correctly.
1094 */
1095
1096 #define MASK (SWMASK('A')|SWMASK('B')|SWMASK('I')|SWMASK('R'))
1097
1098 t_stat cr_attach ( UNIT *uptr,
1099 char *cptr )
1100 {
1101 t_stat reason;
1102 extern int32 sim_switches;
1103
1104 if (sim_switches & ~MASK)
1105 return (SCPE_INVSW);
1106 /* file must previously exist; kludge */
1107 sim_switches |= SWMASK ('R');
1108 reason = attach_unit (uptr, cptr);
1109 if (!(uptr->flags & UNIT_ATT)) {
1110 crs &= ~CRCSR_ONLINE;
1111 crs |= CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY;
1112 cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER;
1113 } else {
1114 setupCardFile (uptr, sim_switches);
1115 crs |= CRCSR_ONLINE;
1116 crs &= ~(CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY);
1117 cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER);
1118 EOFcard = FALSE;
1119 }
1120 return (reason);
1121 }
1122
1123 t_stat cr_detach ( UNIT *uptr )
1124 {
1125 crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE;
1126 /* interrupt? */
1127 crs &= ~CRCSR_ONLINE;
1128 cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER | CDCSR_OFFLINE;
1129 cardFormat = "unknown";
1130 if (blowerState != BLOW_OFF) {
1131 blowerState = BLOW_STOP;
1132 sim_activate (uptr, spinDown);
1133 }
1134 return (detach_unit (uptr));
1135 }
1136
1137 t_stat cr_set_type ( UNIT *uptr,
1138 int32 val,
1139 char *cptr,
1140 void *desc )
1141 {
1142 /* disallow type change if currently attached */
1143 if (uptr->flags & UNIT_ATT)
1144 return (SCPE_NOFNC);
1145 cpm = (val & UNIT_CR11) ? 285 : 1000;
1146 uptr->wait = (60 * 1000) / cpm;
1147 return (SCPE_OK);
1148 }
1149
1150 t_stat cr_show_format ( FILE *st,
1151 UNIT *uptr,
1152 int32 val,
1153 void *desc )
1154 {
1155 fprintf (st, "%s format", cardFormat);
1156 return (SCPE_OK);
1157 }
1158
1159 t_stat cr_set_rate ( UNIT *uptr,
1160 int32 val,
1161 char *cptr,
1162 void *desc )
1163 {
1164 t_stat status = SCPE_OK;
1165 int32 i;
1166
1167 if (!cptr)
1168 return (SCPE_MISVAL);
1169 if (strcmp (cptr, "DEFAULT") == 0)
1170 i = (uptr->flags & UNIT_CR11) ? 285 : 1000;
1171 else
1172 i = (int32) get_uint (cptr, 10, 0xFFFFFFFF, &status);
1173 if (status == SCPE_OK) {
1174 if (i < 200 || i > 1200)
1175 status = SCPE_ARG;
1176 else {
1177 cpm = i;
1178 uptr->wait = (60 * 1000) / cpm;
1179 }
1180 }
1181 return (status);
1182 }
1183
1184 t_stat cr_show_rate ( FILE *st,
1185 UNIT *uptr,
1186 int32 val,
1187 void *desc )
1188 {
1189 fprintf (st, "%d cards per minute", cpm);
1190 return (SCPE_OK);
1191 }
1192
1193 /* simulate pressing the card reader RESET button */
1194
1195 t_stat cr_set_reset ( UNIT *uptr,
1196 int32 val,
1197 char *cptr,
1198 void *desc )
1199 {
1200 if (DEBUG_PRS (cr_dev))
1201 fprintf (sim_deb, "cr_set_reset\n");
1202 /*
1203 Ignore the RESET switch while a read cycle is in progress or the
1204 unit simply is not attached.
1205 */
1206 if ((crs & CRCSR_BUSY) || !(uptr->flags & UNIT_ATT))
1207 return (SCPE_OK);
1208 /* if no errors, signal transition to on line */
1209 crs |= CRCSR_ONLINE;
1210 crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_SUPPLY|CRCSR_RDCHK|CRCSR_TIMERR|
1211 CRCSR_BUSY|CRCSR_COLRDY|CRCSR_EJECT|CSR_GO);
1212 cdst |= CDCSR_ONLINE;
1213 cdst &= ~(CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK | CDCSR_HOPPER |
1214 CDCSR_EOF);
1215 if ((crs & CSR_IE) || (cdst & CSR_IE)) {
1216 SET_INT (CR);
1217 if (DEBUG_PRS (cr_dev))
1218 fprintf (sim_deb, "cr_set_reset setting interrupt\n");
1219 }
1220 /* start up the blower if the hopper is not empty */
1221 if (blowerState != BLOW_ON)
1222 blowerState = BLOW_START;
1223 return (SCPE_OK);
1224 }
1225
1226 /* simulate pressing the card reader STOP button */
1227
1228 t_stat cr_set_stop ( UNIT *uptr,
1229 int32 val,
1230 char *cptr,
1231 void *desc )
1232 {
1233 if (DEBUG_PRS (cr_dev))
1234 fprintf (sim_deb, "set_stop\n");
1235 crs &= ~CRCSR_ONLINE;
1236 crs |= CSR_ERR | CRCSR_OFFLINE;
1237 cdst |= CDCSR_OFFLINE;
1238 /* CD11 does not appear to interrupt on STOP. */
1239 if (crs & CSR_IE)
1240 SET_INT (CR);
1241 if (blowerState != BLOW_OFF) {
1242 blowerState = BLOW_STOP;
1243 /* set timer to turn it off completely */
1244 sim_activate (uptr, spinDown);
1245 }
1246 return (SCPE_OK);
1247 }
1248
1249 static const char * const trans[] = {
1250 "unknown", "026", "026FTN", "029", "EBCDIC"
1251 };
1252
1253 t_stat cr_set_trans ( UNIT *uptr,
1254 int32 val,
1255 char *cptr,
1256 void *desc )
1257 {
1258 int i;
1259
1260 if (!cptr)
1261 return (SCPE_MISVAL);
1262 if (strcmp (cptr, "DEFAULT") == 0)
1263 i = 3;
1264 else {
1265 for (i = 1; i < 5; i++) {
1266 if (strcmp (cptr, trans[i]) == 0)
1267 break;
1268 }
1269 }
1270 if (i < 1 || i > 4)
1271 return (SCPE_ARG);
1272 table = i;
1273 initTranslation (); /* reinitialize tables */
1274 return (SCPE_OK);
1275 }
1276
1277 t_stat cr_show_trans ( FILE *st,
1278 UNIT *uptr,
1279 int32 val,
1280 void *desc )
1281 {
1282 fprintf (st, "translation %s", trans[table]);
1283 return (SCPE_OK);
1284 }