New Hardware support: - IBM 653 Storage Unit: provides machine opcodes for Floating Point, Immediate Access Storage (IAS), Three Index registers, Cards Punch-read synchronizers 2 and 3. New Software included: - FORTRANSIT: version II (S), plus run time PACKAGE with standard Fortran functions. - Reorganized sw directory, separating each language in its own folder. Each one Includes a 00_readme.txt file with restoration notes and comments. New features: - Support for SOAP opcode mnemonics in addition to regular IBM mnemonics - FAST / REALTIME CPU options - PROP pseudo register - CARDDECK ECHOLAST command
1122 lines
44 KiB
C
1122 lines
44 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 | MODE_LOWER
|
|
|
|
/* 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[4] = {
|
|
{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
|
|
};
|
|
|
|
// 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;
|
|
char pad;
|
|
|
|
if (l < 0) {
|
|
l=-l; pad = ' '; // if l < 0 pad with space
|
|
} else {
|
|
pad = '0'; // if l > 0 pag with zero
|
|
}
|
|
d=AbsWord(d);
|
|
for (i=9;i>=0;i--) {
|
|
n = (int) (d % 10);
|
|
d = d / 10;
|
|
s[i] = '0' + n;
|
|
}
|
|
s[10] = 0;
|
|
if (pad == ' ') {
|
|
for(i=0;i<9;i++) {
|
|
if (s[i] != '0') break;
|
|
s[i] = ' ';
|
|
}
|
|
}
|
|
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
|
|
#define wf_nnnnnnnnnNs 5
|
|
#define wf_nnnnnnnnnH 6
|
|
#define wf_NNNNNNNNNN 7
|
|
|
|
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 if (wFormat == wf_nnnnnnnnnNs) {
|
|
encode_lpt_num(d,-10); // replace leading zeroes by spaces
|
|
encode_char(0, neg ? '-':' ');
|
|
} else if (wFormat == wf_nnnnnnnnnH) {
|
|
if (d < 10) {
|
|
encode_lpt_spc(9);
|
|
} else {
|
|
encode_lpt_num(d / 10, -9); // print 9 digits, replacing leading zeroes by spaces
|
|
}
|
|
n = d % 10;
|
|
encode_char(0, (n==0) ? '+':'A'+n-1); // hi punch on last digit
|
|
} else if (wFormat == wf_NNNNNNNNNN) {
|
|
encode_lpt_num(d,10);
|
|
} 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.
|
|
// if bSetHiPuch=3, set HiPunch on third digit
|
|
// if last digit is negative, never set HiPunch even if asked for (a card column cannot have both X(11) and Y(12) punched)
|
|
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==2) && (bSetHiPuch == 3)) hi = 1; // Set Hi Punch on third digit
|
|
if ((i==9) && ( (bSetHiPuch == 1) || (bSetHiPuch == 2) ) && (neg == 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(void)
|
|
{
|
|
// encode 8 numerical words per card
|
|
// get the decoded data from IOSync
|
|
int i, NegZero;
|
|
t_int64 d;
|
|
char pch_word[20];
|
|
|
|
// punch card
|
|
for(i=0;i<8;i++) {
|
|
d = IOSync[i];
|
|
NegZero = IOSync_NegativeZeroFlag[i];
|
|
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++) {
|
|
d = IOSync[i];
|
|
NegZero = IOSync_NegativeZeroFlag[i];
|
|
encode_lpt_word(d, NegZero, wf_NN_NNNN_NNNNs);
|
|
encode_lpt_spc(1);
|
|
}
|
|
}
|
|
|
|
void encode_soap_wiring(void)
|
|
{
|
|
// 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, IOSync[0]);
|
|
word_to_ascii(data_addr, 1, 5, IOSync[1]);
|
|
word_to_ascii(inst_addr, 1, 5, IOSync[2]);
|
|
word_to_ascii(OpCode, 1, 3, IOSync[3]);
|
|
word_to_ascii(Data_Tag, 4, 1, IOSync[3]);
|
|
word_to_ascii(Instr_Tag, 5, 1, IOSync[3]);
|
|
word_to_ascii(rem1, 1, 5, IOSync[4]);
|
|
word_to_ascii(rem2, 1, 5, IOSync[5]);
|
|
instr = IOSync[6];
|
|
location = (int) ((IOSync[7] / D4) % D4);
|
|
ty = (int) ( IOSync[7] % 10);
|
|
CardNum = (int) ( IOSync[8] % D4);
|
|
d = IOSync[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(IOSync[9])); // to echo the control word 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, IOSync[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 = IOSync[i*2];
|
|
pat1 = (int) ((d / D4) % D4);
|
|
pat2 = (int) ( d % D4);
|
|
d = IOSync[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) || (ty == 5)) {
|
|
// print coment for card type 1 (SOAP II) or type 5 (SOAP modified for IT)
|
|
encode_char(0, '0' + ty);
|
|
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 {
|
|
if (ty == 0) {
|
|
encode_lpt_spc(1);
|
|
} else {
|
|
encode_char(0, '0' + ty);
|
|
}
|
|
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(void)
|
|
{
|
|
// 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 = (IOSync[0] < 0) ? 2 : 0; // first bSetHiPunch is 2 if word negative (signals a load card must be punched)
|
|
|
|
loc = (int) ((IOSync[0] / D4) % D4);
|
|
CardNum = (int) ((IOSync[9] / D4) % D4);
|
|
wc = (int) ((IOSync[1] / D4) % D4);
|
|
PrNum = (int) ( IOSync[8]);
|
|
bTraceCard = (IOSync[0] / 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++) {
|
|
d = IOSync[i];
|
|
NegZero = IOSync_NegativeZeroFlag[i];
|
|
if ((i==0) && (d < 0)) d = -d; // get absolute value for IOSync[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) {
|
|
d = IOSync[i+2];
|
|
NegZero = IOSync_NegativeZeroFlag[i+2];
|
|
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);
|
|
d = IOSync[i];
|
|
NegZero = IOSync_NegativeZeroFlag[i];
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void encode_it_wiring(void)
|
|
{
|
|
// encode card for IT compiler modified soap
|
|
// from IT manual at http://www.bitsavers.org/pdf/ibm/650/CarnegieInternalTranslator.pdf
|
|
// storage in output block
|
|
// +-------------------+
|
|
// Word 1977: | <- Loc. Label -> | Alphabetic
|
|
// 1978: | <- Op Code -> | Alphabetic
|
|
// 1979: | <- Data Addr -> | Alphabetic
|
|
// 1980: | <- Inst Addr -> | Alphabetic
|
|
// 1981: | <- Remarks -> | Alphabetic
|
|
// 1982: | <- Remarks -> | Alphabetic
|
|
// +-------------------+
|
|
// 1983: | | Not Used
|
|
// 1984: | | Not Used
|
|
// +-------------------+
|
|
// 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 =8 -> reservation card
|
|
// b = 0/8 (regional setting) =0 -> card type 3, =8 -> card type 4
|
|
// c = 0/8
|
|
// d = 0/8 =8 -> negative value
|
|
// e = 0/8
|
|
// f = 0/8
|
|
// g = 0/8 =8 -> punching a PIT card
|
|
// h = 0/8 =8 -> type 1 data out format
|
|
// i = 0/8
|
|
// j = 0/8
|
|
//
|
|
// SIT printout format
|
|
// | Card Num | Ty | Location | Sg | OpCode | Data Addr | Instr Addr | Remarks
|
|
// SIT punch format is SOAP source card format
|
|
// Column: 41 | 42 | 43 44 45 46 47 | 48 49 50 | 51 52 53 54 55 | 56 | 57 58 59 60 61 | 62 | 63 64 65 66 67 68 69 70 71 72
|
|
// Ty | Sg | Location | OpCode | Data Addr | | Instr Addr | | Remarks
|
|
//
|
|
// Ty = Type = blank, 3 or 4 (regional setting)
|
|
// Sg = sign = blank or -
|
|
//
|
|
// If word 1986 contains 8 in digit h, it is a type 1 data out card format
|
|
// +----+------+-------+
|
|
// Word 1977: | VV | +NNN | SSSS | IT variable 1
|
|
// 1978: | Word |
|
|
// +-------------------+
|
|
// 1979: | | IT variable 2 (zero if none)
|
|
// 1980: | |
|
|
// +-------------------+
|
|
// 1981: | | IT variable 3
|
|
// 1982: | |
|
|
// +-------------------+
|
|
// 1983: | | IT variable 4
|
|
// 1984: | |
|
|
// +-------------------+
|
|
// 1985: | | Not used
|
|
// 1986: |8|0|0|0|0|0|8|8|0|0| control word for type 1 data out card
|
|
//
|
|
// VV = IT variable being punched: 01 -> I type, 02 -> Y type, 03 -> C type
|
|
// + N N N = variable number (I5 -> 01 0005). + means zoro with Y(12) overpunch
|
|
// S S S S = statement number of IT source program where TYPE command that generates the card is
|
|
// Word = value from IT variable. If type I, is an integer. If type C or Y
|
|
// type is word is float (M MMMMMMM EE -> M=mantisa, EE=exponent)
|
|
// can be is negative (X(11) overpunch in last digit)
|
|
// up to 4 pairs var-word per card
|
|
// leading zeroes of each word are replaced by spaces
|
|
|
|
char pch_word[20];
|
|
char loc[6], data_addr[6], inst_addr[6], OpCode[6], rem1[6], rem2[6];
|
|
t_int64 d;
|
|
int CardNum, ty;
|
|
int b, neg, b_pit, b_reg, b_resv, b_data; // punch control flags
|
|
int i;
|
|
|
|
word_to_ascii(loc, 1, 5, IOSync[0]);
|
|
word_to_ascii(OpCode, 1, 3, IOSync[1]);
|
|
word_to_ascii(data_addr, 1, 5, IOSync[2]);
|
|
word_to_ascii(inst_addr, 1, 5, IOSync[3]);
|
|
word_to_ascii(rem1, 1, 5, IOSync[4]);
|
|
word_to_ascii(rem2, 1, 5, IOSync[5]);
|
|
CardNum = (int) ((IOSync[8] / D4) % D4);
|
|
d = IOSync[9];
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b_data = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b_pit = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
neg = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b_reg = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b_resv = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
|
|
// printf("bits %06d%04d%c ", printfw(IOSync[9])); // to echo the control word of punched card
|
|
|
|
// generate card
|
|
if (b_data) {
|
|
// punch type 1 data out card
|
|
for (i=0;i<4;i++) {
|
|
sprintf_word(pch_word, IOSync[i*2+0], 0, (i==0) ? 3:0); // punch variable name
|
|
encode_pch_str(pch_word);
|
|
sprintf_word(pch_word, IOSync[i*2+1], 0, (i==0) ? 3:0); // punch variable value
|
|
encode_pch_str(pch_word);
|
|
if (IOSync[i*2+2] == 0) break; // if next word is zero, no more variables to punch
|
|
}
|
|
} else {
|
|
// punch SOAP source instruction
|
|
for(i=0;i<40;i++) encode_pch_str(" "); // leave 40 first columns blank
|
|
if (b_resv) {
|
|
if (b_reg) {
|
|
ty = 4;
|
|
} else {
|
|
ty = 3;
|
|
}
|
|
} else {
|
|
ty = 0;
|
|
}
|
|
encode_char(ty == 0 ? ' ' : '0'+ty, 0);
|
|
encode_char(neg == 0 ? ' ' : '-', 0);
|
|
encode_pch_str(loc);
|
|
encode_pch_str(OpCode);
|
|
encode_pch_str(data_addr);
|
|
encode_pch_str(" ");
|
|
encode_pch_str(inst_addr);
|
|
encode_pch_str(" ");
|
|
encode_pch_str(rem1);
|
|
encode_pch_str(rem2);
|
|
// convert to lowercase for punching
|
|
for (i=40;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_data) {
|
|
// print type 1 data out card. replace leading zeroes by spaces on each word
|
|
for (i=0;i<4;i++) {
|
|
encode_lpt_word(IOSync[i*2+0], 0, wf_nnnnnnnnnNs); // print variable name
|
|
encode_lpt_spc(1);
|
|
encode_lpt_word(IOSync[i*2+1], 0, wf_nnnnnnnnnNs); // print variable value
|
|
encode_lpt_spc(1);
|
|
if (IOSync[i*2+2] == 0) break; // if next word is zero, no more variables to punch
|
|
}
|
|
} else {
|
|
// print generated soap source listing
|
|
encode_lpt_spc(2);
|
|
encode_lpt_num(CardNum, -4);
|
|
encode_lpt_spc(2);
|
|
encode_char(0, ty == 0 ? ' ' : '0'+ty);
|
|
encode_lpt_spc(2);
|
|
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_spc(1); encode_lpt_spc(2);
|
|
encode_lpt_str(inst_addr); encode_lpt_spc(6);
|
|
encode_lpt_str(rem1); encode_lpt_str(rem2);
|
|
}
|
|
}
|
|
|
|
void encode_fortransit_wiring(void)
|
|
{
|
|
// encode card for FORTRANSIT modified IT compiler
|
|
// from FORTRANSIT manual at http://bitsavers.org/pdf/ibm/650/28-4028_FOR_TRANSIT.pdf
|
|
// implemented Fortransit II (S)
|
|
// word 1986 (control word) specifies what is being punched)
|
|
// storage in output block
|
|
// +-------------------+
|
|
// Word 1977: | <- statement -> | Alphabetic
|
|
// 1978: | <- statement -> | Alphabetic
|
|
// 1979: | <- statement -> | Alphabetic
|
|
// 1980: | <- statement -> | Alphabetic
|
|
// 1981: | <- statement -> | Alphabetic
|
|
// 1982: | <- statement -> | Alphabetic
|
|
// +-------------------+
|
|
// 1983: | | Not Used
|
|
// 1984: | | Not Used
|
|
// +-----------+-------+
|
|
// 1985: | |N N N N| N N N N=Statement Number
|
|
// 1986: |a|b|c|d|e|f|g|h|i|j| Control Word
|
|
// a = 0/8 =8 -> punch a data card
|
|
// b = 0/8
|
|
// c = 0/8
|
|
// d = 0/8 =8 -> ???
|
|
// e = 0/8
|
|
// f = 0/8
|
|
// g = 0/8 =8 -> punching a IT source card, =0 -> punching SOAP card
|
|
// h = 0/8
|
|
// i = 0/8 =8 -> punching a FORTRANSIT card
|
|
// j = 0/8 =8 -> punching an IT header card (8 word load card format)
|
|
//
|
|
// IT card punch format
|
|
// Column: 1 2 3 4 | 5 | 6 - 42 | 43 - 70 | 71 72 | 73 - 80 |
|
|
// N N N N | + | | Statement | | Statement |
|
|
// Statement | Y(12) | | max 28 | | number as |
|
|
// Number | Punch | | chars | | comment |
|
|
//
|
|
//
|
|
// SOAP card storage in output block
|
|
// +-------------------+
|
|
// Word 1977: | <- Loc. Label -> | Alphabetic
|
|
// 1978: | <- Data Addr -> | Alphabetic
|
|
// 1979: | <- Inst Addr -> | Alphabetic
|
|
// 1980: | <- Op Code -> | Alphabetic
|
|
// 1981: | <- Remarks -> | Alphabetic
|
|
// 1982: | <- Remarks -> | Alphabetic
|
|
// +-------------------+
|
|
// 1983: | | Not Used
|
|
// 1984: | | Not Used
|
|
// +-------------------+
|
|
// 1985: | |N N N N| N N N N=Card Number as defined above
|
|
// 1986: | <- Control Word-> | As defined above
|
|
|
|
char pch_word[20];
|
|
char lin[31];
|
|
char loc[6], data_addr[6], inst_addr[6], OpCode[6], rem1[6], rem2[6];
|
|
t_int64 d;
|
|
int CardNum;
|
|
int b, neg, b_it_hdr, b_it_src, b_fort, b_soap, b_data; // punch control word flags
|
|
int i;
|
|
|
|
word_to_ascii(&lin[0], 1, 5, IOSync[0]);
|
|
word_to_ascii(&lin[5], 1, 5, IOSync[1]);
|
|
word_to_ascii(&lin[10], 1, 5, IOSync[2]);
|
|
word_to_ascii(&lin[15], 1, 5, IOSync[3]);
|
|
word_to_ascii(&lin[20], 1, 5, IOSync[4]);
|
|
word_to_ascii(&lin[25], 1, 5, IOSync[5]);
|
|
lin[30] = 0;
|
|
|
|
CardNum = (int) (IOSync[8] % D4);
|
|
|
|
word_to_ascii(loc, 1, 5, IOSync[0]);
|
|
word_to_ascii(data_addr, 1, 5, IOSync[1]);
|
|
word_to_ascii(inst_addr, 1, 5, IOSync[2]);
|
|
word_to_ascii(OpCode, 1, 3, IOSync[3]);
|
|
word_to_ascii(rem1, 1, 5, IOSync[4]);
|
|
word_to_ascii(rem2, 1, 5, IOSync[5]);
|
|
|
|
neg = 0;
|
|
|
|
d = IOSync[9];
|
|
b_it_hdr = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b_fort = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b_it_src = ((int) (d % 10) == 8) ? 1:0; d = d / 10; b_soap = ((b_fort == 1) && (b_it_src == 0));
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
b_data = ((int) (d % 10) == 8) ? 1:0; d = d / 10;
|
|
|
|
// printf("bits %06d%04d%c ", printfw(IOSync[9])); // to echo the control word of punched card
|
|
// generate card
|
|
if (b_data) {
|
|
// punch data card output for PUNCH fortransit command
|
|
for (i=0;i<8;i++) {
|
|
sprintf_word(pch_word, IOSync[i], 0, 0);
|
|
encode_pch_str(pch_word);
|
|
}
|
|
} else if (b_it_hdr) {
|
|
// punch IT header card as 8 word per card load card format
|
|
for (i=0;i<8;i++) {
|
|
sprintf_word(pch_word, IOSync[i], 0, 1);
|
|
encode_pch_str(pch_word);
|
|
}
|
|
} else if (b_soap) {
|
|
// punch SOAP source instruction
|
|
for(i=0;i<40;i++) encode_pch_str(" "); // leave 40 first columns blank
|
|
encode_pch_str(" ");
|
|
encode_char(neg == 0 ? ' ' : '-', 0);
|
|
encode_pch_str(loc);
|
|
encode_pch_str(OpCode);
|
|
encode_pch_str(data_addr);
|
|
encode_pch_str(" ");
|
|
encode_pch_str(inst_addr);
|
|
encode_pch_str(" ");
|
|
encode_pch_str(rem1);
|
|
encode_pch_str(rem2);
|
|
// convert to lowercase for punching
|
|
for (i=40;i<card_nbuf;i++)
|
|
if ((card_buf[i] >= 'A') && (card_buf[i] <= 'Z'))
|
|
card_buf[i] = card_buf[i] - 'A' + 'a';
|
|
} else if (b_it_src) {
|
|
// punch IT source card
|
|
sprintf_word(pch_word, CardNum, 0, 0); // punch statement number
|
|
for (i=0;i<4;i++) pch_word[i] = pch_word[i+6];
|
|
pch_word[4] = '+';
|
|
for (i=5;i<10;i++) pch_word[i] = ' '; // punch separation spaces
|
|
encode_pch_str(pch_word);
|
|
for (i=10;i<42;i++) encode_pch_str(" ");
|
|
encode_pch_str(lin); // punch statement
|
|
encode_pch_str(" ");
|
|
sprintf_word(pch_word, CardNum, 0, 0); // punch statement number again as comment
|
|
for (i=0;i<4;i++) pch_word[i] = pch_word[i+6];
|
|
pch_word[4] = 0;
|
|
encode_pch_str(pch_word);
|
|
// convert to lowercase for punching
|
|
for (i=0;i<card_nbuf;i++)
|
|
if ((card_buf[i] >= 'A') && (card_buf[i] <= 'Z'))
|
|
card_buf[i] = card_buf[i] - 'A' + 'a';
|
|
}
|
|
|
|
// generate printout
|
|
if (b_data) {
|
|
// print data card output for PUNCH fortransit command
|
|
for (i=0;i<8;i++) {
|
|
d = IOSync[i];
|
|
if ((d == 0) && (i != 0)) {
|
|
encode_lpt_spc(11);
|
|
} else {
|
|
encode_lpt_word(d, 0, wf_nnnnnnnnnNs);
|
|
}
|
|
encode_lpt_spc(1);
|
|
}
|
|
} else if (b_it_hdr) {
|
|
// print IT header card as 8 word per card load card format
|
|
for (i=0;i<8;i++) {
|
|
if (i==4) {
|
|
encode_lpt_word(IOSync[i], 0, wf_NNNNNNNNNN);
|
|
} else {
|
|
encode_lpt_word(IOSync[i], 0, wf_nnnnnnnnnH);
|
|
}
|
|
}
|
|
} else if (b_soap) {
|
|
// print generated SOAP source listing
|
|
encode_lpt_spc(2);
|
|
encode_lpt_num(CardNum, -4);
|
|
encode_lpt_spc(6);
|
|
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_spc(3);
|
|
encode_lpt_str(inst_addr); encode_lpt_spc(6);
|
|
encode_lpt_str(rem1); encode_lpt_str(rem2);
|
|
} else if (b_it_src) {
|
|
// print generated it source listing
|
|
if (CardNum == 0) {
|
|
encode_lpt_spc(5);
|
|
} else {
|
|
encode_lpt_num(CardNum, -4);
|
|
encode_lpt_str("+");
|
|
}
|
|
encode_lpt_spc(37);
|
|
encode_lpt_str(lin);
|
|
encode_lpt_spc(4);
|
|
encode_lpt_num(CardNum, 4);
|
|
}
|
|
}
|
|
|
|
|
|
/* 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)\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();
|
|
} else if (wiring == WIRING_IS) {
|
|
// encode floating point interpretive system (bell interpreter) card
|
|
encode_is_wiring();
|
|
} else if (wiring == WIRING_IT) {
|
|
// encode Carnegie Internal Translator compiler card
|
|
encode_it_wiring();
|
|
} else if (wiring == WIRING_FORTRANSIT) {
|
|
// encode Fortransit translator card
|
|
encode_fortransit_wiring();
|
|
} else if (wiring == WIRING_8WORD) {
|
|
// encode 8 words per card
|
|
encode_8word_wiring();
|
|
} else {
|
|
// default wiring: decode up to 8 numerical words per card
|
|
encode_8word_wiring();
|
|
}
|
|
|
|
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\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\n");
|
|
uptr->u5 |= URCSTA_BUSY;
|
|
uptr->u6++; // incr number of punched cards
|
|
|
|
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;
|
|
|
|
r = sim_card_attach(uptr, file);
|
|
if (SCPE_BARE_STATUS(r) != SCPE_OK)
|
|
return r;
|
|
uptr->u5 = 0;
|
|
uptr->u6 = 0; // u6 = number of cards punched
|
|
|
|
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";
|
|
}
|
|
|
|
|