blob: 5b10c3fa32d955439771c10feacf564570cc65a2 [file] [log] [blame] [raw]
/* 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<card_nbuf;i++)
if ((card_buf[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<wc) {
ReadDrum(addr + i + 2, &d, &NegZero);
if ((d < 0) || ((d==0) && (NegZero))) {
encode_pch_str("-");
d = -d;
} else {
encode_pch_str("+");
}
sprintf_word(pch_word, d, 0, 0);
encode_pch_str(pch_word);
} else {
encode_pch_str(" "); // 11 spaces
}
}
if (PrNum < 0) PrNum = 0;
if (PrNum > 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;i<card_nlpt;i++) sim_putchar(card_lpt[i]);
}
/* printout punched cards? */
if (uptr->flags & 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";
}