From 1bfc2bc57e279b21430ee1660356cf677850af12 Mon Sep 17 00:00:00 2001 From: Timothe Litt Date: Fri, 5 Jul 2013 00:16:11 -0400 Subject: [PATCH] PDP-10 update: CD20 Make the card reader work on TOPS-10 and TOPS-20. Augmented Image ECO was not implemented. Simplify UI by defining commands for the various options/models emulated based on the simulator being built. Document, and make the help conditional on model where that reduces clutter. Deal with reading ASCII files (file is opened 'rb' in scp's attach ; it shouldn't be. Add translation support for DEC 026/029 full 7-bit ASCII, an ANSI standard & used by TOPS-10/20. Deliver EOF at the correct time(s). Preliminary support for update to card image spec being negotiated with the author. --- PDP11/pdp11_cr.c | 1204 ++++++++++++++++++++++++++++-------------- PDP11/pdp11_cr_dat.h | 39 +- 2 files changed, 840 insertions(+), 403 deletions(-) diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c index 28e6c1bf..5faea762 100644 --- a/PDP11/pdp11_cr.c +++ b/PDP11/pdp11_cr.c @@ -1,4 +1,4 @@ -/* pdp11_cr.c: CR/CM/CD-11 card reader simulator +/* pdp11_cr.c: CR/CM/CD-11/CD20 card reader simulator Copyright (c) 2005-2010, John A. Dundas III Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu @@ -28,7 +28,7 @@ ------------------------------------------------------------------------------ - cr CR11/CD11 punched and mark sense card reader for SIMH + cr CR11/CD11/CD20 punched and mark sense card reader for SIMH The CR11 controller is also compatible with the CM11-F, CME11, and CMS11. Information necessary to create this simulation was gathered from @@ -51,8 +51,16 @@ http://www.cs.uiowa.edu/~jones/cards/ Paul Mattes' x026 keypunch simulator http://x3270.bgp.nu/x026.html - CD2SER.MAC - TOPS card reader driver source + CD2SER.MAC - TOPS-10 card reader driver source http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cd2ser.mac + CDRIVE.MAC - TOPS GALAXY card reader spooler + http://pdp-10.trailing-edge.com/BB-BT99U-BB_1990/03/10,7/galaxy/cdrive/cdrive.mac + SPRINT.MAC - TOPS GALAXY control card interpreter + http://pdp-10.trailing-edge.com/BB-H138C-BM/01/galaxy-sources/sprint.mac + CDKSDV.MAC - TOPS-20 card reader driver source + http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/cdksdv.mac + PROKS.MAC - TOPS-20 bit definitions + http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/proks.mac The Card Image format code and documentation is adapted from Prof. Jones's site, with his permission. Please see his site for additional @@ -88,7 +96,8 @@ Don't have any information about Unix or Ultrix-11 yet. Same for VAX Unices. - TOPS: only the CD11 is supported, under the name CD20. + TOPS: only the CD20 variant of the CD11 is supported. CD20 implies + ECOs (at least) for Data Buffer status and augmented image mode. Revision History: 23-Feb-13 JGP Added DEC version of the 026 codepage @@ -174,28 +183,52 @@ 08-Jan-05 JAD Original creation and testing */ +/* Configuration notes: + * Keep VM_arch symbols here and use them only to select features. + * CR attributes use generic symbols so device support is easy to change, + * e.g. if software is discovered that uses a previously unsupported option. + * Conventions: + * *_ONLY (AND *_req) means feature * is unconditionally present/required. + * *_OK means feature * is selectable at runtime. + * neither means feature is not present. + * To support only one controller model, define _ONLY. + * To support more than one, define them all as _OK. + * Don't mix "_ONLY" and "_OK" for the same feature. You won't like it. + * + * The CD/CR will work on any UNIBUS, and the CR will also work on a QBUS. + * The configuration options used here are more restrictive to reflect + * known software support, as this reduces user configuration errors/confusion. + */ + #if defined (VM_PDP10) /* PDP10 version */ #include "pdp10_defs.h" extern int32 int_req; #define DFLT_DIS (DEV_DIS) -#define DFLT_CR11 (0) /* CD11 only */ -#define DFLT_CPM 1000 - +#define DFLT_TYPE (UNIT_CD20) /* CD20 (CD11) only */ +#define CD20_ONLY (1) +#define DFLT_CPM 1200 +#define AIECO_REQ (1) /* Requires Augmented Image ECO */ #elif defined (VM_VAX) /* VAX version */ #include "vax_defs.h" extern int32 int_req[IPL_HLVL]; #define DFLT_DIS (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ -#define DFLT_CR11 (UNIT_CR11) /* CR11 only */ +#define DFLT_TYPE (UNIT_CR11) /* CR11 only */ +#define CR11_ONLY (1) #define DFLT_CPM 285 - #else /* PDP-11 version */ #include "pdp11_defs.h" extern int32 int_req[IPL_HLVL]; #define DFLT_DIS (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ -#define DFLT_CR11 (UNIT_CR11) /* Default, but changable */ +#define DFLT_TYPE (UNIT_CR11) /* Default, but changable */ #define DFLT_CPM 285 +#define CD20_OK (1) +#define AIECO_OK (1) /* Augmented Image ECO optional */ +#define CR11_OK (1) +#define CD11_OK (1) #endif +/* **** No VM_xxx macros should be referenced after this line **** */ + /* create a int32 constant from four characters */ #define I4C(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) #define I4C_CBN I4C ('C','B','N',' ') @@ -203,10 +236,46 @@ extern int32 int_req[IPL_HLVL]; #define I4C_H82 I4C ('H','8','2',' ') #define I4C_H40 I4C ('H','4','0',' ') -#define UNIT_V_CR11 (UNIT_V_UF + 0) -#define UNIT_CR11 (1u << UNIT_V_CR11) -#define UNIT_V_AUTOEOF (UNIT_V_UF + 1) +#define UNIT_V_TYPE (UNIT_V_UF + 0) /* Bit-encoded 2-bit field */ +#define UNIT_TYPE (3u << UNIT_V_TYPE) +#define UNIT_CR11 (1u << UNIT_V_TYPE) +#define UNIT_CD20 (2u << UNIT_V_TYPE) + +#define UNIT_V_AUTOEOF (UNIT_V_UF + 2) #define UNIT_AUTOEOF (1u << UNIT_V_AUTOEOF) +#define UNIT_V_RDCHECK (UNIT_V_UF + 3) +#define UNIT_RDCHECK (1u << UNIT_V_RDCHECK) +#define UNIT_V_AIECO (UNIT_V_UF + 4) +#define UNIT_AIECO (1u << UNIT_V_AIECO) + +/* Tests for which device is being emulated. + * Note that CD20 is a CD11 + mandatory ECOs. CD11_CTL will be true for both. + */ +#if defined (CD11_ONLY) || defined (CD20_ONLY) +#define CR11_CTL(up) (0) +#define CD11_CTL(up) (1) +#elif defined (CR11_ONLY) +#define CR11_CTL(up) (1) +#define CD11_CTL(up) (0) +#else +#define CR11_CTL(up) ((up)->flags & UNIT_CR11) +#define CD11_CTL(up) (!CR11_CTL(up)) +#endif + +#if defined (CD20_ONLY) +#define CD20_CTL(up) (1) +#elif defined (CD20_OK) +#define CD20_CTL(up) ((up)->flags & UNIT_CD20) +#else +#define CD20_CTL(up) (0) +#endif + +/* Configuration */ +#if defined (AIECO_REQ) +#define DFLT_AIECO (UNIT_AIECO) +#else +#define DFLT_AIECO (0) +#endif #include #define ERROR (00404) @@ -254,19 +323,22 @@ extern int32 int_req[IPL_HLVL]; /* CD */ /* also use CSR_ERR, CSR_IE, and CSR_GO */ -#define CDCSR_V_RDRCHK 14 /* reader check */ +/* ERR */ +#define CDCSR_V_RDRCHK 14 /* reader check: HOPPER,STACK,PICK,READ */ #define CDCSR_V_EOF 13 /* CD11-E EOF button */ #define CDCSR_V_OFFLINE 12 /* off line */ -#define CDCSR_V_DATAERR 11 /* data error */ +#define CDCSR_V_DATAERR 11 /* data packing error */ #define CDCSR_V_LATE 10 /* data late */ #define CDCSR_V_NXM 9 /* non-existent memory */ #define CDCSR_V_PWRCLR 8 /* power clear */ #define CDCSR_V_RDY 7 /* ready */ -#define CDCSR_V_XBA17 5 +/* IE */ +#define CDCSR_V_XBA17 5 /* NPR bus address bits<17:16> */ #define CDCSR_V_XBA16 4 #define CDCSR_V_ONLINE 3 /* on line transition */ #define CDCSR_V_HOPPER 2 /* hopper check */ #define CDCSR_V_PACK 1 /* data packing */ +/* GO */ #define CDCSR_RDRCHK (1u << CDCSR_V_RDRCHK) #define CDCSR_EOF (1u << CDCSR_V_EOF) @@ -282,6 +354,8 @@ extern int32 int_req[IPL_HLVL]; #define CDCSR_HOPPER (1u << CDCSR_V_HOPPER) #define CDCSR_PACK (1u << CDCSR_V_PACK) +#define CDCSR_ANYERR (CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM) + #define CDCSR_IMP (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | \ CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | \ CDCSR_PWRCLR | CDCSR_RDY | CSR_IE | \ @@ -291,6 +365,23 @@ extern int32 int_req[IPL_HLVL]; #define CDCSR_RW (CDCSR_PWRCLR | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | \ CDCSR_PACK | CSR_GO) +/* CD11 second status register bits. Valid only when not busy. All + * also set CDCSR_RDRCK (and CSR_ERR) + */ + +#define CDDB_V_READ 14 /* Read check (extra punches, not readER check) */ +#define CDDB_V_PICK 13 /* Pick check (card present, not grabbed) */ +#define CDDB_V_STACK 12 /* Card did not arrive in stacker */ + +/* N.B. Per TOPS-20 driver, which references CD11 manual and printset: + * Stacker full is indicated by: + * CDCSR_RDRCHK && !(CDDB_READ|CDDB_PICK|CDDB_STACK) + */ +#define CDDB_READ (1U << CDDB_V_READ) +#define CDDB_PICK (1u << CDDB_V_PICK) +#define CDDB_STACK (1u << CDDB_V_STACK) + + /* Blower state values */ #define BLOW_OFF (0) /* steady state off */ #define BLOW_START (1) /* starting up */ @@ -299,32 +390,53 @@ extern int32 int_req[IPL_HLVL]; /* Card Reader state */ static char *cardFormat = "unknown"; -static t_bool (*readRtn)(FILE *, int16 *, char *, char *); +static t_bool (*readRtn)(UNIT *, int16 *, char *, char *); static char ascii_code[4096]; /* 2^12 possible values */ static int currCol; /* current column when reading */ static int colStart; /* starting column */ static int colEnd; /* ending column */ -static int table = 3; /* character translation table */ -static const int *codeTbl = o29_code; /* punch translation table */ +static const int *codeTbl = /* punch translation table */ +#if defined(CD20_ONLY) || (defined(DFLT_TYPE) && (DFLT_TYPE == UNIT_CD20)) + o29_decascii_code; +#else + o29_code; +#endif +static struct trans { + const char *const name; + const int *const table; +} transcodes[] = { + { "DEFAULT", o29_code, }, + { "026", o26_dec_code, }, + { "026FTN", o26_ftn_code, }, + { "026DECASCII", o26_decascii_code, }, + { "029", o29_code, }, + { "EBCDIC", EBCDIC_code, }, + { "026DEC", o26_dec_code, }, + { "029DECASCII", o29_decascii_code }, +}; +#define NTRANS (sizeof transcodes /sizeof transcodes[0]) + static int32 blowerState = BLOW_OFF; /* reader vacuum/blower motor */ -static int32 spinUp = 3000; /* blower spin-up time: 3 seconds */ -static int32 spinDown = 2000; /* blower spin-down time: 2 seconds */ -static t_bool EOFcard = FALSE; /* played special card yet? */ +static int32 spinUp = 3000000; /* blower spin-up time: 3 seconds (usec) */ +static int32 spinDown = 2000000; /* blower spin-down time: 2 seconds (usec) */ +static int EOFcard = 0; /* played special card yet? */ +static t_bool eofPending = FALSE; /* Manual EOF switch pressed */ static int32 cpm = DFLT_CPM; /* reader rate: cards per minute */ /* card image in various formats */ static int16 hcard[82]; /* Hollerith format */ static char ccard[82]; /* DEC compressed format */ static char acard[82]; /* ASCII format */ /* CR/CM registers */ -static int32 crs = 0; /* control/status */ +static int32 crs = CSR_ERR | CRCSR_OFFLINE | CRCSR_SUPPLY; /* control/status */ static int32 crb1 = 0; /* 12-bit Hollerith characters */ static int32 crb2 = 0; /* 8-bit compressed characters */ static int32 crm = 0; /* CMS maintenance register */ /* CD registers */ -static int32 cdst = 0; /* control/status */ +static int32 cdst = CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER; /* Control/status - off-line until attached */ static int32 cdcc = 0; /* column count */ static int32 cdba = 0; /* current address, low 16 bits */ static int32 cddb = 0; /* data, 2nd status */ +static int32 cddbs = 0; /* second status bits (or with cddb) */ /* forward references */ DEVICE cr_dev; @@ -336,11 +448,14 @@ t_stat cr_reset (DEVICE *); t_stat cr_attach (UNIT *, char *); t_stat cr_detach (UNIT *); t_stat cr_set_type (UNIT *, int32, char *, void *); +t_stat cr_set_aieco (UNIT *, int32, char *, void *); t_stat cr_show_format (FILE *, UNIT *, int32, void *); t_stat cr_set_rate (UNIT *, int32, char *, void *); t_stat cr_show_rate (FILE *, UNIT *, int32, void *); t_stat cr_set_reset (UNIT *, int32, char *, void *); t_stat cr_set_stop (UNIT *, int32, char *, void *); +t_stat cr_set_eof (UNIT *, int32, char *, void *); +t_stat cr_show_eof (FILE *, UNIT *, int32, void *); t_stat cr_set_trans (UNIT *, int32, char*, void *); t_stat cr_show_trans (FILE *, UNIT *, int32, void *); static t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); @@ -364,19 +479,23 @@ static DIB cr_dib = { IOBA_AUTO, IOLN_CR, &cr_rd, &cr_wr, static UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE+UNIT_DISABLE+ - DFLT_CR11+UNIT_AUTOEOF, 0), - (60 * 1000) / DFLT_CPM }; + DFLT_TYPE+UNIT_AUTOEOF+UNIT_RDCHECK+DFLT_AIECO, 0), + (60 * 1000000) / (DFLT_CPM * 80) }; static const REG cr_reg[] = { { GRDATAD (BUF, cr_unit.buf, DEV_RDX, 8, 0, "ASCII value of last column processed") }, +#if defined (CR11_OK) || defined (CR11_ONLY) { GRDATAD (CRS, crs, DEV_RDX, 16, 0, "CR11 status register") }, { GRDATAD (CRB1, crb1, DEV_RDX, 16, 0, "CR11 12-bit Hollerith character") }, { GRDATAD (CRB2, crb2, DEV_RDX, 16, 0, "CR11 8-bit compressed character") }, { GRDATAD (CRM, crm, DEV_RDX, 16, 0, "CR11 maintenance register") }, +#endif +#if defined (CD11_OK) || defined (CD11_ONLY) || defined (CD20_OK) || defined (CD20_ONLY) { GRDATAD (CDST, cdst, DEV_RDX, 16, 0, "CD11 control/status register") }, { GRDATAD (CDCC, cdcc, DEV_RDX, 16, 0, "CD11 column count") }, { GRDATAD (CDBA, cdba, DEV_RDX, 16, 0, "CD11 current bus address") }, { GRDATAD (CDDB, cddb, DEV_RDX, 16, 0, "CD11 data buffer, 2nd status") }, +#endif { GRDATAD (BLOWER, blowerState, DEV_RDX, 2, 0, "blower state value") }, { FLDATAD (INT, IREQ (CR), INT_V_CR, "interrupt pending flag") }, { FLDATAD (ERR, crs, CSR_V_ERR, "error flag (CRS<15>)") }, @@ -387,26 +506,52 @@ static const REG cr_reg[] = { { GRDATA (DEVVEC, cr_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } }; -static const MTAB cr_mod[] = { -#if defined (VM_PDP11) - { UNIT_CR11, UNIT_CR11, "CR11", "CR11", +static char *translation_help = NULL; +static MTAB cr_mod[] = { +#if defined (CR11_OK) + { UNIT_TYPE, UNIT_CR11, "CR11", "CR11", &cr_set_type, NULL, NULL, "Set device type to CR11" }, - { UNIT_CR11, 0, "CD11", "CD11", +#endif +#if defined (CD11_OK) + { UNIT_TYPE, 0, "CD11", "CD11", &cr_set_type, NULL, NULL, "Set device type to CD11" }, -#else - { UNIT_CR11, UNIT_CR11, "CR11", NULL }, - { UNIT_CR11, 0, "CD11", NULL }, +#endif +#if defined (CD20_OK) + { UNIT_TYPE, UNIT_CD20, "CD20", "CD20", + &cr_set_type, NULL, NULL, "Set device type to CD20" }, +#endif +#if defined (CR11_ONLY) || defined (CD11_ONLY) || defined (CD20_ONLY) + { UNIT_TYPE, UNIT_CR11, "CR11", NULL, }, + { UNIT_TYPE, 0, "CD11", NULL, }, + { UNIT_TYPE, UNIT_CD20, "CD20", NULL, }, +#endif +#if defined (AIECO_OK) + { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|UNIT_AIECO), "augmented image ECO", "AIECO", + &cr_set_aieco, NULL, NULL, "Enable CD20 augmented image ECO" }, + { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|0), "standard", "NOAIECO", + &cr_set_aieco, NULL, NULL, "Disable CD20 augmented image ECO" }, #endif { UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", NULL, NULL, NULL, "Enable auto EOF mode" }, { UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", NULL, NULL, NULL, "Disable auto EOF mode" }, +#if !defined (CR11_ONLY) + { UNIT_RDCHECK, UNIT_RDCHECK, "read check", "RDCHECK", + NULL, NULL, NULL, "Enable read check errors" }, + { UNIT_RDCHECK, 0, "no read check", "NORDCHECK", + NULL, NULL, NULL, "Disable read check errors" }, +#endif + /* card reader STOP switch */ + { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP", + &cr_set_stop, NULL, NULL, "Pulse reader Stop button" }, /* card reader RESET switch */ { MTAB_XTD|MTAB_VDV, 0, NULL, "RESET", &cr_set_reset, NULL, NULL, "Pulse reader reset button" }, - /* card reader STOP switch */ - { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP", - &cr_set_stop, NULL, NULL, "Pulse reader Stop button" }, +#if !defined (CR11_ONLY) + /* card reader EOF switch */ + { MTAB_XTD|MTAB_VDV, MTAB_XTD|MTAB_VDV, "EOF pending", "EOF", + &cr_set_eof, &cr_show_eof, NULL, "Pulse reader EOF button" }, +#endif { MTAB_XTD|MTAB_VUN, 0, "FORMAT", NULL, NULL, &cr_show_format, NULL, "Set reader input format" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 006, "ADDRESS", "ADDRESS", @@ -416,7 +561,7 @@ static const MTAB cr_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "RATE", "RATE={DEFAULT|200..1200}", &cr_set_rate, &cr_show_rate, NULL, "Display input rate" }, { MTAB_XTD|MTAB_VDV, 0, "TRANSLATION", - "TRANSLATION={DEFAULT|026|026FTN|029|EBCDIC|026DEC}", + NULL, &cr_set_trans, &cr_show_trans, NULL, "Display translation mode" }, { 0 } }; @@ -443,6 +588,12 @@ TRUE if a card was read (possibly with errors) and FALSE if the "hopper is empty" (EOF) or fatal file errors prevented any portion of a card from being read. +Note that the hopper becomes empty when the last card moves to the +read station. Thus hopper empty without an error means that data +from that card is valid. Thus hopper empty is first signalled when +the NEXT card read would return EOF. Reads after that will return +some error bit. + Errors other than EOF are signaled out of band in the controller state variables. Possible errors are data in columns 0 or 81 (signalled as read check; currently these columns are ignored), or @@ -453,142 +604,143 @@ check". Retry 3 times. After that, give up with error. */ -static t_bool readCardImage ( FILE *fp, +/* Common handling for end of file and errors on input */ + +static t_bool fileEOF ( UNIT *uptr, + int16 *hcard, + char *ccard, + char *acard, + int32 cddbsBits ) +{ + int col; + + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "hopper empty\n"); + + if (!EOFcard && (uptr->flags & UNIT_AUTOEOF) && !ferror(uptr->fileref)) { + EOFcard = -1; + /* Generate EOD card, which empties the hopper */ + for (col = 1; col <= 8; col++) { + hcard[col] = PUNCH_EOD; + ccard[col] = h2c_code[PUNCH_EOD]; + acard[col] = ' '; + } + while (col <= colEnd) { + hcard[col] = PUNCH_SPACE; + ccard[col] = PUNCH_SPACE; + acard[col] = ' '; + col++; + } + /* The CR11 doesn't set SUPPPLY at this time, but waits until the EOF card is done. */ + cdst |= CDCSR_HOPPER; + return (TRUE); + } + /* Not auto EOF, or EOF already handled. This is an attempt to read + * with an empty hopper. Report a pick, read or stacker check as well + * as hopper empty to indicate that no data was transfered. One might + * think that cdcc unchanged would be sufficient, but that's not what + * the OSs check. + */ + + crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; + crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); + + cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; + cddbs |= cddbsBits; + + if (((uptr->flags & UNIT_AUTOEOF) || eofPending) && !ferror(uptr->fileref)) { + cdst |= CDCSR_EOF; + eofPending = FALSE; + } + return (FALSE); +} + +static t_bool readCardImage ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { int c1, c2, c3, col; + FILE *fp = uptr->fileref; if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "readCardImage pos %d\n", (int) ftell (fp)); - /* get card header bytes */ - c1 = fgetc (fp); - c2 = fgetc (fp); - c3 = fgetc (fp); - cr_unit.pos = ftell (fp); - /* check for EOF */ - if (c1 == EOF) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "hopper empty\n"); - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - return (TRUE); - } - crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - return (FALSE); - } - /* check for valid header */ - if ((c2 == EOF) || (c3 == EOF) || ((c1 & 0x80) == 0) || - ((c2 & 0x80) == 0) || ((c3 & 0x80) == 0)) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "header error\n"); - /* unexpected EOF or format problems */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } - assert (colStart < colEnd); - assert (colStart >= 0); - assert (colEnd <= 81); - for (col = colStart; col < colEnd; ) { - int16 i; - /* get 3 bytes */ + do { + /* get card header bytes */ c1 = fgetc (fp); c2 = fgetc (fp); c3 = fgetc (fp); - cr_unit.pos = ftell (fp); - if (ferror (fp) || feof (fp)) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "file error\n"); -/* signal error; unexpected EOF, format problems, or file error(s) */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } - /* convert to 2 columns */ - i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; - hcard[col] = i; - ccard[col] = h2c_code[i]; - acard[col] = ascii_code[i]; - col++; + uptr->pos = ftell (fp); + /* check for EOF */ + if (c1 == EOF) + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); + + /* check for valid card header */ + if ((c2 == EOF) || (c3 == EOF) || ((c1 & c2 & c3 & 0x80) == 0) ) { + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "header error\n"); + /* unexpected EOF or format problems */ + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); + } + + /* Read card image into internal buffer */ + + assert (colStart < colEnd); + assert (colStart >= 0); + assert (colEnd <= 81); + for (col = colStart; col < colEnd; ) { + int16 i; + int c1, c2, c3; + /* get 3 bytes */ + c1 = fgetc (fp); + c2 = fgetc (fp); + c3 = fgetc (fp); + uptr->pos = ftell (fp); + if (ferror (fp) || (c1 == EOF) || (c2 == EOF) || (c3 == EOF)) { + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "file error\n"); + /* signal error; unexpected EOF, format problems, or file error(s) */ + return fileEOF (uptr, hcard, ccard, acard, ferror(fp)? CDDB_READ: CDDB_PICK); + } + /* convert to 2 columns */ + i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; + hcard[col] = i; + ccard[col] = h2c_code[i]; + acard[col] = ascii_code[i]; + col++; + + i = (((c2 & 017) << 8) | c3) & 0xFFF; + hcard[col] = i; + ccard[col] = h2c_code[i]; + acard[col] = ascii_code[i]; + col++; + } + } while ((c3 & 0x3f) == 0x3f); /* Skip metacards (Revised Jones spec) */ - i = (((c2 & 017) << 8) | c3) & 0xFFF; - hcard[col] = i; - ccard[col] = h2c_code[i]; - acard[col] = ascii_code[i]; - col++; - } if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "successfully loaded card\n"); return (TRUE); } -static t_bool readColumnBinary ( FILE *fp, +static t_bool readColumnBinary ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { int col; + FILE *fp = uptr->fileref; for (col = colStart; col <= colEnd; col++) { - int16 i; - i = fgetc (fp) & 077; - i |= ((fgetc (fp) & 077) << 6); - cr_unit.pos = ftell (fp); - if (feof (fp)) { - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - return (TRUE); - } - crs |= CSR_ERR | CRCSR_SUPPLY | - CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - return (FALSE); - } - if (ferror (fp)) { - /* signal error */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } + int c1, c2; + uint16 i; + c1 = fgetc (fp); + c2 = fgetc (fp); + uptr->pos = ftell (fp); + if (c1 == EOF) + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); + if ((c2 == EOF) || ferror(fp)) + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); + i = (c1 & 077) | ((c2 & 077) << 6); hcard[col] = i; ccard[col] = h2c_code[i]; acard[col] = ascii_code[i]; @@ -600,16 +752,17 @@ static t_bool readColumnBinary ( FILE *fp, Should this routine perform special handling of non-printable, (e.g., control) characters or characters that have no encoded -representation? +representation? (In DEC026/DEC029 they all do...) */ -static t_bool readCardASCII ( FILE *fp, +static t_bool readCardASCII ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { - int c = 0, col; + int c = 0, col, peek; + FILE *fp = uptr->fileref; assert (colStart < colEnd); assert (colStart >= 1); @@ -621,40 +774,26 @@ static t_bool readCardASCII ( FILE *fp, switch (c = fgetc (fp)) { case EOF: if (ferror (fp)) { - /* signal error */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - cr_unit.pos = ftell (fp); - return (FALSE); + uptr->pos = ftell (fp); + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); } if (col == colStart) { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "hopper empty\n"); - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - c = '\n'; - goto fill_card; - } - crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - cr_unit.pos = ftell (fp); - return (FALSE); + uptr->pos = ftell (fp); + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); } /* fall through */ case '\r': + peek = fgetc (uptr->fileref); + if ((peek != EOF) && (peek != '\n')) + ungetc (peek, uptr->fileref); + goto fill; case '\n': - fill_card: + peek = fgetc (uptr->fileref); + if ((peek != EOF) && (peek != '\r')) + ungetc (peek, uptr->fileref); + fill: while (col <= colEnd) { hcard[col] = PUNCH_SPACE; ccard[col] = PUNCH_SPACE; @@ -678,7 +817,7 @@ static t_bool readCardASCII ( FILE *fp, if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "error character at column %d (%c)\n", - col, c & 0177); + col, c & 0177); } ccard[col] = h2c_code[hcard[col]]; acard[col] = c; @@ -690,12 +829,22 @@ static t_bool readCardASCII ( FILE *fp, if (c != '\n' && c != '\r') { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "truncating card\n"); - do c = fgetc (fp); - while ((c != EOF) && (c != '\n') && (c != '\r')); + c = fgetc (fp); + while (c != EOF) { + if ((c == '\n') || (c == '\r')) { + peek = fgetc (uptr->fileref); + if (peek == EOF) + break; + if (((c == '\n') && (peek != '\r')) || ((c == '\r') && (peek != '\n'))) + ungetc (peek, uptr->fileref); + break; + } + c = fgetc (fp); + } } if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "successfully loaded card\n"); - cr_unit.pos = ftell (fp); + uptr->pos = ftell (fp); return (TRUE); } @@ -711,39 +860,8 @@ static void initTranslation (void) int32 i; memset (ascii_code, '~', sizeof (ascii_code)); - switch (table) { - case 1: - codeTbl = o26_comm_code; - for (i = ' '; i < '`'; i++) - ascii_code[o26_comm_code[i]] = i; - break; - case 2: - codeTbl = o26_ftn_code; - for (i = ' '; i < '`'; i++) - ascii_code[o26_ftn_code[i]] = i; - break; - case 3: - codeTbl = o29_code; - for (i = ' '; i < '`'; i++) - ascii_code[o29_code[i]] = i; - break; - case 4: - codeTbl = EBCDIC_code; - for (i = 0; i < 0177; i++) - ascii_code[EBCDIC_code[i]] = i; - break; - case 5: - codeTbl = o26_dec_code; - for (i = 0; i < 0177; i++) - ascii_code[EBCDIC_code[i]] = i; - break; - default: - /* can't happen */ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, - "bad CR translation initialization value\n"); - break; - } + for (i = 0; i < 0177; i++) + ascii_code[codeTbl[i]] = i; } /* @@ -833,11 +951,11 @@ t_stat cr_rd ( int32 *data, { switch ((PA >> 1) & 03) { case 0: /* CSR */ - if (cdst & (077000)) + if (cdst & (CDCSR_ANYERR)) cdst |= CSR_ERR; else cdst &= ~CSR_ERR; - *data = (cr_unit.flags & UNIT_CR11) ? + *data = (CR11_CTL(&cr_unit)) ? crs & CRCSR_IMP : cdst & CDCSR_IMP; /* CR: if error removed, clear 15, 14, 11, 10 */ if (DEBUG_PRS (cr_dev)) @@ -845,11 +963,11 @@ t_stat cr_rd ( int32 *data, crs, cdst); break; case 1: - /* Get word of data from crb1 (Hollerith code) */ - *data = (cr_unit.flags & UNIT_CR11) ? crb1 : cdcc; + /* Get word of data from crb1 (Hollerith code) or CD11 CC */ + *data = (CR11_CTL(&cr_unit)) ? crb1 : cdcc; crs &= ~CRCSR_COLRDY; if (DEBUG_PRS (cr_dev)) { - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) fprintf (sim_deb, "cr_rd crb1 %06o '%c' %d\n", crb1, cr_unit.buf, cr_unit.buf); else @@ -859,11 +977,11 @@ t_stat cr_rd ( int32 *data, crb1 = 0; break; case 2: - /* Get word of data from crb2 (DEC Compressed) */ - *data = (cr_unit.flags & UNIT_CR11) ? crb2 : cdba; + /* Get word of data from crb2 (DEC Compressed) or CD11 BA */ + *data = (CR11_CTL(&cr_unit)) ? crb2 : cdba; crs &= ~CRCSR_COLRDY; if (DEBUG_PRS (cr_dev)) { - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) fprintf (sim_deb, "cr_rd crb2 %06o\n", crb2); else fprintf (sim_deb, "\r\ncr_rd cdba %06o\n", cdba); @@ -872,12 +990,14 @@ t_stat cr_rd ( int32 *data, break; case 3: default: - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) /* CR11 maintenance */ *data = crm; - else - *data = 0100000 | (cdst & CDCSR_RDRCHK) | - (cdst & CDCSR_OFFLINE) ? - cddb & 0777 : 0777; + else /* CD11 data buffer/status. Note this implementation returns extended + * status even while busy (rather than the zone). Might be wrong. + */ + *data = 0100000 | (cddbs & (CDDB_READ|CDDB_PICK|CDDB_STACK)) | + ((crs & CRCSR_BUSY) ? + cddb & 0777 : 0777); if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_rd crm %06o cddb %06o data %06o\n", crm, cddb, *data); @@ -892,7 +1012,7 @@ t_stat cr_wr ( int32 data, { switch ((PA >> 1) & 03) { case 0: - if (cr_unit.flags & UNIT_CR11) { + if (CR11_CTL(&cr_unit)) { /* ignore high-byte writes */ if (PA & 1) break; @@ -902,66 +1022,107 @@ t_stat cr_wr ( int32 data, if (!(data & CSR_IE)) CLR_INT (CR); crs = (crs & ~CRCSR_RW) | (data & CRCSR_RW); - /* Clear status bits after CSR load */ + /* Clear status bits after CSR load */ crs &= ~(CSR_ERR | CRCSR_ONLINE | CRCSR_CRDDONE | CRCSR_TIMERR); + if (crs & CRCSR_OFFLINE) + crs |= CSR_ERR; if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr data %06o crs %06o\n", data, crs); if (data & CSR_GO) { if (blowerState != BLOW_ON) { blowerState = BLOW_START; - sim_activate (&cr_unit, spinUp); + sim_activate_after (&cr_unit, spinUp); } else { - sim_activate (&cr_unit, cr_unit.wait); - } + sim_activate_after (&cr_unit, cr_unit.wait); + } } - } else { + } else { /* CD11 */ + if (access == WRITEB) + data = (PA & 1)? (((data & 0xff)<<8) | (cdst & 0x00ff)): + ((data & 0x00ff) | (cdst & 0xFF00)); + if (data & CDCSR_PWRCLR) { CLR_INT (CR); sim_cancel (&cr_unit); - cdst &= ~(CDCSR_RDRCHK |CDCSR_OFFLINE | - CDCSR_RDY | CDCSR_HOPPER); - cdst |= CDCSR_RDY; cdcc = 0; cdba = 0; + cddb = 0; + cddbs = 0; + if (!(cr_unit.flags & UNIT_ATT)) { /* Clear troublesome bits, but leave error/offline */ + cdst &= ~(CSR_IE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | + CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK); + cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK; + cddbs |= CDDB_STACK; + break; + } + + crs &= ~CRCSR_BUSY; + cdst &= (CDCSR_OFFLINE | CDCSR_RDY | CDCSR_HOPPER); + if( (cr_unit.flags & UNIT_ATT) && !feof(cr_unit.fileref) && !ferror(cr_unit.fileref) ) + cdst &= ~(CDCSR_HOPPER); + if (cdst & (CDCSR_ANYERR)) + cdst |= CSR_ERR; + cdst |= CDCSR_RDY; break; } - if (!(data & CSR_IE)) + + if (data & CSR_GO) { + /* To simplify the service code, don't start if CDCC == 0. + * In the hardware, it's not sensible... + */ + if ((crs & CRCSR_BUSY) || (cdcc == 0)) { + cdst |= (CDCSR_RDRCHK | CDCSR_HOPPER | CSR_ERR); + } else { + cdst &= ~(CDCSR_RDRCHK | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | CDCSR_ONLINE); + cdst = (cdst & ~(CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK | CDCSR_HOPPER)) + | (data & (CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK)); + cddbs &= ~(CDDB_READ|CDDB_PICK|CDDB_STACK); + + /* Always attempt to start. If not attached, errors will set after delay */ + if (!(cdst & CDCSR_HOPPER) ) + cdst &= ~(CSR_ERR); + if (blowerState != BLOW_ON) { + blowerState = BLOW_START; + sim_activate_after (&cr_unit, spinUp); + } else { + sim_activate_after (&cr_unit, cr_unit.wait); + } + } + } else { + cdst = (cdst & ~(CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | + CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)) + |(data & (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | + CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)); + } + /* Apparently the hardware does not SET_INT if ready/online are already set. If it did, TOPS-10's driver wouldn't work */ + if (!(cdst & CSR_IE)) CLR_INT (CR); - cdst = (cdst & ~CDCSR_RW) | (data & CDCSR_RW); + if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr data %06o cdst %06o\n", data, cdst); - if (data & CSR_GO) { - if (blowerState != BLOW_ON) { - sim_activate (&cr_unit, spinUp); - blowerState = BLOW_START; - } else { - sim_activate (&cr_unit, cr_unit.wait); - } - } } break; case 1: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr cdcc %06o\n", data); - if (cr_unit.flags & UNIT_CR11) - break; - cdcc = data & 0177777; + if (CD11_CTL(&cr_unit)) + cdcc = data & 0177777; break; case 2: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr crba %06o\n", data); - if (cr_unit.flags & UNIT_CR11) - break; - cdba = data & 0177777; + if (CD11_CTL(&cr_unit)) + cdba = data & 0177777; break; case 3: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr cddb/crm %06o\n", data); /* ignore writes to cddb */ - if (!(cr_unit.flags & UNIT_CR11)) + if (CD11_CTL(&cr_unit)) break; + /* fixup data for byte writes and read-modify-write */ if (access == WRITEB) data = (PA & 1) ? @@ -996,7 +1157,8 @@ t_stat cr_svc ( UNIT *uptr ) { uint32 pa; uint8 c; - uint16 w; + uint16 w; + int n; /* Blower stopping: set it to OFF and do nothing */ if (blowerState == BLOW_STOP) { @@ -1007,45 +1169,120 @@ t_stat cr_svc ( UNIT *uptr ) if (blowerState == BLOW_START) blowerState = BLOW_ON; - /* (almost) anything we do now will cause a CR interrupt */ - if (crs & CSR_IE) + /* (almost) anything we do now will cause a CR (But not a CD) interrupt */ + if ((CR11_CTL(uptr)) && (crs & CSR_IE)) SET_INT (CR); - /* Unit not attached, or error status => do nothing */ - if (!(uptr->flags & UNIT_ATT) || (crs & CSR_ERR) || (cdst & CSR_ERR)) + /* Unit not attached, or error status while idle */ + if (!(uptr->flags & UNIT_ATT) || (!(crs & CRCSR_BUSY) && ((CR11_CTL(uptr)?crs : cdst) & CSR_ERR))) { + if (CD11_CTL(uptr)) { + if (!(uptr->flags & UNIT_ATT)){ + cdst |= (CDCSR_HOPPER | CDCSR_RDRCHK | CDCSR_OFFLINE | CSR_ERR); + cddbs |= CDDB_STACK; + } + if (cdst & CSR_IE) + SET_INT (CR); + } return (SCPE_OK); + } /* End of card: unit busy and column past end column */ if ((crs & CRCSR_BUSY) && (currCol > colEnd)) { /* clear busy state and set card done bit */ - crs &= ~(CRCSR_BUSY | CSR_GO | CRCSR_COLRDY); + crs &= ~(CRCSR_BUSY | CRCSR_COLRDY); crs |= CRCSR_CRDDONE; - /* Check CD11 error status */ - if (cdst & (CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM)) - cdst |= CSR_ERR; - if (DEBUG_PRS (cr_dev)) + + if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_svc card done\n"); - return (SCPE_OK); + + /* Check CD11 error status that stops transfers */ + if (CD11_CTL(uptr) && (cdst & (CDCSR_LATE | CDCSR_NXM))) { + cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDY | CDCSR_RDRCHK; + SET_INT (CR); + return (SCPE_OK); + } + + if (CR11_CTL(uptr)) + return (SCPE_OK); + + /* If a CD11 gets this far, an interrupt is required. If CDCC != 0, + * continue reading the next card. + */ + SET_INT (CR); + if (cdcc == 0) + return (SCPE_OK); } - /* Unit not busy: try to read a card */ + /* If unit is not busy: try to read a card */ if (!(crs & CRCSR_BUSY)) { crs &= ~CRCSR_CRDDONE; /* This line WAS commented out - JGP 2013.02.05 */ - /* Call the appropriate read card routine. */ - /* If no card is read (FALSE return), stop the show */ - if (!readRtn (uptr->fileref, hcard, ccard, acard)) { - blowerState = BLOW_STOP; - sim_activate (uptr, spinDown); + + /* Call the appropriate read card routine. + * If no card is read (FALSE return), we tried to read with an empty hopper. + * The card read routine set the appropriate error bits. Shutdown. + */ + if (!readRtn (uptr, hcard, ccard, acard)) { + if (CD11_CTL(uptr)) { +readFault: + blowerState = BLOW_STOP; + cdst |= CDCSR_RDY; + if (cdst & (CDCSR_RDRCHK | CDCSR_HOPPER)) + cdst |= CSR_ERR | CDCSR_OFFLINE; + if (cdst & CSR_IE) + SET_INT (CR); + } + sim_activate_after (uptr, spinDown); return (SCPE_OK); - } else { - /* Card read: reset column counter and assert BUSY */ - currCol = colStart; - crs |= CRCSR_BUSY; + } + + /* Card read: reset column counter and assert BUSY */ + currCol = colStart; + crs |= CRCSR_BUSY; + + /* Update status if this read emptied hopper. + * The CR11 doesn't set SUPPLY until after the last card is read. + */ + + /* I/O error status bits have been set during read. + * Look ahead to see if another card is in file. + */ + n = feof (uptr->fileref); + if (n) + n = EOF; + else { + n = fgetc (uptr->fileref); + if (n != EOF) + ungetc (n, uptr->fileref); + } + + if ((n == EOF) && ((EOFcard > 0) || !(uptr->flags & UNIT_AUTOEOF))) { + /* EOF and generated EOFcard sent or not an autoEOF unit. + * Set status to reflect last card taken. + */ + cdst |= (CDCSR_RDRCHK | CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER); + if (eofPending) { + cdst |= CDCSR_EOF; + eofPending = FALSE; + } + } + if (EOFcard) + EOFcard = 1; + + if (CD11_CTL(uptr)) { + /* Handle read check: punches in col 0 or 81/last (DEC only did 80 cols, but...) */ + if ((uptr->flags & UNIT_RDCHECK) && + (((colStart == 0) && (hcard[0] != 0)) || ((colEnd & 1) && (hcard[colEnd] != 0)))) { + cdst |= (CDCSR_RDRCHK | CSR_ERR); + cddbs |= CDDB_READ; + if (1) /* 0 if read check should transfer card */ + goto readFault; + } + /* CDDB_PICK, CDDB_STACK, flags & UNIT_CR11) && (crs & CRCSR_COLRDY)) + if (CR11_CTL(uptr) && (crs & CRCSR_COLRDY)) crs |= CSR_ERR | CRCSR_TIMERR; /* Update the "buffer" registers with current column */ @@ -1054,7 +1291,7 @@ t_stat cr_svc ( UNIT *uptr ) uptr->buf = acard[currCol] & 0377; /* Helpful for debug: ASCII value */ /* CD11 specific code follows */ - if (!(uptr->flags & UNIT_CR11)) { + if (CD11_CTL(uptr)) { pa = cdba | ((cdst & 060) << 12); /* The implementation of _NXM here is not quite the same as I interpret @@ -1067,38 +1304,61 @@ code detects and flags the NXM condition but allows attempts at subsequent memory writes, thus insuring the address registers are incremented properly. If this causes problems, I'll fix it. */ - if (cdst & CDCSR_PACK) { + if (cdst & CDCSR_PACK) c = cddb = ccard[currCol] & 0377; - if (Map_WriteB (pa, 1, &c)) - cdst |= CDCSR_NXM; - pa = (pa + 1) & 0777777; - } else { - w = cddb = hcard[currCol] & 07777; - if (Map_WriteW (pa, 2, &w)) - cdst |= CDCSR_NXM; - pa = (pa + 2) & 0777777; + else + w = cddb = hcard[currCol] & 07777; /* Punched zones: <12><11><0><1><2><3><4><5><6><7><8><9> */ + + if (cdcc == 0) /* Transfer requires CC non-zero */ + cdst |= CDCSR_LATE; + else { + if (cdst & CDCSR_PACK) { + if (Map_WriteB (pa, 1, &c)) + cdst |= CDCSR_NXM; + pa = (pa + 1) & 0777777; + } else { + /* "Augmented Image" - provides full column binary and packed encoding in 15 bits. + * Bits <14:12> encode which zone, if any, of 1-7 is punched. 0 => none, otherwise zone #. + * Bit 15 set indicates that more than one punch occured in zones 1-7; in this case the packed + * encoding is not valid. (Card may be binary data.) + * This was probably an ECO to the CD11. TOPS-10/20 depend on it, so it's definitely in the CD20. + */ + if (uptr->flags & UNIT_AIECO) { + uint16 z; + w |= ((ccard[currCol] & 07) << 12); /* Encode zones 1..7 - same as 'packed' format */ + z = w & 0774; + if ((z & -z) != z) /* More than one punch in 1..7 */ + w |= 0100000; /* sets Hollerith (encoding) failure (not an error) */ + } + if (Map_WriteW (pa, 2, &w)) + cdst |= CDCSR_NXM; + pa = (pa + 2) & 0777777; + } + cdba = pa & 0177777; + cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) | + ((pa & 0600000) >> 12); + cdcc = (cdcc + 1) & 0177777; + /* Interrupt at end of buffer; read continues to end of card. + * If this is the last column, defer interrupt so end doesn't interrupt again. + */ + if ((cdcc == 0) && (cdst & CSR_IE) && (currCol < colEnd)) + SET_INT (CR); } - cdba = pa & 0177777; - cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) | - ((pa & 0600000) >> 12); - cdcc = (cdcc + 1) & 0177777; -#if 0 - if (!(cdst & CSR_IE) && !(crs & CRCSR_CRDDONE)) + } else { /* CR11 */ + /* Handle EJECT bit: if set DO NOT assert COLRDY */ + /* nor interrupt */ + if ((crs & CRCSR_EJECT)) { CLR_INT (CR); -#endif + } else { + crs |= CRCSR_COLRDY; + } } - + /* CD11 and CR11 */ currCol++; /* advance the column counter */ - /* Handle EJECT bit: if set DO NOT assert COLRDY */ - /* nor interrupt */ - if (!(crs & CRCSR_EJECT)) { - crs |= CRCSR_COLRDY; - } else { - CLR_INT (CR); - } + /* Schedule next service cycle */ - sim_activate (uptr, uptr->wait); + sim_activate_after (uptr, uptr->wait); return (SCPE_OK); } @@ -1106,10 +1366,33 @@ t_stat cr_reset ( DEVICE *dptr ) { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_reset\n"); + + if (!translation_help) { + int i; + const char trans_hlp[] = "TRANSLATION={"; + size_t size = sizeof(trans_hlp) +1; + + for ( i = 0; i < NTRANS; i++ ) + size += strlen (transcodes[i].name)+1; + translation_help = (char *)malloc (size ); + strcpy(translation_help, trans_hlp); + for (i = 0; i < NTRANS; i++) { + strcat(translation_help, transcodes[i].name); + strcat(translation_help,"|"); + } + strcpy(translation_help+strlen(translation_help)-1, "}"); + for (i = 0; i < (sizeof cr_mod / sizeof cr_mod[0]); i++ ) + if (cr_mod[i].pstring && !strcmp(cr_mod[i].pstring, "TRANSLATION")) { + cr_mod[i].mstring = translation_help; + break; + } + } cr_unit.buf = 0; currCol = 1; crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_TIMERR|CRCSR_ONLINE|CRCSR_BUSY| CRCSR_COLRDY|CSR_IE|CRCSR_EJECT|CSR_GO); + if (crs & (CRCSR_OFFLINE)) + crs |= CSR_ERR; crb1 = 0; crb2 = 0; crm = 0; @@ -1117,23 +1400,31 @@ t_stat cr_reset ( DEVICE *dptr ) CDCSR_NXM|CSR_IE|CDCSR_XBA17|CDCSR_XBA16|CDCSR_ONLINE| CDCSR_PACK|CSR_GO); cdst |= CDCSR_RDY; + if (cdst & CDCSR_ANYERR) + cdst |= CSR_ERR; cdcc = 0; cdba = 0; cddb = 0; + /* ATTACHed doesn't mean ONLINE; set CR reset (pushing the reset switch) + * is what puts the reader on-line. Reset doesn't control fingers. + */ if ((cr_unit.flags & UNIT_ATT) && !feof (cr_unit.fileref)) { - crs |= CRCSR_ONLINE; /* non-standard */ - crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE); + if (!(crs & CRCSR_OFFLINE)) + crs |= CRCSR_ONLINE; /* non-standard */ + crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY ); cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER); + cddbs = 0; } else { cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - crs = CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE; + cddbs |= CDDB_STACK; + crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY; } sim_cancel (&cr_unit); /* deactivate unit */ if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; - sim_activate (&cr_unit, spinDown); + sim_activate_after (&cr_unit, spinDown); } - EOFcard = FALSE; + EOFcard = 0; CLR_INT (CR); /* TBD: flush current card */ /* init uptr->wait ? */ @@ -1166,20 +1457,6 @@ t_stat cr_attach ( UNIT *uptr, setupCardFile(uptr, sim_switches); } - /* Old code, with status bit changes */ - /* - if (!(uptr->flags & UNIT_ATT)) { - crs &= ~CRCSR_ONLINE; - crs |= CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY; - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - } else { - setupCardFile (uptr, sim_switches); - crs |= CRCSR_ONLINE; - crs &= ~(CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY); - cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER); - EOFcard = FALSE; - } - */ return (reason); } @@ -1193,11 +1470,12 @@ t_stat cr_detach ( UNIT *uptr ) cardFormat = "unknown"; if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; - sim_activate (uptr, spinDown); + sim_activate_after (uptr, spinDown); } return (detach_unit (uptr)); } +#if defined (CR11_OK) || defined (CD11_OK) || defined (CD20_OK) t_stat cr_set_type ( UNIT *uptr, int32 val, char *cptr, @@ -1206,19 +1484,40 @@ t_stat cr_set_type ( UNIT *uptr, DEVICE *dptr = find_dev_from_unit (uptr); /* disallow type change if currently attached */ + if (uptr->flags & UNIT_ATT) return (SCPE_NOFNC); if (val == UNIT_CR11) { dptr->flags |= DEV_QBUS; /* Can be a Qbus device - programmed I/O only */ - } else { /* CD11 is 18bit DMA device */ + } else { /* CD11/CD20 are 18bit DMA devices */ if (!UNIBUS) return SCPE_NOFNC; dptr->flags &= ~DEV_QBUS; /* Not on a Qbus (22bit) */ } - cpm = (val & UNIT_CR11) ? 285 : 1000; - uptr->wait = (60 * 1000) / cpm; + cpm = (val & UNIT_CR11) ? 285 : ((val & UNIT_CD20)? 1200 :1000); + uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. + * Readers are rated in card/min for 80 column cards */ + transcodes[0].table = (val & UNIT_CD20)? o29_decascii_code : o29_code; + return (SCPE_OK); } +#endif + +#if defined (AIECO_OK) +t_stat cr_set_aieco ( UNIT *uptr, + int32 val, + char *cptr, + void *desc ) +{ + /* disallow eco change if currently attached or not CD20 */ + + if (uptr->flags & UNIT_ATT || !CD20_CTL(uptr)) + return (SCPE_NOFNC); + + uptr->flags = (uptr->flags & ~UNIT_AIECO) | (val & UNIT_AIECO); + return (SCPE_OK); +} +#endif t_stat cr_show_format ( FILE *st, UNIT *uptr, @@ -1240,7 +1539,7 @@ t_stat cr_set_rate ( UNIT *uptr, if (!cptr) return (SCPE_MISVAL); if (strcmp (cptr, "DEFAULT") == 0) - i = (uptr->flags & UNIT_CR11) ? 285 : 1000; + i = CR11_CTL(uptr) ? 285 : (CD20_CTL(uptr)? 1200 :1000); else i = (int32) get_uint (cptr, 10, 0xFFFFFFFF, &status); if (status == SCPE_OK) { @@ -1248,7 +1547,8 @@ t_stat cr_set_rate ( UNIT *uptr, status = SCPE_ARG; else { cpm = i; - uptr->wait = (60 * 1000) / cpm; + uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. + * Readers are rated in card/min for 80 column cards */ } } return (status); @@ -1266,6 +1566,8 @@ t_stat cr_show_rate ( FILE *st, /* simulate pressing the card reader RESET button */ /* Per CR11 docs, transition to ONLINE, reset card */ /* reader logic. */ +/* RESET is somewhat of a misnomer; START is the function */ + t_stat cr_set_reset ( UNIT *uptr, int32 val, char *cptr, @@ -1288,8 +1590,13 @@ t_stat cr_set_reset ( UNIT *uptr, cdst |= CDCSR_ONLINE; cdst &= ~(CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK | CDCSR_HOPPER | CDCSR_EOF); + /* I don't think the hardware clears these errors, but TOPS-10 seems to expect it. + * Since we know the reader is idle, and this is OPR intervention, it seems safe. + */ + cdst &= ~(CDCSR_LATE | CDCSR_NXM); + /* Assert interrupt if interrupts enabled */ - if ((crs & CSR_IE) || (cdst & CSR_IE)) { + if ((CR11_CTL(uptr)?crs : cdst) & CSR_IE) { SET_INT (CR); if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_set_reset setting interrupt\n"); @@ -1303,12 +1610,13 @@ t_stat cr_set_reset ( UNIT *uptr, cdcc = 0; cdba = 0; cddb = 0; - EOFcard = FALSE; + cddbs = 0; + EOFcard = 0; /* start up the blower if the hopper is not empty if (blowerState != BLOW_ON) { blowerState = BLOW_START; - sim_activate(uptr, spinUp); + sim_activate_after(uptr, spinUp); } */ return (SCPE_OK); @@ -1325,9 +1633,9 @@ t_stat cr_set_stop ( UNIT *uptr, fprintf (sim_deb, "set_stop\n"); crs &= ~CRCSR_ONLINE; crs |= CSR_ERR | CRCSR_OFFLINE; - cdst |= CDCSR_OFFLINE; + cdst |= CSR_ERR | CDCSR_OFFLINE; /* CD11 does not appear to interrupt on STOP. */ - if (crs & CSR_IE) + if (CR11_CTL(uptr) && (crs & CSR_IE)) SET_INT (CR); if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; @@ -1335,9 +1643,28 @@ t_stat cr_set_stop ( UNIT *uptr, return (SCPE_OK); } -static const char * const trans[] = { - "unknown", "026", "026FTN", "029", "EBCDIC", "026DEC" -}; +/* simulate pressing the card reader EOF button */ + +t_stat cr_set_eof ( UNIT *uptr, + int32 val, + char *cptr, + void *desc ) +{ + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "set_eof\n"); + eofPending = 1; + + return (SCPE_OK); +} + +t_stat cr_show_eof ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ + fprintf (st, (eofPending? "EOF pending": "no EOF pending")); + return (SCPE_OK); +} t_stat cr_set_trans ( UNIT *uptr, int32 val, @@ -1348,17 +1675,14 @@ t_stat cr_set_trans ( UNIT *uptr, if (!cptr) return (SCPE_MISVAL); - if (strcmp (cptr, "DEFAULT") == 0) - i = 3; - else { - for (i = 1; i < 6; i++) { - if (strcmp (cptr, trans[i]) == 0) - break; - } + + for (i = 0; i < NTRANS; i++) { + if (strcmp (cptr, transcodes[i].name) == 0) + break; } - if (i < 1 || i > 5) + if (i >= NTRANS) return (SCPE_ARG); - table = i; + codeTbl = transcodes[i].table; initTranslation (); /* reinitialize tables */ return (SCPE_OK); } @@ -1368,32 +1692,66 @@ t_stat cr_show_trans ( FILE *st, int32 val, void *desc ) { - fprintf (st, "translation=%s", trans[table]); + int i; + for (i = 1; i < NTRANS; i++ ) + if (transcodes[i].table == codeTbl) { + fprintf (st, "translation=%s", transcodes[i].name); + return SCPE_OK; + } + fprintf (st, "translation=%s", transcodes[0].name); return (SCPE_OK); } +/* Only used from here to EOF, so not passing size of string. + * This ugliness is more maintainable than a preprocessor mess. + */ + +static void cr_supported ( char *string, int32 *bits ) +{ +int32 crtypes = 0; +#define MAXDESCRIP sizeof ("CR11/CD11/CD20/") /* sizeof includes \0 */ +char devtype[MAXDESCRIP] = ""; + +#if defined (CR11_ONLY) || defined (CR11_OK) + crtypes |= 1; +#endif +#if defined (CD11_ONLY) || defined (CD11_OK) + crtypes |= 2; +#endif +#if defined (CD20_ONLY) || defined (CD20_OK) + crtypes |= 4; +#endif + +if (string) { + if (crtypes & 1) + strcat (devtype, "CR11/"); + if (crtypes & 2) + strcat (devtype, "CD11/"); + if (crtypes & 4) + strcat (devtype, "CD20/"); + devtype[strlen(devtype)-1] = '\0'; + strcpy (string, devtype); +} +if (bits) + *bits = crtypes; +return; +} + static t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -#if defined(VM_PDP11) -char *devtype = "CR11/CD11"; -#else -char *devtype = (DFLT_CR11) ? "CR11" : "CD11"; -#endif +char devtype[MAXDESCRIP]; +int32 crtypes; +cr_supported (devtype, &crtypes); fprintf (st, "%s Card Reader (CR)\n\n", devtype); -#if defined(VM_PDP11) -fprintf (st, "The card reader (CR) implements a single controller (either the CR11 or the\n"); -fprintf (st, "CD11) and a card reader (e.g., Documation M200, GDI Model 100) by reading a\n"); +fprintf (st, "The card reader (CR) implements a single controller (the model(s) shown\n"); +fprintf (st, "above) and a card reader (e.g., Documation M200, GDI Model 100) by reading a\n"); fprintf (st, "file and presenting lines or cards to the simulator. Card decks may be\n"); fprintf (st, "represented by plain text ASCII files, card image files, or column binary\n"); fprintf (st, "files.\n\n"); -#else -fprintf (st, "The card reader (CR) implements a single controller (the %s) and a\n", devtype); -fprintf (st, "card reader (e.g., Documation M200, GDI Model 100) by reading a file and\n"); -fprintf (st, "presenting lines or cards to the simulator. Card decks may be represented\n"); -fprintf (st, "by plain text ASCII files, card image files, or column binary files.\n"); -#endif -fprintf (st, "The CR11 controller is also compatible with the CM11-F, CME11, and CMS11.\n\n"); + +fprintf (st, "The controller is also compatible with the CM11-F, CME11, and CMS11.\n\n"); + fprintf (st, "Card image files are a file format designed by Douglas W. Jones at the\n"); fprintf (st, "University of Iowa to support the interchange of card deck data. These files\n"); fprintf (st, "have a much richer information carrying capacity than plain ASCII files. Card\n"); @@ -1401,43 +1759,64 @@ fprintf (st, "Image files can contain such interchange information as card-stock fprintf (st, "corner cuts, special artwork, as well as the binary punch data representing all\n"); fprintf (st, "12 columns. Complete details on the format, as well as sample code, are\n"); fprintf (st, "available at Prof. Jones's site: http://www.cs.uiowa.edu/~jones/cards/.\n\n"); -#if defined (VM_PDP11) -fprintf (st, "The card reader device an be configured to support either of the two\n"); -fprintf (st, "controllers supported by DEC:\n\n"); -fprintf (st, " SET CR CR11 set controller type to CR11\n"); -fprintf (st, " SET CR CD11 set controller type to CD11\n\n"); -fprintf (st, "The controller type must be set before attaching a virtual card deck to the\n"); -fprintf (st, "device. You may NOT change controller type once a file is attached.\n\n"); -fprintf (st, "The primary differences between these two controllers are summarized in the\n"); -fprintf (st, "table below. By default, CR11 simulation is selected.\n\n"); -fprintf (st, " CR11 CD11\n"); -fprintf (st, " BR 6 4\n"); -fprintf (st, " registers 4 3\n"); -fprintf (st, " data transfer BR DMA\n"); -fprintf (st, " card rate 200-600 1000-1200\n"); -fprintf (st, " hopper cap. <= 1000 1000-2250\n"); -fprintf (st, " cards Mark-sense & punched only\n"); -fprintf (st, " punched\n\n"); -fprintf (st, "The CD11 simulation includes the Rev. J modification to make the CDDB act as\n"); -fprintf (st, "a second status register during non-data transfer periods.\n\n"); + +if ((crtypes & -crtypes) != crtypes) { + fprintf (st, "The card reader device an be configured to emulate the following\n"); + fprintf (st, "controller models with these commands:\n\n"); + if (crtypes & 1) + fprintf (st, " SET CR CR11 set controller type to CR11\n"); + if (crtypes & 2) + fprintf (st, " SET CR CD11 set controller type to CD11\n"); + if (crtypes & 4) { + fprintf (st, " SET CR CD20 set controller type to CD20\n"); +#if defined (AIECO_OK) + fprintf (st, " SET CR AIECO emulate the CD20 \"augmented image\" ECO\n"); + fprintf (st, " default is %semulated.\n", (DFLT_AIECO? "":"not ")); #endif -fprintf (st, "Examples of the CR11 include the M8290 and M8291 (CMS11). All card readers use\n"); -fprintf (st, "a common vector at 0230 and CSR at 177160. Even though the CR11 is normally\n"); -fprintf (st, "configured as a BR6 device, it is configured for BR4 in this simulation.\n\n"); +} + fprintf (st, "\nThe controller type must be set before attaching a virtual card deck to the\n"); + fprintf (st, "device. You may NOT change controller type once a file is attached.\n\n"); + fprintf (st, "The primary differences between the controllers are summarized in the\n"); + fprintf (st, "table below. By default, %s simulation is selected.\n\n", + (DFLT_TYPE & UNIT_CD20)? "CD20": ((DFLT_TYPE & UNIT_CR11)? "CR11" : "CD11")); + fprintf (st, " CR11 CD11/CD20\n"); + fprintf (st, " BR 6 4\n"); + fprintf (st, " registers 4 3\n"); + fprintf (st, " data transfer BR DMA\n"); + fprintf (st, " card rate 200-600 1000-1200\n"); + fprintf (st, " hopper cap. <= 1000 1000-2250\n"); + fprintf (st, " cards Mark-sense & punched only\n"); + fprintf (st, " punched\n\n"); + fprintf (st, "The CD11 simulation includes the Rev. J modification to make the CDDB act as\n"); + fprintf (st, "a second status register during non-data transfer periods.\n\n"); +} +if (crtypes & 1) { + fprintf (st, "Examples of the CR11 include the M8290 and M8291 (CMS11). All card readers use\n"); + fprintf (st, "a common vector at 0230 and CSR at 177160. Even though the CR11 is normally\n"); + fprintf (st, "configured as a BR6 device, it is configured for BR4 in this simulation.\n\n"); +} fprintf (st, "The card reader supports ASCII, card image, and column binary format card\n"); fprintf (st, "\"decks.\" When reading plain ASCII files, lines longer than 80 characters are\n"); fprintf (st, "silently truncated. Card image support is included for 80 column Hollerith,\n"); -fprintf (st, "82 column Hollerith (silently ignoring columns 0 and 81), and 40 column\n"); -fprintf (st, "Hollerith (mark-sense) cards. Column binary supports 80 column card images\n"); -fprintf (st, "only. All files are attached read-only (as if the -R switch were given).\n\n"); +fprintf (st, "82 column Hollerith, and 40 column Hollerith (mark-sense) cards. \n"); +fprintf (st, "Column binary supports 80 column card images only.\n"); +if (crtypes & 6) { + fprintf (st, "The CD11/CD20 optionally check columns 0/81/41 for punches, which produce\n"); + fprintf( st, "read check errors. As verifiers may produce these, this can be controlled:\n"); + fprintf( st, " SET CR RDCHECK - Enable read check errors (default)\n"); + fprintf( st, " SET CR NORDCHECK - Disable read check errors\n\n"); +} +fprintf (st, "All files are attached read-only (as if the -R switch were given).\n"); fprintf (st, " ATTACH -A CR file is ASCII text\n"); fprintf (st, " ATTACH -B CR file is column binary\n"); fprintf (st, " ATTACH -I CR file is card image format\n\n"); + fprintf (st, "If no flags are given, the file extension is evaluated. If the filename ends\n"); fprintf (st, "in .TXT, the file is treated as ASCII text. If the filename ends in .CBN, the\n"); fprintf (st, "file is treated as column binary. Otherwise, the CR driver looks for a card\n"); fprintf (st, "image header. If a correct header is found the file is treated as card image\n"); fprintf (st, "format, otherwise it is treated as ASCII text.\n\n"); + fprintf (st, "The correct character translation MUST be set if a plain text file is to be\n"); fprintf (st, "used for card deck input. The correct translation SHOULD be set to allow\n"); fprintf (st, "correct ASCII debugging of a card image or column binary input deck. Depending\n"); @@ -1445,28 +1824,46 @@ fprintf (st, "upon the operating system in use, how it was generated, and how th fprintf (st, "will be read and used, the translation must be set correctly so that the proper\n"); fprintf (st, "character set is used by the driver. Use the following command to explicitly\n"); fprintf (st, "set the correct translation:\n\n"); -fprintf (st, " SET TRANSLATION={DEFAULT|026|026FTN|026DEC|029|EBCDIC}\n\n"); +fprintf (st, " SET TRANSLATION={DEFAULT|026|026FTN|026DEC|026DECASCII|029|029DECASCII|EBCDIC}\n\n"); fprintf (st, "This command should be given after a deck is attached to the simulator. The\n"); fprintf (st, "mappings above are completely described at\n"); fprintf (st, " http://www.cs.uiowa.edu/~jones/cards/codes.html.\n"); -fprintf (st, "Note that DEC typically used 029 or 026FTN mappings.\n\n"); +fprintf (st, "Note that early DEC software typically used 029 or 026FTN mappings.\n"); +fprintf (st, "Later systems used the 026DECASCII and/or 029DECASCII mappings, which include all 7-bit ASCII characters\n"); fprintf (st, "DEC operating systems used a variety of methods to determine the end of a deck\n"); fprintf (st, "(recognizing that 'hopper empty' does not necessarily mean the end of a deck.\n"); fprintf (st, "Below is a summary of the various operating system conventions for signaling\n"); -fprintf (st, "end of deck:\n\n"); +fprintf (st, "end of deck (or end of file with multi-file batch systems):\n\n"); fprintf (st, " RT-11: 12-11-0-1-6-7-8-9 punch in column 1\n"); fprintf (st, " RSTS/E: 12-11-0-1 or 12-11-0-1-6-7-8-9 punch in column 1\n"); fprintf (st, " RSX: 12-11-0-1-6-7-8-9 punch in first 8 columns\n"); fprintf (st, " VMS: 12-11-0-1-6-7-8-9 punch in first 8 columns\n"); fprintf (st, " TOPS: 12-11-0-1 or 12-11-0-1-6-7-8-9 punch in column 1\n\n"); fprintf (st, "Using the AUTOEOF setting, the card reader can be set to automatically generate\n"); -fprintf (st, "an EOF card consisting of the 12-11-0-1-6-7-8-9 punch in columns 1-8. When set\n"); -fprintf (st, "to CD11 mode, this switch also enables automatic setting of the EOF bit in the\n"); -fprintf (st, "controller after the EOF card has been processed. [The CR11 does not have a\n"); -fprintf (st, "similar capability.] By default AUTOEOF is enabled.\n\n"); -fprintf (st, "The default card reader rate for the CR11 is 285 cpm. The reader rate can be\n"); -fprintf (st, "set to its default value or to anywhere in the range 200 to 1200 cpm. This\n"); -fprintf (st, "rate may be changed while the unit is attached.\n\n"); +fprintf (st, "an EOF card consisting of the 12-11-0-1-6-7-8-9 punch in columns 1-8. "); +if (crtypes & 6) { + fprintf (st, "When set,\nThe %s ", ((crtypes & 6) == 2)? "CD11": ((crtypes & 6) == 4)? "CD20": "CD11/CD20"); + + fprintf (st, "will automatically set the EOF bit in the\n"); + fprintf (st, "controller after the EOF card has been processed. By default AUTOEOF is enabled.\n"); + fprintf (st, "The controller also supports an EOF switch that will set the EOF bit when the\n"); + fprintf (st, "hopper empties. The switch resets each time the hopper empties. The SET EOF command emulates this.\n"); + if (crtypes &1) + fprintf (st, "The CR11 does not support the EOF switch/bit.\n"); + else + fprintf (st, "\n"); +} +fprintf (st, "The default card reader rate for the "); +if (crtypes & 4) { + fprintf (st, "CD20 is 1200"); + if (crtypes != 4) + fprintf (st, " and for the "); +} +if (crtypes & 3) + fprintf (st, "CR/CD11 is 285"); +fprintf (st, " cpm.\n"); +fprintf (st, "The reader rate can be set to its default value or to anywhere in the range\n"); +fprintf (st, "of 200 to 1200 cpm.This rate may be changed while the unit is attached.\n\n"); fprintf (st, "It is standard operating procedure for operators to load a card deck and press\n"); fprintf (st, "the momentary action RESET button to clear any error conditions and alert the\n"); fprintf (st, "processor that a deck is available to read. Use the SET CR RESET command to\n"); @@ -1478,15 +1875,18 @@ fprintf (st, "simulate pressing the card reader STOP button.\n\n"); fprintf (st, "The simulator does not support the BOOT command. The simulator does not\n"); fprintf (st, "stop on file I/O errors. Instead the controller signals a reader check to\n"); fprintf (st, "the CPU.\n"); + fprint_reg_help (st, dptr); return SCPE_OK; } char *cr_description (DEVICE *dptr) - { -#if defined(VM_PDP11) - return "CR11/CD11 card reader"; -#else - return (DFLT_CR11) ? "CR11 card reader" : "CD11 card reader"; -#endif - } +{ + /* Not thread-safe, but malloc() would be leak. */ + static char desc[MAXDESCRIP+sizeof(" card reader")-1] = ""; + if (desc[0] == '\0') { + cr_supported (desc, NULL); + strcat (desc, " card reader"); + } + return desc; +} diff --git a/PDP11/pdp11_cr_dat.h b/PDP11/pdp11_cr_dat.h index f5f1b6bd..2dce182a 100644 --- a/PDP11/pdp11_cr_dat.h +++ b/PDP11/pdp11_cr_dat.h @@ -128,7 +128,44 @@ static const int EBCDIC_code[] = { 06004,06002,06001,03200,03100,03040,03020,03010, /* pqrstuvw */ 03004,03002,03001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ }; - +/* DEC's 026 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ +static const int o26_decascii_code[] = { + 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, + 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, + 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, + 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, + 00000, 04006, 01022, 01012, 02102, 01006, 02006, 00012, + 01042, 04042, 02042, 04000, 01102, 02000, 04102, 01400, + 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, + 00002, 00001, 02202, 01202, 04012, 00102, 02012, 04202, + 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, + 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, + 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, + 01004, 01002, 01001, 02022, 00006, 04022, 00022, 00202, + 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, + 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, + 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, + 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, +}; +/* DEC's 029 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ +static const int o29_decascii_code[] = { + 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, + 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, + 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, + 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, + 00000, 04006, 00006, 00102, 02102, 01042, 04000, 00022, + 04022, 02022, 02042, 04012, 01102, 02000, 04102, 01400, + 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, + 00002, 00001, 00202, 02012, 04042, 00012, 01012, 01006, + 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, + 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, + 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, + 01004, 01002, 01001, 04202, 01202, 02202, 02006, 01022, + 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, + 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, + 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, + 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, +}; static const int h2c_code[4096] = { 0000, 0020, 0010, 0030, 0007, 0027, 0017, 0037, 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037,