Fix divide of 0 on KS10 processor. Fix write access for auxiliary processor memory. Updated support new PIDP10 panel. Allow eight Unibux ports on the TEN device. Added GE DATANET-760 device to PDP6 Removed USER mode restriction for idle detection. Added Data Disc 6600 Television Display System.
684 lines
19 KiB
C
684 lines
19 KiB
C
/* kx10_tym.c: TYM, interface to Tymbase and Tymnet.
|
||
|
||
Copyright (c) 2022, Lars Brinkhoff
|
||
|
||
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
|
||
LARS BRINKHOFF 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.
|
||
*/
|
||
|
||
|
||
#include "kx10_defs.h"
|
||
#include "sim_tmxr.h"
|
||
|
||
#ifndef NUM_DEVS_TYM
|
||
#define NUM_DEVS_TYM 0
|
||
#endif
|
||
|
||
#if NUM_DEVS_TYM > 0
|
||
|
||
#define TYM_NAME "TYM"
|
||
#define MAX_LINES 32 /* Maximum found in the wild. */
|
||
|
||
#define KEY 0633751506262LL /* Base key. */
|
||
#define BASE 02000 /* Default base address. */
|
||
#define SIZE 01000 /* Default size. */
|
||
|
||
#define LOCK 000 /* Key. */
|
||
#define DUMP 002 /* Base dump loc * 16. */
|
||
#define IRNG 003 /* Input ring loc * 16. */
|
||
#define ISIZ 004 /* Input ring size * 16. */
|
||
#define IHP 005 /* Host set input pointer. */
|
||
#define IBP 006 /* Base set input pointer. */
|
||
#define ORNG 007 /* Output ring loc * 16. */
|
||
#define OSIZ 010 /* Output ring size * 16. */
|
||
#define OHP 011 /* Host set output pointer. */
|
||
#define OBP 012 /* Base set output pointer. */
|
||
#define BCRSH 013 /* Base set crash indicator + reason. */
|
||
#define HCRSH 014 /* Host set crash reason. */
|
||
|
||
#define TYMBAS_ANS 001
|
||
#define TYMBAS_SHT 002
|
||
#define TYMBAS_CRS 003
|
||
#define TYMBAS_DIE 004
|
||
#define TYMBAS_NSP 005
|
||
#define TYMBAS_LOG 006
|
||
#define TYMBAS_AUX 007
|
||
#define TYMBAS_NOP 010
|
||
#define TYMBAS_OUP 011
|
||
#define TYMBAS_GOB 012
|
||
#define TYMBAS_ZAP 013
|
||
#define TYMBAS_EDC 014
|
||
#define TYMBAS_LDC 015
|
||
#define TYMBAS_GRN 016
|
||
#define TYMBAS_RED 017
|
||
#define TYMBAS_YEL 020
|
||
#define TYMBAS_ORG 021
|
||
#define TYMBAS_HNG 022
|
||
#define TYMBAS_ETM 023
|
||
#define TYMBAS_LTM 024
|
||
#define TYMBAS_LOS 025
|
||
#define TYMBAS_SUP 026
|
||
#define TYMBAS_SUR 027
|
||
#define TYMBAS_AXC 030
|
||
#define TYMBAS_TSP 031
|
||
#define TYMBAS_TSR 032
|
||
#define TYMBAS_SAD 033
|
||
#define TYMBAS_ECN 034
|
||
#define TYMBAS_ECF 035
|
||
#define TYMBAS_TCS 036
|
||
#define TYMBAS_TCP 037
|
||
#define TYMBAS_TCR 040
|
||
#define TYMBAS_HSI 041
|
||
#define TYMBAS_DATA 0200
|
||
|
||
static t_stat tym_reset(DEVICE *dptr);
|
||
static t_stat tym_attach(UNIT * uptr, CONST char * cptr);
|
||
static t_stat tym_detach(UNIT * uptr);
|
||
static t_stat tym_interface_srv(UNIT *);
|
||
static t_stat tym_alive_srv(UNIT *);
|
||
static t_stat tym_input_srv(UNIT *);
|
||
static t_stat tym_output_srv(UNIT *);
|
||
static const char *tym_description(DEVICE *dptr);
|
||
|
||
static TMLN tym_ldsc[MAX_LINES] = { 0 };
|
||
static TMXR tym_desc = { MAX_LINES, 0, 0, tym_ldsc };
|
||
|
||
static UNIT tym_unit[] = {
|
||
{ UDATA(tym_input_srv, TT_MODE_8B|UNIT_IDLE|UNIT_ATTABLE, 0) },
|
||
{ UDATA(tym_output_srv, UNIT_IDLE, 0) },
|
||
{ UDATA(tym_interface_srv, UNIT_IDLE, 0) },
|
||
{ UDATA(tym_alive_srv, UNIT_IDLE, 0) }
|
||
};
|
||
|
||
static MTAB tym_mod[] = {
|
||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
|
||
&tmxr_dscln, NULL, &tym_desc, "Disconnect a specific line" },
|
||
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
|
||
NULL, &tmxr_show_summ, (void *) &tym_desc, "Display a summary of line states" },
|
||
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||
NULL, &tmxr_show_cstat, (void *) &tym_desc, "Display current connections" },
|
||
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
|
||
NULL, &tmxr_show_cstat, (void *) &tym_desc, "Display multiplexer statistics" },
|
||
{ 0 }
|
||
};
|
||
|
||
/* Simulator debug controls */
|
||
static DEBTAB tym_debug[] = {
|
||
{"CMD", DEBUG_CMD, "Show command execution to devices"},
|
||
{"DATA", DEBUG_DATA, "Show data transfers"},
|
||
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
|
||
{"EXP", DEBUG_EXP, "Show exception information"},
|
||
{"IRQ", DEBUG_IRQ, "Show IRQ requests"},
|
||
{0, 0}
|
||
};
|
||
|
||
static int tym_host = 0;
|
||
static int tym_base = BASE;
|
||
static int tym_size = SIZE;
|
||
static uint64 tym_key = KEY;
|
||
static int output_port;
|
||
static int output_count;
|
||
|
||
static REG tym_reg[] = {
|
||
{ ORDATA(HOST, tym_host, 16) },
|
||
{ ORDATA(BASE, tym_base, 22) },
|
||
{ ORDATA(SIZE, tym_size, 18) },
|
||
{ ORDATA(KEY, tym_key, 36) },
|
||
{ ORDATA(PORTS, tym_desc.lines, 8) },
|
||
{ 0 }
|
||
};
|
||
|
||
DEVICE tym_dev = {
|
||
"TYM", tym_unit, tym_reg, tym_mod,
|
||
4, 8, 0, 1, 8, 36,
|
||
NULL, NULL, &tym_reset, NULL, &tym_attach, &tym_detach,
|
||
NULL, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, tym_debug,
|
||
NULL, NULL, NULL, NULL, NULL, &tym_description
|
||
};
|
||
|
||
static t_stat tym_reset(DEVICE *dptr)
|
||
{
|
||
if (tym_unit[0].flags & UNIT_ATT) {
|
||
sim_activate(&tym_unit[2], 1000);
|
||
sim_activate(&tym_unit[3], 1000);
|
||
} else {
|
||
sim_cancel(&tym_unit[0]);
|
||
sim_cancel(&tym_unit[1]);
|
||
sim_cancel(&tym_unit[2]);
|
||
sim_cancel(&tym_unit[3]);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
static void block(void)
|
||
{
|
||
int i;
|
||
for (i = 0; i < MAX_LINES; i++) {
|
||
tym_ldsc[i].rcve = 0;
|
||
tym_ldsc[i].xmte = 0;
|
||
}
|
||
}
|
||
|
||
static t_stat tym_attach(UNIT *uptr, CONST char *cptr)
|
||
{
|
||
t_stat stat = tmxr_attach(&tym_desc, uptr, cptr);
|
||
block();
|
||
tym_reset(&tym_dev);
|
||
return stat;
|
||
}
|
||
|
||
static t_stat tym_detach(UNIT *uptr)
|
||
{
|
||
t_stat stat = tmxr_detach(&tym_desc, uptr);
|
||
block();
|
||
tym_reset(&tym_dev);
|
||
return stat;
|
||
}
|
||
|
||
static uint64 word(int pointer, int base)
|
||
{
|
||
t_addr address = (M[tym_base + base] >> 4) & RMASK;
|
||
address += M[tym_base + pointer] & RMASK;
|
||
return M[address];
|
||
}
|
||
|
||
static void next(int pointer, int size)
|
||
{
|
||
uint64 modulo = M[tym_base + size] >> 4;
|
||
M[tym_base + pointer] = (M[tym_base + pointer] + 1) % modulo;
|
||
}
|
||
|
||
static void tym_input(uint64 data)
|
||
{
|
||
t_addr address = (M[tym_base + IRNG] >> 4) & RMASK;
|
||
address += M[tym_base + IBP] & RMASK;
|
||
M[address] = data;
|
||
}
|
||
|
||
static uint64 room (int h, int t, int s)
|
||
{
|
||
uint64 head = M[tym_base + h];
|
||
uint64 tail = M[tym_base + t];
|
||
uint64 size = M[tym_base + s] >> 4;
|
||
return size - (head - tail) % size;
|
||
}
|
||
|
||
static void send_word(int type, int port, int data1, int data2)
|
||
{
|
||
uint64 data;
|
||
sim_debug(DEBUG_DETAIL, &tym_dev,
|
||
"Input from base: %03o %03o %03o %03o\n",
|
||
type, port, data1, data2);
|
||
/* The input ring buffer must have at least one word free. */
|
||
if (room (IBP, IHP, ISIZ) <= 1)
|
||
return;
|
||
data = (uint64)type << 28;
|
||
data |= (uint64)port << 20;
|
||
data |= (uint64)data1 << 12;
|
||
data |= (uint64)data2 << 4;
|
||
tym_input(data);
|
||
next(IBP, ISIZ);
|
||
}
|
||
|
||
static void send_character(int port, int c)
|
||
{
|
||
sim_debug(DEBUG_DATA, &tym_dev, "Base: send port %d %03o '%c'.\n",
|
||
port, c, c);
|
||
send_word(TYMBAS_DATA | 1, port, c, 0);
|
||
}
|
||
|
||
static void send_string(int port, const char *string)
|
||
{
|
||
int n = strlen(string);
|
||
int m;
|
||
|
||
for (;;) {
|
||
if (n <= 0)
|
||
return;
|
||
else if (n == 1) {
|
||
send_character(port, string[0]);
|
||
return;
|
||
}
|
||
|
||
m = n > 0177 ? 0177 : n;
|
||
n -= m;
|
||
send_word(TYMBAS_DATA | m, port, string[0], string[1]);
|
||
string += 2;
|
||
m -= 2;
|
||
while (m > 0) {
|
||
send_word(string[0], string[1], string[2], string[3]);
|
||
string += 4;
|
||
m -= 4;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void send_login(int port)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "Base: send login %d.\n", port);
|
||
send_word(TYMBAS_LOG, port, 0, 0);
|
||
/* This isn't right, but good enough for now. */
|
||
send_string(port, ".....USER\r");
|
||
}
|
||
|
||
static void send_zap(int port)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "Base: send zap %d.\n", port);
|
||
send_word(TYMBAS_ZAP, port, 0, 0);
|
||
}
|
||
|
||
static void send_orange (int port)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "Base: send orange ball %d.\n", port);
|
||
send_word(TYMBAS_ORG, port, 0, 0);
|
||
}
|
||
|
||
static void recv_ans(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "system is answering\n");
|
||
sim_activate(&tym_unit[0], 1000);
|
||
}
|
||
|
||
static void recv_sht(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "system is up but shut\n");
|
||
}
|
||
|
||
static void recv_crs(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "sender is crashed\n");
|
||
}
|
||
|
||
static void recv_die(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "recipient should crash\n");
|
||
}
|
||
|
||
static void recv_nsp(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "base taken over by new supervisor\n");
|
||
}
|
||
|
||
static void recv_log(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "login\n");
|
||
//next 4 data chrs are the info about terminal type, and port or
|
||
//origin, then name, etc.
|
||
}
|
||
|
||
static void recv_aux(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "supervisor response to establishing auxillary circuit\n");
|
||
}
|
||
|
||
static void recv_nop(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " backpressure on\n");
|
||
}
|
||
|
||
static void recv_oup(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " backpressure off\n");
|
||
}
|
||
|
||
static void recv_gob(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " character gobbler\n");
|
||
}
|
||
|
||
static void recv_zap(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, "Zap circuit, port %d\n", port);
|
||
tmxr_reset_ln (&tym_ldsc[port]);
|
||
tym_ldsc[port].rcve = 0;
|
||
tym_ldsc[port].xmte = 0;
|
||
}
|
||
|
||
static void recv_edc(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " enter defered echo mode\n");
|
||
}
|
||
|
||
static void recv_ldc(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " leave deferred echo mode\n");
|
||
}
|
||
|
||
static void recv_grn(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " green ball\n");
|
||
}
|
||
|
||
static void recv_red(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " red ball\n");
|
||
}
|
||
|
||
static void recv_yel(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " yellow ball\n");
|
||
send_orange (port);
|
||
}
|
||
|
||
static void recv_org(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " orange ball\n");
|
||
}
|
||
|
||
static void recv_hng(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " hang character - not used\n");
|
||
}
|
||
|
||
static void recv_etm(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " enter 2741 transparent mode\n");
|
||
}
|
||
|
||
static void recv_ltm(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " leave 2741 transparent mode\n");
|
||
}
|
||
|
||
static void recv_los(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " lost ball\n");
|
||
//data has been lost from buffers. the data filed may tell how
|
||
//many were lost
|
||
}
|
||
|
||
static void recv_sup(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " supervisor request(aux circuits)\n");
|
||
}
|
||
|
||
static void recv_sur(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " supervisor response(aux circuits)\n");
|
||
}
|
||
|
||
static void recv_axc(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " supervisor string character\n");
|
||
}
|
||
|
||
static void recv_tsp(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " test pattern probe\n");
|
||
}
|
||
|
||
static void recv_tsr(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " test pattern response\n");
|
||
}
|
||
|
||
static void recv_sad(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " host sad\n");
|
||
}
|
||
|
||
static void recv_ecn(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " echo on\n");
|
||
}
|
||
|
||
static void recv_ecf(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " echo off\n");
|
||
}
|
||
|
||
static void recv_tcs(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " term characteristics\n");
|
||
//first data byte indicates which characteristics second data byte
|
||
//indicates value to set to
|
||
}
|
||
|
||
static void recv_tcp(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " term characteristcs probe\n");
|
||
//data byte indicates which terminal characteristic were requested
|
||
}
|
||
|
||
static void recv_tcr(int port, int subtype, int data)
|
||
{
|
||
sim_debug(DEBUG_CMD, &tym_dev, " term characteristcs response\n");
|
||
//data is just like tcs, comes in response to a probe; also is
|
||
//reflected by remote when terminal characteristics are sent
|
||
}
|
||
|
||
static void recv_hsi(int port, int subtype, int data)
|
||
{
|
||
tym_host = (subtype << 8) | data;
|
||
sim_debug(DEBUG_CMD, &tym_dev, "Host number %06o, %d ports\n",
|
||
tym_host, port);
|
||
/* Close ports above the host-annonuced maximum. */
|
||
tym_desc.lines = port;
|
||
if (tym_desc.lines > MAX_LINES)
|
||
tym_desc.lines = MAX_LINES;
|
||
for (port = tym_desc.lines; port < MAX_LINES; port++)
|
||
tmxr_reset_ln (&tym_ldsc[port]);
|
||
sim_activate(&tym_unit[0], 1000);
|
||
}
|
||
|
||
typedef void (*msgfn) (int, int, int);
|
||
static msgfn output[] = {
|
||
NULL,
|
||
recv_ans,
|
||
recv_sht,
|
||
recv_crs,
|
||
recv_die,
|
||
recv_nsp,
|
||
recv_log,
|
||
recv_aux,
|
||
recv_nop,
|
||
recv_oup,
|
||
recv_gob,
|
||
recv_zap,
|
||
recv_edc,
|
||
recv_ldc,
|
||
recv_grn,
|
||
recv_red,
|
||
recv_yel,
|
||
recv_org,
|
||
recv_hng,
|
||
recv_etm,
|
||
recv_ltm,
|
||
recv_los,
|
||
recv_sup,
|
||
recv_sur,
|
||
recv_axc,
|
||
recv_tsp,
|
||
recv_tsr,
|
||
recv_sad,
|
||
recv_ecn,
|
||
recv_ecf,
|
||
recv_tcs,
|
||
recv_tcp,
|
||
recv_tcr,
|
||
recv_hsi
|
||
};
|
||
|
||
static void output_data(int port, int n)
|
||
{
|
||
uint64 data;
|
||
int i = 2, c;
|
||
|
||
sim_debug(DEBUG_DATA, &tym_dev,
|
||
"Output from host: %d characters to port %d\n", n, port);
|
||
|
||
data = word(OBP, ORNG) << 16; /* Discard header. */
|
||
goto start;
|
||
|
||
while (n > 0) {
|
||
data = word(OBP, ORNG);
|
||
start:
|
||
for (; i < 4 && n > 0; i++, n--) {
|
||
c = (data >> 28) & 0177;
|
||
data <<= 8;
|
||
sim_debug(DEBUG_DATA, &tym_dev,
|
||
"Host: send port %d %03o '%c'.\n", port, c, c);
|
||
tmxr_putc_ln(&tym_ldsc[port], c);
|
||
tmxr_poll_tx(&tym_desc);
|
||
}
|
||
i = 0;
|
||
next(OBP, OSIZ);
|
||
}
|
||
}
|
||
|
||
static void tym_output(void)
|
||
{
|
||
int type, port, subtype, data;
|
||
while (M[tym_base + OBP] != M[tym_base + OHP]) {
|
||
sim_debug(DEBUG_DETAIL, &tym_dev, "Output from host: %llu %012llo\n",
|
||
M[tym_base + OBP], word(OBP, ORNG));
|
||
type = word(OBP, ORNG) >> 28;
|
||
port = (word(OBP, ORNG) >> 20) & 0377;
|
||
subtype = (word(OBP, ORNG) >> 12) & 0377;
|
||
data = (word(OBP, ORNG) >> 4) & 0377;
|
||
sim_debug(DEBUG_DETAIL, &tym_dev,
|
||
"Type %03o, port %03o, subtype %03o, data %03o\n",
|
||
type, port, subtype, data);
|
||
if (type >= 1 && type <= 41) {
|
||
output[type] (port, subtype, data);
|
||
next(OBP, OSIZ);
|
||
} else if (type & 0200)
|
||
output_data(port, type & 0177);
|
||
}
|
||
}
|
||
|
||
static uint64 lock = ~0ULL;
|
||
static uint64 dump = ~0ULL;
|
||
static uint64 irng = ~0ULL;
|
||
static uint64 isiz = ~0ULL;
|
||
static uint64 ihp = ~0ULL;
|
||
static uint64 ibp = ~0ULL;
|
||
static uint64 orng = ~0ULL;
|
||
static uint64 osiz = ~0ULL;
|
||
static uint64 ohp = ~0ULL;
|
||
static uint64 obp = ~0ULL;
|
||
static uint64 bcrsh = ~0ULL;
|
||
static uint64 hcrsh = ~0ULL;
|
||
|
||
static void check(const char *name, int offset, uint64 *value)
|
||
{
|
||
uint64 x = M[tym_base + offset];
|
||
if (x != *value) {
|
||
sim_debug(DEBUG_DETAIL, &tym_dev, "%s: %012llo\n", name, x);
|
||
*value = x;
|
||
}
|
||
}
|
||
|
||
static t_stat tym_interface_srv(UNIT *uptr)
|
||
{
|
||
check("Dump location", DUMP, &dump);
|
||
check("Input ring location", IRNG, &irng);
|
||
check("Input ring size", ISIZ, &isiz);
|
||
check("Host input pointer", IHP, &ihp);
|
||
check("Base input pointer", IBP, &ibp);
|
||
check("Output ring location", ORNG, &orng);
|
||
check("Output ring size", OSIZ, &osiz);
|
||
check("Host output pointer", OHP, &ohp);
|
||
check("Base output pointer", OBP, &obp);
|
||
check("Base crash reason", BCRSH, &bcrsh);
|
||
check("Host crash reason", HCRSH, &hcrsh);
|
||
|
||
if (ohp != obp)
|
||
tym_output();
|
||
|
||
sim_activate_after(&tym_unit[2], 1000);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
static t_stat tym_alive_srv(UNIT *uptr)
|
||
{
|
||
if (M[tym_base + LOCK] == tym_key) {
|
||
M[tym_base + LOCK] = 1;
|
||
}
|
||
|
||
sim_activate_after(&tym_unit[3], 500000);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
static t_stat tym_input_srv(UNIT *uptr)
|
||
{
|
||
int32 ch;
|
||
int i;
|
||
|
||
if (room (IBP, IHP, ISIZ) > 1) {
|
||
i = tmxr_poll_conn(&tym_desc);
|
||
if (i >= 0) {
|
||
tym_ldsc[i].rcve = 1;
|
||
tym_ldsc[i].xmte = 1;
|
||
send_login(i);
|
||
}
|
||
}
|
||
|
||
tmxr_poll_rx(&tym_desc);
|
||
|
||
for (i = 0; i < tym_desc.lines; i++) {
|
||
if (tym_ldsc[i].xmte && tym_ldsc[i].conn == 0) {
|
||
tmxr_reset_ln (&tym_ldsc[i]);
|
||
tym_ldsc[i].rcve = 0;
|
||
tym_ldsc[i].xmte = 0;
|
||
send_zap(i);
|
||
continue;
|
||
}
|
||
|
||
/* The input ring buffer must have at least one word free. */
|
||
if (room (IBP, IHP, ISIZ) <= 1)
|
||
continue;
|
||
|
||
ch = tmxr_getc_ln(&tym_ldsc[i]);
|
||
if (ch & TMXR_VALID)
|
||
send_character(i, ch & 0377);
|
||
}
|
||
|
||
sim_activate(&tym_unit[0], 1000);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
static t_stat tym_output_srv(UNIT *uptr)
|
||
{
|
||
uint64 data;
|
||
int c;
|
||
|
||
if (!tmxr_txdone_ln(&tym_ldsc[output_port])) {
|
||
sim_activate(&tym_unit[1], 1000);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
data = word(OBP, ORNG);
|
||
|
||
c = (data >> 28) & 0177;
|
||
data <<= 8;
|
||
sim_debug(DEBUG_DATA, &tym_dev,
|
||
"Host: send port %d %03o '%c'.\n", output_port, c, c);
|
||
if (tmxr_putc_ln(&tym_ldsc[output_port], c) == SCPE_STALL)
|
||
return SCPE_OK;
|
||
|
||
next(OBP, OSIZ);
|
||
if (output_count > 0)
|
||
sim_activate(&tym_unit[1], 1000);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
static const char *tym_description(DEVICE *dptr)
|
||
{
|
||
return "Tymnet interface";
|
||
}
|
||
#endif
|