/* i650_cdp.c: IBM 650 Card punch. Copyright (c) 2018, Roberto Sancho Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ROBERTO SANCHO BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This is the standard card punch. These units each buffer one record in local memory and signal ready when the buffer is full or empty. The channel must be ready to recieve/transmit data when they are activated since they will transfer their block during chan_cmd. All data is transmitted as BCD characters. */ #include "i650_defs.h" #include "sim_card.h" #define UNIT_CDP UNIT_ATTABLE | MODE_026 /* std devices. data structures cdp_dev Card Punch device descriptor cdp_unit Card Punch unit descriptor cdp_reg Card Punch register list cdp_mod Card Punch modifiers list */ uint32 cdp_cmd(UNIT *, uint16, uint16); t_stat cdp_srv(UNIT *); t_stat cdp_reset(DEVICE *); t_stat cdp_attach(UNIT *, CONST char *); t_stat cdp_detach(UNIT *); t_stat cdp_help(FILE *, DEVICE *, UNIT *, int32, const char *); const char *cdp_description(DEVICE *dptr); t_stat cdp_set_wiring (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cdp_show_wiring (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat cdp_set_echo (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cdp_show_echo (FILE *st, UNIT *uptr, int32 val, CONST void *desc); UNIT cdp_unit[] = { {UDATA(cdp_srv, UNIT_CDP, 0), 600}, // unit 0 is the printing mechanism of 407 {UDATA(cdp_srv, UNIT_CDP, 0), 600}, {UDATA(cdp_srv, UNIT_CDP, 0), 600}, {UDATA(cdp_srv, UNIT_CDP, 0), 600}, }; MTAB cdp_mod[] = { {MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", &sim_card_set_fmt, &sim_card_show_fmt, NULL, "Set card format"}, {MTAB_XTD | MTAB_VUN, 0, "WIRING", "WIRING", &cdp_set_wiring, &cdp_show_wiring, NULL, "Set card punch/print control panel Wiring"}, {MTAB_XTD | MTAB_VUN, 0, "ECHO", "ECHO", &cdp_set_echo, &cdp_show_echo, NULL, "Set console printout for punched cards"}, {MTAB_XTD | MTAB_VUN, 1, "PRINT", "PRINT", &cdp_set_echo, &cdp_show_echo, NULL, "Set printout on CDP0 unit for punched cards"}, {0} }; DEVICE cdp_dev = { "CDP", cdp_unit, NULL, cdp_mod, 4, 8, 15, 1, 8, 8, NULL, NULL, NULL, NULL, &cdp_attach, &cdp_detach, &cdp_dib, DEV_DISABLE | DEV_DEBUG, 0, crd_debug, NULL, NULL, &cdp_help, NULL, NULL, &cdp_description }; static struct card_wirings wirings[] = { {WIRING_8WORD, "8WORD"}, {WIRING_SOAP, "SOAP"}, {WIRING_IS, "IS"}, {0, 0}, }; // vars where card is encoded for punching char card_buf[120]; int card_nbuf; // vars where card is encoded for printing char card_lpt[120]; int card_nlpt; void encode_char(int cPunch, int cLpt) { if ((cPunch) && (card_nbuf < 80)) { card_buf[card_nbuf++] = cPunch; } if ((cLpt) && (card_nlpt < 120)) { card_lpt[card_nlpt++] = cLpt; } } void encode_lpt_spc(int nSpaces) { while (nSpaces-- >0) encode_char(0, 32); } void encode_lpt_str(const char * buf) { while (*buf) encode_char(0, *buf++); } void encode_lpt_num(t_int64 d, int l) { char s[20]; int i,n; d=AbsWord(d); for (i=9;i>=0;i--) { n = (int) (d % 10); d = d / 10; s[i] = '0' + n; } s[10] = 0; encode_lpt_str(&s[10-l]); } #define wf_NNNNNNNNNNs 0 #define wf_NN_NNNN_NNNNs 1 #define wf_sN_NNNNNNN_NN 3 #define wf_sN_NNN_NNN_NNN 4 void encode_lpt_word(t_int64 d, int NegZero, int wFormat) { int n; int neg=0; if (d < 0) {d=-d; neg=1;} else if ((d==0) && (NegZero)) neg=1; if (wFormat == wf_NN_NNNN_NNNNs) { n = Shift_Digits(&d, 2); encode_lpt_num(n, 2); encode_lpt_spc(1); n = Shift_Digits(&d, 4); encode_lpt_num(n, 4); encode_lpt_spc(1); n = Shift_Digits(&d, 4); encode_lpt_num(n, 4); encode_char(0, neg ? '-':' '); } else if (wFormat == wf_sN_NNNNNNN_NN) { encode_char(0, neg ? '-':'+'); n = Shift_Digits(&d, 1); encode_lpt_num(n, 1); encode_lpt_spc(1); n = Shift_Digits(&d, 7); encode_lpt_num(n, 7); encode_lpt_spc(1); n = Shift_Digits(&d, 2); encode_lpt_num(n, 2); } else if (wFormat == wf_sN_NNN_NNN_NNN) { encode_char(0, neg ? '-':'+'); n = Shift_Digits(&d, 1); encode_lpt_num(n, 1); encode_lpt_spc(1); n = Shift_Digits(&d, 3); encode_lpt_num(n, 3); encode_lpt_spc(1); n = Shift_Digits(&d, 3); encode_lpt_num(n, 3); encode_lpt_spc(1); n = Shift_Digits(&d, 3); encode_lpt_num(n, 3); } else { // default: wFormat == wf_NNNNNNNNNNs encode_lpt_num(d,10); encode_char(0, neg ? '-':' '); } } // set pch_word[10] with encoded word d. // if d negative, sign on last digit (units digit) // if bSetHiPuch=1, set HiPunch on last digit. // if bSetHiPuch=2, set HiPunch on last digit and on second digit. void sprintf_word(char * pch_word, t_int64 d, int NegZero, int bSetHiPuch) { int i,n,neg, hi; if (d < 0) { neg = 1; d = -d; } else if ((d == 0) && (NegZero)) { neg = 1; // Negative Zero -> also puncho X(11) on last 0 digit } else { neg = 0; } for (i=9;i>=0;i--) { hi = 0; if ((i==1) && (bSetHiPuch == 2)) hi = 1; // Set Hi Punch on second digit if ((i==9) && (bSetHiPuch > 0)) hi = 1; // Set Hi Punch on last digit (units digit) n = (int) (d % 10); d = d / 10; n = n + hi * 10; if ((neg == 1) && (i==9)) n = n + 20; // Set negative punch X(11) on last digit pch_word[i] = digits_ascii[n]; } pch_word[10] = 0; } void encode_pch_str(const char * buf) { while (*buf) { encode_char(*buf++, 0); } } void encode_8word_wiring(int addr) { // encode 8 numerical words per card // get the decoded data from drum at addr int i, NegZero; t_int64 d; char pch_word[20]; // punch card for(i=0;i<8;i++) { ReadDrum(addr + i, &d, &NegZero); sprintf_word(pch_word, d, NegZero, 0); encode_pch_str(pch_word); } // print out card contents // 8 words in format NN NNNN NNNN+ for(i=0;i<8;i++) { ReadDrum(addr + i, &d, &NegZero); encode_lpt_word(d, NegZero, wf_NN_NNNN_NNNNs); encode_lpt_spc(1); } } void encode_soap_wiring(int addr) { // encode soap card simulating soap control panel wiring for 533 // from SOAP II manual at http://www.bitsavers.org/pdf/ibm/650/24-4000-0_SOAPII.pdf // storage in output block // Word 1977: | <- Location -> | Alphabetic // 1978: | <- Data Addr -> | Alphabetic // 1979: | <- Inst Addr -> | Alphabetic // +-+-+-|-+-+-|-+-|-+-| // 1980: | Op Code |DTg|ITg| Alphabetic // +-+-+-|-+-+-|-+-|-+-| // 1981: | <- Remarks -> | Alphabetic // 1982: | <- Remarks -> | Alphabetic // 1983: |<-Assembled Instr->| // +-+-|-+-+-+-|-+-+-|-| // 1984: | |N N N N| |T| N N N N=Location, T=Type (0 if Blank) // 1985: | |N N N N| N N N N=Card Number // 1986: |a|b|c|d|e|f|g|h|i|j| a = 0/8 (for non blank type) // b = 0/8 (negative) // c = 0/8 (bypass) // d = 0/8 (punch a) =8 -> do not print Loc op da ir // e = 0/8 (punch b) =8 -> punch availability table // f = 0/8 (800X instruction) // g = 0/8 (blank out L) // h = 0/8 (blank out D) // i = 0/8 (blank out I) // j = 0/8 (blank out OP) // // SOAP printout format // | Sg | Location | OpCode | Data Addr | Tg | Instr Addr | Tg | Remarks | Drum Addr | NN NNNN NNNN[-] (signed word value at this drum addr) // SOAP punch format (load card, 1 word per card) // simulates punching over prepunched 1-word load card // | word1 | nnnn | 24 addr 800? | NNNNNNNNNN[-] | source soap line // nnnn=card number // addr=drum address where the word is loaded // NNNNNNNNNN=word to be loaded at addr, with sign char loc[6], data_addr[6], inst_addr[6], OpCode[6], Data_Tag[6], Instr_Tag[6], rem1[6], rem2[6]; char pch_word[20]; t_int64 d, instr; int location, CardNum, ty; int b_non_blank, neg, b_blk_op, b_blk_i, b_blk_d, b_blk_l, b_800X, b_pch_b, b_pch_a, b_bypass; // punch control flags int i, sv_card_nbuf, n; int pat1, pat2; word_to_ascii(loc, 1, 5, DRUM[addr + 0]); word_to_ascii(data_addr, 1, 5, DRUM[addr + 1]); word_to_ascii(inst_addr, 1, 5, DRUM[addr + 2]); word_to_ascii(OpCode, 1, 3, DRUM[addr + 3]); word_to_ascii(Data_Tag, 4, 1, DRUM[addr + 3]); word_to_ascii(Instr_Tag, 5, 1, DRUM[addr + 3]); word_to_ascii(rem1, 1, 5, DRUM[addr + 4]); word_to_ascii(rem2, 1, 5, DRUM[addr + 5]); instr = DRUM[addr + 6]; location = (int) ((DRUM[addr + 7] / D4) % D4); ty = (int) ( DRUM[addr + 7] % 10); CardNum = (int) ( DRUM[addr + 8] % D4); d = DRUM[addr + 9]; b_blk_op = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_blk_i = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_blk_d = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_blk_l = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_800X = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_pch_b = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_pch_a = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_bypass = ((int) (d % 10) == 8) ? 1:0; d = d / 10; neg = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_non_blank = ((int) (d % 10) == 8) ? 1:0; d = d / 10; // printf("bits %06d%04d%c ", printfw(DRUM[addr + 9])); // to echo the status digits of punched card // generate card if (b_pch_b) { // punch availability table (pat pseudo-op output) for(i=0;i<8;i++) { sprintf_word(pch_word, DRUM[addr + i], 0, 1); encode_pch_str(pch_word); } } else { if (b_pch_a) { // punch non generating code card encode_pch_str("0?0000800?"); // load card sprintf(pch_word, " %04d", CardNum); // card number encode_pch_str(pch_word); encode_pch_str(" "); // two blank words encode_pch_str(" "); if (b_non_blank) encode_pch_str("1"); else encode_pch_str(" "); } else { // punch generating code card if (b_800X) { encode_pch_str("6I1954800?"); // load card for word to be stored in 800X addr } else { encode_pch_str("6I1954195C"); // load card for word to be stored in drum } sprintf(pch_word, " %04d", CardNum); // card number encode_pch_str(pch_word); sprintf(pch_word, "24%04d800?", location);// addr to place the loaded word encode_pch_str(pch_word); sprintf_word(pch_word, AbsWord(instr) * (neg ? -1:1), ((neg) && (instr == 0)) ? 1:0, 1); encode_pch_str(pch_word); encode_char(ty == 0 ? ' ' : '0'+ty, 0); } encode_pch_str(" "); sv_card_nbuf = card_nbuf; // save pch bufer current pos encode_pch_str(loc); encode_pch_str(OpCode); encode_pch_str(data_addr); encode_pch_str(Data_Tag); encode_pch_str(inst_addr); encode_pch_str(Instr_Tag); encode_pch_str(rem1); encode_pch_str(rem2); // convert to lowercase for punching for (i=sv_card_nbuf;i= 'A') && (card_buf[i] <= 'Z')) card_buf[i] = card_buf[i] - 'A' + 'a'; card_buf[card_nbuf] = 0; } // generate printout if (b_pch_b) { // print availability table (pat pseudo-op output) for(i=0; i<4; i++) { d = DRUM[addr + i*2]; pat1 = (int) ((d / D4) % D4); pat2 = (int) ( d % D4); d = DRUM[addr + i*2 + 1]; encode_lpt_num(pat1, 4); encode_lpt_spc(2); encode_lpt_num(d, 10); encode_lpt_spc(2); encode_lpt_num(pat2, 4); encode_lpt_spc(5); } } else if (ty == 1) { // print coment line encode_lpt_str("1"); encode_lpt_spc(14); encode_lpt_str(loc); encode_lpt_str(OpCode); encode_lpt_str(data_addr); encode_lpt_str(Data_Tag); encode_lpt_str(inst_addr); encode_lpt_str(Instr_Tag); encode_lpt_str(rem1); encode_lpt_str(rem2); } else { encode_lpt_spc(1); encode_lpt_str(loc); encode_lpt_spc(2); encode_char(0, neg ? '-':' '); encode_lpt_spc(1); encode_lpt_str(OpCode); encode_lpt_spc(3); encode_lpt_str(data_addr); encode_lpt_str(Data_Tag); encode_lpt_spc(2); encode_lpt_str(inst_addr); encode_lpt_str(Instr_Tag); encode_lpt_spc(5); encode_lpt_str(rem1); encode_lpt_str(rem2); if (b_pch_a) { // blank op -> do not print location and intruction if (b_bypass) { encode_lpt_spc(4); encode_lpt_str("BYPASS"); } } else { encode_lpt_spc(4); if (b_blk_l) { encode_lpt_spc(4); } else encode_lpt_num(location, 4); encode_lpt_spc(2); encode_char(0, neg ? '-':' '); encode_lpt_spc(1); d = instr; n = Shift_Digits(&d, 2); // operation code (2 digits) if (b_blk_op) { encode_lpt_spc(2); } else encode_lpt_num(n, 2); encode_lpt_spc(2); n = Shift_Digits(&d, 4); // data addr (4 digits) if (b_blk_d) { encode_lpt_spc(4); } else encode_lpt_num(n, 4); encode_lpt_spc(2); n = Shift_Digits(&d, 4); // instr addr (4 digits) if (b_blk_i) { encode_lpt_spc(4); } else encode_lpt_num(n, 4); encode_lpt_spc(1); if (b_blk_l) encode_lpt_str("BLANK L"); else if (b_blk_op) encode_lpt_str("BLANK OP"); else if (b_blk_d) encode_lpt_str("BLANK D"); else if (b_blk_i) encode_lpt_str("BLANK I"); } } } void encode_is_wiring(int addr) { // encode Floationg Decimal Interpretive System (IS) card simulating control panel wiring for 533 as described // in manual at http://www.bitsavers.org/pdf/ibm/650/28-4024_FltDecIntrpSys // storage in output block // +-+-+-+-+-+-|-+-+-+-| // Word 1977: |Trc|N N N N| | Location // 1978: | |N N N N| | Word Count // +-------------------+ // 1979: | word1 | // 1980: | word2 | // 1981: | word3 | // 1982: | word4 | // 1983: | word5 | // 1984: | word6 | // +-------------------+ // 1985: | Problem Number | // 1986: | |N N N N| | Card Number // +-------------------+ // // if word at 1977 is negative, a load card is punched, but no printout is generated // if word at 1977 is positive, regular output card format is used on punch // Column: 1 2 3 4 | 5 6 | 7 8 9 | 10 | 11 | 12 - 21 | 22 | 23 - 32 | 33 | 34 - 43 | 44 | 45 - 54 | 55 | 56 - 65 | 66 | 67 - 76 | 77 78 79 | 80 // Card | | | Location | wc | s1 | Word1 | s2 | Word2 | s3 | Word3 | s4 | Word4 | s5 | Word5 | s6 | Word6 | Problem | // Num | if location is > 9999, will use column 6 Num // wordN is printed as +N NNNNNNN NN (IT sci notation) // // IT printout format for non tracing cards: // | Location | Word1 | Word2 | Word3 | Word4 | Word5 | Word6 // wordN is printed as +N NNNNNNN NN (IT sci notation) // // IT printout format for tracing cards (Trc digits in word 1977 are non-zero): // | Location | Word1 | Word2 | Word3 | Word4 | Word5 | Word6 // word1 to 3 are printed as +N NNN NNN NNN (IT instruction format) // word4 to 6 are printed as +N NNNNNNN NN (IT sci notation) // int i, NegZero; t_int64 d; int CardNum, loc, wc, PrNum, bTraceCard; char pch_word[20]; int bSetHiPunch; bSetHiPunch = (DRUM[addr] < 0) ? 2 : 0; // first bSetHiPunch is 2 if word negative (signals a load card must be punched) loc = (int) ((DRUM[addr] / D4) % D4); CardNum = (int) ((DRUM[addr+9] / D4) % D4); wc = (int) ((DRUM[addr+1] / D4) % D4); PrNum = (int) ( DRUM[addr+8]); bTraceCard = (DRUM[addr] / D8) > 0 ? 1 : 0; // if to higher digits are nonzero -> is a trace card if (bSetHiPunch) { // punch a load card for(i=0;i<8;i++) { ReadDrum(addr + i, &d, &NegZero); if ((i==0) && (d < 0)) d = -d; // get absolute value for DRUM[addr + 0] sprintf_word(pch_word, d, NegZero, bSetHiPunch); if (bSetHiPunch==2) bSetHiPunch = 1; // if bSetHiPunch is 2 change it to bSetHiPunch = 1 encode_pch_str(pch_word); } } else { // punch a card using output format if (loc < 1000) { sprintf(pch_word, "%04d %03d%01d", CardNum, loc, wc); } else { sprintf(pch_word, "%04d %04d%01d", CardNum, loc, wc); } encode_pch_str(pch_word); for(i=0;i<6;i++) { if (i 999) PrNum = 999; sprintf(pch_word, "%03d", PrNum); encode_pch_str(pch_word); } if (bSetHiPunch) { // load card, does not generate printout // mark lpt output buffer to not print if (card_nlpt == 0) { card_lpt[card_nlpt++] = 0; } } else { // not load card -> do normal printout for card if (wc > 6) wc = 6; if (loc < 1000) { encode_lpt_spc(1); encode_lpt_num(loc, 3); } else { encode_lpt_num(loc, 4); } for(i=2;i<2+wc;i++) { encode_lpt_spc(2); ReadDrum(addr + i, &d, &NegZero); if ((bTraceCard) && (i<5)) { // if printing a trace card, first three words are printed as intructions (+N NNN NNN NNN) encode_lpt_word(d, NegZero, wf_sN_NNN_NNN_NNN); } else { // print numbers adding spaces to ease reading IT floating point format (+N NNNNNNN NN) encode_lpt_word(d, NegZero, wf_sN_NNNNNNN_NN); } } } } /* Card punch routine */ uint32 cdp_cmd(UNIT * uptr, uint16 cmd, uint16 addr) { int i,c,h; struct _card_data *data; uint32 wiring; /* Are we currently tranfering? */ if (uptr->u5 & URCSTA_BUSY) return SCPE_BUSY; /* Test ready */ if ((uptr->flags & UNIT_ATT) == 0) { sim_debug(DEBUG_CMD, &cdp_dev, "No cards (no file attached)\r\n"); return SCPE_NOCARDS; } // copy and translate drum memory words to chars to punch // using the control panel wiring. wiring = (uptr->flags & UNIT_CARD_WIRING); card_nbuf = card_nlpt = 0; if (wiring == WIRING_SOAP) { // encode soap card simulating soap control panel wiring for 533 (gasp!) encode_soap_wiring(addr); } else if (wiring == WIRING_IS) { // encode it card encode_is_wiring(addr); } else if (wiring == WIRING_8WORD) { // encode 8 words per card encode_8word_wiring(addr); } else { // default wiring: decode up to 8 numerical words per card encode_8word_wiring(addr); } if ((card_nlpt == 1) && (card_lpt[0] == 0)) { // skip this line printout & echo } else { /* echo? */ encode_char(0, 13); encode_char(0, 10); if (uptr->flags & UNIT_CARD_ECHO) { for (i=0;iflags & UNIT_CARD_PRINT) { // printout will be directed to file attached to CDP0 unit, if any if (cdp_unit[0].flags & UNIT_ATT) { sim_fwrite(&card_lpt, 1, card_nlpt, cdp_unit[0].fileref); } } } // trim right spaces for printing punch card card_buf[card_nbuf] = 0; sim_debug(DEBUG_DETAIL, &cpu_dev, "Punch Card: %s\r\n", card_buf); /* punch the cards */ data = (struct _card_data *)uptr->up7; for (i=0; i<80; i++) { if (i >= card_nbuf) { c = 32; } else { c = card_buf[i]; } if (c == 32) { // no punch data->image[i] = 0; } else { // punch char h = ascii_to_hol[c & 127]; data->image[i] = h; } } sim_punch_card(uptr, NULL); sim_debug(DEBUG_CMD, &cdp_dev, "PUNCH\r\n"); uptr->u5 |= URCSTA_BUSY; uptr->u4 = 0; uptr->u5 &= ~URCSTA_BUSY; return SCPE_OK; } /* Handle transfer of data for card punch */ t_stat cdp_srv(UNIT *uptr) { // I/O is synchronous. No need to set up srv return SCPE_OK; } /* Set card read/punch control panel wiring */ t_stat cdp_set_wiring (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { int f; if (uptr == NULL) return SCPE_IERR; if (cptr == NULL) return SCPE_ARG; for (f = 0; wirings[f].name != 0; f++) { if (strcmp (cptr, wirings[f].name) == 0) { uptr->flags = (uptr->flags & ~UNIT_CARD_WIRING) | wirings[f].mode; return SCPE_OK; } } return SCPE_ARG; } /* Show card read/punch control panel wiring */ t_stat cdp_show_wiring (FILE *st, UNIT *uptr, int32 val, CONST void *desc) { int f; for (f = 0; wirings[f].name != 0; f++) { if ((uptr->flags & UNIT_CARD_WIRING) == wirings[f].mode) { fprintf (st, "%s wiring", wirings[f].name); return SCPE_OK; } } fprintf (st, "invalid control panel wiring (%d)", uptr->flags & UNIT_CARD_WIRING); return SCPE_OK; } /* Set card read/punch echo to console */ t_stat cdp_set_echo (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { int u = (uptr - cdp_unit); t_stat r; int num; if (uptr == NULL) return SCPE_IERR; if (cptr == NULL) { num = 1; // no param means set (=1) } else { num = (int) get_uint (cptr, 10, 1, &r); if (r != SCPE_OK) return r; } if (u == 0) { sim_printf("this option cannot be set for CDP0\r\n"); return SCPE_ARG; } switch(val) { case 0: if (num== 0) { uptr->flags = uptr->flags & ~UNIT_CARD_ECHO; } else { uptr->flags = uptr->flags | UNIT_CARD_ECHO; } break; case 1: if (num== 0) { uptr->flags = uptr->flags & ~UNIT_CARD_PRINT; } else { uptr->flags = uptr->flags | UNIT_CARD_PRINT; } break; } return SCPE_OK; } /* Show card read/punch control panel wiring */ t_stat cdp_show_echo (FILE *st, UNIT *uptr, int32 val, CONST void *desc) { switch(val) { case 0: fprintf (st, (uptr->flags & UNIT_CARD_ECHO) ? "ECHO": "No ECHO"); break; case 1: fprintf (st, (uptr->flags & UNIT_CARD_PRINT) ? "PRINT": "No PRINT"); break; } return SCPE_OK; } t_stat cdp_attach(UNIT * uptr, CONST char *file) { t_stat r; if ((r = sim_card_attach(uptr, file)) != SCPE_OK) return r; uptr->u5 = 0; return SCPE_OK; } t_stat cdp_detach(UNIT * uptr) { return sim_card_detach(uptr); } t_stat cdp_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) { fprintf (st, "%s\r\n\r\n", cdp_description(dptr)); fprintf (st, "The 533 Card Read-punch writes cards using the selected\r\n"); fprintf (st, "control panel wiring to set the format of punched cards.\r\n"); fprintf (st, "It is possible to simulate a 407 accounting machine for\r\n"); fprintf (st, "printing using SET CDP1 PRINT=1. In this case, punched\r\n"); fprintf (st, "cards will be printed to file attached to unit 0 (CDP0).\r\n"); fprintf (st, "SET CDP ECHO=1 will display on console cards printout.\r\n"); sim_card_attach_help(st, dptr, uptr, flag, cptr); fprint_set_help(st, dptr); fprint_show_help(st, dptr); return SCPE_OK; } const char * cdp_description(DEVICE *dptr) { return "533 Card Punch + 407 Accounting for printing"; }