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