341 lines
12 KiB
C
341 lines
12 KiB
C
/* 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
|
||
|