mirror of
https://github.com/rcornwell/sims.git
synced 2026-01-13 15:27:04 +00:00
SEL32: Fix device address assignment for ethernet controller. SEL32: Allow mag tape to be enabled/attached after system boot. SEL32: Change delay after SIO to be applied for each unit. SEL32: Create 1 tape backup of /usr for UTX. SEL32: Fix test for device on system to use disabled flag. SEL32: Correct wakeup status for 8-line support. SEL32: Support -i -n flags options to attach command. SEL32: Only support disk track replacement logic for diag tracks. SEL32: Fix two Coverity warning errors from last update. SEL32: Correct status flage setting for mag tape. SEL32: Update SEL32 Documentation. SEL32: Correct mkvmtape in taptools to 8 chars for owner and group names.
1039 lines
50 KiB
C
1039 lines
50 KiB
C
/* sel32_com.c: SEL 32 8-Line IOP communications controller
|
|
|
|
Copyright (c) 2018-2021, James C. Bevier
|
|
Portions provided by Richard Cornwell and other SIMH contributers
|
|
|
|
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
|
|
JAMES C. BEVIER 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 "sel32_defs.h"
|
|
#include "sim_sock.h"
|
|
#include "sim_tmxr.h"
|
|
#include <ctype.h>
|
|
|
|
#if NUM_DEVS_COM > 0
|
|
|
|
/* Constants */
|
|
#define COM_LINES 8 /* max lines */
|
|
#define COM_LINES_DFLT 8 /* default lines */
|
|
#define COM_INIT_POLL 8000
|
|
#define COML_WAIT 500
|
|
#define COM_WAIT 500
|
|
#define COM_NUMLIN com_desc.lines /* curr # lines */
|
|
|
|
#define COMC 0 /* channel thread */
|
|
#define COMI 1 /* input thread */
|
|
|
|
/* Line status */
|
|
#define COML_XIA 0x01 /* xmt intr armed */
|
|
#define COML_XIR 0x02 /* xmt intr req */
|
|
#define COML_REP 0x04 /* rcv enable pend */
|
|
#define COML_RBP 0x10 /* rcv break pend */
|
|
|
|
/* Channel state */
|
|
#define COMC_IDLE 0 /* idle */
|
|
#define COMC_INIT 1 /* init */
|
|
#define COMC_RCV 2 /* receive */
|
|
#define COMC_END 3 /* end */
|
|
|
|
uint8 com_rbuf[COM_LINES]; /* rcv buf */
|
|
uint8 com_xbuf[COM_LINES]; /* xmt buf */
|
|
uint8 com_sta[COM_LINES]; /* status */
|
|
uint32 com_lstat[COM_LINES][2] = { 0 }; /* 8 bytes of line settings status */
|
|
uint32 com_tps = 2; /* polls/second */
|
|
uint32 com_scan = 0; /* scanner */
|
|
uint32 com_slck = 0; /* scanner locked */
|
|
uint32 comc_cmd = COMC_IDLE; /* channel state */
|
|
|
|
TMLN com_ldsc[COM_LINES] = { 0 }; /* line descrs */
|
|
TMXR com_desc = { COM_LINES_DFLT, 0, 0, com_ldsc }; /* com descr */
|
|
|
|
/* Held in u3 is the device command and status */
|
|
#define COM_INCH 0x00 /* Initialize channel command */
|
|
#define COM_WR 0x01 /* Write terminal */
|
|
#define COM_RD 0x02 /* Read terminal */
|
|
#define COM_NOP 0x03 /* No op command */
|
|
#define COM_SNS 0x04 /* Sense command */
|
|
#define COM_WRSCM 0x05 /* Write w/Sub chan monitor */
|
|
#define COM_RDECHO 0x06 /* Read with Echo */
|
|
#define COM_RDFC 0x0A /* Read w/flow control */
|
|
#define COM_DEFSC 0x0B /* Define special char */
|
|
#define COM_WRHFC 0x0D /* Write hardware flow control */
|
|
#define COM_RDTR 0x13 /* Reset DTR (ADVR) */
|
|
#define COM_SDTR 0x17 /* Set DTR (ADVF) */
|
|
#define COM_RRTS 0x1B /* Reset RTS */
|
|
#define COM_SRTS 0x1F /* Set RTS */
|
|
#define COM_RBRK 0x33 /* Reset BREAK */
|
|
#define COM_SBRK 0x37 /* Set BREAK */
|
|
#define COM_RDHFC 0x8E /* Read w/hardware flow control only */
|
|
#define COM_SACE 0xFF /* Set ACE parameters */
|
|
|
|
#define COM_MSK 0xFF /* Command mask */
|
|
|
|
/* Status held in u3 */
|
|
/* controller/unit address in upper 16 bits */
|
|
#define COM_INPUT 0x0100 /* Input ready for unit */
|
|
#define COM_CR 0x0200 /* Output at beginning of line */
|
|
#define COM_REQ 0x0400 /* Request key pressed */
|
|
#define COM_EKO 0x0800 /* Echo input character */
|
|
#define COM_OUTPUT 0x1000 /* Output ready for unit */
|
|
#define COM_READ 0x2000 /* Read mode selected */
|
|
|
|
/* ACE data kept in u4 */
|
|
/* ACE information in u4 */
|
|
#if 0
|
|
/* ACE byte 0 Modem Control/Operation status */
|
|
/* stored in u4 bytes 0-3 */
|
|
#define SNS_HALFD 0x80000000 /* Half-duplix operation set */
|
|
#define SNS_MRINGE 0x40000000 /* Modem ring enabled */
|
|
#define SNS_ACEFP 0x20000000 /* Forced parity 0=odd, 1=even */
|
|
#define SNS_ACEP 0x10000000 /* Parity 0=odd, 1=even */
|
|
#define SNS_ACEPE 0x08000000 /* Parity enable 0=dis, 1=enb */
|
|
#define SNS_ACESTOP 0x04000000 /* Stop bit 0=1, 1=1.5 or 2 */
|
|
#define SNS_ACECLEN 0x02000000 /* Character length 00=5, 01=6, 11=7, 11=8 */
|
|
#define SNS_ACECL2 0x01000000 /* 2nd bit for above */
|
|
|
|
/* ACE byte 1 Baud rate */
|
|
#define SNS_NUB50 0x00800000 /* Zero N/U */
|
|
#define SNS_NUB51 0x00400000 /* Zero N/U */
|
|
#define SNS_RINGCR 0x00200000 /* Ring or wakeup character recognition 0=enb, 1=dis */
|
|
#define SNS_DIAGL 0x00100000 /* Set diagnostic loopback */
|
|
#define SNS_BAUD 0x000F0000 /* Baud rate bits 4-7 */
|
|
#define BAUD50 0x00000000 /* 50 baud */
|
|
#define BAUD75 0x00010000 /* 75 baud */
|
|
#define BAUD110 0x00020000 /* 110 baud */
|
|
#define BAUD114 0x00030000 /* 134 baud */
|
|
#define BAUD150 0x00040000 /* 150 baud */
|
|
#define BAUD300 0x00050000 /* 300 baud */
|
|
#define BAUD600 0x00060000 /* 600 baud */
|
|
#define BAUD1200 0x00070000 /* 1200 baud */
|
|
#define BAUD1800 0x00080000 /* 1800 baud */
|
|
#define BAUD2000 0x00090000 /* 2000 baud */
|
|
#define BAUD2400 0x000A0000 /* 2400 baud */
|
|
#define BAUD3600 0x000B0000 /* 3600 baud */
|
|
#define BAUD4800 0x000C0000 /* 4800 baud */
|
|
#define BAUD7200 0x000D0000 /* 7200 baud */
|
|
#define BAUD9600 0x000E0000 /* 9600 baud */
|
|
#define BAUD19200 0x000F0000 /* 19200 baud */
|
|
|
|
/* ACE byte 2 Wake-up character */
|
|
#define ACE_WAKE 0x0000FF00 /* 8 bit wake-up character */
|
|
#endif
|
|
#define ACE_WAKE 0x0000FF00 /* 8 bit wake-up character in byte 2 of ACE */
|
|
|
|
/* in u5 packs sense byte 0,1 and 3 */
|
|
/* sense byte 3 */
|
|
|
|
/* in u5 packs sense byte 0, 1, 2 and 3 */
|
|
/* Sense byte 0 */
|
|
#define SNS_CMDREJ 0x80000000 /* Command reject */
|
|
#define SNS_INTVENT 0x40000000 /* Unit intervention required (N/U) */
|
|
#define SNS_BOCHK 0x20000000 /* Bus out check (IOP parity error */
|
|
#define SNS_EQUIPCK 0x10000000 /* Equipment check (device error) */
|
|
#define SNS_DATACK 0x08000000 /* Data check */
|
|
#define SNS_OVERRN 0x04000000 /* Overrun (N/U) */
|
|
#define SNS_NUB01 0x02000000 /* Zero (N/U) */
|
|
#define SNS_NUB02 0x01000000 /* Zero (N/U) */
|
|
/* Sense byte 1 */
|
|
#define SNS_ASCIICD 0x00800000 /* ASCII control char detected interrupt */
|
|
#define SNS_SPCLCD 0x00400000 /* Special char detected interrupt */
|
|
#define SNS_ETX 0x00200000 /* ETX interrupt */
|
|
#define SNS_BREAK 0x00100000 /* BREAK interrupt */
|
|
#define SNS_ACEFE 0x00080000 /* ACE framing error interrupt */
|
|
#define SNS_ACEPEI 0x00040000 /* ACE parity error interrupt */
|
|
#define SNS_ACEOVR 0x00020000 /* ACE overrun error interrupt */
|
|
#define SNS_RING 0x00010000 /* Ring character interrupt */
|
|
/* Sense byte 2 Modem status */
|
|
#define SNS_RLSDS 0x00008000 /* Received line signal detect status */
|
|
#define SNS_RINGST 0x00004000 /* Ring indicator line status */
|
|
#define SNS_DSRS 0x00002000 /* DSR Data set ready line status */
|
|
#define SNS_CTSS 0x00001000 /* CTS Clear to send line status */
|
|
#define SNS_DELTA 0x00000800 /* Delta receive line signal detect failure interrupt */
|
|
#define SNS_MRING 0x00000400 /* RI Modem ring interrupt */
|
|
#define SNS_DELDSR 0x00000200 /* Delta data set ready interrupt */
|
|
#define SNS_DELCLR 0x00000100 /* Ring character interrupt */
|
|
/* Sense byte 3 Modem Control/Operation status */
|
|
#define SNS_RDY 0x80 /* device ready */
|
|
#define SNS_ONLN 0x40 /* device online */
|
|
//#define SNS_DSR 0x04 /* data set ready */
|
|
#define SNS_HALFD 0x00000080 /* Half-duplix operation set */
|
|
#define SNS_MRINGE 0x00000040 /* Modem ring enabled (1) */
|
|
#define SNS_ACEDEF 0x00000020 /* ACE parameters defined */
|
|
#define SNS_DIAGM 0x00000010 /* Diagnostic mode set */
|
|
#define SNS_AUXOL2 0x00000008 /* Auxiliary output level 2 */
|
|
#define SNS_AUXOL1 0x00000004 /* Auxiliary output level 1 */
|
|
#define SNS_RTS 0x00000002 /* RTS Request to send set */
|
|
#define SNS_DTR 0x00000001 /* DTR Data terminal ready set */
|
|
/* Sense byte 4 ACE Parameters status */
|
|
#define SNS_ACEDLE 0x80000000 /* Divisor latch enable 0=dis, 1=enb */
|
|
#define SNS_ACEBS 0x40000000 /* Break set 0=reset, 1=set */
|
|
#define SNS_ACEFP 0x20000000 /* Forced parity 0=odd, 1=even */
|
|
#define SNS_ACEP 0x10000000 /* Parity 0=odd, 1=even */
|
|
#define SNS_ACEPE 0x08000000 /* Parity enable 0=dis, 1=enb */
|
|
#define SNS_ACESTOP 0x04000000 /* Stop bit 0=1, 1=1.5 or 2 */
|
|
#define SNS_ACECLEN 0x02000000 /* Character length 00=5, 01=6, 11=7, 11=8 */
|
|
#define SNS_ACECL2 0x01000000 /* 2nd bit for above */
|
|
/* Sense byte 5 Baud rate */
|
|
#define SNS_NUB50 0x00800000 /* Zero N/U */
|
|
#define SNS_NUB51 0x00400000 /* Zero N/U */
|
|
#define SNS_RINGCR 0x00200000 /* Ring or wakeup character recognition 0=enb, 1=dis */
|
|
#define SNS_DIAGL 0x00100000 /* Set diagnostic loopback */
|
|
#define SNS_BAUD 0x000F0000 /* Baud rate bits 4-7 */
|
|
#define BAUD50 0x00000000 /* 50 baud */
|
|
#define BAUD75 0x00010000 /* 75 baud */
|
|
#define BAUD110 0x00020000 /* 110 baud */
|
|
#define BAUD114 0x00030000 /* 134 baud */
|
|
#define BAUD150 0x00040000 /* 150 baud */
|
|
#define BAUD300 0x00050000 /* 300 baud */
|
|
#define BAUD600 0x00060000 /* 600 baud */
|
|
#define BAUD1200 0x00070000 /* 1200 baud */
|
|
#define BAUD1800 0x00080000 /* 1800 baud */
|
|
#define BAUD2000 0x00090000 /* 2000 baud */
|
|
#define BAUD2400 0x000A0000 /* 2400 baud */
|
|
#define BAUD3600 0x000B0000 /* 3600 baud */
|
|
#define BAUD4800 0x000C0000 /* 4800 baud */
|
|
#define BAUD7200 0x000D0000 /* 7200 baud */
|
|
#define BAUD9600 0x000E0000 /* 9600 baud */
|
|
#define BAUD19200 0x000F0000 /* 19200 baud */
|
|
/* Sense byte 6 Firmware ID, Revision Level */
|
|
#define SNS_FID 0x00006200 /* ID part 1 */
|
|
/* Sense byte 7 Firmware ID, Revision Level */
|
|
#define SNS_REV 0x0000004f /* ID part 2 plus 4 bit rev # */
|
|
|
|
/* u6 */
|
|
|
|
/* forward definitions */
|
|
uint16 com_preio(UNIT *uptr, uint16 chan);
|
|
uint16 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd);
|
|
uint16 com_haltio(UNIT *uptr);
|
|
void com_ini(UNIT *, t_bool);
|
|
void coml_ini(UNIT *, t_bool);
|
|
uint16 coml_rschnlio(UNIT *uptr);
|
|
uint16 com_rschnlio(UNIT *uptr);
|
|
t_stat comc_srv(UNIT *uptr);
|
|
t_stat como_srv(UNIT *uptr);
|
|
t_stat comi_srv(UNIT *uptr);
|
|
t_stat com_reset(DEVICE *dptr);
|
|
t_stat com_attach(UNIT *uptr, CONST char *cptr);
|
|
t_stat com_detach(UNIT *uptr);
|
|
void com_reset_ln(int32 ln);
|
|
const char *com_description(DEVICE *dptr); /* device description */
|
|
|
|
/* COM data structures
|
|
com_chp COM channel program information
|
|
com_dev COM device descriptor
|
|
com_unit COM unit descriptor
|
|
com_reg COM register list
|
|
com_mod COM modifieers list
|
|
*/
|
|
|
|
//#define COM_UNITS 2
|
|
#define COM_UNITS 1
|
|
|
|
/* channel program information */
|
|
CHANP com_chp[COM_UNITS] = {0};
|
|
|
|
/* dummy mux for 16 lines */
|
|
MTAB com_mod[] = {
|
|
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL},
|
|
{MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &com_desc},
|
|
{UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tmxr_show_summ, (void *) &com_desc},
|
|
{MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat,(void *)&com_desc},
|
|
{MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, (void *)&com_desc},
|
|
// {MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", &io_set_dvc, &io_show_dvc, NULL},
|
|
// {MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", &io_set_dva, &io_show_dva, NULL},
|
|
// {MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", &com_vlines, &tmxr_show_lines, (void *)&com_desc},
|
|
// {MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, NULL, &io_show_cst, NULL},
|
|
// {MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "POLL", "POLL", &rtc_set_tps, &rtc_show_tps,(void *)&com_tps},
|
|
/// { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
|
|
/// { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
|
|
/// { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
|
|
/// { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
|
|
/// { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &com_desc },
|
|
/// { 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 }
|
|
};
|
|
|
|
UNIT com_unit[] = {
|
|
{UDATA(&comi_srv, UNIT_ATTABLE|UNIT_IDLE, 0), COM_WAIT, UNIT_ADDR(0x0000)}, /* 0 */
|
|
};
|
|
|
|
DIB com_dib = {
|
|
com_preio, /* uint16 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */
|
|
com_startcmd, /* uint16 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start command */
|
|
NULL, /* uint16 (*halt_io)(UNIT *uptr) */ /* Halt I/O */
|
|
NULL, /* uint16 (*stop_io)(UNIT *uptr) */ /* Stop I/O */
|
|
NULL, /* uint16 (*test_io)(UNIT *uptr) */ /* Test I/O */
|
|
NULL, /* uint16 (*rsctl_io)(UNIT *uptr) */ /* Reset Controller */
|
|
com_rschnlio, /* uint16 (*rschnl_io)(UNIT *uptr) */ /* Reset Channel */
|
|
NULL, /* uint16 (*iocl_io)(CHANP *chp, int32 tic_ok)) */ /* Process IOCL */
|
|
com_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
|
|
com_unit, /* UNIT* units */ /* Pointer to units structure */
|
|
com_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
|
|
NULL, /* IOCLQ *ioclq_ptr */ /* IOCL entries, 1 per UNIT */
|
|
COM_UNITS, /* uint8 numunits */ /* number of units defined */
|
|
0xFF, /* uint8 mask */ /* 16 devices - device mask */
|
|
0x7E00, /* uint16 chan_addr */ /* parent channel address */
|
|
0, /* uint32 chan_fifo_in */ /* fifo input index */
|
|
0, /* uint32 chan_fifo_out */ /* fifo output index */
|
|
{0} /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */
|
|
};
|
|
|
|
REG com_reg[] = {
|
|
{ BRDATAD (STA, com_sta, 16, 8, COM_LINES, "status buffers, lines 0 to 7") },
|
|
{ BRDATAD (RBUF, com_rbuf, 16, 8, COM_LINES, "input buffer, lines 0 to 7") },
|
|
{ BRDATAD (XBUF, com_xbuf, 16, 8, COM_LINES, "output buffer, lines 0 to 7") },
|
|
{ ORDATAD (SCAN, com_scan, 6, "scanner line number") },
|
|
{ FLDATAD (SLCK, com_slck, 0, "scanner lock") },
|
|
{ DRDATA (TPS, com_tps, 8), REG_HRO},
|
|
{ NULL }
|
|
};
|
|
|
|
/* devices for channel 0x7ecx */
|
|
DEVICE com_dev = {
|
|
"COMC", com_unit, com_reg, com_mod,
|
|
COM_UNITS, 8, 15, 1, 8, 8,
|
|
&tmxr_ex, &tmxr_dep, &com_reset, NULL, &com_attach, &com_detach,
|
|
/* ctxt is the DIB pointer */
|
|
&com_dib, DEV_NET|DEV_DISABLE|DEV_DEBUG, 0, dev_debug,
|
|
// &com_dib, DEV_NET|DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, dev_debug,
|
|
NULL, NULL, NULL, NULL, NULL, &com_description
|
|
};
|
|
|
|
/* COML data structures
|
|
coml_dev COM device descriptor
|
|
coml_unit COM unit descriptor
|
|
coml_reg COM register list
|
|
coml_mod COM modifieers list
|
|
*/
|
|
|
|
/*#define UNIT_COML UNIT_ATTABLE|UNIT_DISABLE|UNIT_IDLE */
|
|
#define UNIT_COML UNIT_IDLE|UNIT_DISABLE
|
|
|
|
/* channel program information */
|
|
CHANP coml_chp[COM_LINES*2] = {0};
|
|
|
|
UNIT coml_unit[] = {
|
|
/* 0-7 is input, 8-f is output */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC0)}, /* 0 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC1)}, /* 1 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC2)}, /* 2 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC3)}, /* 3 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC4)}, /* 4 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC5)}, /* 5 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC6)}, /* 6 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC7)}, /* 7 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC8)}, /* 8 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC9)}, /* 9 */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECA)}, /* A */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECB)}, /* B */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECC)}, /* C */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECD)}, /* D */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECE)}, /* E */
|
|
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECF)}, /* F */
|
|
};
|
|
|
|
DIB coml_dib = {
|
|
NULL, /* uint16 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */
|
|
com_startcmd, /* uint16 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start command */
|
|
NULL, /* uint16 (*halt_io)(UNIT *uptr) */ /* Halt I/O */
|
|
NULL, /* uint16 (*stop_io)(UNIT *uptr) */ /* Stop I/O */
|
|
NULL, /* uint16 (*test_io)(UNIT *uptr) */ /* Test I/O */
|
|
NULL, /* uint16 (*rsctl_io)(UNIT *uptr) */ /* Reset Controller */
|
|
coml_rschnlio, /* uint16 (*rschnl_io)(UNIT *uptr) */ /* Reset Channel */
|
|
NULL, /* uint16 (*iocl_io)(CHANP *chp, int32 tic_ok)) */ /* Process IOCL */
|
|
coml_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
|
|
coml_unit, /* UNIT* units */ /* Pointer to units structure */
|
|
coml_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
|
|
NULL, /* IOCLQ *ioclq_ptr */ /* IOCL entries, 1 per UNIT */
|
|
COM_LINES*2, /* uint8 numunits */ /* number of units defined */
|
|
0xff, /* uint8 mask */ /* 16 devices - device mask */
|
|
0x7E00, /* uint16 chan_addr */ /* parent channel address */
|
|
};
|
|
|
|
REG coml_reg[] = {
|
|
{ URDATA (TIME, coml_unit[0].wait, 10, 24, 0, COM_LINES, REG_NZ + PV_LEFT) },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB coml_mod[] = {
|
|
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL},
|
|
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
|
|
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
|
|
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
|
|
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
|
|
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
|
|
&tmxr_dscln, NULL, &com_desc },
|
|
{ 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 }
|
|
};
|
|
|
|
DEVICE coml_dev = {
|
|
"COML", coml_unit, coml_reg, coml_mod,
|
|
COM_LINES*2, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &com_reset,
|
|
NULL, NULL, NULL,
|
|
/* ctxt is the DIB pointer */
|
|
&coml_dib, DEV_DISABLE|DEV_DEBUG, 0, dev_debug,
|
|
// &coml_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, dev_debug,
|
|
NULL, NULL, NULL, NULL, NULL, &com_description
|
|
};
|
|
|
|
/* 8-line serial routines */
|
|
void coml_ini(UNIT *uptr, t_bool f)
|
|
{
|
|
/* maybe do someting here on master channel init */
|
|
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
sim_cancel(uptr); /* stop any timer */
|
|
}
|
|
|
|
/* handle rschnlio cmds for coml */
|
|
uint16 coml_rschnlio(UNIT *uptr) {
|
|
DEVICE *dptr = get_dev(uptr);
|
|
uint16 chsa = GET_UADDR(uptr->u3);
|
|
int cmd = uptr->u3 & COM_MSK;
|
|
|
|
sim_debug(DEBUG_EXP, dptr,
|
|
"coml_rschnl chsa %04x cmd = %02x\n", chsa, cmd);
|
|
coml_ini(uptr, 0); /* reset the unit */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* 8-line serial routines */
|
|
void com_ini(UNIT *uptr, t_bool f)
|
|
{
|
|
DEVICE *dptr = get_dev(uptr);
|
|
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"COM init device %s controller 0x7e00\n", dptr->name);
|
|
sim_cancel(uptr); /* stop input poll */
|
|
sim_activate(uptr, 1000); /* start input poll */
|
|
}
|
|
|
|
/* handle rschnlio cmds for com */
|
|
uint16 com_rschnlio(UNIT *uptr) {
|
|
DEVICE *dptr = get_dev(uptr);
|
|
uint16 chsa = GET_UADDR(uptr->u3);
|
|
int cmd = uptr->u3 & COM_MSK;
|
|
|
|
sim_debug(DEBUG_EXP, dptr,
|
|
"com_rschnl chsa %04x cmd = %02x\n", chsa, cmd);
|
|
com_ini(uptr, 0); /* reset the unit */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* start a com operation */
|
|
uint16 com_preio(UNIT *uptr, uint16 chan) {
|
|
DEVICE *dptr = get_dev(uptr);
|
|
int unit = (uptr - dptr->units);
|
|
uint16 chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */
|
|
// int cmd = uptr->u3 & 0xff;
|
|
|
|
#ifndef WAIT_FOR_TESTING
|
|
sim_debug(DEBUG_CMD, dptr, "com_preio CMD %08x unit %02x chsa %04x\n",
|
|
uptr->u3, unit, chsa);
|
|
if ((uptr->u3 & COM_MSK) != 0) { /* just return if busy */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_preio unit %02x chsa %04x BUSY\n", unit, chsa);
|
|
return SNS_BSY;
|
|
}
|
|
#endif
|
|
|
|
sim_debug(DEBUG_CMD, dptr, "t_preio unit %02x chsa %04xOK\n", unit, chsa);
|
|
return SCPE_OK; /* good to go */
|
|
}
|
|
|
|
/* called from sel32_chan to start an I/O operation */
|
|
uint16 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
|
|
{
|
|
DEVICE *dptr = get_dev(uptr);
|
|
int unit = (uptr - dptr->units);
|
|
uint16 chsa = (((uptr->u3 & LMASK) >> 16) | (chan << 8));
|
|
uint8 ch;
|
|
|
|
if ((uptr->u3 & COM_MSK) != 0) { /* is unit busy */
|
|
return SNS_BSY; /* yes, return busy */
|
|
}
|
|
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"CMD unit %04x chan %04x cmd %02x\n", unit, chan, cmd);
|
|
|
|
/* process the commands */
|
|
switch (cmd & 0xFF) {
|
|
case COM_INCH: /* 00 */ /* INCH command */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: CMD INCH\n", chan);
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
uptr->u3 |= (0x7f & COM_MSK); /* save 0x7f as INCH cmd command */
|
|
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
|
|
sim_activate(uptr, 20); /* start us up */
|
|
break;
|
|
|
|
/* write commands must use address 8-f */
|
|
case COM_WR: /* 0x01 */ /* Write command */
|
|
case COM_WRSCM: /* 0x05 */ /* Write w/sub channel monitor */
|
|
case COM_WRHFC: /* 0x0D */ /* Write w/hardware flow control */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd WRITE %02x\n", chan, cmd);
|
|
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
uptr->u3 |= (cmd & COM_MSK); /* save command */
|
|
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
|
|
sim_activate(uptr, 150); /* TRY 08-13-18 */
|
|
return 0; /* no status change */
|
|
break;
|
|
|
|
/* read commands must use address 0-7 */
|
|
/* DSR must be set when a read command is issued, else it is unit check */
|
|
/* bit 1-3 (ASP) of command has more definition */
|
|
/* bit 1 A=1 ASCII control character detect (7-char mode only) */
|
|
/* bit 2 S=1 Special character detect (7-char mode only) */
|
|
/* bit 3 P=1 Purge input buffer */
|
|
case COM_RD: /* 0x02 */ /* Read command */
|
|
case COM_RDECHO: /* 0x06 */ /* Read command w/ECHO */
|
|
case 0x32: /* 0x32 */ /* Read command ASCII & Purge input */
|
|
case 0x46: /* 0x46 */ /* Read command w/ECHO & ASCII */
|
|
case 0x56: /* 0x56 */ /* Read command w/ECHO & ASCII & Purge input */
|
|
/* if bit 0 set for COM_RDFC, use DTR for flow, else use RTS for flow control */
|
|
case COM_RDFC: /* 0x0A */ /* Read command w/flow control */
|
|
case COM_RDHFC: /* 0x8E */ /* Read command w/hardware flow control only */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: Cmd read\n", chan);
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
uptr->u3 |= (cmd & COM_MSK); /* save command */
|
|
if ((cmd & 0x06) == COM_RDECHO) /* echo command? */
|
|
uptr->u3 |= COM_EKO; /* save echo status */
|
|
uptr->u3 |= COM_READ; /* show read mode */
|
|
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: input cnt = %04x\n",
|
|
chan, coml_chp[unit].ccw_count);
|
|
return 0;
|
|
break;
|
|
|
|
case COM_NOP: /* 0x03 */ /* NOP has do nothing */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x NOP\n", chan, cmd);
|
|
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
uptr->u3 |= (cmd & COM_MSK); /* save command */
|
|
sim_activate(uptr, 20); /* start us up */
|
|
break;
|
|
|
|
case COM_SNS: /* 0x04 */ /* Sense (8 bytes) */
|
|
com_lstat[unit][0] = 0; /* Clear status wd 0 */
|
|
com_lstat[unit][1] = 0; /* Clear status wd 1 */
|
|
/* value 4 is Data Set Ready */
|
|
/* value 5 is Data carrier detected n/u */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: unit %04x Cmd Sense %02x\n",
|
|
chan, unit, uptr->u5);
|
|
|
|
ch = (com_lstat[unit][0] >> 24) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
com_lstat[unit][0] |= (SNS_RING); /* set char detect status */
|
|
com_lstat[unit][0] |= (SNS_ASCIICD); /* set char detect status */
|
|
ch = (com_lstat[unit][0] >> 16) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
com_lstat[unit][0] |= (SNS_CTSS|SNS_DSRS); /* set CTS & DSR status */
|
|
com_lstat[unit][0] |= (SNS_MRING); /* set char detect status */
|
|
ch = (com_lstat[unit][0] >> 8) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
com_lstat[unit][0] |= (SNS_DTR); /* set DTR status */
|
|
ch = (com_lstat[unit][0] >> 0) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
ch = (com_lstat[unit][1] >> 24) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
ch = (com_lstat[unit][1] >> 16) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
ch = (com_lstat[unit][1] >> 8) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
ch = (com_lstat[unit][1] >> 0) & 0xff;
|
|
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
|
|
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd Cmd SENSE return chan %04x u5-status %04x ls0 %08x ls1 %08x\n",
|
|
chan, uptr->u5, com_lstat[unit][0], com_lstat[unit][1]);
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
case COM_DEFSC: /* 0x0B */ /* Define special char */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x DEFSC\n", chsa, cmd);
|
|
if (chan_read_byte(GET_UADDR(uptr->u3), &ch)) { /* read char from memory */
|
|
/* nothing to read, error */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* good return */
|
|
}
|
|
uptr->u4 &= ~ACE_WAKE; /* clear out old wake char */
|
|
uptr->u4 |= ((uint32)ch << 8); /* insert special char */
|
|
uptr->u5 = ~SNS_RTS; /* Request to send not ready */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x DEFSC char %02x ACE %08x\n",
|
|
chsa, cmd, ch, uptr->u4);
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
case COM_RRTS: /* 0x1B */ /* Reset RTS */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: Cmd %02x RRTS\n", chan, cmd);
|
|
uptr->u5 &= ~SNS_RTS; /* Request to send not ready */
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
case COM_SRTS: /* 0x1F */ /* Set RTS */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: Cmd %02x SRTS\n", chan, cmd);
|
|
uptr->u5 |= SNS_RTS; /* Requestd to send ready */
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
case COM_RBRK: /* 0x33 */ /* Reset BREAK */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: Cmd %02x RBRK\n", chan, cmd);
|
|
uptr->u5 &= ~SNS_BREAK; /* Request to send not ready */
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
case COM_SBRK: /* 0x37 */ /* Set BREAK */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: Cmd %02x SBRK\n", chan, cmd);
|
|
uptr->u5 |= SNS_BREAK; /* Requestd to send ready */
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
case COM_RDTR: /* 0x13 */ /* Reset DTR (ADVR) */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: Cmd %02x RDTR\n", chan, cmd);
|
|
uptr->u5 &= ~SNS_DTR; /* Data terminal not ready */
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
case COM_SDTR: /* 0x17 */ /* Set DTR (ADVF) */
|
|
sim_debug(DEBUG_CMD, dptr, "com_startcmd %04x: Cmd %02x SDTR\n", chan, cmd);
|
|
uptr->u5 |= SNS_DTR; /* Data terminal ready */
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
#if 0
|
|
/* ACE byte 0 Modem Control/Operation status */
|
|
/* stored in u4 bytes 0-3 */
|
|
#define SNS_HALFD 0x80000000 /* Half-duplix operation set */
|
|
#define SNS_MRINGE 0x40000000 /* Modem ring enabled */
|
|
#define SNS_ACEFP 0x20000000 /* Forced parity 0=odd, 1=even */
|
|
#define SNS_ACEP 0x10000000 /* Parity 0=odd, 1=even */
|
|
#define SNS_ACEPE 0x08000000 /* Parity enable 0=dis, 1=enb */
|
|
#define SNS_ACESTOP 0x04000000 /* Stop bit 0=1, 1=1.5 or 2 */
|
|
#define SNS_ACECLEN 0x02000000 /* Character length 00=5, 01=6, 10=7, 11=8 */
|
|
#define SNS_ACECL2 0x01000000 /* 2nd bit for above */
|
|
|
|
/* ACE byte 1 Baud rate */
|
|
#define SNS_NUB50 0x00800000 /* Zero N/U */
|
|
#define SNS_NUB51 0x00400000 /* Zero N/U */
|
|
#define SNS_RINGCR 0x00200000 /* Ring or wakeup character recognition 0=enb, 1=dis */
|
|
#define SNS_DIAGL 0x00100000 /* Set diagnostic loopback */
|
|
#define SNS_BAUD 0x000F0000 /* Baud rate bits 4-7 */
|
|
#define BAUD50 0x00000000 /* 50 baud */
|
|
#define BAUD75 0x00010000 /* 75 baud */
|
|
#define BAUD110 0x00020000 /* 110 baud */
|
|
#define BAUD114 0x00030000 /* 134 baud */
|
|
#define BAUD150 0x00040000 /* 150 baud */
|
|
#define BAUD300 0x00050000 /* 300 baud */
|
|
#define BAUD600 0x00060000 /* 600 baud */
|
|
#define BAUD1200 0x00070000 /* 1200 baud */
|
|
#define BAUD1800 0x00080000 /* 1800 baud */
|
|
#define BAUD2000 0x00090000 /* 2000 baud */
|
|
#define BAUD2400 0x000A0000 /* 2400 baud */
|
|
#define BAUD3600 0x000B0000 /* 3600 baud */
|
|
#define BAUD4800 0x000C0000 /* 4800 baud */
|
|
#define BAUD7200 0x000D0000 /* 7200 baud */
|
|
#define BAUD9600 0x000E0000 /* 9600 baud */
|
|
#define BAUD19200 0x000F0000 /* 19200 baud */
|
|
|
|
/* ACE byte 2 Wake-up character */
|
|
#define ACE_WAKE 0x0000FF00 /* 8 bit wake-up character */
|
|
#endif
|
|
|
|
case COM_SACE: /* 0xff */ /* Set ACE parameters (3 chars) */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x SACE\n", chsa, cmd);
|
|
|
|
if (chan_read_byte(GET_UADDR(uptr->u3), &ch)) { /* read char 0 */
|
|
/* nothing to read, error */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* good return */
|
|
}
|
|
uptr->u4 = ((uint32)ch)<<24; /* byte 0 of ACE data */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x ACE byte 0 %02x\n",
|
|
chsa, cmd, ch);
|
|
|
|
if (chan_read_byte(GET_UADDR(uptr->u3), &ch)) { /* read char 1 */
|
|
/* nothing to read, error */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* good return */
|
|
}
|
|
uptr->u4 |= ((uint32)ch)<<16; /* byte 1 of ACE data */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x ACE byte 1 %02x\n",
|
|
chsa, cmd, ch);
|
|
|
|
if (chan_read_byte(GET_UADDR(uptr->u3), &ch)) { /* read char 2 */
|
|
/* nothing to read, error */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* good return */
|
|
}
|
|
uptr->u4 |= ((uint32)ch)<<8; /* byte 2 of ACE data */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x ACE byte 2 %02x\n",
|
|
chsa, cmd, ch);
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd %02x ACE bytes %08x\n",
|
|
chan, cmd, uptr->u4);
|
|
|
|
return SNS_CHNEND|SNS_DEVEND; /* good return */
|
|
break;
|
|
|
|
|
|
default: /* invalid command */
|
|
uptr->u5 |= SNS_CMDREJ; /* command rejected */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_startcmd %04x: Cmd Invald %02x status %02x\n",
|
|
chan, cmd, uptr->u5);
|
|
return SNS_CHNEND|STATUS_PCHK; /* program check */
|
|
break;
|
|
}
|
|
|
|
if (uptr->u5 & 0xff)
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
|
return SNS_CHNEND|SNS_DEVEND;
|
|
}
|
|
|
|
/* Unit service - polled input
|
|
Poll for new connections
|
|
Poll all connected lines for input
|
|
*/
|
|
t_stat comi_srv(UNIT *uptr)
|
|
{
|
|
uint8 ch;
|
|
DEVICE *dptr = get_dev(uptr);
|
|
int32 newln, ln, c;
|
|
uint16 chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */
|
|
int cmd = uptr->u3 & 0xff;
|
|
|
|
ln = uptr - com_unit; /* line # */
|
|
/* handle NOP and INCH cmds */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"comi_srv entry chsa %04x line %02x cmd %02x\n", chsa, ln, cmd);
|
|
if (cmd == COM_NOP || cmd == 0x7f) { /* check for NOP or INCH */
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"comi_srv NOP or INCH done chsa %04x line %02x cmd %02x\n",
|
|
chsa, ln, cmd);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
|
|
return SCPE_OK; /* return */
|
|
}
|
|
|
|
/* handle SACE, 3 char already read, so we are done */
|
|
if (cmd == COM_SACE) { /* check for SACE 0xff */
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
sim_debug(DEBUG_CMD, &com_dev,
|
|
"comi_srv SACE done chsa %04x line %02x cmd %02x ACE %08x\n",
|
|
chsa, ln, cmd, uptr->u4);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
|
|
return SCPE_OK; /* return */
|
|
}
|
|
|
|
ln = uptr - com_unit; /* line # */
|
|
if ((com_unit[COMC].flags & UNIT_ATT) == 0){ /* attached? */
|
|
return SCPE_OK;
|
|
}
|
|
newln = tmxr_poll_conn(&com_desc); /* look for connect */
|
|
if (newln >= 0) { /* rcv enb pending? */
|
|
uint16 chsa = GET_UADDR(coml_unit[newln].u3); /* get channel/sub-addr */
|
|
com_ldsc[newln].rcve = 1; /* enable rcv */
|
|
com_ldsc[newln].xmte = 1; /* enable xmt for output line */
|
|
com_sta[newln] &= ~COML_REP; /* clr pending */
|
|
/* send attention to OS here for this channel */
|
|
/* need to get chsa here for the channel */
|
|
sim_debug(DEBUG_CMD, &com_dev,
|
|
"comi_srv wakeup on chsa %04x line %02x cmd %02x ACE %08x\n",
|
|
chsa, ln, cmd, uptr->u4);
|
|
set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND); /* tell user */
|
|
}
|
|
/* poll all devices for input */
|
|
tmxr_poll_rx(&com_desc); /* poll for input */
|
|
for (ln = 0; ln < COM_NUMLIN; ln++) { /* loop thru lines */
|
|
UNIT *comlp = coml_unit+ln; /* get uptr for coml line */
|
|
int cmd = comlp->u3 & 0xff; /* get the active cmd */
|
|
uint16 chsa = GET_UADDR(comlp->u3); /* get channel/sub-addr */
|
|
if (com_ldsc[ln].conn) { /* connected? */
|
|
if ((c = tmxr_getc_ln(&com_ldsc[ln]))) { /* get char */
|
|
ch = c; /* just the char */
|
|
/* echo the char out */
|
|
tmxr_putc_ln(&com_ldsc[ln], ch); /* output char */
|
|
tmxr_poll_tx(&com_desc); /* poll xmt */
|
|
if (c & SCPE_BREAK) /* break? */
|
|
com_sta[ln] |= COML_RBP; /* set rcv brk */
|
|
else { /* normal char */
|
|
com_sta[ln] &= ~COML_RBP; /* clr rcv brk */
|
|
c = sim_tt_inpcvt(c, TT_GET_MODE(coml_unit[ln].flags));
|
|
com_rbuf[ln] = c; /* save char */
|
|
if ((cmd & COM_RD) == COM_RD) { /* read active? */
|
|
ch = c; /* clean the char */
|
|
if (ch == '\n') /* convert newline */
|
|
ch = '\r'; /* to C/R */
|
|
/* write byte to memory */
|
|
if (chan_write_byte(chsa, &ch)) {
|
|
/* done, reading chars */
|
|
comlp->u3 &= LMASK; /* nothing left, clear cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
|
|
} else {
|
|
/* more to go, continue */
|
|
if (ch == '\r') { /* see if done */
|
|
comlp->u3 &= LMASK; /* nothing left, clear cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* see if user hit the wakeup key */
|
|
if (((comlp->u4 & ACE_WAKE) >> 8) == ch) {
|
|
/* send attention to OS here for this channel */
|
|
/* need to get chsa here for the channel */
|
|
/* tell user */
|
|
sim_debug(DEBUG_CMD, &com_dev,
|
|
"comi_srv user wakeup on chsa %04x line %02x cmd %02x ACE %08x\n",
|
|
chsa, ln, cmd, uptr->u4);
|
|
set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND);
|
|
}
|
|
}
|
|
} /* end else char */
|
|
} /* end if char */
|
|
} /* end if conn */
|
|
else {
|
|
com_sta[ln] &= ~COML_RBP; /* disconnected */
|
|
com_sta[ln] |= COML_REP; /* set pending */
|
|
}
|
|
} /* end for */
|
|
return sim_clock_coschedule(uptr, 200); /* continue poll */
|
|
}
|
|
|
|
/* Unit service - output transfers */
|
|
t_stat como_srv(UNIT *uptr)
|
|
{
|
|
DEVICE *dptr = get_dev(uptr);
|
|
uint16 chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */
|
|
uint32 ln = (uptr - coml_unit) & 0x7; /* use line # 0-7 for 8-15 */
|
|
uint32 done;
|
|
int cmd = uptr->u3 & 0xff; /* get active cmd */
|
|
uint8 ch;
|
|
|
|
/* handle NOP and INCH cmds */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"como_srv entry chsa %04x line %04x cmd %02x\n", chsa, ln, cmd);
|
|
if (cmd == COM_NOP || cmd == 0x7f) { /* check for NOP or INCH */
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
sim_debug(DEBUG_CMD, &com_dev,
|
|
"como_srv NOP or INCH done chsa %04x line %04x cmd %02x\n",
|
|
chsa, ln, cmd);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
|
|
return SCPE_OK; /* return */
|
|
}
|
|
|
|
/* handle SACE, 3 char already read, so we are done */
|
|
if (cmd == COM_SACE) { /* check for SACE 0xff */
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
sim_debug(DEBUG_CMD, &com_dev,
|
|
"como_srv SACE done chsa %04x line %02x cmd %02x ACE %08x\n",
|
|
chsa, ln, cmd, uptr->u4);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
|
|
return SCPE_OK; /* return */
|
|
}
|
|
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"como_srv entry 1 chsa %04x line %04x cmd %02x\n", chsa, ln, cmd);
|
|
if (cmd) {
|
|
/* get a user byte from memory */
|
|
done = chan_read_byte(chsa, &ch); /* get byte from memory */
|
|
if (done)
|
|
uptr->u3 &= LMASK; /* leave only chsa */
|
|
} else
|
|
return SCPE_OK;
|
|
|
|
if (com_dev.flags & DEV_DIS) { /* disabled */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"como_srv chsa %04x line %04x DEV_DIS set\n", chsa, ln);
|
|
if (done) {
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"como_srv Write DONE %04x status %04x\n",
|
|
ln, SNS_CHNEND|SNS_DEVEND);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
|
|
}
|
|
return SCPE_OK; /* return */
|
|
}
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"como_srv poll chsa %04x line %04x DEV_DIS set\n", chsa, ln);
|
|
|
|
if (com_ldsc[ln].conn) { /* connected? */
|
|
if (com_ldsc[ln].xmte) { /* xmt enabled? */
|
|
if (done) { /* are we done writing */
|
|
endit:
|
|
uptr->u3 &= LMASK; /* nothing left, command complete */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_srvo write %04x: chnend|devend\n", ln);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
|
|
return SCPE_OK;
|
|
}
|
|
/* send the next char out */
|
|
tmxr_putc_ln(&com_ldsc[ln], ch); /* output char */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_srvo writing char 0x%02x to ln %04x\n", ch, ln);
|
|
tmxr_poll_tx(&com_desc); /* poll xmt */
|
|
sim_activate(uptr, uptr->wait); /* wait */
|
|
return SCPE_OK;
|
|
} else { /* buf full */
|
|
if (done) /* are we done writing */
|
|
goto endit; /* done */
|
|
/* just dump the char */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_srvo write dumping char 0x%02x on line %04x\n", ch, ln);
|
|
tmxr_poll_tx(&com_desc); /* poll xmt */
|
|
sim_activate(uptr, uptr->wait); /* wait */
|
|
return SCPE_OK;
|
|
}
|
|
} else {
|
|
/* not connected, so dump char on ground */
|
|
if (done) {
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"com_srvo write dump DONE line %04x status %04x\n",
|
|
ln, SNS_CHNEND|SNS_DEVEND);
|
|
uptr->u3 &= LMASK; /* nothing left, command complete */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
|
|
}
|
|
sim_activate(uptr, uptr->wait); /* wait */
|
|
return SCPE_OK;
|
|
}
|
|
}
|
|
|
|
/* Reset routine */
|
|
t_stat com_reset (DEVICE *dptr)
|
|
{
|
|
int32 i;
|
|
|
|
if (com_dev.flags & DEV_DIS) /* master disabled? */
|
|
com_dev.flags |= DEV_DIS; /* disable lines */
|
|
else
|
|
com_dev.flags &= ~DEV_DIS;
|
|
if (com_unit[COMC].flags & UNIT_ATT) /* master att? */
|
|
sim_clock_coschedule(&com_unit[0], 200); /* activate */
|
|
for (i = 0; i < COM_LINES; i++) /* reset lines */
|
|
com_reset_ln(i);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* attach master unit */
|
|
t_stat com_attach(UNIT *uptr, CONST char *cptr)
|
|
{
|
|
DEVICE *dptr = get_dev(uptr);
|
|
t_stat r;
|
|
|
|
r = tmxr_attach(&com_desc, uptr, cptr); /* attach */
|
|
if (r != SCPE_OK) /* error? */
|
|
return r; /* return error */
|
|
sim_debug(DEBUG_CMD, dptr, "com_srv comc is now attached\n");
|
|
sim_activate(uptr, 0); /* start poll at once */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* detach master unit */
|
|
t_stat com_detach(UNIT *uptr)
|
|
{
|
|
int32 i;
|
|
t_stat r;
|
|
|
|
r = tmxr_detach(&com_desc, uptr); /* detach */
|
|
for (i = 0; i < COM_LINES; i++) /* disable rcv */
|
|
com_reset_ln(i); /* reset the line */
|
|
sim_cancel(uptr); /* stop poll, cancel timer */
|
|
return r;
|
|
}
|
|
|
|
/* Reset an individual line */
|
|
void com_reset_ln (int32 ln)
|
|
{
|
|
sim_cancel(&coml_unit[ln]);
|
|
com_sta[ln] = 0;
|
|
com_sta[ln] |= COML_REP; /* set pending */
|
|
com_rbuf[ln] = 0; /* clear read buffer */
|
|
com_xbuf[ln] = 0; /* clear write buffer */
|
|
com_ldsc[ln].rcve = 0;
|
|
return;
|
|
}
|
|
|
|
t_stat com_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
|
{
|
|
fprintf (st, "SEL32 8512 8-Line Async Controller Terminal Interfaces\n\n");
|
|
fprintf (st, "Terminals perform input and output through Telnet sessions connected to a \n");
|
|
fprintf (st, "user-specified port.\n\n");
|
|
fprintf (st, "The ATTACH command specifies the port to be used:\n\n");
|
|
tmxr_attach_help (st, dptr, uptr, flag, cptr);
|
|
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");
|
|
fprintf (st, " sim> SET COMLn DATASET simulate attachment to a dataset (modem)\n");
|
|
fprintf (st, " sim> SET COMLn NODATASET simulate direct attachment to a terminal\n\n");
|
|
fprintf (st, "Finally, each line supports output logging. The SET COMLn LOG command enables\n");
|
|
fprintf (st, "logging on a line:\n\n");
|
|
fprintf (st, " sim> SET COMLn LOG=filename log output of line n to filename\n\n");
|
|
fprintf (st, "The SET COMLn NOLOG command disables logging and closes the open log file,\n");
|
|
fprintf (st, "if any.\n\n");
|
|
fprintf (st, "Once DCI is attached and the simulator is running, the terminals listen for\n");
|
|
fprintf (st, "connections on the specified port. They assume that the incoming connections\n");
|
|
fprintf (st, "are Telnet connections. The connections remain open until disconnected either\n");
|
|
fprintf (st, "by the Telnet client, a SET DCI DISCONNECT command, or a DETACH DCI command.\n\n");
|
|
fprintf (st, "Other special commands:\n\n");
|
|
fprintf (st, " sim> SHOW COMC CONNECTIONS show current connections\n");
|
|
fprintf (st, " sim> SHOW COMC STATISTICS show statistics for active connections\n");
|
|
fprintf (st, " sim> SET COMLn DISCONNECT disconnects the specified line.\n");
|
|
fprintf (st, "\nThe additional terminals do not support save and restore. All open connections\n");
|
|
fprintf (st, "are lost when the simulator shuts down or DCI is detached.\n");
|
|
fprint_set_help (st, dptr);
|
|
fprint_show_help (st, dptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* description of controller */
|
|
const char *com_description (DEVICE *dptr)
|
|
{
|
|
return "SEL-32 8512 8-Line async communications controller";
|
|
}
|
|
|
|
#endif
|