simh-testsetgenerator/PDP10/kx10_cr.c

341 lines
12 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.

/* kx10_cr.c: PDP10 Card reader.
Copyright (c) 2016-2020, 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 "kx10_defs.h"
#include "sim_card.h"
#include "sim_defs.h"
#if (NUM_DEVS_CR > 0)
#define UNIT_CDR UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | MODE_DEC29 | MODE_LOWER
#define CR_DEVNUM 0150
#if KL
#define CR_DIS DEV_DIS
#endif
#ifndef CR_DIS
#define CR_DIS 0
#endif
/* std devices. data structures
cr_dev Card Reader device descriptor
cr_unit Card Reader unit descriptor
cr_reg Card Reader register list
cr_mod Card Reader modifiers list
*/
/* CONO Bits */
#define PIA 0000007
#define CLR_DRDY 0000010 /* Clear data ready */
#define CLR_END_CARD 0000020 /* Clear end of card */
#define CLR_EOF 0000040 /* Clear end of File Flag */
#define EN_READY 0000100 /* Enable ready irq */
#define CLR_DATA_MISS 0000200 /* Clear data miss */
#define EN_TROUBLE 0000400 /* Enable trouble IRQ */
#define READ_CARD 0001000 /* Read card */
#define OFFSET_CARD 0004000
#define CLR_READER 0010000 /* Clear reader */
/* CONI Bits */
#define DATA_RDY 00000010 /* Data ready */
#define END_CARD 00000020 /* End of card */
#define END_FILE 00000040 /* End of file */
#define RDY_READ 00000100 /* Ready to read */
#define DATA_MISS 00000200 /* Data missed */
#define TROUBLE 00000400 /* Trouble */
#define READING 00001000 /* Reading card */
#define HOPPER_EMPTY 00002000
#define CARD_IN_READ 00004000 /* Card in reader */
#define STOP 00010000
#define MOTION_ERROR 00020000
#define CELL_ERROR 00040000
#define PICK_ERROR 00100000
#define RDY_READ_EN 00200000
#define TROUBLE_EN 00400000
#define STATUS u3
#define COL u4
#define DATA u5
#define CARD_RDY(u) (sim_card_input_hopper_count(u) > 0 || \
sim_card_eof(u) == 1)
t_stat cr_devio(uint32 dev, uint64 *data);
t_stat cr_srv(UNIT *);
t_stat cr_reset(DEVICE *);
t_stat cr_attach(UNIT *, CONST char *);
t_stat cr_detach(UNIT *);
t_stat cr_help(FILE *, DEVICE *, UNIT *, int32, const char *);
const char *cr_description(DEVICE *dptr);
uint16 cr_buffer[80];
DIB cr_dib = { CR_DEVNUM, 1, cr_devio, NULL};
UNIT cr_unit = {
UDATA(cr_srv, UNIT_CDR, 0), 2000,
};
MTAB cr_mod[] = {
{ MODE_CHAR, MODE_026, "IBM026", "IBM026", NULL, NULL, NULL,
"IBM 026 punch encoding"},
{ MODE_CHAR, MODE_029, "IBM029", "IBM029", NULL, NULL, NULL,
"IBM 029 punch encoding"},
{ MODE_CHAR, MODE_DEC29, "DEC029", "DEC029", NULL, NULL, NULL,
"DEC 029 punch encoding"},
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_card_set_fmt, &sim_card_show_fmt, NULL},
{0}
};
REG cr_reg[] = {
{BRDATA(BUFF, cr_buffer, 16, 16, sizeof(cr_buffer)/sizeof(uint16)), REG_HRO},
{0}
};
DEVICE cr_dev = {
"CR", &cr_unit, cr_reg, cr_mod,
NUM_DEVS_CR, 8, 15, 1, 8, 8,
NULL, NULL, NULL, NULL, &cr_attach, &cr_detach,
&cr_dib, DEV_DISABLE | DEV_DEBUG | DEV_CARD | CR_DIS, 0, crd_debug,
NULL, NULL, &cr_help, NULL, NULL, &cr_description
};
/*
* Device entry points for card reader.
*/
t_stat cr_devio(uint32 dev, uint64 *data) {
UNIT *uptr = &cr_unit;
switch(dev & 3) {
case CONI:
if (uptr->flags & UNIT_ATT &&
(uptr->STATUS & (TROUBLE|READING|CARD_IN_READ|END_CARD)) == 0 &&
CARD_RDY(uptr)) {
uptr->STATUS |= RDY_READ;
}
*data = uptr->STATUS;
sim_debug(DEBUG_CONI, &cr_dev, "CR: CONI %012llo\n", *data);
break;
case CONO:
clr_interrupt(dev);
sim_debug(DEBUG_CONO, &cr_dev, "CR: CONO %012llo PC=%06o\n", *data, PC);
if (*data & CLR_READER) {
uptr->STATUS = 0;
if (!CARD_RDY(uptr))
uptr->STATUS |= END_FILE;
sim_cancel(uptr);
break;
}
uptr->STATUS &= ~(PIA);
uptr->STATUS |= *data & PIA;
uptr->STATUS &= ~(*data & (CLR_DRDY|CLR_END_CARD|CLR_EOF|CLR_DATA_MISS));
if (*data & EN_TROUBLE)
uptr->STATUS |= TROUBLE_EN;
if (*data & EN_READY)
uptr->STATUS |= RDY_READ_EN;
if (uptr->flags & UNIT_ATT && *data & READ_CARD) {
uptr->STATUS |= READING;
uptr->STATUS &= ~(CARD_IN_READ|RDY_READ|DATA_RDY);
uptr->COL = 0;
sim_activate(uptr, uptr->wait);
break;
}
if (CARD_RDY(uptr))
uptr->STATUS |= RDY_READ;
else
uptr->STATUS |= STOP;
if (uptr->STATUS & RDY_READ_EN && uptr->STATUS & RDY_READ)
set_interrupt(dev, uptr->STATUS);
if (uptr->STATUS & TROUBLE_EN && uptr->STATUS & TROUBLE)
set_interrupt(dev, uptr->STATUS);
break;
case DATAI:
clr_interrupt(dev);
if (uptr->STATUS & DATA_RDY) {
*data = uptr->DATA & ~RSIGN;
if (uptr->DATA & RSIGN)
*data |= SMASK;
sim_debug(DEBUG_DATAIO, &cr_dev, "CR: DATAI %012llo\n", *data);
uptr->STATUS &= ~DATA_RDY;
} else
*data = 0;
break;
case DATAO:
break;
}
return SCPE_OK;
}
/* Handle transfer of data for card reader */
t_stat
cr_srv(UNIT *uptr) {
/* Read in card, ready to read next one set IRQ */
if (uptr->flags & UNIT_ATT /*&& uptr->STATUS & END_CARD*/) {
if ((uptr->STATUS & (READING|CARD_IN_READ|RDY_READ)) == 0 &&
(CARD_RDY(uptr))) {
sim_debug(DEBUG_EXP, &cr_dev, "CR: card ready %d\n",
sim_card_input_hopper_count(uptr));
uptr->STATUS |= RDY_READ; /* INdicate ready to start reading */
if (uptr->STATUS & RDY_READ_EN)
set_interrupt(CR_DEVNUM, uptr->STATUS);
return SCPE_OK;
}
}
/* Check if new card requested. */
if ((uptr->STATUS & (READING|CARD_IN_READ)) == READING) {
uptr->STATUS &= ~(END_CARD|RDY_READ);
switch(sim_read_card(uptr, cr_buffer)) {
case CDSE_EOF:
sim_debug(DEBUG_EXP, &cr_dev, "CR: card eof\n");
uptr->STATUS &= ~(CARD_IN_READ|READING);
uptr->STATUS |= END_FILE;
if (sim_card_input_hopper_count(uptr) != 0)
sim_activate(uptr, uptr->wait);
set_interrupt(CR_DEVNUM, uptr->STATUS);
return SCPE_OK;
case CDSE_EMPTY:
sim_debug(DEBUG_EXP, &cr_dev, "CR: card empty\n");
uptr->STATUS &= ~(CARD_IN_READ|READING);
uptr->STATUS |= HOPPER_EMPTY|TROUBLE;
if (uptr->STATUS & TROUBLE_EN)
set_interrupt(CR_DEVNUM, uptr->STATUS);
return SCPE_OK;
case CDSE_ERROR:
sim_debug(DEBUG_EXP, &cr_dev, "CR: card error\n");
uptr->STATUS &= ~(CARD_IN_READ|READING);
uptr->STATUS |= TROUBLE|PICK_ERROR|STOP;
if (uptr->STATUS & TROUBLE_EN)
set_interrupt(CR_DEVNUM, uptr->STATUS);
return SCPE_OK;
case CDSE_OK:
sim_debug(DEBUG_EXP, &cr_dev, "CR: card ok\n");
uptr->STATUS |= CARD_IN_READ;
break;
}
uptr->COL = 0;
sim_activate(uptr, uptr->wait);
return SCPE_OK;
}
/* Copy next column over */
if (uptr->STATUS & CARD_IN_READ) {
uint32 data;
int i;
if (uptr->COL >= 80) {
uptr->STATUS &= ~(CARD_IN_READ|READING);
if (sim_card_input_hopper_count(uptr) == 0)
uptr->STATUS |= HOPPER_EMPTY;
uptr->STATUS |= END_CARD;
set_interrupt(CR_DEVNUM, uptr->STATUS);
sim_activate(uptr, uptr->wait);
return SCPE_OK;
}
data = cr_buffer[uptr->COL++];
uptr->DATA = data;
/* Generate upper 18 bits of data */
uptr->DATA |= ((data & 0x001) << 25) |
((data & 0xe00) << 13) |
((data & 0x002) << 20);
for (i = 1; i <= 7; i++) {
if (data & 0x100) {
/* Set flag it more then one punch */
if ((uptr->DATA & 07000000) != 0){
uptr->DATA |= (int32)RSIGN;
break;
}
uptr->DATA |= i << 18;
}
data <<= 1;
}
if (uptr->STATUS & DATA_RDY) {
uptr->STATUS |= DATA_MISS;
}
uptr->STATUS |= DATA_RDY;
sim_debug(DEBUG_DATA, &cr_dev, "CR Char > %d %03x\n", uptr->COL, uptr->DATA);
set_interrupt(CR_DEVNUM, uptr->STATUS);
sim_activate(uptr, uptr->wait);
}
return SCPE_OK;
}
t_stat
cr_attach(UNIT * uptr, CONST char *file)
{
t_stat r;
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
return r;
if ((uptr->STATUS & (READING|CARD_IN_READ)) == 0) {
uptr->STATUS |= RDY_READ;
uptr->STATUS &= ~(HOPPER_EMPTY|STOP|TROUBLE|CELL_ERROR|PICK_ERROR);
if (uptr->STATUS & RDY_READ_EN)
set_interrupt(CR_DEVNUM, uptr->STATUS);
}
return SCPE_OK;
}
t_stat
cr_detach(UNIT * uptr)
{
if (uptr->flags & UNIT_ATT) {
uptr->STATUS |= TROUBLE|HOPPER_EMPTY;
if (uptr->STATUS & TROUBLE_EN)
set_interrupt(CR_DEVNUM, uptr->STATUS);
}
uptr->STATUS &= ~ RDY_READ;
return sim_card_detach(uptr);
}
t_stat
cr_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "Card Reader\n\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 *
cr_description(DEVICE *dptr)
{
return "Card Reader";
}
#endif