mirror of
https://github.com/open-simh/simh.git
synced 2026-04-30 21:49:00 +00:00
SDS: Add Card Reader and Card Punch devices
This commit is contained in:
committed by
Mark Pizzolato
parent
541d1c3c90
commit
79878eb6ed
381
SDS/sds_cr.c
Normal file
381
SDS/sds_cr.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user