simh-testsetgenerator/SDS/sds_cp.c
2020-12-18 23:47:36 -08:00

318 lines
10 KiB
C

/* sds_cp.c - SDS-930 Card Punch
Copyright (c) 2020, Ken Rector
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
KEN RECTOR 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.
Except as contained in this notice, the name of Ken Rector shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Ken Rector.
03-Mar-20 kenr Initial Version
*/
/*
This card punch simulator uses sim_card.c to write output records
in CBN format. Data is passed directly to sim_card.c when binary
mode is specified by the buffer control EOM. When BCD mode is
specified by the EOM, output data is translated into Hollerith code
from SDS Internal Code as defined by the SDS 930 Computer Reference Manual
The SDS card punch protocol defined by the 930 Computer Reference manual
specifies that the output image be sent to the buffer 12 times, once
for each row. In this simulator the card image is only written after
termination (TOP) of the twelfth image output.
The Symbol assembler punch routine uses the PBT (Punch Buffer Test)
before issueing a connect EOM to determine if it needs to write 12 rows
per card, or just 1. To make Symbol work right we always return TRUE,
(skip) for this test.
I can't find anything in the computer reference manuals that describes
how this should work. Why did Symbol do this?
*/
#include "sds_defs.h"
#include "sim_card.h"
#define CARD_IN_PUNCH 00004000 /* Card ready to punch */
#define STATUS u3
extern uint32 xfr_req;
extern int32 stop_invins, stop_invdev, stop_inviop;
uint16 cp_buffer[80]; /* card output image */
int32 cp_bptr = 0; /* buf ptr */
int32 cp_blnt = 0; /* buf length */
int32 cp_row = 0; /* row counter */
int32 cp_chr = 0;
int32 cp_eor;
int32 cp_inst; /* saved instr */
t_stat cp_devio(uint32 fnc, uint32 inst, uint32 *dat);
t_stat cp_svc(UNIT *);
t_stat cp_attach(UNIT * uptr, CONST char *file);
t_stat cp_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
t_stat cp_detach(UNIT * uptr);
t_stat cp_wrend(UNIT * uptr);
t_stat cp_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
void cp_set_err (UNIT *uptr);
DSPT cp_tplt[] = { { 1, 0 }, { 0, 0 } }; /* template */
DIB cp_dib = { CHAN_W, DEV_CP, XFR_CP, cp_tplt, &cp_devio };
UNIT cp_unit = {UDATA(&cp_svc, UNIT_ATTABLE , 0), 2000 };
MTAB cp_mod[] = {
{MTAB_XTD | MTAB_VDV, 0, "CHANNEL", "CHANNEL",
&set_chan, &show_chan,
NULL, "Device Channel"},
{MTAB_XTD | MTAB_VDV, 0, "FORMAT", "FORMAT",
&sim_card_set_fmt, &sim_card_show_fmt,
NULL,"Card Format"},
{ MTAB_XTD|MTAB_VDV, 0, "CAPACITY", NULL,
NULL, &cp_show_cap, NULL, "Stacker Count" },
{0}
};
REG cp_reg[] = {
{ BRDATA (BUFF, cp_buffer, 16, 16, sizeof(cp_buffer)/sizeof(*cp_buffer)), REG_HRO},
{ DRDATA (BPTR, cp_bptr, 18), PV_LEFT },
{ DRDATA (BLNT, cp_blnt, 18), PV_LEFT },
{ FLDATA (XFR, xfr_req, XFR_V_CP) },
{ ORDATA (INST, cp_inst, 24) },
{ DRDATA (POS, cp_unit.pos, T_ADDR_W), PV_LEFT },
{ NULL }
};
DEVICE cp_dev = {
"CP", &cp_unit, cp_reg, cp_mod,
1, 8, 15, 1, 8, 8,
NULL, NULL, NULL, NULL, &cp_attach, &cp_detach,
&cp_dib, DEV_DISABLE | DEV_DEBUG | DEV_CARD, 0, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
/* Convert SDS BCD character into hollerith code */
uint16 sdsbcd_to_hol(uint8 bcd) {
uint16 hol;
/* Handle space correctly */
if (bcd == 0) /* 0 to row 10 */
return 0x200;
if (bcd == 060) /* 60 no punch */
return 0;
/* Convert to top column */
switch (bcd & 060) {
default:
case 000:
hol = 0x000; /* no zone */
break;
case 020:
hol = 0x800; /* 0x200 row 12 */
break;
case 040:
hol = 0x400; /* row 11 */
break;
case 060:
hol = 0x200; /* row 10 */
break;
}
/* Convert to 0-9 row */
bcd &= 017;
if (bcd > 9) {
hol |= 0x2; /* row 8 */
bcd -= 8;
}
if (bcd != 0)
hol |= 1 << (9 - bcd);
return hol;
}
t_stat cp_devio(uint32 fnc, uint32 inst, uint32 *dat) {
UNIT *uptr = &cp_unit;
int32 new_ch;
uint8 chr;
t_stat r;
uint32 t;
switch (fnc) {
case IO_CONN:
new_ch = I_GETEOCH (inst); /* get new chan */
if (new_ch != cp_dib.chan) /* wrong chan? err */
return SCPE_IERR;
if (sim_is_active(uptr))
CRETIOP;
if (uptr->flags & UNIT_ATT) {
cp_inst = inst;
cp_blnt = 0;
cp_bptr = 0;
xfr_req = xfr_req & ~XFR_CP; /* clr xfr flag */
sim_activate (uptr, uptr->wait); /* start timer */
}
else {
cp_set_err (uptr); /* no, err, disc */
CRETIOP;
}
break;
case IO_EOM1: /* I/O Control EOM */
break;
case IO_DISC: /* disconnect TOP */
xfr_req = xfr_req & ~XFR_CP; /* clr xfr flag */
cp_row++;
if (cp_row >= 12) {
if ((r = cp_wrend(uptr)) != SCPE_OK)
return r;
uptr->STATUS &= ~CARD_IN_PUNCH;
}
sim_cancel (uptr); /* deactivate unit */
break;
case IO_WREOR: /* write eor */
break;
case IO_SKS:
new_ch = I_GETSKCH (inst); /* get chan # */
if (new_ch != cp_dib.chan) /* wrong chan? */
return SCPE_IERR;
t = I_GETSKCND (inst); /* get skip cond */
switch (t) { /* case sks cond */
case 010: /* sks 12046 */
// PBT
// /* skip if punch buffer empty */
*dat = 1;
break;
case 020: /* sks 14046 */
// CPT
/* skip if punch is ready to accept connection */
if ((uptr->flags & UNIT_ATT) &&
!(uptr->STATUS & CARD_IN_PUNCH))
*dat = 1;
break;
}
break;
case IO_WRITE:
if (!(uptr->STATUS & CARD_IN_PUNCH))
break;
chr = (*dat) & 077;
xfr_req = xfr_req & ~XFR_CP; /* clr xfr flag */
if (cp_bptr < cp_blnt) {
if (cp_inst & 01000) {
if (cp_chr & 1) /* column binary */
cp_buffer[cp_bptr++] |= chr;
else
cp_buffer[cp_bptr] = (chr << 6);
cp_chr++;
}
else {
cp_buffer[cp_bptr++] = sdsbcd_to_hol(chr); /* bcd */
}
chan_set_ordy (cp_dib.chan);
}
break;
case IO_READ:
CRETINS;
}
return SCPE_OK;
}
/* punch service */
t_stat cp_svc(UNIT *uptr) {
uptr->STATUS |= CARD_IN_PUNCH;
cp_bptr = 0;
cp_blnt = 80;
cp_chr = 0;
chan_set_ordy (cp_dib.chan);
return SCPE_OK;
}
t_stat cp_wrend(UNIT * uptr) {
t_stat st;
st = sim_punch_card(uptr, cp_buffer);
cp_row = 0;
if (st != CDSE_OK) {
cp_set_err(uptr);
return SCPE_IOERR;
}
uptr->STATUS = 0;
return SCPE_OK;
}
/* Fatal error */
void cp_set_err (UNIT *uptr)
{
chan_set_flag (cp_dib.chan, CHF_EOR | CHF_ERR); /* eor, error */
chan_disc (cp_dib.chan); /* disconnect */
xfr_req = xfr_req & ~XFR_CP; /* clear xfr */
sim_cancel (uptr); /* stop */
cp_bptr = 0; /* buf empty */
return;
}
t_stat cp_attach(UNIT * uptr, CONST char *cptr) {
t_stat r;
sim_card_set_fmt (uptr,0,"CBN",NULL);
if ((r = sim_card_attach(uptr, cptr)) != SCPE_OK)
return r;
cp_row = 0;
return SCPE_OK;
}
t_stat cp_detach(UNIT * uptr) {
if (uptr->STATUS & CARD_IN_PUNCH)
sim_punch_card(uptr, cp_buffer);
return sim_card_detach(uptr);
}
/* Channel assignment routines */
t_stat cp_set_chan (UNIT *uptr, int32 val, CONST char *sptr, void *desc)
{
t_stat r;
r = set_chan (uptr, val, sptr, desc);
return r;
}
t_stat cp_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
int n;
if ((n = sim_card_output_hopper_count(uptr)) == 0)
fprintf(st,"stacker empty");
else {
if (n == 1)
fprintf(st,"1 card");
else
fprintf(st,"%d cards",n);
fprintf(st," in stacker");
}
return SCPE_OK;
}