733 lines
27 KiB
C
733 lines
27 KiB
C
/* 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";
|
|
}
|
|
|
|
|