284 lines
9.7 KiB
C
284 lines
9.7 KiB
C
/* ks10_cty.c: KS-10 front end (console terminal) simulator
|
|
|
|
Copyright (c) 2021, 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"
|
|
#include "sim_sock.h"
|
|
#include "sim_tmxr.h"
|
|
#include <ctype.h>
|
|
|
|
#if KS
|
|
#define UNIT_DUMMY (1 << UNIT_V_UF)
|
|
|
|
#define STATUS 031
|
|
#define CTY_IN 032
|
|
#define CTY_OUT 033
|
|
#define KLINK_IN 034
|
|
#define KLINK_OUT 035
|
|
#define BOOT_ADDR 036
|
|
#define BOOT_DRIVE 037
|
|
#define MAG_FMT 040
|
|
|
|
#define KA_FAIL 0000000000001LL /* Keep Alive failed to change */
|
|
#define FORCE_RELOAD 0000000000002LL /* Force reload */
|
|
#define PWR_FAIL1 0000000000004LL /* Power failure */
|
|
#define BOOT_SW 0000000000010LL /* Boot switch */
|
|
#define KEEP_ALIVE 0000000177400LL /* Keep alive */
|
|
#define TRAPS_ENB 0000040000000LL /* Traps enabled */
|
|
#define ONE_MS 0000100000000LL /* 1ms enabled */
|
|
#define CACHE_ENB 0000200000000LL /* Cache enable */
|
|
#define DP_PAR_ENB 0000400000000LL /* DP parity error enable */
|
|
#define CRAM_PAR_ENB 0001000000000LL /* CRAM parity error enable */
|
|
#define PAR_ENB 0002000000000LL /* Parity error detect enable */
|
|
#define KLINK_ENB 0004000000000LL /* Klink active */
|
|
#define EX_KEEP_ALV 0010000000000LL /* Examine Keep Alive */
|
|
#define RELOAD 0020000000000LL /* Reload */
|
|
|
|
#define CTY_CHAR 0000000000400LL /* Character pending */
|
|
#define KLINK_CHAR 0000000000400LL /* Character pending */
|
|
#define KLINK_ACT 0000000001000LL /* KLINK ACTIVE */
|
|
#define KLINK_HANG 0000000001400LL /* KLINK HANGUP */
|
|
|
|
extern int32 tmxr_poll;
|
|
t_stat ctyi_svc (UNIT *uptr);
|
|
t_stat ctyo_svc (UNIT *uptr);
|
|
t_stat ctyrtc_srv(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);
|
|
uint64 keep_alive = 0;
|
|
int keep_num = 0;
|
|
|
|
extern DEVICE *rh_boot_dev;
|
|
extern int rh_boot_unit;
|
|
|
|
static int32 rtc_tps = 1;
|
|
|
|
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 }
|
|
};
|
|
|
|
UNIT cty_unit[] = {
|
|
{ UDATA (&ctyo_svc, TT_MODE_7B, 0), 20000},
|
|
{ UDATA (&ctyi_svc, TT_MODE_7B|UNIT_DIS, 0), 4000 },
|
|
{ UDATA (&ctyrtc_srv, UNIT_IDLE|UNIT_DIS, 0), 1000 }
|
|
};
|
|
|
|
REG cty_reg[] = {
|
|
{HRDATAD(WRU, sim_int_char, 8, "interrupt character") },
|
|
{ 0 },
|
|
};
|
|
|
|
|
|
DEVICE cty_dev = {
|
|
"CTY", cty_unit, cty_reg, cty_mod,
|
|
3, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &cty_reset,
|
|
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, dev_debug,
|
|
NULL, NULL, &cty_help, NULL, NULL, &cty_description
|
|
};
|
|
|
|
void
|
|
cty_wakeup()
|
|
{
|
|
sim_debug(DEBUG_EXP, &cty_dev, "CTY wakeup\n");
|
|
sim_activate(&cty_unit[0], cty_unit[0].wait);
|
|
}
|
|
|
|
|
|
/* Check for input from CTY and put on queue. */
|
|
t_stat ctyi_svc (UNIT *uptr)
|
|
{
|
|
uint64 buffer;
|
|
int32 ch;
|
|
|
|
sim_clock_coschedule (uptr, tmxr_poll * 3);
|
|
|
|
if (Mem_read_word(CTY_IN, &buffer, 0))
|
|
return SCPE_OK;
|
|
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY Read %012llo\n", buffer);
|
|
if (buffer & CTY_CHAR) {
|
|
cty_interrupt();
|
|
return SCPE_OK;
|
|
}
|
|
ch = sim_poll_kbd ();
|
|
if (ch & SCPE_KFLAG) {
|
|
ch = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (cty_unit[0].flags));
|
|
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY char %o '%c'\n", ch,
|
|
((ch > 040 && ch < 0177)? ch: '.'));
|
|
buffer = (uint64)(ch) | CTY_CHAR;
|
|
if (Mem_write_word(CTY_IN, &buffer, 0) == 0) {
|
|
cty_interrupt();
|
|
} else {
|
|
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY write failed %o '%c'\n", ch,
|
|
((ch > 040 && ch < 0177)? ch: '.'));
|
|
}
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Handle output of characters to CTY. Started whenever there is output pending */
|
|
t_stat ctyo_svc (UNIT *uptr)
|
|
{
|
|
uint64 buffer;
|
|
/* Check if any input pending? */
|
|
if (Mem_read_word(CTY_OUT, &buffer, 0))
|
|
return SCPE_OK;
|
|
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY Write %012llo\n", buffer);
|
|
if (buffer & CTY_CHAR) {
|
|
int32 ch;
|
|
ch = buffer & 0377;
|
|
ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags));
|
|
if (sim_putchar_s(ch) != SCPE_OK) {
|
|
sim_activate(uptr, 2000);
|
|
return SCPE_OK;
|
|
}
|
|
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY write %o '%c'\n", ch,
|
|
((ch > 040 && ch < 0177)? ch: '.'));
|
|
|
|
buffer = 0;
|
|
if (Mem_write_word(CTY_OUT, &buffer, 0) == 0) {
|
|
cty_interrupt();
|
|
} else {
|
|
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY write failed %o '%c'\n", ch,
|
|
((ch > 040 && ch < 0177)? ch: '.'));
|
|
}
|
|
}
|
|
|
|
if (Mem_read_word(KLINK_OUT, &buffer, 0))
|
|
return SCPE_OK;
|
|
if (buffer != 0) {
|
|
buffer = 0;
|
|
if (Mem_write_word(CTY_OUT, &buffer, 0) == 0) {
|
|
cty_interrupt();
|
|
}
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* Handle FE timer interrupts. And keepalive counts */
|
|
t_stat
|
|
ctyrtc_srv(UNIT * uptr)
|
|
{
|
|
uint64 buffer;
|
|
|
|
sim_activate_after(uptr, 1000000/rtc_tps);
|
|
if (Mem_read_word(STATUS, &buffer, 0))
|
|
return SCPE_OK;
|
|
if (buffer & ONE_MS) {
|
|
fprintf(stderr, "1MS\n\r");
|
|
}
|
|
if (buffer & RELOAD && rh_boot_dev != NULL) {
|
|
reset_all(1); /* Reset everybody */
|
|
if (rh_boot_dev->boot(rh_boot_unit, rh_boot_dev) != SCPE_OK)
|
|
return SCPE_STOP;
|
|
}
|
|
/* Check if clock requested */
|
|
if (buffer & EX_KEEP_ALV) {
|
|
if (keep_alive != (buffer & KEEP_ALIVE)) {
|
|
keep_alive = buffer;
|
|
keep_num = 0;
|
|
} else {
|
|
if (++keep_num >= 15) {
|
|
keep_num = 0;
|
|
buffer &= ~0377LL;
|
|
buffer |= 1;
|
|
cty_execute(071);
|
|
M[STATUS] = buffer;
|
|
M[CTY_IN] = 0;
|
|
M[CTY_OUT] = 0;
|
|
M[KLINK_IN] = 0;
|
|
M[KLINK_OUT] = 0;
|
|
}
|
|
}
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
t_stat cty_reset (DEVICE *dptr)
|
|
{
|
|
sim_activate(&cty_unit[1], cty_unit[1].wait);
|
|
sim_activate(&cty_unit[2], cty_unit[2].wait);
|
|
M[STATUS] = 0;
|
|
M[CTY_IN] = 0;
|
|
M[CTY_OUT] = 0;
|
|
M[KLINK_IN] = 0;
|
|
M[KLINK_OUT] = 0;
|
|
M[CTY_SWITCH] = 0;
|
|
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;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Stop operating system */
|
|
|
|
t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
M[CTY_SWITCH] = 1; /* tell OS to stop */
|
|
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");
|
|
fprintf (st, "This will write a 1 to location %03o, causing TOPS10 to stop\n\n", CTY_SWITCH);
|
|
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
|