1 /* pdp11_cr.c: CR/CM/CD-11 card reader simulator
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
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:
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
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.
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.
29 ------------------------------------------------------------------------------
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.
34 Information necessary to create this simulation was gathered from
35 a number of sources including:
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
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
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
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
71 Operating System Notes
73 RT-11 (and CTS-300) support one CR11 or CM11, but no CD11.
75 VMS supports multiple CR11 controllers, but no CD11.
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.
80 For RSX there exists a CR/CM task handler. Is there a CD
83 Don't have any information about Unix or Ultrix-11 yet. Same
86 TOPS: only the CD11 is supported, under the name CD20.
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
94 Mark the trans[] array contents constant.
95 Make device data structures static and constant
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
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
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
121 Make sure readColumnBinary() generates a complete
123 08-Feb-05 JAD Replace blowerWait with different times for blower
125 06-Feb-05 JAD After DETACH: mark CD offline, set appropriate
127 Make sure unit wait time is recalculated every
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
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
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
163 08-Jan-05 JAD Original creation and testing
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
173 #elif defined (VM_VAX) /* VAX version */
174 #include "vax_defs.h"
175 extern int32 int_req
[IPL_HLVL
];
177 #define DFLT_CR11 (UNIT_CR11)
180 #else /* PDP-11 version */
181 #include "pdp11_defs.h"
182 extern int32 int_req
[IPL_HLVL
];
184 #define DFLT_CR11 (UNIT_CR11)
188 extern FILE *sim_deb
; /* sim_console.c */
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',' ')
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)
203 #define ERROR (00404)
204 #include "pdp11_cr_dat.h"
205 #define PUNCH_EOD (07417)
206 #define PUNCH_SPACE (0) /* same for all encodings */
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 */
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)
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 */
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
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)
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 */
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)
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)
282 #define CDCSR_RW (CDCSR_PWRCLR | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | \
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 */
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 */
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 */
320 /* forward references */
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 *);
338 /* CR data structures
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
347 static DIB cr_dib
= { IOBA_CR
, IOLN_CR
, &cr_rd
, &cr_wr
,
348 1, IVCL (CR
), VEC_CR
, { NULL
} };
350 static UNIT cr_unit
= {
352 UNIT_ATTABLE
+UNIT_SEQ
+UNIT_ROABLE
+UNIT_DISABLE
+
353 DFLT_CR11
+UNIT_AUTOEOF
, 0),
354 (60 * 1000) / DFLT_CPM
};
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
},
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
},
381 { UNIT_CR11
, UNIT_CR11
, "CR11", NULL
},
382 { UNIT_CR11
, 0, "CD11", NULL
},
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
},
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
};
412 /* Utility routines */
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.
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).
430 Might rethink this. Should probably treat file errors as "pick
431 check". Retry 3 times. After that, give up with error.
435 static t_bool
readCardImage ( FILE *fp
,
442 if (DEBUG_PRS (cr_dev
))
443 fprintf (sim_deb
, "readCardImage pos %d\n", ftell (fp
));
444 /* get card header bytes */
448 cr_unit
.pos
= ftell (fp
);
451 if (DEBUG_PRS (cr_dev
))
452 fprintf (sim_deb
, "hopper empty\n");
453 if (!EOFcard
&& (cr_unit
.flags
& UNIT_AUTOEOF
)) {
455 for (col
= 1; col
<= 8; col
++) {
456 hcard
[col
] = PUNCH_EOD
;
457 ccard
[col
] = h2c_code
[PUNCH_EOD
];
460 while (col
<= colEnd
) {
461 hcard
[col
] = PUNCH_SPACE
;
462 ccard
[col
] = PUNCH_SPACE
;
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
)
473 blowerState
= BLOW_STOP
;
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
;
488 assert (colStart
< colEnd
);
489 assert (colStart
>= 0);
490 assert (colEnd
<= 81);
491 for (col
= colStart
; col
< colEnd
; ) {
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
;
508 /* convert to 2 columns */
509 i
= ((c1
<< 4) | ( c2
>> 4)) & 0xFFF;
511 ccard
[col
] = h2c_code
[i
];
512 acard
[col
] = ascii_code
[i
];
515 i
= (((c2
& 017) << 8) | c3
) & 0xFFF;
517 ccard
[col
] = h2c_code
[i
];
518 acard
[col
] = ascii_code
[i
];
521 if (DEBUG_PRS (cr_dev
))
522 fprintf (sim_deb
, "successfully loaded card\n");
526 static t_bool
readColumnBinary ( FILE *fp
,
533 for (col
= colStart
; col
<= colEnd
; col
++) {
535 i
= fgetc (fp
) & 077;
536 i
|= ((fgetc (fp
) & 077) << 6);
537 cr_unit
.pos
= ftell (fp
);
539 if (!EOFcard
&& (cr_unit
.flags
& UNIT_AUTOEOF
)) {
541 for (col
= 1; col
<= 8; col
++) {
542 hcard
[col
] = PUNCH_EOD
;
543 ccard
[col
] = h2c_code
[PUNCH_EOD
];
546 while (col
<= colEnd
) {
547 hcard
[col
] = PUNCH_SPACE
;
548 ccard
[col
] = PUNCH_SPACE
;
554 crs
|= CSR_ERR
| CRCSR_RDCHK
| CRCSR_SUPPLY
|
556 crs
&= ~(CRCSR_COLRDY
| CRCSR_ONLINE
);
557 cdst
|= CSR_ERR
| CDCSR_RDRCHK
| CDCSR_HOPPER
;
558 if (cr_unit
.flags
& UNIT_AUTOEOF
)
560 blowerState
= BLOW_STOP
;
565 crs
|= CSR_ERR
| CRCSR_RDCHK
| CRCSR_OFFLINE
;
566 crs
&= ~CRCSR_ONLINE
;
567 cdst
|= CSR_ERR
| CDCSR_RDRCHK
;
568 blowerState
= BLOW_STOP
;
572 ccard
[col
] = h2c_code
[i
];
573 acard
[col
] = ascii_code
[i
];
580 Should this routine perform special handling of non-printable,
581 (e.g., control) characters or characters that have no encoded
586 static t_bool
readCardASCII ( FILE *fp
,
593 assert (colStart
< colEnd
);
594 assert (colStart
>= 1);
595 assert (colEnd
<= 80);
597 if (DEBUG_PRS (cr_dev
))
598 fprintf (sim_deb
, "readCardASCII\n");
599 for (col
= colStart
; col
<= colEnd
; ) {
600 switch (c
= fgetc (fp
)) {
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
);
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
)) {
616 for (col
= 1; col
<= 8; col
++) {
617 hcard
[col
] = PUNCH_EOD
;
618 ccard
[col
] = h2c_code
[PUNCH_EOD
];
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
)
629 blowerState
= BLOW_STOP
;
630 cr_unit
.pos
= ftell (fp
);
637 while (col
<= colEnd
) {
638 hcard
[col
] = PUNCH_SPACE
;
639 ccard
[col
] = PUNCH_SPACE
;
646 hcard
[col
] = PUNCH_SPACE
;
647 ccard
[col
] = PUNCH_SPACE
;
650 } while (((col
& 07) != 1) && (col
<= colEnd
));
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
))
659 "error character at column %d\n",
662 ccard
[col
] = h2c_code
[hcard
[col
]];
668 /* silently truncate/flush long lines, or flag over-length card? */
670 if (DEBUG_PRS (cr_dev
))
671 fprintf (sim_deb
, "truncating card\n");
673 while ((c
!= EOF
) && (c
!= '\n') && (c
!= '\r'));
675 if (DEBUG_PRS (cr_dev
))
676 fprintf (sim_deb
, "successfully loaded card\n");
677 cr_unit
.pos
= ftell (fp
);
683 Initialize the binary translation table. Generally called when a
684 new deck is attached but could be set manually as well.
688 static void initTranslation (void)
692 memset (ascii_code
, '~', sizeof (ascii_code
));
695 codeTbl
= o26_comm_code
;
696 for (i
= ' '; i
< '`'; i
++)
697 ascii_code
[o26_comm_code
[i
]] = i
;
700 codeTbl
= o26_ftn_code
;
701 for (i
= ' '; i
< '`'; i
++)
702 ascii_code
[o26_ftn_code
[i
]] = i
;
706 for (i
= ' '; i
< '`'; i
++)
707 ascii_code
[o29_code
[i
]] = i
;
710 codeTbl
= EBCDIC_code
;
711 for (i
= 0; i
< 0177; i
++)
712 ascii_code
[EBCDIC_code
[i
]] = i
;
716 if (DEBUG_PRS (cr_dev
))
718 "bad CR translation initialization value\n");
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
731 static void setupCardFile ( UNIT
*uptr
,
736 if (switches
& SWMASK ('A'))
738 else if (switches
& SWMASK ('B'))
740 else if (switches
& SWMASK ('I'))
742 else if (match_ext (uptr
->filename
, "TXT"))
744 else if (match_ext (uptr
->filename
, "CBN"))
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
);
758 cardFormat
= "card image";
759 readRtn
= readCardImage
;
764 cardFormat
= "card image";
765 readRtn
= readCardImage
;
770 cardFormat
= "card image";
771 readRtn
= readCardImage
;
776 cardFormat
= "column binary";
777 readRtn
= readColumnBinary
;
782 cardFormat
= "ASCII";
783 readRtn
= readCardASCII
;
784 fseek (uptr
->fileref
, 0L, SEEK_SET
);
788 if (DEBUG_PRS (cr_dev
))
789 fprintf (sim_deb
, "colStart = %d, colEnd = %d\n",
791 cr_unit
.pos
= ftell (uptr
->fileref
);
794 /* Card reader routines
798 cr_svc process event (reader ready)
799 cr_reset process reset
800 cr_attach process attach
801 cr_detach process detach
804 t_stat
cr_rd ( int32
*data
,
808 switch ((PA
>> 1) & 03) {
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",
822 *data
= (cr_unit
.flags
& UNIT_CR11
) ? crb1
: cdcc
;
823 /* Does crb1 clear after read? Implied by VMS driver. */
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
);
831 fprintf (sim_deb
, "cr_rd cdcc %06o\n", cdcc
);
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
);
842 fprintf (sim_deb
, "\r\ncr_rd cdba %06o\n", cdba
);
847 if (cr_unit
.flags
& UNIT_CR11
)
850 *data
= 0100000 | (cdst
& CDCSR_RDRCHK
) |
851 (cdst
& CDCSR_OFFLINE
) ?
853 if (DEBUG_PRS (cr_dev
))
854 fprintf (sim_deb
, "cr_rd crm %06o cddb %06o data %06o\n",
861 t_stat
cr_wr ( int32 data
,
865 switch ((PA
>> 1) & 03) {
867 if (cr_unit
.flags
& UNIT_CR11
) {
868 /* ignore high-byte writes */
871 /* fixup data for low byte write */
872 if (access
== WRITEB
)
873 data
= (crs
& ~0377) | (data
& 0377);
874 if (!(data
& CSR_IE
))
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",
882 if (blowerState
!= BLOW_ON
) {
883 sim_activate (&cr_unit
, spinUp
);
884 blowerState
= BLOW_START
;
886 sim_activate (&cr_unit
, cr_unit
.wait
);
889 if (data
& CDCSR_PWRCLR
) {
891 sim_cancel (&cr_unit
);
892 cdst
&= ~(CDCSR_RDRCHK
|CDCSR_OFFLINE
|
893 CDCSR_RDY
| CDCSR_HOPPER
);
899 if (!(data
& CSR_IE
))
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",
906 if (blowerState
!= BLOW_ON
) {
907 sim_activate (&cr_unit
, spinUp
);
908 blowerState
= BLOW_START
;
910 sim_activate (&cr_unit
, cr_unit
.wait
);
915 if (DEBUG_PRS (cr_dev
))
916 fprintf (sim_deb
, "cr_wr cdcc %06o\n", data
);
917 if (cr_unit
.flags
& UNIT_CR11
)
919 cdcc
= data
& 0177777;
922 if (DEBUG_PRS (cr_dev
))
923 fprintf (sim_deb
, "cr_wr crba %06o\n", data
);
924 if (cr_unit
.flags
& UNIT_CR11
)
926 cdba
= data
& 0177777;
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
))
934 /* fixup data for byte writes and read-modify-write */
935 if (access
== WRITEB
)
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
))
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 */
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.
966 t_stat
cr_svc ( UNIT
*uptr
)
972 if (blowerState
== BLOW_STOP
) {
973 blowerState
= BLOW_OFF
;
976 if (blowerState
== BLOW_START
)
977 blowerState
= BLOW_ON
;
978 /* (almost) anything we do now will cause a CR interrupt */
981 if (!(uptr
->flags
& UNIT_ATT
) || (crs
& CSR_ERR
) || (cdst
& CSR_ERR
))
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
))
990 if (DEBUG_PRS (cr_dev
))
991 fprintf (sim_deb
, "cr_svc card done\n");
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
);
1002 crs
|= CRCSR_BUSY
; /* indicate reader busy */
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);
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.
1023 if (cdst
& CDCSR_PACK
) {
1024 c
= cddb
= ccard
[currCol
] & 0377;
1025 if (Map_WriteB (pa
, 1, &c
))
1027 pa
= (pa
+ 1) & 0777777;
1029 w
= cddb
= hcard
[currCol
] & 07777;
1030 if (Map_WriteW (pa
, 2, &w
))
1032 pa
= (pa
+ 2) & 0777777;
1034 cdba
= pa
& 0177777;
1035 cdst
= (cdst
& ~(CDCSR_XBA17
|CDCSR_XBA16
)) |
1036 ((pa
& 0600000) >> 12);
1037 cdcc
= (cdcc
+ 1) & 0177777;
1039 if (!(cdst
& CSR_IE
) && !(crs
& CRCSR_CRDDONE
))
1043 currCol
++; /* advance the column counter */
1044 if (!(crs
& CRCSR_EJECT
))
1045 crs
|= CRCSR_COLRDY
;
1048 sim_activate (uptr
, uptr
->wait
);
1052 t_stat
cr_reset ( DEVICE
*dptr
)
1054 if (DEBUG_PRS (cr_dev
))
1055 fprintf (sim_deb
, "cr_reset\n");
1058 crs
&= ~(CSR_ERR
|CRCSR_CRDDONE
|CRCSR_TIMERR
|CRCSR_ONLINE
|CRCSR_BUSY
|
1059 CRCSR_COLRDY
|CSR_IE
|CRCSR_EJECT
|CSR_GO
);
1063 cdst
&= ~(CSR_ERR
|CDCSR_RDRCHK
|CDCSR_EOF
|CDCSR_DATAERR
|CDCSR_LATE
|
1064 CDCSR_NXM
|CSR_IE
|CDCSR_XBA17
|CDCSR_XBA16
|CDCSR_ONLINE
|
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
);
1075 cdst
|= CSR_ERR
| CDCSR_RDRCHK
| CDCSR_HOPPER
;
1076 crs
= CSR_ERR
| CRCSR_RDCHK
| CRCSR_SUPPLY
| CRCSR_OFFLINE
;
1078 sim_cancel (&cr_unit
); /* deactivate unit */
1079 if (blowerState
!= BLOW_OFF
) {
1080 blowerState
= BLOW_STOP
;
1081 sim_activate (&cr_unit
, spinDown
);
1085 /* TBD: flush current card */
1086 /* init uptr->wait ? */
1091 Handle the interface status and SIMH portion of the ATTACH. Another
1092 routine is used to evaluate the file and initialize other state
1096 #define MASK (SWMASK('A')|SWMASK('B')|SWMASK('I')|SWMASK('R'))
1098 t_stat
cr_attach ( UNIT
*uptr
,
1102 extern int32 sim_switches
;
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
;
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
);
1123 t_stat
cr_detach ( UNIT
*uptr
)
1125 crs
|= CSR_ERR
| CRCSR_RDCHK
| CRCSR_SUPPLY
| CRCSR_OFFLINE
;
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
);
1134 return (detach_unit (uptr
));
1137 t_stat
cr_set_type ( UNIT
*uptr
,
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
;
1150 t_stat
cr_show_format ( FILE *st
,
1155 fprintf (st
, "%s format", cardFormat
);
1159 t_stat
cr_set_rate ( UNIT
*uptr
,
1164 t_stat status
= SCPE_OK
;
1168 return (SCPE_MISVAL
);
1169 if (strcmp (cptr
, "DEFAULT") == 0)
1170 i
= (uptr
->flags
& UNIT_CR11
) ? 285 : 1000;
1172 i
= (int32
) get_uint (cptr
, 10, 0xFFFFFFFF, &status
);
1173 if (status
== SCPE_OK
) {
1174 if (i
< 200 || i
> 1200)
1178 uptr
->wait
= (60 * 1000) / cpm
;
1184 t_stat
cr_show_rate ( FILE *st
,
1189 fprintf (st
, "%d cards per minute", cpm
);
1193 /* simulate pressing the card reader RESET button */
1195 t_stat
cr_set_reset ( UNIT
*uptr
,
1200 if (DEBUG_PRS (cr_dev
))
1201 fprintf (sim_deb
, "cr_set_reset\n");
1203 Ignore the RESET switch while a read cycle is in progress or the
1204 unit simply is not attached.
1206 if ((crs
& CRCSR_BUSY
) || !(uptr
->flags
& UNIT_ATT
))
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
|
1215 if ((crs
& CSR_IE
) || (cdst
& CSR_IE
)) {
1217 if (DEBUG_PRS (cr_dev
))
1218 fprintf (sim_deb
, "cr_set_reset setting interrupt\n");
1220 /* start up the blower if the hopper is not empty */
1221 if (blowerState
!= BLOW_ON
)
1222 blowerState
= BLOW_START
;
1226 /* simulate pressing the card reader STOP button */
1228 t_stat
cr_set_stop ( UNIT
*uptr
,
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. */
1241 if (blowerState
!= BLOW_OFF
) {
1242 blowerState
= BLOW_STOP
;
1243 /* set timer to turn it off completely */
1244 sim_activate (uptr
, spinDown
);
1249 static const char * const trans
[] = {
1250 "unknown", "026", "026FTN", "029", "EBCDIC"
1253 t_stat
cr_set_trans ( UNIT
*uptr
,
1261 return (SCPE_MISVAL
);
1262 if (strcmp (cptr
, "DEFAULT") == 0)
1265 for (i
= 1; i
< 5; i
++) {
1266 if (strcmp (cptr
, trans
[i
]) == 0)
1273 initTranslation (); /* reinitialize tables */
1277 t_stat
cr_show_trans ( FILE *st
,
1282 fprintf (st
, "translation %s", trans
[table
]);