/* i7090_com.c: IBM 7094 7750 communications interface simulator | |
Copyright (c) 2010-2016, 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 | |
com 7750 controller | |
coml 7750 lines | |
This module implements an abstract simulator for the IBM 7750 communications | |
computer as used by the CTSS system. The 7750 supports up to 112 lines; | |
the simulator supports 33. The 7750 can handle both high-speed lines, in | |
6b and 12b mode, and normal terminals, in 12b mode only; the simulator | |
supports only terminals. The 7750 can handle many different kinds of | |
terminals; the simulator supports only a limited subset. | |
Input is asynchronous. The 7750 sets ATN1 to signal availability of input. | |
When the 7094 issues a CTLRN, the 7750 gathers available input characters | |
into a message. The message has a 12b sequence number, followed by 12b line | |
number/character pairs, followed by end-of-medium (03777). Input characters | |
can either be control characters (bit 02000 set) or data characters. Data | |
characters are 1's complemented and are 8b wide: 7 data bits and 1 parity | |
bit (which may be 0). | |
Output is synchronous. When the 7094 issues a CTLWN, the 7750 interprets | |
the channel output as a message. The message has a 12b line number, followed | |
by a 12b character count, followed by characters, followed by end-of-medium. | |
If bit 02000 of the line number is set, the characters are 12b wide. If | |
bit 01000 is set, the message is a control message. 12b characters consist | |
of 7 data bits, 1 parity bit, and 1 start bit. Data characters are 1's | |
complemented. Data character 03777 is special and causes the 7750 to | |
repeat the previous bit for the number of bit times specified in the next | |
character. This is used to generate delays for positioning characters. | |
The 7750 supports flow control for output. To help the 7094 account for | |
usage of 7750 buffer memory, the 7750 sends 'character output completion' | |
messages for every 'n' characters output on a line, where n <= 31. | |
Note that the simulator console is mapped in as line n+1. | |
Sense word based on 7074 Principles of Operation. | |
1 A Reserved. | |
3 4 Program Check Summary byte | |
4 2 Exceptional Condtion Summary byte | |
5 1 Data Check Summary byte | |
7 A Reserved | |
9 4 Message Length Check Program Check | |
10 2 Channel Hold Program Check | |
11 1 Channel Queue Full Program Check | |
13 A Reserved | |
15 4 Reserved | |
16 2 Reserved | |
17 1 Interface Timeout Data Check | |
19 A Reserved | |
21 4 Data Message Ready Exceptional Condition | |
22 2 Input space available Exceptional Condition | |
23 1 Service Message Ready Exceptional Condition | |
*/ | |
#include "i7000_defs.h" | |
#include "sim_timer.h" | |
#include "sim_sock.h" | |
#include "sim_tmxr.h" | |
#include <ctype.h> | |
#ifdef NUM_DEVS_COM | |
#define COM_MLINES 32 /* mux lines */ | |
#define COM_TLINES (COM_MLINES) | |
#define COM_BUFSIZ 120 /* max chan transfer */ | |
#define COM_PKTSIZ 16384 /* character buffer */ | |
#define UNIT_V_2741 (UNIT_V_UF + 0) /* 2741 - ni */ | |
#define UNIT_V_K35 (UNIT_V_UF + 1) /* KSR-35 */ | |
#define UNIT_2741 (1 << UNIT_V_2741) | |
#define UNIT_K35 (1 << UNIT_V_K35) | |
#define TMR_COM 2 | |
#define CONN u3 /* line is connected */ | |
#define NEEDID u4 /* need to send ID */ | |
#define ECHO u5 /* echoing output */ | |
#define COM_INIT_POLL 8000 /* polling interval */ | |
#define COMC_WAIT 2 /* channel delay time */ | |
#define COML_WAIT 500 /* char delay time */ | |
#define COM_LBASE 4 /* start of lines */ | |
/* Input threads */ | |
#define COM_PLU 0 /* multiplexor poll */ | |
#define COM_CIU 1 /* console input */ | |
#define COM_CHU 2 /* console output */ | |
/* Communications input */ | |
#define COMI_LCOMP 002000 /* line complete */ | |
#define COMI_DIALUP 002001 /* dialup */ | |
#define COMI_ENDID 002002 /* end ID */ | |
#define COMI_INTR 002003 /* interrupt */ | |
#define COMI_QUIT 002004 /* quit */ | |
#define COMI_HANGUP 002005 /* hangup */ | |
#define COMI_EOM 013777 /* end of medium */ | |
#define COMI_COMP(x) ((uint16) (03000 + ((x) & COMI_CMAX))) | |
#define COMI_K35 6 /* KSR-35 ID */ | |
#define COMI_K37 7 /* KSR-37 ID */ | |
#define COMI_2741 8 /* 2741 ID */ | |
#define COMI_CMAX 31 /* max chars returned */ | |
#define COMI_PARITY 00200 /* parity bit */ | |
#define COMI_BMAX 50 /* buffer max, words */ | |
#define COMI_12BMAX ((3 * COMI_BMAX) - 1) /* last 12b char */ | |
/* Communications output - characters */ | |
#define COMO_LIN12B 02000 /* line is 12b */ | |
#define COMO_LINCTL 01000 /* control msg */ | |
#define COMO_GETLN(x) ((x) & 0777) | |
#define COMO_CTLRST 07777 /* control reset */ | |
#define COMO_BITRPT 03777 /* bit repeat */ | |
#define COMO_EOM12B 07777 /* end of medium */ | |
#define COMO_EOM6B 077 /* end of medium */ | |
#define COMO_BMAX 94 /* buffer max, words */ | |
#define COMO_12BMAX ((3 * COMO_BMAX) - 1) | |
/* Report variables */ | |
#define COMR_FQ 1 /* free queue */ | |
#define COMR_IQ 2 /* input queue */ | |
#define COMR_OQ 4 /* output queue */ | |
/* Sense word flags */ | |
#define EXPT_SRVRDY 0x1001 /* Service message available */ | |
#define EXPT_INAVAIL 0x1002 /* Input available */ | |
#define EXPT_DATRDY 0x1004 /* Data ready. */ | |
#define DATA_TIMEOUT 0x2010 /* Timeout */ | |
#define PROG_FULL 0x4100 /* No more space to send message */ | |
#define PROG_HOLD 0x4200 /* Channel hold */ | |
#define PROG_MSGLEN 0x4400 /* Invalid message length */ | |
/* Input and output ring buffers */ | |
uint16 in_buff[256]; | |
int in_head; | |
int in_tail; | |
int in_count; /* Number of entries in queue */ | |
int in_delay = 5000; | |
typedef struct | |
{ | |
uint16 link; | |
uint16 data; | |
} OLIST; | |
uint32 com_posti = 0; /* Posted a IRQ */ | |
uint32 com_active = 0; /* Channel active */ | |
uint32 com_ocnt = 0; /* Number of characters to output */ | |
uint32 com_oln = 0; /* Output line number */ | |
uint32 com_o12b = 0; /* Outputing 12 bit */ | |
uint32 com_enab = 0; /* 7750 enabled */ | |
uint32 com_msgn = 0; /* next input msg num */ | |
uint32 com_sta = 0; /* 7750 state */ | |
uint32 com_quit = 3; /* quit code */ | |
uint32 com_intr = 4; /* interrupt code */ | |
uint32 com_tps = 50; /* polls/second */ | |
uint8 com_out_inesc[COM_TLINES]; | |
uint16 com_out_head[COM_TLINES]; | |
uint16 com_out_tail[COM_TLINES]; | |
uint16 com_comp_cnt[COM_TLINES]; | |
int com_line; /* Current line */ | |
uint16 com_free; /* free list */ | |
OLIST com_buf[10240]; | |
TMLN com_ldsc[COM_TLINES]; /* line descriptors */ | |
TMXR com_desc = { COM_TLINES, 0, 0, com_ldsc }; /* mux descriptor */ | |
uint32 com_sense = 0; /* Sense word */ | |
uint16 com_data; | |
uint8 com_dflg = 0; | |
/* 2741 convertion table */ | |
static const uint8 com_2741_out[256] = { | |
/* Upper case */ | |
/* 0 1 2 3 4 5 6 7 */ | |
' ', '-', '2', '+', '*', 'Q', 'Y', 'H', /* 000 */ | |
':', 'M', 'U', 'D', '_', '_', '_', '_', /* 010 */ | |
'@', 'K', 'S', 'B', ')', '_', '_', '_', /* 020 */ | |
'\'', 'O', 'W', 'F','\n','\b', ' ', '_', /* 030 */ | |
'=', 'J', '?', 'A', '(', 'R', 'Z', 'I', /* 040 */ | |
'%', 'N', 'V', 'E', '_','\n','\r', '\t', /* 050 */ | |
';', 'L', 'T', 'C', '#', '$', ',', '.', /* 060 */ | |
'"', 'P', 'X', 'G', '_','\t', '<', '\0', /* 070 */ | |
' ', '-', '@', '&', '8', 'q', 'y', 'h', /* 100 */ | |
'4', 'm', 'u', 'd', '_', '_', '_', '_', /* 110 */ | |
'2', 'k', 's', 'b', '0', '_', '_', '_', /* 120 */ | |
'6', 'o', 'w', 'f', '_','\b', ' ', '_', /* 130 */ | |
'1', 'j', '/', 'a', '9', 'r', 'z', 'i', /* 140 */ | |
'5', 'n', 'v', 'e','\n','\n','\r', '\t', /* 150 */ | |
'3', 'l', 't', 'c', '_', '!', ',', '.', /* 160 */ | |
'7', 'p', 'x', 'g', '_','\t', '_','\0', /* 170 */ | |
}; | |
/* 76 43 177 15 */ | |
/* 76 23 177 16 */ | |
static const uint8 com_2741_in[128] = { | |
/* Control */ | |
0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, /*0-37*/ | |
/*Control*/ | |
0135, 0057, 0155, 0000, 0000, 0155, 0000, 0000, | |
/*Control*/ | |
0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, | |
/*Control*/ | |
0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, | |
/* sp ! " # $ % & ' */ | |
0100, 0365, 0070, 0264, 0165, 0150, 0303, 0130, /* 40 - 77 */ | |
/* ( ) * + , - . / */ | |
0144, 0124, 0004, 0203, 0166, 0001, 0067, 0342, | |
/* 0 1 2 3 4 5 6 7 */ | |
0324, 0240, 0220, 0360, 0210, 0350, 0330, 0270, | |
/* 8 9 : ; < = > ? */ | |
0204, 0344, 0010, 0160, 0000, 0040, 0000, 0142, | |
/* @ A B C D E F G */ | |
0202, 0043, 0023, 0163, 0013, 0153, 0133, 0073, /* 100 - 137 */ | |
/* H I J K L M N O */ | |
0007, 0147, 0141, 0121, 0061, 0111, 0051, 0031, | |
/* P Q R S T U V W */ | |
0171, 0105, 0045, 0122, 0062, 0112, 0052, 0032, | |
/* X Y Z [ \ ] ^ _ */ | |
0172, 0106, 0046, 0000, 0000, 0000, 0000, 0000, | |
/* ` a b c d e f g */ | |
0000, 0243, 0223, 0363, 0213, 0353, 0333, 0273, /* 140 - 177 */ | |
/* h i j k l m n o */ | |
0207, 0347, 0341, 0321, 0261, 0311, 0251, 0231, | |
/* p q r s t u v w */ | |
0371, 0305, 0245, 0322, 0262, 0312, 0252, 0232, | |
/* x y z { | } ~ del*/ | |
0372, 0306, 0246, 0000, 0000, 0000, 0000, 0177 | |
}; | |
uint32 com_cmd(UNIT * uptr, uint16 cmd, uint16 dev); | |
t_stat com_svc(UNIT * uptr); | |
t_stat comi_svc(UNIT * uptr); | |
t_stat como_svc(UNIT * uptr); | |
t_stat comti_svc(UNIT * uptr); | |
t_stat comto_svc(UNIT * uptr); | |
t_stat com_reset(DEVICE * dptr); | |
t_stat com_attach(UNIT * uptr, CONST char *cptr); | |
t_stat com_detach(UNIT * uptr); | |
t_stat com_summ(FILE * st, UNIT * uptr, int32 val, CONST void *desc); | |
t_stat com_show(FILE * st, UNIT * uptr, int32 val, CONST void *desc); | |
void com_reset_ln(uint32 i); | |
t_stat com_queue_in(uint32 ln, uint16 ch); | |
uint32 com_queue_out(uint32 ln, uint16 * c1); | |
t_stat com_send_id(uint32 ln); | |
t_stat com_send_ccmp(uint32 ln); | |
void com_skip_outc(uint32 ln); | |
t_bool com_get(int ln, uint16 *ch); | |
t_bool com_put(int ln, uint16 ch); | |
void com_post_eom(); | |
t_bool com_inp_msg(uint32 ln, uint16 msg); | |
const char *com_description(DEVICE *dptr); | |
t_stat com_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); | |
const char *coml_description(DEVICE *dptr); | |
t_stat coml_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); | |
/* COM data structures | |
com_dev COM device descriptor | |
com_unit COM unit descriptor | |
com_reg COM register list | |
com_mod COM modifiers list | |
*/ | |
#ifdef I7010 | |
#define COM_CHAN 4 | |
#else | |
#define COM_CHAN 5 | |
#endif | |
UNIT com_unit[] = { | |
{UDATA(&comi_svc, UNIT_S_CHAN(COM_CHAN) | UNIT_ATTABLE, 0), COM_INIT_POLL}, | |
{UDATA(&comti_svc, UNIT_S_CHAN(COM_CHAN) | UNIT_DIS, 0), KBD_POLL_WAIT}, | |
{UDATA(&com_svc, UNIT_S_CHAN(COM_CHAN) | UNIT_DIS, 0), COMC_WAIT}, | |
}; | |
REG com_reg[] = { | |
{FLDATA(ENABLE, com_enab, 0)}, | |
{ORDATA(STATE, com_sta, 6)}, | |
{ORDATA(MSGNUM, com_msgn, 12)}, | |
{NULL} | |
}; | |
MTAB com_mod[] = { | |
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "CHAN", "CHAN", | |
&set_chan, &get_chan, NULL, "Set channel"}, | |
#ifndef I7010 | |
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "SELECT", "SELECT", | |
&chan9_set_select, &chan9_get_select, NULL, "Set selection channel"}, | |
#endif | |
{UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &com_summ}, | |
{MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, | |
NULL, &com_show, NULL}, | |
{MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, | |
NULL, &com_show, NULL}, | |
{0} | |
}; | |
DEVICE com_dev = { | |
"COM", com_unit, com_reg, com_mod, | |
3, 10, 31, 1, 16, 8, | |
&tmxr_ex, &tmxr_dep, &com_reset, | |
NULL, &com_attach, &com_detach, | |
&com_dib, DEV_DISABLE| DEV_DEBUG|DEV_NET, 0, dev_debug, | |
NULL, NULL, &com_help, NULL, NULL, &com_description | |
}; | |
/* COMLL data structures | |
coml_dev COML device descriptor | |
coml_unit COML unit descriptor | |
coml_reg COML register list | |
coml_mod COML modifiers list | |
*/ | |
UNIT coml_unit[] = { | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 0 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 1 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 2 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 3 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 4 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 5 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 6 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 7 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 8 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 9 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 0 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 1 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 2 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 3 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 4 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 5 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 6 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 7 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 8 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 9 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 0 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 1 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 2 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 3 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 4 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 5 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 6 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 7 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 8 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 9 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 0 */ | |
{UDATA(&como_svc, 0, 0), COML_WAIT}, /* 1 */ | |
}; | |
MTAB coml_mod[] = { | |
{UNIT_K35 + UNIT_2741, 0, "KSR-37", "KSR-37", NULL, NULL, NULL, | |
"Standard KSR"}, | |
{UNIT_K35 + UNIT_2741, UNIT_K35, "KSR-35", "KSR-35", NULL, NULL, NULL, | |
"Upper case only KSR"}, | |
{UNIT_K35 + UNIT_2741, UNIT_2741, "2741", "2741", NULL, NULL, NULL, | |
"IBM 2741 terminal"}, | |
{MTAB_XTD | MTAB_VUN, 0, NULL, "DISCONNECT", | |
&tmxr_dscln, NULL, &com_desc, "Disconnect line"}, | |
{MTAB_XTD | MTAB_VUN | MTAB_NC, 0, "LOG", "LOG", | |
&tmxr_set_log, &tmxr_show_log, &com_desc}, | |
{MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, "NOLOG", | |
&tmxr_set_nolog, NULL, &com_desc}, | |
{0} | |
}; | |
REG coml_reg[] = { | |
{URDATA(TIME, coml_unit[0].wait, 16, 24, 0, | |
COM_TLINES, REG_NZ + PV_LEFT)}, | |
{NULL} | |
}; | |
DEVICE coml_dev = { | |
"COML", coml_unit, coml_reg, coml_mod, | |
COM_TLINES, 10, 31, 1, 16, 8, | |
NULL, NULL, &com_reset, NULL, NULL, NULL, | |
NULL, DEV_DISABLE, 0, NULL, NULL, | |
NULL, &coml_help, NULL, NULL, &coml_description | |
}; | |
/* COM: channel select */ | |
uint32 com_cmd(UNIT * uptr, uint16 cmd, uint16 dev) | |
{ | |
/* Activate the com device */ | |
sim_activate(&com_unit[COM_CHU], 10); | |
#if 0 /* Commented out until I can detect hangup signal */ | |
if (!sim_is_active(&com_unit[COM_CIU])) /* console */ | |
sim_activate(&com_unit[COM_CIU], com_unit[COM_CIU].wait); | |
if (!sim_is_active(&com_unit[COM_PLU])) { | |
if (com_unit[COM_PLU].flags & UNIT_ATT) { /* master att? */ | |
int32 t = | |
sim_rtcn_init(com_unit[COM_PLU].wait, TMR_COM); | |
sim_activate(&com_unit[COM_PLU], t); | |
} | |
} | |
#endif | |
com_sta = 1; | |
com_dflg = 0; | |
com_active = 1; | |
return SCPE_OK; | |
} | |
/* Unit service - channel program */ | |
t_stat com_svc(UNIT * uptr) | |
{ | |
int chan = UNIT_G_CHAN(uptr->flags); | |
int sel = (uptr->flags & UNIT_SELECT) ? 1 : 0; | |
uint8 ch; | |
if (sel != chan_test(chan, CTL_SEL)) | |
return SCPE_OK; | |
/* Handle disconnect */ | |
if (com_sta != 0 && chan_stat(chan, DEV_DISCO)) { | |
chan_clear(chan, DEV_WEOR|DEV_SEL); | |
com_sta = 0; | |
com_active = 0; | |
return SCPE_OK; | |
} | |
if (chan_test(chan, CTL_SNS)) { | |
int eor = (com_sta == 4)?DEV_REOR:0; | |
ch = (com_sense >> ((4 - com_sta) * 4)) & 0xf; | |
if (ch & 010) /* Move A bit over one */ | |
ch ^= 030; | |
sim_debug(DEBUG_SNS, &com_dev, "sense unit=%02x\n", ch); | |
switch(chan_write_char(chan, &ch, eor)) { | |
case TIME_ERROR: | |
case END_RECORD: | |
com_sta = -1; | |
com_sense = 0; | |
break; | |
case DATA_OK: | |
com_sta++; | |
} | |
sim_activate(uptr, 50); | |
return SCPE_OK; | |
} | |
/* Start a command, only do read/write */ | |
if (chan_test(chan, CTL_CNTL)) { | |
chan_clear(chan, DEV_FULL); | |
chan_set(chan, DEV_REOR|DEV_SEL); | |
sim_activate(uptr, 50); | |
return SCPE_OK; | |
} | |
/* Send down next buffer word */ | |
if (chan_test(chan, CTL_READ)) { | |
/* Send low order character if one */ | |
if (com_dflg) { | |
ch = com_data & 0377; | |
sim_debug(DEBUG_DATA, &com_dev, "sent=%02o\n", ch); | |
switch (chan_write_char(chan, &ch, (com_sta == 3)?DEV_REOR:0)) { | |
case DATA_OK: | |
case END_RECORD: | |
com_dflg = 0; | |
break; | |
case TIME_ERROR: | |
com_sense |= DATA_TIMEOUT; | |
} | |
sim_activate(uptr, 50); | |
return SCPE_OK; | |
} | |
switch (com_sta) { | |
case 1: | |
com_data = com_msgn; /* 1st char is msg num */ | |
com_msgn = (com_msgn + 1) & 03777; /* incr msg num */ | |
com_sta++; | |
com_posti = 0; | |
chan9_clear_error(chan, sel); | |
break; | |
case 2: | |
/* Check if queue empty. */ | |
if (in_head == in_tail) { | |
com_data = COMI_EOM; | |
com_sta++; | |
} else { | |
/* Grab next entry. */ | |
in_head++; | |
/* Wrap around end of ring */ | |
if (in_head >= (sizeof(in_buff)/sizeof(uint16))) | |
in_head = 0; | |
com_data = in_buff[in_head]; | |
/* Check if end of current transfer */ | |
if (com_data == COMI_EOM) | |
com_sta++; | |
in_count--; | |
} | |
break; | |
case 3: | |
chan_set(chan, DEV_REOR|CTL_END); | |
sim_activate(uptr, 50); | |
com_posti = 0; | |
com_sta++; | |
return SCPE_OK; /* q empty, done */ | |
} | |
sim_debug(DEBUG_DATA, &com_dev, "send data=%04o\n", com_data); | |
ch = (com_data >> 6) & 077; | |
com_data &= 077; | |
switch (chan_write_char(chan, &ch, 0)) { | |
case DATA_OK: | |
case END_RECORD: | |
com_dflg = 1; | |
break; | |
case TIME_ERROR: | |
com_sense |= DATA_TIMEOUT; | |
} | |
sim_activate(uptr, 50); | |
return SCPE_OK; | |
} | |
if (chan_test(chan, CTL_WRITE)) { | |
uint32 ln; | |
/* Read in two characters */ | |
if (com_dflg == 0) { | |
switch(chan_read_char(chan, &ch, 0)) { | |
case DATA_OK: | |
com_dflg = 1; | |
com_data = (ch & 077) << 6; | |
break; | |
case END_RECORD: | |
case TIME_ERROR: | |
com_sense |= DATA_TIMEOUT; | |
} | |
sim_activate(uptr, 50); | |
return SCPE_OK; | |
} else { | |
switch(chan_read_char(chan, &ch, 0)) { | |
case DATA_OK: | |
com_dflg = 0; | |
com_data |= (ch & 077); | |
break; | |
case END_RECORD: | |
case TIME_ERROR: | |
com_sense |= DATA_TIMEOUT; | |
sim_activate(uptr, 50); | |
return SCPE_OK; | |
} | |
} | |
sim_debug(DEBUG_DATA, &com_dev, "recieved=%04o\n", com_data); | |
switch (com_sta) { | |
case 1: | |
com_oln = com_data; | |
if (com_data == 07777) { /* turn on? */ | |
sim_debug(DEBUG_DETAIL, &com_dev, "enable\n"); | |
com_enab = 1; /* enable 7750 */ | |
in_delay = 200; | |
com_msgn = 0; /* init message # */ | |
com_sta = 4; | |
chan_set(chan, DEV_REOR|CTL_END); | |
} else if (com_data & COMO_LINCTL) { /* control message? */ | |
ln = COMO_GETLN(com_data); /* line number */ | |
sim_debug(DEBUG_DETAIL, &com_dev, "line %d\n", ln); | |
if (ln >= (COM_TLINES + COM_LBASE)) /* invalid line? */ | |
return STOP_INVLIN; | |
if (ln > COM_LBASE) /* valid line? */ | |
com_reset_ln(ln - COM_LBASE); | |
com_sta = 4; | |
chan_set(chan, DEV_REOR|CTL_END); | |
} else /* data message */ | |
com_sta++; | |
break; | |
case 2: | |
com_ocnt = (com_data & 07777) + 1; /* char count plus EOM */ | |
if (com_oln & COMO_LIN12B) { | |
com_ocnt = com_ocnt << 1; /* 12b double */ | |
com_o12b = 1; | |
} else | |
com_o12b = 0; | |
com_oln = COMO_GETLN(com_oln); /* line number */ | |
sim_debug(DEBUG_DETAIL, &com_dev, "output line %d\n", com_oln); | |
com_sta++; /* next state */ | |
break; | |
case 3: /* other words */ | |
ln = com_oln; /* effective line */ | |
/* unpack chars */ | |
if (com_o12b) { | |
com_ocnt -= 2; | |
if (com_data == COMO_EOM12B) { | |
com_sta++; | |
if (com_ocnt != 0) { | |
chan9_set_error(chan, SNS_UEND); | |
com_sense |= PROG_MSGLEN; | |
} | |
chan_set(chan, DEV_REOR|CTL_END); /* end, last state */ | |
break; /* EOM? */ | |
} | |
} else { | |
com_ocnt--; | |
if (((com_data >> 6) & 077) == COMO_EOM6B) { | |
com_sta++; | |
if (com_ocnt != 0) { | |
sim_debug(DEBUG_EXP, &com_dev, "messge length error %d\n", com_ocnt); | |
chan9_set_error(chan, SNS_UEND); | |
com_sense |= PROG_MSGLEN; | |
} | |
chan_set(chan, DEV_REOR|CTL_END); /* end, last state */ | |
break; /* EOM? */ | |
} | |
sim_debug(DEBUG_DETAIL, &com_dev, "queing %o %d\n", (com_data >> 6) & 077, com_ocnt); | |
if (com_put(ln, (com_data >> 6) & 077)) { | |
sim_debug(DEBUG_EXP, &com_dev, "Insert error\n"); | |
chan9_set_error(chan, SNS_UEND); | |
com_sense |= PROG_FULL; | |
} | |
com_ocnt--; | |
com_data &= 077; | |
if (com_data == COMO_EOM6B) { | |
com_sta++; | |
if (com_ocnt != 0) { | |
sim_debug(DEBUG_EXP, &com_dev, "messge length error %d\n", com_ocnt); | |
chan9_set_error(chan, SNS_UEND); | |
com_sense |= PROG_MSGLEN; | |
} | |
chan_set(chan, DEV_REOR|CTL_END); /* end, last state */ | |
break; /* EOM? */ | |
} | |
} | |
sim_debug(DEBUG_DETAIL, &com_dev, "queing %o %d\n", com_data, com_ocnt); | |
if (com_put(ln, com_data)) { | |
sim_debug(DEBUG_EXP, &com_dev, "Insert error\n"); | |
chan9_set_error(chan, SNS_UEND); | |
com_sense |= PROG_FULL; | |
} | |
break; | |
} | |
sim_activate(uptr, 50); | |
} | |
return SCPE_OK; | |
} | |
/* Unit service - console receive - always running, even if device is not */ | |
t_stat | |
comti_svc(UNIT * uptr) | |
{ | |
int32 c; | |
t_stat r; | |
sim_activate(uptr, uptr->wait); /* continue poll */ | |
c = sim_poll_kbd(); /* get character */ | |
if (c && (c < SCPE_KFLAG)) | |
return c; /* error? */ | |
if (((com_unit[COM_PLU].flags & UNIT_ATT) == 0) || /* not att, not enab, */ | |
!com_enab || (c & SCPE_BREAK)) | |
return SCPE_OK; /* break? done */ | |
c = c & 0177; | |
if (c) { | |
r = com_queue_in(0, c); | |
if (r != SCPE_OK) | |
return r; | |
sim_putchar(c); | |
if (c == '\r') | |
sim_putchar('\n'); | |
} | |
return SCPE_OK; | |
} | |
/* Unit service - receive side | |
Poll all active lines for input | |
Poll for new connections */ | |
t_stat | |
comi_svc(UNIT * uptr) | |
{ | |
int32 c, ln, t; | |
t_stat r; | |
if ((uptr->flags & UNIT_ATT) == 0) | |
return SCPE_OK; /* attached? */ | |
if (in_delay-- <= 0) { /* Check for any inputs to send over. */ | |
in_delay = 50; /* Time to wait for polling again. */ | |
if (!com_active && in_count > 0) | |
com_post_eom(); | |
} | |
t = sim_rtcn_calb(com_tps, TMR_COM); /* calibrate */ | |
sim_activate(uptr, t); /* continue poll */ | |
ln = tmxr_poll_conn(&com_desc); /* look for connect */ | |
if (ln >= 0) { /* got one? */ | |
com_ldsc[ln].rcve = 1; /* rcv enabled */ | |
coml_unit[ln].CONN = 1; /* flag connected */ | |
coml_unit[ln].NEEDID = 1; /* need ID */ | |
coml_unit[ln].ECHO = 1; /* echoing output */ | |
} | |
if (!com_enab) | |
return SCPE_OK; /* not enabled? exit */ | |
tmxr_poll_rx(&com_desc); /* poll for input */ | |
for (ln = 0; ln < COM_TLINES; ln++) { /* loop thru mux */ | |
if (com_ldsc[ln].conn) { /* connected? */ | |
if (coml_unit[ln].NEEDID) | |
com_send_id(ln); | |
c = tmxr_getc_ln(&com_ldsc[ln]); /* get char */ | |
if (c) { /* any char? */ | |
c = c & 0177; /* mask to 7b */ | |
r = com_queue_in(ln, c); | |
if (r != SCPE_OK) | |
return r; /* queue char, err? */ | |
if (coml_unit[ln].ECHO && com_ldsc[ln].xmte) { /* output enabled? */ | |
if (coml_unit[ln].flags & UNIT_K35) { /* KSR-35? */ | |
if (islower(c)) | |
c = toupper(c); /* convert LC to UC */ | |
} | |
tmxr_putc_ln(&com_ldsc[ln], c); /* echo char */ | |
if (c == '\r') /* add LF after CR */ | |
tmxr_putc_ln(&com_ldsc[ln], '\n'); | |
} /* end if enabled */ | |
} /* end if char */ | |
} /* end if conn */ | |
else if (coml_unit[ln].CONN) { /* not conn, was conn? */ | |
coml_unit[ln].CONN = 0; /* clear connected */ | |
coml_unit[ln].NEEDID = 0; /* clear need id */ | |
if (com_inp_msg(ln, COMI_HANGUP)) /* hangup message */ | |
return STOP_NOIFREE; | |
} | |
} /* end for */ | |
tmxr_poll_tx(&com_desc); /* poll xmt */ | |
return SCPE_OK; | |
} | |
/* Unit service - console transmit */ | |
t_stat | |
comto_svc(UNIT * uptr) | |
{ | |
uint16 c, c1; | |
if (com_out_head[0] == 0) | |
return com_send_ccmp(0); /* Send out a completion code */ | |
c = com_queue_out(0, &c1); /* get character, cvt */ | |
if (c) | |
sim_putchar(c); /* printable? output */ | |
if (c1) | |
sim_putchar(c1); /* second char? output */ | |
sim_activate(uptr, uptr->wait); /* next char */ | |
if (com_comp_cnt[0] >= COMI_CMAX) /* completion needed? */ | |
return com_send_ccmp(0); /* generate msg */ | |
return SCPE_OK; | |
} | |
/* Unit service - transmit side */ | |
t_stat | |
como_svc(UNIT * uptr) | |
{ | |
uint16 c, c1; | |
int32 ln = uptr - coml_unit; /* line # */ | |
if (com_out_head[ln] == 0) /* no more characters? */ | |
return com_send_ccmp(ln); /* free any remaining */ | |
if (com_ldsc[ln].conn) { /* connected? */ | |
if (com_ldsc[ln].xmte) { /* output enabled? */ | |
c = com_queue_out(ln, &c1); /* get character, cvt */ | |
if (c) | |
tmxr_putc_ln(&com_ldsc[ln], c); /* printable? output */ | |
if (c1) | |
tmxr_putc_ln(&com_ldsc[ln], c1); /* print second */ | |
} /* end if */ | |
tmxr_poll_tx(&com_desc); /* poll xmt */ | |
sim_activate(uptr, uptr->wait); /* next char */ | |
if (com_comp_cnt[ln] >= COMI_CMAX) /* completion needed? */ | |
return com_send_ccmp(ln); /* generate msg */ | |
} /* end if conn */ | |
return SCPE_OK; | |
} | |
/* Send ID sequence on input */ | |
t_stat | |
com_send_id(uint32 ln) | |
{ | |
com_inp_msg(ln, COMI_DIALUP); /* input message: */ | |
if (coml_unit[ln].flags & UNIT_2741) /* dialup, ID, endID */ | |
com_inp_msg(ln, COMI_2741); | |
else if (coml_unit[ln].flags & UNIT_K35) | |
com_inp_msg(ln, COMI_K35); | |
else | |
com_inp_msg(ln, COMI_K37); | |
com_inp_msg(ln, 0); | |
com_inp_msg(ln, 0); | |
com_inp_msg(ln, 0); | |
com_queue_in(ln, 'T'); | |
com_queue_in(ln, '0' + ((ln+1) / 10)); | |
com_queue_in(ln, '0' + ((ln+1) % 10)); | |
if (com_inp_msg(ln, COMI_ENDID)) /* make sure there */ | |
return STOP_NOIFREE; /* was room for msg */ | |
coml_unit[ln].NEEDID = 0; | |
com_sense |= EXPT_SRVRDY; | |
return SCPE_OK; | |
} | |
/* Translate and queue input character */ | |
t_stat | |
com_queue_in(uint32 ln, uint16 c) | |
{ | |
uint16 out; | |
uint16 parity; | |
if (c == com_intr) | |
out = COMI_INTR; | |
else if (c == com_quit) | |
out = COMI_QUIT; | |
else { | |
if (coml_unit[ln].flags & UNIT_K35) { /* KSR-35? */ | |
if (islower(c)) | |
c = toupper(c); /* convert LC to UC */ | |
} | |
if ((coml_unit[ln].flags & UNIT_K35) == 0) { /* KSR-37 or 2741 */ | |
if (c == '\r') | |
c = '\n'; | |
} | |
if (coml_unit[ln].flags & UNIT_2741) { | |
c = com_2741_in[c]; | |
if (c & 0200) { /* Check if lower case */ | |
if ((com_out_inesc[ln] & 2) == 0) { /* In upper case? */ | |
uint8 c2; | |
c2 = com_2741_out[c & 077]; /* Check if no need to change */ | |
if (c2 != com_2741_out[(c&077)|0100]) { | |
com_inp_msg(ln, 0034); /* Switch case */ | |
com_out_inesc[ln] &= 1; | |
} | |
} | |
} else { | |
if (com_out_inesc[ln] & 2) { /* In lower case? */ | |
uint8 c2; | |
c2 = com_2741_out[c & 077]; /* Check if no need to change */ | |
if (c2 != com_2741_out[(c&077)|0100]) { | |
com_inp_msg(ln, 0037); /* Switch case */ | |
com_out_inesc[ln] |= 2; | |
} | |
} | |
} | |
c &= 0177; | |
} | |
out = (~c) & 0177; /* 1's complement */ | |
parity = out ^ (out >> 4); | |
parity = parity ^ (parity >> 2); | |
parity = parity ^ (parity >> 1); | |
if (parity & 1) | |
out |= COMI_PARITY; /* add even parity */ | |
} | |
if (com_inp_msg(ln, out)) | |
return STOP_NOIFREE; /* input message */ | |
com_sense |= EXPT_DATRDY; | |
return SCPE_OK; | |
} | |
/* Retrieve and translate output character */ | |
uint32 | |
com_queue_out(uint32 ln, uint16 * c1) | |
{ | |
uint16 c, raw; | |
*c1 = 0; /* assume non-printing */ | |
if (com_get(ln, &raw)) /* Try to get character */ | |
return 0; | |
if (raw == COMO_BITRPT) { /* insert delay? */ | |
com_skip_outc(ln); | |
return 0; | |
} | |
c = (~raw >> 1) & 0177; /* remove start, parity */ | |
if (coml_unit[ln].flags & UNIT_2741) { | |
uint8 c2; | |
c2 = c & 077; | |
if (com_out_inesc[ln] & 4) { | |
com_out_inesc[ln] &= 3; | |
switch (c) { | |
case '\043': /* Red */ | |
tmxr_putc_ln(&com_ldsc[ln], '\033'); | |
tmxr_putc_ln(&com_ldsc[ln], '['); | |
tmxr_putc_ln(&com_ldsc[ln], '3'); | |
tmxr_putc_ln(&com_ldsc[ln], '1'); | |
tmxr_putc_ln(&com_ldsc[ln], 'm'); | |
return 0; | |
case '\023': /* Black */ | |
tmxr_putc_ln(&com_ldsc[ln], '\033'); | |
tmxr_putc_ln(&com_ldsc[ln], '['); | |
tmxr_putc_ln(&com_ldsc[ln], '0'); | |
tmxr_putc_ln(&com_ldsc[ln], 'm'); | |
return 0; | |
} | |
*c1 = c; | |
return '\033'; | |
} | |
switch (c2) { | |
case '\034': com_out_inesc[ln] &= 2; return 0; /* UC */ | |
case '\037': com_out_inesc[ln] |= 1; return 0; /* LC */ | |
case '\076': com_out_inesc[ln] |= 4; return 0; /* Esc */ | |
case '\016': coml_unit[ln].ECHO = FALSE; return 0; /* Poff */ | |
case '\015': coml_unit[ln].ECHO = TRUE; return 0; /* Pon */ | |
} | |
c2 = com_2741_out[(com_out_inesc[ln]&1)? (0100|c2): c2]; | |
sim_debug(DEBUG_DETAIL, &com_dev, "printing %d %04o '%c' %o\n", | |
ln, c, (c2>= ' ')?c2: 0, com_out_inesc[ln]&1); | |
if (c2 == '\n') | |
*c1 = '\r'; | |
return c2; | |
} | |
if (com_out_inesc[ln]) { | |
com_out_inesc[ln] = 0; | |
switch (c) { | |
case '3': /* Red */ | |
tmxr_putc_ln(&com_ldsc[ln], '\033'); | |
tmxr_putc_ln(&com_ldsc[ln], '['); | |
tmxr_putc_ln(&com_ldsc[ln], '3'); | |
tmxr_putc_ln(&com_ldsc[ln], '1'); | |
tmxr_putc_ln(&com_ldsc[ln], 'm'); | |
return 0; | |
case '4': /* Black */ | |
tmxr_putc_ln(&com_ldsc[ln], '\033'); | |
tmxr_putc_ln(&com_ldsc[ln], '['); | |
tmxr_putc_ln(&com_ldsc[ln], '0'); | |
tmxr_putc_ln(&com_ldsc[ln], 'm'); | |
return 0; | |
case ':': /* Poff */ | |
coml_unit[ln].ECHO = FALSE; | |
return 0; | |
case ';': /* Pon */ | |
coml_unit[ln].ECHO = TRUE; | |
return 0; | |
} | |
*c1 = c; | |
return '\033'; | |
} | |
sim_debug(DEBUG_DETAIL, &com_dev, "printing %d %04o '%c'\n", ln, c, (c >= ' ')?c:0); | |
if (c >= 040) { /* printable? */ | |
if (c == 0177) | |
return 0; /* DEL? ignore */ | |
if ((coml_unit[ln].flags & UNIT_K35) && islower(c)) /* KSR-35 LC? */ | |
c = toupper(c); /* cvt to UC */ | |
return c; | |
} | |
switch (c) { | |
case '\033': /* Escape character */ | |
com_out_inesc[ln] = 1; | |
return 0; | |
case '\t': | |
case '\f': | |
case '\b': | |
case '\a': /* valid ctrls */ | |
return c; | |
case '\r': /* carriage return? */ | |
if (coml_unit[ln].flags & UNIT_K35) /* KSR-35? */ | |
*c1 = '\n'; /* lf after cr */ | |
return c; | |
case '\n': /* line feed? */ | |
if (!(coml_unit[ln].flags & UNIT_K35)) { /* KSR-37? */ | |
*c1 = '\n'; /* lf after cr */ | |
return '\r'; | |
} | |
return c; /* print lf */ | |
#if 0 | |
case 022: /* DC2 */ | |
if (!(com_unit[ln].flags & UNIT_K35)) { /* KSR-37? */ | |
com_skip_outc(ln); /* skip next */ | |
return '\n'; /* print lf */ | |
} | |
break; | |
case 024: /* DC4 */ | |
if (!(com_unit[ln].flags & UNIT_K35)) /* KSR-37? */ | |
com_skip_outc(ln); /* skip next */ | |
break; | |
#endif | |
} | |
return 0; /* ignore others */ | |
} | |
/* Generate completion message, if needed */ | |
t_stat | |
com_send_ccmp(uint32 ln) | |
{ | |
uint32 t; | |
t = com_comp_cnt[ln]; | |
if (t != 0) { /* chars not returned? */ | |
if (t > COMI_CMAX) | |
t = COMI_CMAX; /* limit to max */ | |
com_comp_cnt[ln] -= t; /* keep count */ | |
if (com_inp_msg(ln, COMI_COMP(t))) /* gen completion msg */ | |
return STOP_NOIFREE; | |
} | |
return SCPE_OK; | |
} | |
/* Skip next char in output queue */ | |
void | |
com_skip_outc(uint32 ln) | |
{ | |
uint16 tmp; | |
if (com_get(ln, &tmp)) | |
com_comp_cnt[ln]++; /* count it */ | |
return; | |
} | |
/* List routines - remove from head and free */ | |
t_bool | |
com_get(int ln, uint16 *ch) | |
{ | |
uint16 ent; | |
ent = com_out_head[ln]; | |
if (ent == 0) /* Check if anything to send. */ | |
return TRUE; | |
*ch = com_buf[ent].data; | |
com_comp_cnt[ln]++; | |
com_out_head[ln] = com_buf[ent].link; /* Get next char */ | |
com_buf[ent].link = com_free; /* Put back on free list */ | |
com_free = ent; | |
if (com_out_head[ln] == 0) { /* done with queue? */ | |
com_out_tail[ln] = 0; | |
} | |
return FALSE; | |
} | |
/* Put a character onto output queue for a line */ | |
t_bool | |
com_put(int ln, uint16 ch) | |
{ | |
uint16 ent; | |
ln -= COM_LBASE; | |
ent = com_free; /* Get a character spot */ | |
if (ent == 0) | |
return TRUE; /* No room */ | |
com_free = com_buf[ent].link; /* Next free character */ | |
com_buf[ent].data = ch; | |
com_buf[ent].link = 0; | |
if (com_out_tail[ln] == 0) { /* Idle line */ | |
com_out_head[ln] = ent; | |
} else { /* Active line */ | |
com_buf[com_out_tail[ln]].link = ent; | |
} | |
com_out_tail[ln] = ent; | |
/* Activate line if not already running */ | |
if (!sim_is_active(&coml_unit[ln])) | |
sim_activate(&coml_unit[ln], coml_unit[ln].wait); | |
return FALSE; | |
} | |
/* Put EOM on input queue and post interupt to wake up CPU */ | |
void | |
com_post_eom() | |
{ | |
int ent; | |
int chan = UNIT_G_CHAN(com_unit[0].flags); | |
int sel = (com_unit[0].flags & UNIT_SELECT) ? 1 : 0; | |
/* See if we can insert a EOM message */ | |
if (in_buff[in_tail] != COMI_EOM) { | |
sim_debug(DEBUG_EXP, &com_dev, "inserting eom %d %d %d\n", | |
in_head, in_tail, in_count); | |
ent = in_tail + 1; | |
if (ent >= (sizeof(in_buff)/sizeof(uint16))) /* Wrap around */ | |
ent = 0; | |
if (ent != in_head) { /* If next element would be head, queue is full */ | |
/* If we can't put one on, handler will do it for us */ | |
in_buff[ent] = COMI_EOM; | |
in_tail = ent; | |
in_count++; | |
} | |
} | |
chan9_set_attn(chan, sel); | |
com_posti = 1; | |
} | |
/* Insert line and message into input queue */ | |
t_bool | |
com_inp_msg(uint32 ln, uint16 msg) | |
{ | |
int ent1, ent2; | |
sim_debug(DEBUG_EXP, &com_dev, "inserting %d %04o %d %d %d\n", ln, msg, | |
in_head, in_tail, in_count); | |
ent1 = in_tail + 1; | |
if (ent1 >= (sizeof(in_buff)/sizeof(uint16))) /* Wrap around */ | |
ent1 = 0; | |
if (ent1 == in_head) /* If next element would be head, queue is full */ | |
return TRUE; | |
ent2 = ent1 + 1; | |
if (ent2 >= (sizeof(in_buff)/sizeof(uint16))) /* Wrap around */ | |
ent2 = 0; | |
if (ent2 == in_head) /* If next element would be head, queue is full */ | |
return TRUE; | |
/* Ok we have room to put this message in. */ | |
ln += COM_LBASE; | |
in_buff[ent1] = 02000 + ln; | |
in_buff[ent2] = msg; | |
in_count += 2; | |
in_tail = ent2; | |
/* Check if over limit */ | |
if (!com_active && in_count > 150) { | |
com_post_eom(); | |
} | |
return FALSE; | |
} | |
/* Reset routine */ | |
t_stat | |
com_reset(DEVICE * dptr) | |
{ | |
uint32 i; | |
if (dptr->flags & DEV_DIS) { /* disabled? */ | |
com_dev.flags = com_dev.flags | DEV_DIS; /* disable lines */ | |
coml_dev.flags = coml_dev.flags | DEV_DIS; | |
} else { | |
com_dev.flags = com_dev.flags & ~DEV_DIS; /* enable lines */ | |
coml_dev.flags = coml_dev.flags & ~DEV_DIS; | |
} | |
#if 0 /* Commented out until I can detect hangup signal */ | |
sim_activate(&com_unit[COM_CIU], com_unit[COM_CIU].wait); /* console */ | |
sim_cancel(&com_unit[COM_CHU]); | |
#endif | |
sim_cancel(&com_unit[COM_PLU]); | |
if (com_unit[COM_PLU].flags & UNIT_ATT) { /* master att? */ | |
int32 t = | |
sim_rtcn_init(com_unit[COM_PLU].wait, TMR_COM); | |
sim_activate(&com_unit[COM_PLU], t); | |
} | |
com_enab = 0; | |
com_msgn = 0; | |
com_sta = 0; | |
com_sense = 0; | |
/* Put dummy message on Queue before first login */ | |
in_head = 0; | |
in_tail = 0; | |
in_count = 0; | |
for (i = 0; i < COM_TLINES; i++) { | |
com_out_tail[i] = 0; | |
com_out_head[i] = 0; | |
com_reset_ln(i); | |
} | |
com_free = sizeof(com_buf)/(sizeof(OLIST)); | |
for (i = 1; i < com_free; i++) { | |
com_buf[i].link = i + 1; | |
com_buf[i].data = 0; | |
} | |
com_buf[com_free - 1].link = 0; /* end of free list */ | |
com_free = 1; | |
return SCPE_OK; | |
} | |
/* Attach master unit */ | |
t_stat | |
com_attach(UNIT * uptr, CONST char *cptr) | |
{ | |
t_stat r; | |
r = tmxr_attach(&com_desc, uptr, cptr); /* attach */ | |
if (r != SCPE_OK) | |
return r; /* error */ | |
sim_rtcn_init(uptr->wait, TMR_COM); | |
sim_activate(uptr, 100); /* quick poll */ | |
return SCPE_OK; | |
} | |
/* Detach master unit */ | |
t_stat | |
com_detach(UNIT * uptr) | |
{ | |
uint32 i; | |
t_stat r; | |
r = tmxr_detach(&com_desc, uptr); /* detach */ | |
for (i = 0; i < COM_MLINES; i++) | |
com_ldsc[i].rcve = 0; /* disable rcv */ | |
sim_cancel(uptr); /* stop poll */ | |
return r; | |
} | |
/* Show summary processor */ | |
t_stat | |
com_summ(FILE * st, UNIT * uptr, int32 val, CONST void *desc) | |
{ | |
uint32 i, t; | |
t = 0; | |
for (i = 0; i < COM_TLINES; i++) | |
t = t + (com_ldsc[i].conn != 0); | |
if (t == 1) | |
fprintf(st, "1 connection"); | |
else | |
fprintf(st, "%d connections", t); | |
return SCPE_OK; | |
} | |
/* SHOW CONN/STAT processor */ | |
t_stat | |
com_show(FILE * st, UNIT * uptr, int32 val, CONST void *desc) | |
{ | |
int32 i, cc; | |
for (cc = 0; (cc < COM_MLINES) && com_ldsc[cc].conn; cc++) ; | |
if (cc) { | |
for (i = 0; i < COM_MLINES; i++) { | |
if (com_ldsc[i].conn) { | |
if (val) | |
tmxr_fconns(st, &com_ldsc[i], i); | |
else | |
tmxr_fstats(st, &com_ldsc[i], i); | |
} | |
} | |
} else | |
fprintf(st, "all disconnected\n"); | |
return SCPE_OK; | |
} | |
/* Reset an individual line */ | |
void | |
com_reset_ln(uint32 ln) | |
{ | |
uint16 ch; | |
while (!com_get(ln, &ch)) ; | |
com_comp_cnt[ln] = 0; | |
com_out_inesc[ln] = 0; | |
sim_cancel(&coml_unit[ln]); | |
if ((ln < COM_MLINES) && (com_ldsc[ln].conn == 0)) | |
coml_unit[ln].CONN = 0; | |
return; | |
} | |
const char * | |
coml_description(DEVICE *dptr) | |
{ | |
return "IBM 7750 terminal"; | |
} | |
t_stat | |
coml_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) | |
{ | |
fprintf (st, "Each COM line can be set to a given type of terminal\n\n"); | |
fprintf (st, " sim> SET COMLn KSR-37 Standard connection\n"); | |
fprintf (st, " sim> SET COMLn KSR-35 Allows only upper case\n"); | |
fprintf (st, " sim> SET COMLn 2741 Set to look like a 2741\n"); | |
fprint_set_help (st, dptr); | |
fprint_show_help (st, dptr); | |
return SCPE_OK; | |
} | |
const char * | |
com_description(DEVICE *dptr) | |
{ | |
return "IBM 7750 terminal controller"; | |
} | |
t_stat | |
com_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) | |
{ | |
fprintf (st, "IBM 7750 terminal controller, this is required for CTSS to run.\n"); | |
fprintf (st, "The ATTACH command specifies the port to be used:\n\n"); | |
tmxr_attach_help (st, dptr, uptr, flag, cptr); | |
help_set_chan_type(st, dptr, "IBM 7750"); | |
#ifndef I7010 | |
fprintf (st, "Each device on the channel can be at either select 0 or 1, \n"); | |
fprintf (st, "this is set with the\n\n"); | |
fprintf (st, " sim> SET COM SELECT=n\n\n"); | |
#endif | |
fprint_set_help (st, dptr); | |
fprint_show_help (st, dptr); | |
return SCPE_OK; | |
} | |
#endif | |