1) Support for new sim_card interface which supports stacking of input decks. 2) Changes to allow IBM 704 to properly run Fortran II and allow i7090 to be set to IBM 704 correctly. 3) Changes to allow 9IOTA diagnostics to pass.
422 lines
12 KiB
C
422 lines
12 KiB
C
/* i7000_cdr.c: IBM 7000 Card reader.
|
||
|
||
Copyright (c) 2005-2016, Richard Cornwell
|
||
|
||
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
|
||
RICHARD CORNWELL 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 reader.
|
||
|
||
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 "i7000_defs.h"
|
||
#include "sim_card.h"
|
||
#include "sim_defs.h"
|
||
#ifdef NUM_DEVS_CDR
|
||
|
||
#define UNIT_CDR UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | MODE_026
|
||
|
||
/* Flags for punch and reader. */
|
||
#define ATTENA (1 << (UNIT_V_UF+7))
|
||
#define ATTENB (1 << (UNIT_V_UF+14))
|
||
|
||
|
||
/* std devices. data structures
|
||
|
||
cdr_dev Card Reader device descriptor
|
||
cdr_unit Card Reader unit descriptor
|
||
cdr_reg Card Reader register list
|
||
cdr_mod Card Reader modifiers list
|
||
*/
|
||
|
||
uint32 cdr_cmd(UNIT *, uint16, uint16);
|
||
t_stat cdr_boot(int32, DEVICE *);
|
||
t_stat cdr_srv(UNIT *);
|
||
t_stat cdr_reset(DEVICE *);
|
||
t_stat cdr_attach(UNIT *, CONST char *);
|
||
t_stat cdr_detach(UNIT *);
|
||
extern t_stat chan_boot(int32, DEVICE *);
|
||
#ifdef I7070
|
||
t_stat cdr_setload(UNIT *, int32, CONST char *, void *);
|
||
t_stat cdr_getload(FILE *, UNIT *, int32, CONST void *);
|
||
#endif
|
||
t_stat cdr_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
const char *cdr_description(DEVICE *dptr);
|
||
|
||
UNIT cdr_unit[] = {
|
||
{UDATA(cdr_srv, UNIT_S_CHAN(CHAN_CHUREC) | UNIT_CDR, 0), 300}, /* A */
|
||
#if NUM_DEVS_CDR > 1
|
||
{UDATA(cdr_srv, UNIT_S_CHAN(CHAN_CHUREC+1) | UNIT_CDR, 0), 300}, /* B */
|
||
#endif
|
||
};
|
||
|
||
MTAB cdr_mod[] = {
|
||
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||
&sim_card_set_fmt, &sim_card_show_fmt, NULL, "Set card format"},
|
||
#ifdef I7070
|
||
{ATTENA|ATTENB, 0, NULL, "NOATTEN", NULL, NULL, NULL, "No attention signal"},
|
||
{ATTENA|ATTENB, ATTENA, "ATTENA", "ATTENA", NULL, NULL, NULL, "Signal Attention A"},
|
||
{ATTENA|ATTENB, ATTENB, "ATTENB", "ATTENB", NULL, NULL, NULL, "Signal Attention B"},
|
||
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "LCOL", "LCOL", &cdr_setload,
|
||
&cdr_getload, NULL, "Load card column indicator"},
|
||
#endif
|
||
#ifdef I7010
|
||
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "CHAN", "CHAN", &set_chan,
|
||
&get_chan, NULL, "Set device channel"},
|
||
#endif
|
||
{0}
|
||
};
|
||
|
||
DEVICE cdr_dev = {
|
||
"CDR", cdr_unit, NULL, cdr_mod,
|
||
NUM_DEVS_CDR, 8, 15, 1, 8, 8,
|
||
NULL, NULL, NULL, &cdr_boot, &cdr_attach, &cdr_detach,
|
||
&cdr_dib, DEV_DISABLE | DEV_DEBUG | DEV_CARD, 0, crd_debug,
|
||
NULL, NULL, &cdr_help, NULL, NULL, &cdr_description
|
||
};
|
||
|
||
|
||
/*
|
||
* Device entry points for card reader.
|
||
*/
|
||
uint32 cdr_cmd(UNIT * uptr, uint16 cmd, uint16 dev)
|
||
{
|
||
int chan = UNIT_G_CHAN(uptr->flags);
|
||
int u = (uptr - cdr_unit);
|
||
int stk = dev & 017;
|
||
|
||
/* Are we currently tranfering? */
|
||
if (uptr->u5 & URCSTA_READ)
|
||
return SCPE_BUSY;
|
||
|
||
/* Test ready */
|
||
if (cmd == IO_TRS && uptr->flags & UNIT_ATT) {
|
||
sim_debug(DEBUG_CMD, &cdr_dev, "%d: Test Rdy\n", u);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
if (stk == 10)
|
||
stk = 0;
|
||
|
||
#ifdef STACK_DEV
|
||
uptr->u5 &= ~0xF0000;
|
||
uptr->u5 |= stk << 16;
|
||
#endif
|
||
if (uptr->u5 & (URCSTA_EOF|URCSTA_ERR))
|
||
return SCPE_IOERR;
|
||
|
||
/* Process commands */
|
||
switch(cmd) {
|
||
case IO_RDS:
|
||
sim_debug(DEBUG_CMD, &cdr_dev, "%d: Cmd RDS %02o\n", u, dev & 077);
|
||
#ifdef I7010
|
||
if (stk!= 9)
|
||
#endif
|
||
uptr->u5 &= ~(URCSTA_CARD|URCSTA_ERR);
|
||
break;
|
||
case IO_CTL:
|
||
sim_debug(DEBUG_CMD, &cdr_dev, "%d: Cmd CTL %02o\n", u, dev & 077);
|
||
#ifdef I7010
|
||
uptr->u5 |= URCSTA_NOXFER;
|
||
#endif
|
||
break;
|
||
default:
|
||
chan_set_attn(chan);
|
||
return SCPE_IOERR;
|
||
}
|
||
|
||
/* If at eof, just return EOF */
|
||
if (uptr->u5 & URCSTA_EOF) {
|
||
chan_set_eof(chan);
|
||
chan_set_attn(chan);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
uptr->u5 |= URCSTA_READ;
|
||
uptr->u4 = 0;
|
||
|
||
if ((uptr->u5 & URCSTA_NOXFER) == 0)
|
||
chan_set_sel(chan, 0);
|
||
/* Wake it up if not busy */
|
||
if ((uptr->u5 & URCSTA_BUSY) == 0)
|
||
sim_activate(uptr, 50);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Handle transfer of data for card reader */
|
||
t_stat
|
||
cdr_srv(UNIT *uptr) {
|
||
int chan = UNIT_G_CHAN(uptr->flags);
|
||
int u = (uptr - cdr_unit);
|
||
uint16 *image = (uint16 *)(uptr->up7);
|
||
|
||
/* Waiting for disconnect */
|
||
if (uptr->u5 & URCSTA_WDISCO) {
|
||
if (chan_stat(chan, DEV_DISCO)) {
|
||
chan_clear(chan, DEV_SEL|DEV_WEOR);
|
||
uptr->u5 &= ~ URCSTA_WDISCO;
|
||
} else {
|
||
/* No disco yet, try again in a bit */
|
||
sim_activate(uptr, 50);
|
||
return SCPE_OK;
|
||
}
|
||
/* If still busy, schedule another wait */
|
||
if (uptr->u5 & URCSTA_BUSY)
|
||
sim_activate(uptr, uptr->wait);
|
||
}
|
||
|
||
if (uptr->u5 & URCSTA_BUSY) {
|
||
uptr->u5 &= ~URCSTA_BUSY;
|
||
#ifdef I7070
|
||
switch(uptr->flags & (ATTENA|ATTENB)) {
|
||
case ATTENA: chan_set_attn_a(chan); break;
|
||
case ATTENB: chan_set_attn_b(chan); break;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/* Check if new card requested. */
|
||
if (uptr->u4 == 0 && uptr->u5 & URCSTA_READ &&
|
||
(uptr->u5 & URCSTA_CARD) == 0) {
|
||
switch(sim_read_card(uptr, image)) {
|
||
case CDSE_EOF:
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "%d: EOF\n", u);
|
||
/* Fall through */
|
||
|
||
case CDSE_EMPTY:
|
||
chan_set_eof(chan);
|
||
chan_set_attn(chan);
|
||
chan_clear(chan, DEV_SEL);
|
||
uptr->u5 |= URCSTA_EOF;
|
||
uptr->u5 &= ~(URCSTA_BUSY|URCSTA_READ);
|
||
return SCPE_OK;
|
||
case CDSE_ERROR:
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "%d: ERF\n", u);
|
||
uptr->u5 |= URCSTA_ERR;
|
||
uptr->u5 &= ~(URCSTA_BUSY|URCSTA_READ);
|
||
chan_set_attn(chan);
|
||
chan_clear(chan, DEV_SEL);
|
||
return SCPE_OK;
|
||
case CDSE_OK:
|
||
uptr->u5 |= URCSTA_CARD;
|
||
#ifdef I7010
|
||
chan_set_attn_urec(chan, cdr_dib.addr);
|
||
#endif
|
||
break;
|
||
}
|
||
#ifdef I7070
|
||
/* Check if load card. */
|
||
if (uptr->capac && (image[uptr->capac-1] & 0x800)) {
|
||
uptr->u5 |= URCSTA_LOAD;
|
||
chan_set_load_mode(chan);
|
||
} else {
|
||
uptr->u5 &= ~URCSTA_LOAD;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
if (uptr->u5 & URCSTA_NOXFER) {
|
||
uptr->u5 &= ~(URCSTA_NOXFER|URCSTA_READ);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Copy next column over */
|
||
if (uptr->u5 & URCSTA_READ && uptr->u4 < 80) {
|
||
uint8 ch = 0;
|
||
|
||
#ifdef I7080
|
||
/* Detect RSU */
|
||
if (image[uptr->u4] == 0x924) {
|
||
uptr->u5 &= ~URCSTA_READ;
|
||
uptr->u5 |= URCSTA_WDISCO;
|
||
chan_set(chan, DEV_REOR);
|
||
sim_activate(uptr, 10);
|
||
return SCPE_OK;
|
||
}
|
||
#endif
|
||
|
||
ch = sim_hol_to_bcd(image[uptr->u4]);
|
||
|
||
/* Handle invalid punch */
|
||
if (ch == 0x7f) {
|
||
#ifdef I7080
|
||
uptr->u5 &= ~(URCSTA_READ|URCSTA_BUSY);
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "%d: bad punch %d\n", u,
|
||
uptr->u4);
|
||
chan_set_attn(chan);
|
||
chan_set_error(chan);
|
||
chan_clear(chan, DEV_SEL);
|
||
#else
|
||
uptr->u5 |= URCSTA_ERR;
|
||
ch = 017;
|
||
#endif
|
||
}
|
||
|
||
#ifdef I7070
|
||
/* During load, only sign on every 10 columns */
|
||
if (uptr->u5 & URCSTA_LOAD && (uptr->u4 % 10) != 9)
|
||
ch &= 0xf;
|
||
#endif
|
||
|
||
switch(chan_write_char(chan, &ch, (uptr->u4 == 79)? DEV_REOR: 0)) {
|
||
case TIME_ERROR:
|
||
case END_RECORD:
|
||
uptr->u5 |= URCSTA_WDISCO|URCSTA_BUSY;
|
||
uptr->u5 &= ~URCSTA_READ;
|
||
break;
|
||
case DATA_OK:
|
||
uptr->u4++;
|
||
break;
|
||
}
|
||
sim_debug(DEBUG_DATA, &cdr_dev, "%d: Char > %02o\n", u, ch);
|
||
sim_activate(uptr, 10);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
cdr_boot(int32 unit_num, DEVICE * dptr)
|
||
{
|
||
UNIT *uptr = &dptr->units[unit_num];
|
||
t_stat r;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0)
|
||
return SCPE_UNATT; /* attached? */
|
||
/* Read in one record */
|
||
r = cdr_cmd(uptr, IO_RDS, cdr_dib.addr);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
r = chan_boot(unit_num, dptr);
|
||
return r;
|
||
}
|
||
|
||
t_stat
|
||
cdr_attach(UNIT * uptr, CONST char *file)
|
||
{
|
||
t_stat r;
|
||
|
||
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
|
||
return r;
|
||
if (uptr->up7 == 0) {
|
||
uptr->up7 = malloc(sizeof(uint16)*80);
|
||
uptr->u5 &= URCSTA_BUSY|URCSTA_WDISCO;
|
||
uptr->u4 = 0;
|
||
uptr->u6 = 0;
|
||
}
|
||
#ifdef I7010
|
||
chan_set_attn_urec(UNIT_G_CHAN(uptr->flags), cdr_dib.addr);
|
||
#endif
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cdr_detach(UNIT * uptr)
|
||
{
|
||
t_stat r;
|
||
|
||
if ((r = sim_card_detach(uptr)) != SCPE_OK)
|
||
return r;
|
||
if (uptr->up7 != 0)
|
||
free(uptr->up7);
|
||
uptr->up7 = 0;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
#ifdef I7070
|
||
t_stat
|
||
cdr_setload(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
int i;
|
||
if (cptr == NULL)
|
||
return SCPE_ARG;
|
||
if (uptr == NULL)
|
||
return SCPE_IERR;
|
||
i = 0;
|
||
while(*cptr != '\0') {
|
||
if (*cptr < '0' || *cptr > '9')
|
||
return SCPE_ARG;
|
||
i = (i * 10) + (*cptr++) - '0';
|
||
}
|
||
if (i > 80)
|
||
return SCPE_ARG;
|
||
uptr->capac = i;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cdr_getload(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
|
||
{
|
||
if (uptr == NULL)
|
||
return SCPE_IERR;
|
||
fprintf(st, "loadcolumn=%d", uptr->capac);
|
||
return SCPE_OK;
|
||
}
|
||
#endif
|
||
|
||
t_stat
|
||
cdr_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "%s\n\n", cdr_description(dptr));
|
||
#if NUM_DEVS_CDR > 1
|
||
fprintf (st, "The system supports up to two card readers.\n");
|
||
#else
|
||
fprintf (st, "The system supports one card reader.\n");
|
||
#endif
|
||
#ifdef I7070
|
||
fprintf (st, "Unit record devices can be configured to interrupt the CPU on\n");
|
||
fprintf (st, "one of two priority channels A or B, to set this\n\n");
|
||
fprintf (st, " sim> SET %s ATTENA To set device to raise Atten A\n\n", dptr->name);
|
||
fprintf (st, "The 7500 Card reader supported a load mode, this was\n");
|
||
fprintf (st, "selected by use of a 12 punch in a given column. When this\n");
|
||
fprintf (st, "was seen the card was read into 8 words. Normal read is\n");
|
||
fprintf (st, "text only\n\n");
|
||
fprintf (st, " sim> SET %s LCOL=72 Sets column to select load mode\n\n", dptr->name);
|
||
#endif
|
||
#if NUM_DEVS_CDR > 1
|
||
#ifdef I7010
|
||
help_set_chan_type(st, dptr, "Card reader");
|
||
#endif
|
||
#endif
|
||
sim_card_attach_help(st, dptr, uptr, flag, cptr);
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
cdr_description(DEVICE *dptr)
|
||
{
|
||
#ifdef I7010
|
||
return "1402 Card Reader";
|
||
#endif
|
||
#ifdef I7070
|
||
return "7500 Card Reader";
|
||
#endif
|
||
#ifdef I7080
|
||
return "711 Card Reader";
|
||
#endif
|
||
}
|
||
|
||
#endif
|
||
|