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

381 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* sds_cr.c: SDS-930 card reader simulator
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 reader simulator uses sim_card.c to attach and read input records
in CBN format. When BCD mode is specified by the buffer control EOM, input data
is translated from the Hollerith encoded data in the card columns to the
SDS Internal Code as defined by the SDS 930 Computer Reference Manual. The
translation function was modified from the sim_card.c code to provide SDS
Internal BCD codes.
The card reader delays the disconnect after the last character until the trailing
edge of the card is detected. In this simulator, this delay is accomplished
by scheduling a final service request after the last characters have been
delivered too the channel. The timing for this service has been adjusted to
handle some example SDS programs. Too long a delay causes errors in some, too short
a delay affects others.
*/
#include "sds_defs.h"
#include "sim_card.h"
#define FEEDING 00001000 /* feeding card to read station */
#define READING 00004000 /* Card at read station */
#define STATUS u3 /* status */
#define CARD_RDY(u) (sim_card_input_hopper_count(u) > 0 || \
sim_card_eof(u) == 1)
extern uint32 xfr_req;
extern int32 stop_invins, stop_invdev, stop_inviop;
extern uint8 chan_cpw[NUM_CHAN]; /* char per word */
extern uint8 chan_cnt[NUM_CHAN]; /* char count */
int32 cr_bptr = 0; /* buf ptr */
int32 cr_blnt = 0; /* buf length */
int32 cr_chr = 0; /* char no.*/
int32 cr_inst = 0; /* saved instr */
int32 cr_eor = 0; /* end of record */
uint16 cr_buffer[80]; /* card record */
DSPT cr_tplt[] = {{1,0},{0,0}}; /* template */
t_stat cr_svc(UNIT *);
t_stat cr_boot(int32, DEVICE *);
t_stat cr_reset(DEVICE *);
t_stat cr_attach(UNIT *, CONST char *);
t_stat cr_detach(UNIT *);
t_stat cr_devio(uint32 fnc, uint32 inst, uint32 *dat);
t_stat cr_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat cr_readrec (UNIT *uptr);
void cr_set_err (UNIT *uptr);
DIB cr_dib = { CHAN_W, DEV_CR, XFR_CR, cr_tplt, &cr_devio };
UNIT cr_unit = {
UDATA(&cr_svc, UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | MODE_029 | MODE_CBN,0),
60
};
REG cr_reg[] = {
{ DRDATA (BPTR, cr_bptr, 18), PV_LEFT },
{ DRDATA (BLNT, cr_blnt, 18), PV_LEFT },
{ FLDATA (XFR, xfr_req, XFR_V_CR) },
{ ORDATA (INST, cr_inst, 24) },
{ DRDATA (POS, cr_unit.pos, T_ADDR_W), PV_LEFT },
{ NULL }
};
MTAB cr_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, &cr_show_cap, NULL, "Card Input Status" },
{0}
};
DEVICE cr_dev = {
"CR", &cr_unit, cr_reg, cr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &cr_reset, &cr_boot, &cr_attach,NULL,
&cr_dib, DEV_DISABLE | DEV_CARD, 0, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
/* Returns the SDS Internal style BCD of the
hollerith code or 0x7f if error
*/
uint8 hol_to_sdsbcd(uint16 hol) {
uint8 bcd;
/* Convert 10,11,12 rows */
switch (hol & 0xe00) {
case 0x000:
if ((hol & 0x1ff) == 0)
return 060;
bcd = 000; // digits 1-9
break;
case 0x200: /* 0 */
if ((hol & 0x1ff) == 0)
return 00; // digit 0
bcd = 060; // /,S-Z
break;
case 0x400: /* 11 */
bcd = 040; // -,J-R
break;
case 0x600: /* 11-10 Punch */
bcd = 052;
break;
case 0x800: /* 12 */
bcd = 020; // +,A-I
break;
case 0xA00: /* 12-10 Punch */
bcd = 032;
break;
default: /* Double punch in 10,11,12 rows */
return 0x7f;
}
hol &= 0x1ff; /* Mask rows 0-9 */
/* Check row 8 punched */
if (hol & 0x2) {
bcd += 8;
hol &= ~0x2;
}
/* Convert rows 0-9 */
while (hol != 0 && (hol & 0x200) == 0) {
bcd++;
hol <<= 1;
}
/* Any more columns punched? */
if ((hol & 0x1ff) != 0)
return 0x7f;
return bcd;
}
/* device i/o routine */
t_stat cr_devio (uint32 fnc, uint32 inst, uint32 *dat) {
UNIT *uptr = &cr_unit; /* get unit ptr */
int32 new_ch;
int32 t;
t_stat r;
unsigned char chr;
switch (fnc) { /* case function */
case IO_CONN: /* bufer control EOM */
new_ch = I_GETEOCH (inst); /* get new chan */
if (new_ch != cr_dib.chan) /* wrong chan? */
return SCPE_IERR;
if (sim_is_active(uptr)) /* busy ?*/
CRETIOP;
/* if not reading and no card in reader and hopper has cards */
if ((uptr->STATUS & (FEEDING|READING)) == 0 &&
(sim_card_input_hopper_count(uptr) > 0)) {
uptr->STATUS = FEEDING;
cr_inst = inst;
cr_blnt = 0;
cr_bptr = 0;
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
sim_activate (uptr,2*uptr->wait); /* start timer */
}
else {
/* if feeding or reading in different mode */
if ((inst & 01000) != (cr_inst & 01000)) {
if (cr_inst & 01000) {
if (cr_chr & 1) { /* was binary - at 2nd 6 bits
*/
cr_bptr++; /* skip to next column*/
}
}
cr_chr = 0;
}
}
cr_inst = inst; /* save EOM with mode */
break;
case IO_EOM1: /* I/O Control EOM */
new_ch = I_GETEOCH (inst); /* get new chan */
if (new_ch != cr_dib.chan) /* wrong chan? err */
return SCPE_IERR;
if ((inst & 07700) == 02000) { /* skip remainder of card*/
sim_cancel (uptr); /* stop timer */
chan_set_flag (cr_dib.chan, CHF_EOR); /* end record */
uptr->STATUS = 0;
chan_disc (cr_dib.chan);
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
}
break;
case IO_DISC: /* disconnect */
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
sim_cancel (uptr); /* deactivate unit */
break;
case IO_SKS: /* SKS */
new_ch = I_GETSKCH (inst); /* get chan # */
if (new_ch != cr_dib.chan) /* wrong chan? */
return SCPE_IERR;
t = I_GETSKCND (inst); /* get skip cond */
switch (t) { /* case sks cond */
case 004: /* sks 1100n */
// CFT
if ((uptr->STATUS & (FEEDING|READING)) == 0 &&
(sim_card_input_hopper_count(uptr) > 0))
*dat = 1; /* skip if not EOF */
break;
case 010: /* sks 1200n */
// CRT
// hopper not empty
// no feed or read cycle is in progress
if ((uptr->STATUS & (FEEDING|READING)) == 0 &&
(sim_card_input_hopper_count(uptr) > 0))
*dat = 1; /* skip if reader ready */
break;
case 020: /* sks 1400n */
if ((uptr->STATUS & READING) && /* first column test */
(((cr_inst & 01000) && (cr_chr < 2)) ||
(cr_chr < 1)))
*dat = 1; /* skip if first column*/
break;
}
break;
case IO_READ:
xfr_req = xfr_req & ~XFR_CR;
if (cr_blnt == 0) { /* first read? */
r = cr_readrec (uptr); /* get data */
if ((r != SCPE_OK) || (cr_blnt == 0)) /* err, inv reclnt? */
return r;
}
if (cr_blnt) {
if (cr_inst & 01000) {
if (cr_chr & 1) /* binary */
chr =cr_buffer[cr_bptr++] & 077;
else
chr = (cr_buffer[cr_bptr] >> 6) & 077;
cr_chr++;
*dat = chr & 077;
}
else {
chr = hol_to_sdsbcd(cr_buffer[cr_bptr++]); /* bcd */
*dat = chr & 077;
}
}
if (cr_bptr >= cr_blnt) {
/* The card reader doesn't disconnect from the channel until the
trailing edge of the card passes the read station so we need to
schedule another service event here. But if it disconnects too
soon some programs (Fortran and 850647 (unencode) don't work right
and if it takes too long Symbol will try to connect to the LP
before it's disconnected.
*/
cr_eor = 1;
sim_cancel(uptr);
sim_activate (uptr, 50);
}
break;
case IO_WREOR:
case IO_WRITE:
CRETINS;
}
return SCPE_OK;
}
/* Service routine */
t_stat cr_svc(UNIT * uptr) {
xfr_req = xfr_req & ~XFR_CR;
if (cr_eor) {
cr_eor = 0;
sim_cancel (uptr);
chan_set_flag (cr_dib.chan, CHF_EOR);
uptr->STATUS = 0;
return SCPE_OK;
}
xfr_req = xfr_req | XFR_CR;
sim_activate (uptr, 50);
return SCPE_OK;
}
/* Read start - get next record */
t_stat cr_readrec (UNIT *uptr) {
int r;
switch(r = sim_read_card(uptr, cr_buffer)) {
case CDSE_EOF: /* parser found tape mark attach */
case CDSE_EMPTY: /* not attached or hopper empty */
case CDSE_ERROR: /* parser found error during attach */
default:
uptr->STATUS = 0; /* read failed, no card in reader */
cr_set_err(uptr);
return r;
case CDSE_OK:
uptr->STATUS = READING;
cr_bptr = 0;
cr_blnt = 80;
cr_chr = 0;
break;
}
return SCPE_OK;
}
/* Fatal error */
void cr_set_err (UNIT *uptr) {
chan_set_flag (cr_dib.chan, CHF_EOR | CHF_ERR); /* eor, error */
chan_disc (cr_dib.chan); /* disconnect */
xfr_req = xfr_req & ~XFR_CR; /* clear xfr */
sim_cancel (uptr); /* stop */
cr_bptr = 0; /* buf empty */
return;
}
t_stat cr_reset (DEVICE *dptr) {
chan_disc (cr_dib.chan); /* disconnect */
cr_bptr = cr_blnt = 0;
xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */
sim_cancel (&cr_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat cr_attach (UNIT *uptr, CONST char *cptr) {
return sim_card_attach(uptr, cptr);
}
/* Boot routine - simulate FILL console command */
t_stat cr_boot (int32 unitno, DEVICE *dptr) {
extern uint32 P, M[];
cr_reset(dptr);
M[0] = 077777771; /* -7B */
M[1] = 007100000; /* LDX 0 */
M[2] = 000203606; /* EOM 3606 read card binary */
M[3] = 003200002; /* WIM 2 */
M[4] = 000100002; /* BRU 2 */
P = 1; /* start at 1 */
return SCPE_OK;
}
t_stat cr_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
int n;
if ((n = sim_card_input_hopper_count(uptr)) == 0)
fprintf(st,"hopper empty");
else {
if (n == 1)
fprintf(st,"1 card");
else
fprintf(st,"%d cards",n);
fprintf(st," in hopper");
}
return SCPE_OK;
}