simh-testsetgenerator/PDP10/kx10_cty.c
2020-03-09 23:07:47 -07:00

237 lines
8.5 KiB
C

/* kx10_cty.c: PDP6, KA-10 and KI-10 front end (console terminal) simulator
Copyright (c) 2013-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.
Except as contained in this notice, the name of Richard Cornwell shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Richard Cornwell
*/
#include "kx10_defs.h"
#if PDP6 | KA | KI
#define UNIT_DUMMY (1 << UNIT_V_UF)
extern int32 tmxr_poll;
t_stat ctyi_svc (UNIT *uptr);
t_stat ctyo_svc (UNIT *uptr);
t_stat cty_reset (DEVICE *dptr);
t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *cty_description (DEVICE *dptr);
/* CTY data structures
cty_dev CTY device descriptor
cty_unit CTY unit descriptor
cty_reg CTY register list
*/
#define TEL_RDY 0010
#define TEL_BSY 0020
#define KEY_RDY 0040
#define KEY_BSY 0100
#define KEY_TST 04000
#define CTY_DEVNUM 0120
#define STATUS u3
#define DATA u4
#define PIA u5
t_stat cty_devio(uint32 dev, uint64 *data);
DIB cty_dib = { CTY_DEVNUM, 1, cty_devio, NULL};
UNIT cty_unit[] = {
{ UDATA (&ctyo_svc, TT_MODE_7B, 0), 10000 },
{ UDATA (&ctyi_svc, TT_MODE_7B|UNIT_IDLE, 0), 0 },
};
MTAB cty_mod[] = {
{ UNIT_DUMMY, 0, NULL, "STOP", &cty_stop_os },
{ TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode },
{ TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
{ TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
{ TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode },
{ 0 }
};
REG cty_reg[] = {
{ HRDATAD (WRU, sim_int_char, 8, "interrupt character") },
{ 0 }
};
DEVICE cty_dev = {
"CTY", cty_unit, cty_reg, cty_mod,
2, 10, 31, 1, 8, 8,
NULL, NULL, &cty_reset,
NULL, NULL, NULL, &cty_dib, DEV_DEBUG, 0, dev_debug,
NULL, NULL, &cty_help, NULL, NULL, &cty_description
};
t_stat cty_devio(uint32 dev, uint64 *data) {
uint64 res;
switch(dev & 3) {
case CONI:
res = cty_unit[0].PIA | (cty_unit[0].STATUS & (TEL_RDY | TEL_BSY));
res |= cty_unit[1].STATUS & (KEY_RDY | KEY_BSY);
res |= cty_unit[0].STATUS & KEY_TST;
*data = res;
sim_debug(DEBUG_CONI, &cty_dev, "CTY %03o CONI %06o\n", dev, (uint32)*data);
break;
case CONO:
res = *data;
cty_unit[0].PIA = res & 07;
cty_unit[1].PIA = res & 07;
cty_unit[0].PIA &= ~(KEY_TST);
cty_unit[0].STATUS &= ~((res >> 4) & (TEL_RDY | TEL_BSY));
cty_unit[0].STATUS |= (res & (TEL_RDY | TEL_BSY | KEY_TST));
cty_unit[1].STATUS &= ~((res >> 4) & (KEY_RDY | KEY_BSY));
cty_unit[1].STATUS |= (res & (KEY_RDY | KEY_BSY));
if ((cty_unit[0].STATUS & TEL_RDY) || (cty_unit[1].STATUS & KEY_RDY))
set_interrupt(dev, cty_unit[0].PIA);
else
clr_interrupt(dev);
sim_debug(DEBUG_CONO, &cty_dev, "CTY %03o CONO %06o\n", dev, (uint32)*data);
break;
case DATAI:
res = cty_unit[1].DATA & 0xff;
cty_unit[1].STATUS &= ~KEY_RDY;
if ((cty_unit[0].STATUS & TEL_RDY) == 0)
clr_interrupt(dev);
*data = res;
sim_debug(DEBUG_DATAIO, &cty_dev, "CTY %03o DATAI %06o\n", dev, (uint32)*data);
break;
case DATAO:
cty_unit[0].DATA = *data & 0x7f;
cty_unit[0].STATUS &= ~TEL_RDY;
cty_unit[0].STATUS |= TEL_BSY;
if ((cty_unit[1].STATUS & KEY_RDY) == 0)
clr_interrupt(dev);
sim_activate(&cty_unit[0], cty_unit[0].wait);
sim_debug(DEBUG_DATAIO, &cty_dev, "CTY %03o DATAO %06o\n", dev, (uint32)*data);
break;
}
return SCPE_OK;
}
t_stat ctyo_svc (UNIT *uptr)
{
t_stat r;
int32 ch;
if (uptr->DATA != 0) {
ch = sim_tt_outcvt ( uptr->DATA, TT_GET_MODE (uptr->flags)) ;
if ((r = sim_putchar_s (ch)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
}
}
uptr->STATUS &= ~TEL_BSY;
uptr->STATUS |= TEL_RDY;
set_interrupt(CTY_DEVNUM, uptr->PIA);
return SCPE_OK;
}
t_stat ctyi_svc (UNIT *uptr)
{
int32 ch;
sim_clock_coschedule (uptr, tmxr_poll);
/* continue poll */
if (uptr->STATUS & KEY_RDY)
return SCPE_OK;
if ((ch = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
return ch;
if (ch & SCPE_BREAK) /* ignore break */
return SCPE_OK;
uptr->DATA = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (uptr->flags));
uptr->DATA = ch & 0177;
uptr->STATUS |= KEY_RDY;
set_interrupt(CTY_DEVNUM, uptr->PIA);
return SCPE_OK;
}
/* Reset */
t_stat cty_reset (DEVICE *dptr)
{
cty_unit[0].STATUS &= ~(TEL_RDY | TEL_BSY);
cty_unit[1].STATUS &= ~(KEY_RDY | KEY_BSY);
clr_interrupt(CTY_DEVNUM);
sim_clock_coschedule (&cty_unit[1], tmxr_poll);
return SCPE_OK;
}
/* Stop operating system */
t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
#if ITS
if (cpu_unit[0].flags & UNIT_ITSPAGE)
M[037] = FMASK;
else
#endif
M[CTY_SWITCH] = 1; /* tell OS to stop */
return SCPE_OK;
}
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
cty_unit[0].flags = (cty_unit[0].flags & ~TT_MODE) | val;
cty_unit[1].flags = (cty_unit[1].flags & ~TT_MODE) | val;
return SCPE_OK;
}
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "To stop the cpu use the command:\n\n");
fprintf (st, " sim> SET CTY STOP\n\n");
#if ITS
fprintf (st, "If the CPU is in standard mode, this will write 1 to location\n\n");
fprintf (st, "%03o, causing TOPS10 to stop. If the CPU is in ITS mode, this\n\n", CTY_SWITCH);
fprintf (st, "will write -1 to location 037, causing ITS to stop.\n\n");
#else
fprintf (st, "This will write a 1 to location %03o, causing TOPS10 to stop\n\n", CTY_SWITCH);
#endif
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
fprintf (st, " mode input characters output characters\n\n");
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
fprintf (st, " to upper case, high-order bit cleared,\n");
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
fprintf (st, " non-printing characters suppressed\n");
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
fprintf (st, " 8B no changes no changes\n\n");
fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n");
fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n");
fprint_reg_help (st, &cty_dev);
return SCPE_OK;
}
const char *cty_description (DEVICE *dptr)
{
return "Console TTY Line";
}
#endif