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.
1188 lines
39 KiB
C
1188 lines
39 KiB
C
/* kl10_dn.c: KL-10 DN network interface.
|
|
|
|
Copyright (c) 2019-2021, Richard Cornwell
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Richard Cornwell shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Richard Cornwell
|
|
|
|
*/
|
|
|
|
#include "kx10_defs.h"
|
|
#include "sim_sock.h"
|
|
#include "sim_tmxr.h"
|
|
#include <ctype.h>
|
|
|
|
#ifndef NUM_DEVS_DN
|
|
#define NUM_DEVS_DN 0
|
|
#endif
|
|
|
|
#if KL
|
|
#if (NUM_DEVS_DN > 0)
|
|
#define UNIT_DUMMY (1 << UNIT_V_UF)
|
|
|
|
#define DTE_DEVNUM 0204
|
|
#define DEV_V_OS (DEV_V_UF + 1) /* Type RSX10/RSX20 */
|
|
#define DEV_M_OS (1 << DEV_V_OS)
|
|
#define TYPE_RSX10 (0 << DEV_V_OS)
|
|
#define TYPE_RSX20 (1 << DEV_V_OS)
|
|
|
|
|
|
/* DTE10 CONI bits */
|
|
|
|
#define DTE_RM 00100000 /* Restricted mode */
|
|
#define DTE_D11 00040000 /* Dead-11 */
|
|
#define DTE_11DB 00020000 /* TO11 Door bell request */
|
|
#define DTE_10DB 00001000 /* TO10 Door bell request */
|
|
#define DTE_11ER 00000400 /* Error during TO11 transfer */
|
|
#define DTE_11DN 00000100 /* TO 11 transfer done */
|
|
#define DTE_10DN 00000040 /* TO 10 transfer done */
|
|
#define DTE_10ER 00000020 /* Error during TO10 transfer */
|
|
#define DTE_PIE 00000010 /* PIO enabled */
|
|
#define DTE_PIA 00000007 /* PI channel assigment */
|
|
|
|
/* internal flags */
|
|
#define DTE_11RELD 01000000 /* Reload 11. */
|
|
#define DTE_TO11 02000000 /* Transfer to 11 */
|
|
#define DTE_SEC 04000000 /* In secondary protocol */
|
|
#define DTE_IND 010000000 /* Next transfer will be indirect */
|
|
#define DTE_SIND 020000000 /* Send indirect data next */
|
|
#define DTE_INIT 040000000 /* Recieved an INIT signal last time */
|
|
|
|
/* DTE CONO bits */
|
|
#define DTE_CO11DB 0020000 /* Set TO11 Door bell */
|
|
#define DTE_CO11CR 0010000 /* Clear reload 11 button */
|
|
#define DTE_CO11SR 0004000 /* Set reload 11 button */
|
|
#define DTE_CO10DB 0001000 /* Clear TO10 Door bell */
|
|
#define DTE_CO11CL 0000100 /* Clear TO11 done and error */
|
|
#define DTE_CO10CL 0000040 /* Clear TO10 done and error */
|
|
#define DTE_PIENB 0000020 /* Load PI and enable bit */
|
|
|
|
/* DTE DATAO */
|
|
#define DTE_TO10IB 010000 /* Interrupt after transfer */
|
|
#define DTE_TO10BC 007777 /* Byte count for transfer */
|
|
|
|
/* Secondary protocol addresses */
|
|
#define SEC_DTFLG 0444 /* Operation complete flag */
|
|
#define SEC_DTCLK 0445 /* Clock interrupt flag */
|
|
#define SEC_DTCI 0446 /* Clock interrupt instruction */
|
|
#define SEC_DTT11 0447 /* 10 to 11 argument */
|
|
#define SEC_DTF11 0450 /* 10 from 11 argument */
|
|
#define SEC_DTCMD 0451 /* To 11 command word */
|
|
#define SEC_DTSEQ 0452 /* Operation sequence number */
|
|
#define SEC_DTOPR 0453 /* Operational DTE # */
|
|
#define SEC_DTCHR 0454 /* Last typed character */
|
|
#define SEC_DTMTD 0455 /* Monitor tty output complete flag */
|
|
#define SEC_DTMTI 0456 /* Monitor tty input flag */
|
|
#define SEC_DTSWR 0457 /* 10 switch register */
|
|
|
|
#define SEC_PGMCTL 00400
|
|
#define SEC_ENDPASS 00404
|
|
#define SEC_LOOKUP 00406
|
|
#define SEC_RDWRD 00407
|
|
#define SEC_RDBYT 00414
|
|
#define SEC_ESEC 00440
|
|
#define SEC_EPRI 00500
|
|
#define SEC_ERTM 00540
|
|
#define SEC_CLKCTL 01000
|
|
#define SEC_CLKOFF 01000
|
|
#define SEC_CLKON 01001
|
|
#define SEC_CLKWT 01002
|
|
#define SEC_CLKRD 01003
|
|
#define SEC_RDSW 01400
|
|
#define SEC_CLRDDT 03000
|
|
#define SEC_SETDDT 03400
|
|
#define SEC_MONO 04000
|
|
#define SEC_MONON 04400
|
|
#define SEC_SETPRI 05000
|
|
#define SEC_RTM 05400
|
|
#define SEC_CMDMSK 07400
|
|
#define DTE_MON 00000001 /* Save in unit1 STATUS */
|
|
#define SEC_CLK 00000002 /* Clock enabled */
|
|
|
|
/* Primary or Queued protocol addresses */
|
|
#define PRI_CMTW_0 0
|
|
#define PRI_CMTW_PPT 1 /* Pointer to com region */
|
|
#define PRI_CMTW_STS 2 /* Status word */
|
|
#define PRI_CMT_PWF SMASK /* Power failure */
|
|
#define PRI_CMT_L11 BIT1 /* Load 11 */
|
|
#define PRI_CMT_INI BIT2 /* Init */
|
|
#define PRI_CMT_TST BIT3 /* Valid examine bit */
|
|
#define PRI_CMT_QP 020000000LL /* Do Queued protocol */
|
|
#define PRI_CMT_FWD 001000000LL /* Do full word transfers */
|
|
#define PRI_CMT_IP RSIGN /* Indirect transfer */
|
|
#define PRI_CMT_TOT 0200000LL /* TOIT bit */
|
|
#define PRI_CMT_10IC 0177400LL /* TO10 IC for queued transfers */
|
|
#define PRI_CMT_11IC 0000377LL /* TO11 IC for queued transfers */
|
|
#define PRI_CMTW_CNT 3 /* Queue Count */
|
|
#define PRI_CMTW_KAC 5 /* Keep alive count */
|
|
#define PRI_IND_FLG 0100000 /* Flag function as indirect */
|
|
|
|
#define PRI_EM2EI 001 /* Initial message to 11 */
|
|
#define PRI_EM2TI 002 /* Replay to initial message. */
|
|
#define PRI_EMSTR 003 /* String data */
|
|
#define PRI_EMLNC 004 /* Line-Char */
|
|
#define PRI_EMRDS 005 /* Request device status */
|
|
#define PRI_EMOPS 006
|
|
#define PRI_EMHDS 007 /* Here is device status */
|
|
#define PRI_EMRDT 011 /* Request Date/Time */
|
|
#define PRI_EMHDR 012 /* Here is date and time */
|
|
#define PRI_EMFLO 013 /* Flush output */
|
|
#define PRI_EMSNA 014 /* Send all (ttys) */
|
|
#define PRI_EMDSC 015 /* Dataset connect */
|
|
#define PRI_EMHUD 016 /* Hang up dataset */
|
|
#define PRI_EMLBE 017 /* Acknowledge line */
|
|
#define PRI_EMXOF 020 /* XOFF line */
|
|
#define PRI_EMXON 021 /* XON line */
|
|
#define PRI_EMHLS 022 /* Here is line speeds */
|
|
#define PRI_EMHLA 023 /* Here is line allocation */
|
|
#define PRI_EMRBI 024 /* Reboot information */
|
|
#define PRI_EMAKA 025 /* Ack ALL */
|
|
#define PRI_EMTDO 026 /* Turn device On/Off */
|
|
#define PRI_EMEDR 027 /* Enable/Disable line */
|
|
#define PRI_EMLDR 030 /* Load LP RAM */
|
|
#define PRI_EMLDV 031 /* Load LP VFU */
|
|
|
|
#define PRI_EMCTY 001 /* Device code for CTY */
|
|
#define PRI_EMDL1 002 /* DL11 */
|
|
#define PRI_EMDH1 003 /* DH11 #1 */
|
|
#define PRI_EMDLS 004 /* DLS (all ttys combined) */
|
|
#define PRI_EMLPT 005 /* Front end LPT */
|
|
#define PRI_EMCDR 006 /* CDR */
|
|
#define PRI_EMCLK 007 /* Clock */
|
|
#define PRI_EMFED 010 /* Front end device */
|
|
#define PRI_NCL 011 /* NCL device */
|
|
#define PRI_DN60 012 /* DN60 */
|
|
#define PRI_CTYDV 000 /* Line number for CTY */
|
|
#define NUM_DLS 5 /* Number of first DH Line */
|
|
|
|
|
|
extern int32 tmxr_poll;
|
|
t_stat dn_devio(uint32 dev, uint64 *data);
|
|
t_addr dn_devirq(uint32 dev, t_addr addr);
|
|
void dn_second(UNIT *uptr);
|
|
void dn_primary(UNIT *uptr);
|
|
void dn_transfer(UNIT *uptr);
|
|
void dn_function(UNIT *uptr);
|
|
void dn_input();
|
|
int dn_start(UNIT *uptr);
|
|
int dn_queue(int func, int dev, int dcnt, uint16 *data);
|
|
t_stat dni_svc (UNIT *uptr);
|
|
t_stat dn_svc (UNIT *uptr);
|
|
t_stat dno_svc (UNIT *uptr);
|
|
t_stat dnrtc_srv(UNIT * uptr);
|
|
t_stat dn_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat dn_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
t_stat dn_reset (DEVICE *dptr);
|
|
t_stat dn_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
|
const char *dn_description (DEVICE *dptr);
|
|
extern uint64 SW; /* Switch register */
|
|
|
|
extern CONST char *pri_name[];
|
|
|
|
#define STATUS u3
|
|
#define CNT u4
|
|
|
|
extern uint32 eb_ptr;
|
|
|
|
struct _dn_queue {
|
|
int dptr; /* Pointer to working item */
|
|
uint16 cnt; /* Number of bytes in packet */
|
|
uint16 func; /* Function code */
|
|
uint16 dev; /* Dev code */
|
|
uint16 spare; /* Dev code */
|
|
uint16 dcnt; /* Data count */
|
|
uint16 data[258]; /* Data packet */
|
|
uint16 sdev; /* Secondary device code */
|
|
uint16 sz; /* Byte size */
|
|
} dn_in[32], dn_out[32];
|
|
|
|
int32 dn_in_ptr;
|
|
int32 dn_in_cmd;
|
|
int32 dn_out_ptr;
|
|
int32 dn_out_res;
|
|
int32 dn_base; /* Base */
|
|
int32 dn_off; /* Our offset */
|
|
int32 dn_dt10_off; /* Offset to 10 deposit region */
|
|
int32 dn_et10_off; /* Offset to 10 examine region */
|
|
int32 dn_et11_off; /* Offset to 11 examine region */
|
|
int32 dn_proc_num; /* Our processor number */
|
|
|
|
struct _buffer {
|
|
int in_ptr; /* Insert pointer */
|
|
int out_ptr; /* Remove pointer */
|
|
char buff[256]; /* Buffer */
|
|
};
|
|
|
|
#define full(q) ((((q)->in_ptr + 1) & 0xff) == (q)->out_ptr)
|
|
#define empty(q) ((q)->in_ptr == (q)->out_ptr)
|
|
#define not_empty(q) ((q)->in_ptr != (q)->out_ptr)
|
|
#define inco(q) (q)->out_ptr = ((q)->out_ptr + 1) & 0xff
|
|
#define inci(q) (q)->in_ptr = ((q)->in_ptr + 1) & 0xff
|
|
|
|
DIB dn_dib[] = {
|
|
{ DTE_DEVNUM|000, 1, dn_devio, dn_devirq},
|
|
};
|
|
|
|
MTAB dn_mod[] = {
|
|
{MTAB_XTD|MTAB_VDV, TYPE_RSX10, NULL, "RSX10", &dn_set_type, NULL,
|
|
NULL, "Sets DTE to RSX10 mode"},
|
|
{MTAB_XTD|MTAB_VDV, TYPE_RSX20, "RSX20", "RSX20", &dn_set_type, &dn_show_type,
|
|
NULL, "Sets DTE to RSX20 mode"},
|
|
{ 0 }
|
|
};
|
|
|
|
UNIT dn_unit[] = {
|
|
{ UDATA (&dn_svc, TT_MODE_7B, 0), 100},
|
|
{ UDATA (&dno_svc, TT_MODE_7B, 0), 100},
|
|
{ UDATA (&dni_svc, TT_MODE_7B|UNIT_DIS, 0), 1000 },
|
|
};
|
|
|
|
REG dn_reg[] = {
|
|
{SAVEDATA(IN, dn_in) },
|
|
{SAVEDATA(OUT, dn_out) },
|
|
{HRDATA(IN_PTR, dn_in_ptr, 32), REG_HRO},
|
|
{HRDATA(IN_CMD, dn_in_cmd, 32), REG_HRO},
|
|
{HRDATA(OUT_PTR, dn_out_ptr, 32), REG_HRO},
|
|
{HRDATA(OUT_RES, dn_out_res, 32), REG_HRO},
|
|
{HRDATA(BASE, dn_base, 32), REG_HRO},
|
|
{HRDATA(OFF, dn_off, 32), REG_HRO},
|
|
{HRDATA(DTOFF, dn_dt10_off, 32), REG_HRO},
|
|
{HRDATA(ETOFF, dn_et10_off, 32), REG_HRO},
|
|
{HRDATA(E1OFF, dn_et11_off, 32), REG_HRO},
|
|
{HRDATA(PROC, dn_proc_num, 32), REG_HRO},
|
|
{HRDATAD(WRU, sim_int_char, 8, "interrupt character") },
|
|
{ 0 },
|
|
};
|
|
|
|
|
|
DEVICE dn_dev = {
|
|
"DN", dn_unit, dn_reg, dn_mod,
|
|
3, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &dn_reset,
|
|
NULL, NULL, NULL, &dn_dib, DEV_DIS | DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
|
NULL, NULL, &dn_help, NULL, NULL, &dn_description
|
|
};
|
|
|
|
|
|
t_stat dn_devio(uint32 dev, uint64 *data) {
|
|
uint32 res;
|
|
switch(dev & 3) {
|
|
case CONI:
|
|
*data = (uint64)(dn_unit[0].STATUS) & RMASK;
|
|
*data |= DTE_RM; /* Restricted mode */
|
|
sim_debug(DEBUG_CONI, &dn_dev, "DN %03o CONI %06o\n", dev, (uint32)*data);
|
|
break;
|
|
case CONO:
|
|
res = (uint32)(*data & RMASK);
|
|
clr_interrupt(dev);
|
|
if (res & DTE_PIENB) {
|
|
dn_unit[0].STATUS &= ~(DTE_PIA|DTE_PIE);
|
|
dn_unit[0].STATUS |= res & (DTE_PIA|DTE_PIE);
|
|
}
|
|
if (res & DTE_CO11CL)
|
|
dn_unit[0].STATUS &= ~(DTE_11DN|DTE_11ER);
|
|
if (res & DTE_CO10CL) {
|
|
dn_unit[0].STATUS &= ~(DTE_10DN|DTE_10ER);
|
|
dn_start(&dn_unit[0]);
|
|
}
|
|
if (res & DTE_CO10DB)
|
|
dn_unit[0].STATUS &= ~(DTE_10DB);
|
|
if (res & DTE_CO11CR)
|
|
dn_unit[0].STATUS &= ~(DTE_11RELD);
|
|
if (res & DTE_CO11SR)
|
|
dn_unit[0].STATUS |= (DTE_11RELD);
|
|
if (res & DTE_CO11DB) {
|
|
sim_debug(DEBUG_CONO, &dn_dev, "DN Ring 11 DB\n");
|
|
dn_unit[0].STATUS |= DTE_11DB;
|
|
dn_unit[0].STATUS &= ~(DTE_10DB);
|
|
sim_activate(&dn_unit[0], 200);
|
|
}
|
|
if (dn_unit[0].STATUS & (DTE_10DB|DTE_11DN|DTE_10DN|DTE_11ER|DTE_10ER))
|
|
set_interrupt(dev, dn_unit[0].STATUS);
|
|
sim_debug(DEBUG_CONO, &dn_dev, "DN %03o CONO %06o %06o\n", dev,
|
|
(uint32)*data, PC);
|
|
break;
|
|
case DATAI:
|
|
sim_debug(DEBUG_DATAIO, &dn_dev, "DN %03o DATAI %06o\n", dev,
|
|
(uint32)*data);
|
|
break;
|
|
case DATAO:
|
|
sim_debug(DEBUG_DATAIO, &dn_dev, "DN %03o DATAO %06o\n", dev,
|
|
(uint32)*data);
|
|
if (*data == 01365) {
|
|
dn_unit[0].STATUS |= DTE_10ER;
|
|
dn_unit[0].STATUS &= ~(DTE_10DB|DTE_IND|DTE_11DB);
|
|
break;
|
|
}
|
|
dn_unit[0].CNT = (*data & (DTE_TO10IB|DTE_TO10BC));
|
|
dn_unit[0].STATUS |= DTE_TO11;
|
|
sim_activate(&dn_unit[0], 10);
|
|
break;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Handle KL style interrupt vectors */
|
|
t_addr
|
|
dn_devirq(uint32 dev, t_addr addr) {
|
|
return 0152;
|
|
}
|
|
|
|
/* Handle TO11 interrupts */
|
|
t_stat dn_svc (UNIT *uptr)
|
|
{
|
|
/* Did the 10 knock? */
|
|
if (uptr->STATUS & DTE_11DB) {
|
|
/* If in secondary mode, do that protocol */
|
|
if (uptr->STATUS & DTE_SEC)
|
|
dn_second(uptr);
|
|
dn_primary(uptr); /* Retrieve data */
|
|
} else if (uptr->STATUS & DTE_TO11) {
|
|
/* Does 10 want us to send it what we have? */
|
|
dn_transfer(uptr);
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Handle secondary protocol */
|
|
void dn_second(UNIT *uptr) {
|
|
uint64 word;
|
|
int32 ch;
|
|
uint32 base = 0;
|
|
int i;
|
|
|
|
#if KI_22BIT
|
|
base = eb_ptr;
|
|
#endif
|
|
/* read command */
|
|
word = M[SEC_DTCMD + base];
|
|
/* Do it */
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN secondary %012llo\n", word);
|
|
for (i = 0; i < 8; i++)
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "EB word %o %012llo\n", i, M[eb_ptr + 0150+i]);
|
|
for (i = 0; i <100; i++) {
|
|
if (Mem_examine_word(1, i, &word))
|
|
break;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 word %3o %012llo\n", i, word);
|
|
}
|
|
switch(word & SEC_CMDMSK) {
|
|
default:
|
|
#if 0
|
|
case SEC_MONO: /* Ouput character in monitor mode */
|
|
ch = (int32)(word & 0177);
|
|
if (full(&cty_out)) {
|
|
sim_activate(uptr, 200);
|
|
return;
|
|
}
|
|
if (ch != 0) {
|
|
cty_out.buff[cty_out.in_ptr] = ch & 0x7f;
|
|
inci(&cty_out);
|
|
sim_activate(&dn_unit[1], 200);
|
|
}
|
|
M[SEC_DTCHR + base] = ch;
|
|
M[SEC_DTMTD + base] = FMASK;
|
|
break;
|
|
#endif
|
|
|
|
case SEC_SETPRI:
|
|
enter_pri:
|
|
if (Mem_examine_word(1, 0, &word))
|
|
return;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN word 0 %012llo\n", word);
|
|
dn_proc_num = (word >> 24) & 037;
|
|
dn_base = dn_proc_num + 1;
|
|
dn_off = dn_base + (word & 0177777);
|
|
dn_dt10_off = 16;
|
|
dn_et10_off = dn_dt10_off + 16;
|
|
dn_et11_off = dn_base + 16;
|
|
uptr->STATUS &= ~DTE_SEC;
|
|
dn_in_ptr = dn_out_ptr = 0;
|
|
dn_in_cmd = dn_out_res = 0;
|
|
|
|
/* Start input process */
|
|
M[SEC_DTCMD + base] = 0;
|
|
M[SEC_DTFLG + base] = FMASK;
|
|
uptr->STATUS &= ~DTE_11DB;
|
|
return;
|
|
#if 0
|
|
case SEC_SETDDT: /* Read character from console */
|
|
if (empty(&cty_in)) {
|
|
M[SEC_DTF11 + base] = 0;
|
|
M[SEC_DTMTI + base] = FMASK;
|
|
break;
|
|
}
|
|
ch = cty_in.buff[cty_in.out_ptr];
|
|
inco(&cty_in);
|
|
M[SEC_DTF11 + base] = 0177 & ch;
|
|
M[SEC_DTMTI + base] = FMASK;
|
|
break;
|
|
|
|
case SEC_CLRDDT: /* Clear DDT input mode */
|
|
uptr->STATUS &= ~DTE_MON;
|
|
break;
|
|
|
|
case SEC_MONON:
|
|
uptr->STATUS |= DTE_MON;
|
|
break;
|
|
|
|
case SEC_RDSW: /* Read switch register */
|
|
M[SEC_DTSWR + base] = SW;
|
|
M[SEC_DTF11 + base] = SW;
|
|
break;
|
|
|
|
case SEC_PGMCTL: /* Program control: Used by KLDCP */
|
|
switch(word) {
|
|
case SEC_ENDPASS:
|
|
case SEC_LOOKUP:
|
|
case SEC_RDWRD:
|
|
case SEC_RDBYT:
|
|
break;
|
|
case SEC_ESEC:
|
|
goto enter_pri;
|
|
case SEC_EPRI:
|
|
case SEC_ERTM:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SEC_CLKCTL: /* Clock control: Used by KLDCP */
|
|
break;
|
|
#endif
|
|
}
|
|
/* Acknowledge command */
|
|
M[SEC_DTCMD + base] = 0;
|
|
M[SEC_DTFLG + base] = FMASK;
|
|
uptr->STATUS &= ~DTE_11DB;
|
|
if (dn_dev.flags & TYPE_RSX20) {
|
|
uptr->STATUS |= DTE_10DB;
|
|
set_interrupt(DTE_DEVNUM, dn_unit[0].STATUS);
|
|
}
|
|
}
|
|
|
|
|
|
/* Handle primary protocol */
|
|
void dn_primary(UNIT *uptr) {
|
|
uint64 word, iword;
|
|
int s;
|
|
int cnt;
|
|
struct _dn_queue *in;
|
|
uint16 data1, *dp;
|
|
int i;
|
|
|
|
if ((uptr->STATUS & DTE_11DB) == 0)
|
|
return;
|
|
|
|
/* Check if there is room for another packet */
|
|
if (((dn_in_ptr + 1) & 0x1f) == dn_in_cmd) {
|
|
/* If not reschedule ourselves */
|
|
sim_activate(uptr, 100);
|
|
return;
|
|
}
|
|
uptr->STATUS &= ~(DTE_11DB);
|
|
clr_interrupt(DTE_DEVNUM);
|
|
Mem_examine_word(1, 0, &word);
|
|
dn_proc_num = (word >> 24) & 037;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 procnum %0o\n", dn_proc_num);
|
|
dn_base = dn_proc_num + 1;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 base %0o\n", dn_base);
|
|
dn_off = dn_base + (word & 0177777);
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 dn_off %0o\n", dn_off);
|
|
dn_dt10_off = 020;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 dn_dt_off %0o\n", dn_dt10_off);
|
|
dn_et10_off = dn_dt10_off + 16;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 dn_et_off %0o\n", dn_et10_off);
|
|
dn_et11_off = dn_base + (8 * dn_base);
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 dn_et11_off %0o\n", dn_et11_off);
|
|
|
|
for (i = 0; i < 8; i++)
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "EB word %o %012llo\n", i, M[eb_ptr + 0150+i]);
|
|
for (i = 0; i <200; i++) {
|
|
if (Mem_examine_word(1, i, &word))
|
|
break;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 word %3o %012llo\n", i, word);
|
|
}
|
|
/* Check status word to see if valid */
|
|
if (Mem_examine_word(1, dn_et11_off + PRI_CMTW_STS, &word)) {
|
|
uint32 base;
|
|
error:
|
|
base = 0;
|
|
#if KI_22BIT
|
|
base = eb_ptr;
|
|
#endif
|
|
/* If we can't read it, go back to secondary */
|
|
M[SEC_DTFLG + base] = FMASK;
|
|
// uptr->STATUS |= DTE_SEC;
|
|
uptr->STATUS &= ~DTE_11DB;
|
|
if (dn_dev.flags & TYPE_RSX20) {
|
|
uptr->STATUS |= DTE_10DB;
|
|
set_interrupt(DTE_DEVNUM, dn_unit[0].STATUS);
|
|
}
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DTE: error %012llo\n", word);
|
|
return;
|
|
}
|
|
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DTE: status %06llo %012llo\n", dn_et11_off + PRI_CMTW_STS + M[0155 + eb_ptr], word);
|
|
if ((word & PRI_CMT_INI) != 0) {
|
|
word &= ~PRI_CMT_TOT;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DTE: istatus %06llo %012llo\n", dn_dt10_off + PRI_CMTW_STS + M[0157 + eb_ptr], word);
|
|
if (Mem_deposit_word(1, dn_dt10_off + PRI_CMTW_STS, &word))
|
|
goto error;
|
|
uptr->STATUS |= DTE_11DN|DTE_10DB|DTE_INIT;
|
|
set_interrupt(DTE_DEVNUM, uptr->STATUS);
|
|
return;
|
|
}
|
|
if ((uptr->STATUS & DTE_INIT) != 0) {
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DTE: dstatus %06llo %012llo\n", dn_dt10_off + PRI_CMTW_STS + M[0157 + eb_ptr], word);
|
|
if (Mem_deposit_word(1, dn_dt10_off + PRI_CMTW_STS, &word))
|
|
goto error;
|
|
uptr->STATUS |= DTE_11DN|DTE_10DB;
|
|
uptr->STATUS &= ~DTE_INIT;
|
|
set_interrupt(DTE_DEVNUM, uptr->STATUS);
|
|
return;
|
|
}
|
|
// if ((word & PRI_CMT_QP) == 0) {
|
|
// goto error;
|
|
// }
|
|
|
|
in = &dn_in[dn_in_ptr];
|
|
/* Check if indirect */
|
|
if ((word & PRI_CMT_IP) != 0) {
|
|
/* Transfer from 10 */
|
|
if ((uptr->STATUS & DTE_IND) == 0) {
|
|
fprintf(stderr, "DTE out of sync\r\n");
|
|
return;
|
|
}
|
|
/* Get size of transfer */
|
|
if (Mem_examine_word(1, dn_et11_off + PRI_CMTW_CNT, &iword))
|
|
goto error;
|
|
sim_debug(DEBUG_EXP, &dn_dev, "DTE: count: %012llo\n", iword);
|
|
in->dcnt = (uint16)(iword & 0177777);
|
|
/* Read in data */
|
|
dp = &in->data[0];
|
|
for (cnt = in->dcnt; cnt > 0; cnt --) {
|
|
/* Read in data */
|
|
s = Mem_read_byte(1, dp, 0);
|
|
if (s == 0)
|
|
goto error;
|
|
in->sz = s;
|
|
sim_debug(DEBUG_DATA, &dn_dev,
|
|
"DTE: Read Idata: %06o %03o %03o %06o cnt=%o\n",
|
|
*dp, *dp >> 8, *dp & 0377,
|
|
((*dp & 0377) << 8) | ((*dp >> 8) & 0377), cnt);
|
|
dp++;
|
|
if (s <= 8)
|
|
cnt--;
|
|
}
|
|
uptr->STATUS &= ~DTE_IND;
|
|
dn_in_ptr = (dn_in_ptr + 1) & 0x1f;
|
|
} else {
|
|
/* Transfer from 10 */
|
|
in->dptr = 0;
|
|
in->dcnt = 0;
|
|
/* Read in count */
|
|
if (!Mem_read_byte(1, &data1, 0))
|
|
goto error;
|
|
in->cnt = data1;
|
|
cnt = in->cnt-2;
|
|
if (!Mem_read_byte(1, &data1, 0))
|
|
goto error;
|
|
in->func = data1;
|
|
cnt -= 2;
|
|
if (!Mem_read_byte(1, &data1, 0))
|
|
goto error;
|
|
in->dev = data1;
|
|
cnt -= 2;
|
|
if (!Mem_read_byte(1, &data1, 0))
|
|
goto error;
|
|
in->spare = data1;
|
|
cnt -= 2;
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: Read CMD: %o c=%o f=%o %s s=%o d=%o\n",
|
|
dn_in_ptr, in->cnt, in->func,
|
|
((in->func & 0377) > PRI_EMLDV)?"***":
|
|
pri_name[in->func & 0377], in->spare, in->dev);
|
|
dp = &in->data[0];
|
|
for (; cnt > 0; cnt -=2) {
|
|
/* Read in data */
|
|
if (!Mem_read_byte(1, dp, 0))
|
|
goto error;
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: Read data: %06o %03o %03o\n",
|
|
*dp, *dp >> 8, *dp & 0377);
|
|
dp++;
|
|
in->dcnt += 2;
|
|
}
|
|
if (in->func & PRI_IND_FLG) {
|
|
uptr->STATUS |= DTE_IND;
|
|
in->dcnt = in->data[0];
|
|
in->sdev = (in->dcnt >> 8) & 0377;
|
|
in->dcnt &= 0377;
|
|
word |= PRI_CMT_TOT;
|
|
if (Mem_deposit_word(1, dn_dt10_off + PRI_CMTW_STS, &word))
|
|
goto error;
|
|
} else {
|
|
dn_in_ptr = (dn_in_ptr + 1) & 0x1f;
|
|
}
|
|
}
|
|
word &= ~PRI_CMT_TOT;
|
|
if (Mem_deposit_word(1, dn_dt10_off + PRI_CMTW_STS, &word))
|
|
goto error;
|
|
uptr->STATUS |= DTE_11DN;
|
|
set_interrupt(DTE_DEVNUM, uptr->STATUS);
|
|
dn_function(uptr);
|
|
}
|
|
|
|
/* Process primary protocol packets */
|
|
void
|
|
dn_function(UNIT *uptr)
|
|
{
|
|
uint16 data1[32];
|
|
int32 ch;
|
|
struct _dn_queue *cmd;
|
|
int func;
|
|
int dev;
|
|
|
|
/* Check if queue is empty */
|
|
while (dn_in_cmd != dn_in_ptr) {
|
|
if (((dn_out_res + 1) & 0x1f) == dn_out_ptr) {
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: func out full %d %d\n",
|
|
dn_out_res, dn_out_ptr);
|
|
return;
|
|
}
|
|
cmd = &dn_in[dn_in_cmd];
|
|
dev = cmd->dev & 0377;
|
|
func = cmd->func & 0377;
|
|
sim_debug(DEBUG_DATA, &dn_dev,
|
|
"DTE: func %o %02o %s dev %o cnt %d dcnt %d\n",
|
|
dn_in_cmd, func, (func > PRI_EMLDV) ? "***" : pri_name[func],
|
|
cmd->dev, cmd->dcnt, cmd->dptr );
|
|
switch (func) {
|
|
case PRI_EM2EI: /* Initial message to 11 */
|
|
break;
|
|
|
|
case PRI_EM2TI: /* Replay to initial message. */
|
|
data1[0] = (6 << 8) | 5;
|
|
data1[1] = (0 << 8) | 0xc0;
|
|
data1[2] = (1 << 8) | 0;
|
|
if (dn_queue(01, PRI_DN60, 3, data1) == 0)
|
|
return;
|
|
break;
|
|
case PRI_EMLBE: /* Acknowledge line */
|
|
/* Should never get these */
|
|
break;
|
|
|
|
case PRI_EMHDR: /* Here is date and time */
|
|
/* Ignore this function */
|
|
break;
|
|
|
|
case PRI_EMRDT: /* Request Date/Time */
|
|
{
|
|
time_t t = sim_get_time(NULL);
|
|
struct tm *tm = localtime(&t);
|
|
int yr = tm->tm_year + 1900;
|
|
int tim = (((tm->tm_hour * 60) + tm->tm_min) * 60) +
|
|
tm->tm_sec;
|
|
data1[0] = 0177777;
|
|
data1[1] = ((yr & 0377) << 8) | ((yr >> 8) & 0377);
|
|
data1[2] = (tm->tm_mon) + ((tm->tm_mday - 1) << 8);
|
|
data1[3] = (((tm->tm_wday + 6) % 7)) +
|
|
(tm->tm_isdst ? 0200 << 8 : 0);
|
|
tim >>= 1;
|
|
data1[4] = ((tim & 0377) << 8) | ((tim >> 8) & 0377);
|
|
if (dn_queue(PRI_EMHDR | PRI_IND_FLG, PRI_EMCLK, 6, data1) == 0)
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case PRI_EMSTR: /* String data */
|
|
|
|
|
|
/* Handle terminal data */
|
|
if (dev == PRI_EMDLS) {
|
|
int ln = cmd->sdev;
|
|
struct _buffer *otty;
|
|
if (ln == PRI_CTYDV)
|
|
goto cty;
|
|
break;
|
|
}
|
|
|
|
if (dev == PRI_EMCTY) {
|
|
cty:
|
|
#if 0
|
|
sim_activate(&dn_unit[1], 100);
|
|
data1[0] = 0;
|
|
if (cmd->sz > 8)
|
|
cmd->dcnt += cmd->dcnt;
|
|
while (cmd->dptr < cmd->dcnt) {
|
|
ch = (int32)(cmd->data[cmd->dptr >> 1]);
|
|
if ((cmd->dptr & 1) == 0)
|
|
ch >>= 8;
|
|
ch &= 0177;
|
|
if (ch != 0) {
|
|
ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags));
|
|
if (full(&cty_out))
|
|
return;
|
|
cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff);
|
|
inci(&cty_out);
|
|
sim_debug(DEBUG_DATA, &dn_dev,"DN queue %o\n",ch);
|
|
}
|
|
cmd->dptr++;
|
|
}
|
|
#endif
|
|
if (cmd->dptr != cmd->dcnt)
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case PRI_EMSNA: /* Send all (ttys) */
|
|
break;
|
|
|
|
case PRI_EMLNC: /* Line-Char */
|
|
break;
|
|
|
|
case PRI_EMOPS:
|
|
break;
|
|
|
|
case PRI_EMRDS: /* Request device status */
|
|
break;
|
|
|
|
case PRI_EMHDS: /* Here is device status */
|
|
break;
|
|
case PRI_EMLDV: /* Load LP VFU */
|
|
break;
|
|
|
|
case PRI_EMLDR: /* Load LP RAM */
|
|
break;
|
|
|
|
|
|
case PRI_EMFLO: /* Flush output */
|
|
break;
|
|
|
|
case PRI_EMDSC: /* Dataset connect */
|
|
break;
|
|
|
|
case PRI_EMHUD: /* Hang up dataset */
|
|
|
|
case PRI_EMXOF: /* XOFF line */
|
|
break;
|
|
|
|
case PRI_EMXON: /* XON line */
|
|
break;
|
|
|
|
case PRI_EMHLS: /* Here is line speeds */
|
|
break;
|
|
|
|
case PRI_EMHLA: /* Here is line allocation */
|
|
case PRI_EMRBI: /* Reboot information */
|
|
case PRI_EMAKA: /* Ack ALL */
|
|
case PRI_EMTDO: /* Turn device On/Off */
|
|
break;
|
|
|
|
case PRI_EMEDR: /* Enable/Disable line */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/* Mark command as finished */
|
|
cmd->cnt = 0;
|
|
dn_in_cmd = (dn_in_cmd + 1) & 0x1F;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle primary protocol,
|
|
* Send to 10 when requested.
|
|
*/
|
|
void dn_transfer(UNIT *uptr) {
|
|
uint16 cnt;
|
|
uint16 scnt;
|
|
struct _dn_queue *out;
|
|
uint16 *dp;
|
|
int i;
|
|
|
|
|
|
/* Check if Queue empty */
|
|
if (dn_out_res == dn_out_ptr)
|
|
return;
|
|
|
|
out = &dn_out[dn_out_ptr];
|
|
uptr->STATUS &= ~DTE_TO11;
|
|
clr_interrupt(DTE_DEVNUM);
|
|
for (i = 0; i < 8; i++)
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "EB Sword %o %012llo\n", i, M[eb_ptr + 0150+i]);
|
|
for (i = 0; i <200; i++) {
|
|
uint64 word;
|
|
if (Mem_examine_word(1, i, &word))
|
|
break;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 Sword %3o %012llo\n", i, word);
|
|
}
|
|
|
|
/* Compute how much 10 wants us to send */
|
|
scnt = ((uptr->CNT ^ DTE_TO10BC) + 1) & DTE_TO10BC;
|
|
/* Check if indirect */
|
|
if ((uptr->STATUS & DTE_SIND) != 0) {
|
|
/* Transfer indirect */
|
|
cnt = out->dcnt;
|
|
dp = &out->data[0];
|
|
if (cnt > scnt) /* Only send as much as we are allowed */
|
|
cnt = scnt;
|
|
for (; cnt > 0; cnt -= 2) {
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: Send Idata: %06o %03o %03o\n",
|
|
*dp, *dp >> 8, *dp & 0377);
|
|
if (Mem_write_byte(1, dp) == 0)
|
|
goto error;
|
|
dp++;
|
|
}
|
|
uptr->STATUS &= ~DTE_SIND;
|
|
} else {
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: %d %d send CMD: [%o] %o %o %o\n",
|
|
dn_out_ptr, dn_out_res, scnt, out->cnt, out->func, out->dev);
|
|
/* Get size of packet */
|
|
cnt = out->cnt;
|
|
if ((out->func & PRI_IND_FLG) == 0)
|
|
cnt += out->dcnt;
|
|
/* If it will not fit, request indirect */
|
|
if (cnt > scnt) { /* If not enough space request indirect */
|
|
out->func |= PRI_IND_FLG;
|
|
cnt = scnt;
|
|
}
|
|
/* Write out header */
|
|
if (!Mem_write_byte(1, &cnt))
|
|
goto error;
|
|
if (!Mem_write_byte(1, &out->func))
|
|
goto error;
|
|
cnt -= 2;
|
|
if (!Mem_write_byte(1, &out->dev))
|
|
goto error;
|
|
cnt -= 2;
|
|
if (!Mem_write_byte(1, &out->spare))
|
|
goto error;
|
|
cnt -= 2;
|
|
if (out->func & PRI_IND_FLG) {
|
|
uint16 dwrd = out->dcnt;
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: Indirect %o %o\n", cnt,
|
|
out->dcnt);
|
|
dwrd |= (out->sdev << 8);
|
|
if (!Mem_write_byte(1, &dwrd))
|
|
goto error;
|
|
uptr->STATUS |= DTE_SIND;
|
|
goto done;
|
|
}
|
|
cnt -= 2;
|
|
dp = &out->data[0];
|
|
for (; cnt > 0; cnt -= 2) {
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: Send data: %06o %03o %03o\n",
|
|
*dp, *dp >> 8, *dp & 0377);
|
|
if (!Mem_write_byte(1, dp))
|
|
goto error;
|
|
dp++;
|
|
}
|
|
}
|
|
out->cnt = 0;
|
|
dn_out_ptr = (dn_out_ptr + 1) & 0x1f;
|
|
done:
|
|
uptr->STATUS |= DTE_10DN;
|
|
set_interrupt(DTE_DEVNUM, uptr->STATUS);
|
|
error:
|
|
return;
|
|
}
|
|
|
|
/* Process input from CTY and TTY's to 10. */
|
|
void
|
|
dn_input()
|
|
{
|
|
uint16 data1;
|
|
uint16 dataq[32];
|
|
int n;
|
|
int ln;
|
|
int save_ptr;
|
|
char ch;
|
|
UNIT *uptr = &dn_unit[0];
|
|
|
|
#if 0
|
|
if ((uptr->STATUS & DTE_SEC) == 0) {
|
|
/* Check if CTY done with input */
|
|
if (cty_done) {
|
|
data1 = PRI_CTYDV;
|
|
if (dn_queue(PRI_EMLBE, PRI_EMDLS, 1, &data1) == 0)
|
|
return;
|
|
cty_done--;
|
|
}
|
|
/* Grab a chunck of input from CTY if any */
|
|
n = 0;
|
|
save_ptr = cty_in.out_ptr;
|
|
while (not_empty(&cty_in) && n < 32) {
|
|
ch = cty_in.buff[cty_in.out_ptr];
|
|
inco(&cty_in);
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN recieve %02x\n", ch);
|
|
dataq[n++] = (PRI_CTYDV << 8) | ch;
|
|
}
|
|
if (n > 0 && dn_queue(PRI_EMLNC, PRI_EMDLS, n, dataq) == 0) {
|
|
/* Restore the input pointer */
|
|
cty_in.out_ptr = save_ptr;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Queue up a packet to send to 10.
|
|
*/
|
|
int
|
|
dn_queue(int func, int dev, int dcnt, uint16 *data)
|
|
{
|
|
uint16 *dp;
|
|
struct _dn_queue *out;
|
|
|
|
/* Check if room in queue for this packet. */
|
|
if (((dn_out_res + 1) & 0x1f) == dn_out_ptr) {
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: %d %d out full\n", dn_out_res, dn_out_ptr);
|
|
return 0;
|
|
}
|
|
out = &dn_out[dn_out_res];
|
|
out->cnt = 10;
|
|
out->func = func;
|
|
out->dev = dev;
|
|
out->dcnt = (dcnt-1)*2;
|
|
out->spare = 0;
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: %d %d queue resp: %o (%o) f=%o %s d=%o\n",
|
|
dn_out_ptr, dn_out_res, out->cnt, out->dcnt, out->func,
|
|
(out->func > PRI_EMLDV)? "***":pri_name[out->func], out->dev);
|
|
for (dp = &out->data[0]; dcnt > 0; dcnt--) {
|
|
*dp++ = *data++;
|
|
}
|
|
/* Advance pointer to next function */
|
|
dn_out_res = (dn_out_res + 1) & 0x1f;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* If anything in queue, start a transfer, if one is not already
|
|
* pending.
|
|
*/
|
|
int
|
|
dn_start(UNIT *uptr)
|
|
{
|
|
uint64 word;
|
|
int dcnt;
|
|
int i;
|
|
|
|
/* Check if queue empty */
|
|
if (dn_out_ptr == dn_out_res)
|
|
return 1;
|
|
|
|
/* If there is interrupt pending, just return */
|
|
if ((uptr->STATUS & (DTE_IND|DTE_10DB|DTE_11DB)) != 0)
|
|
return 1;
|
|
if (Mem_examine_word(1, dn_et11_off + PRI_CMTW_STS, &word)) {
|
|
error:
|
|
/* If we can't read it, go back to secondary */
|
|
uptr->STATUS |= DTE_SEC|DTE_10ER;
|
|
set_interrupt(DTE_DEVNUM, uptr->STATUS);
|
|
return 0;
|
|
}
|
|
/* Bump count of messages sent */
|
|
word = (word & ~(PRI_CMT_10IC|PRI_CMT_IP)) | ((word + 0400) & PRI_CMT_10IC);
|
|
word &= ~PRI_CMT_FWD;
|
|
if ((uptr->STATUS & DTE_SIND) != 0)
|
|
word |= PRI_CMT_IP;
|
|
if (Mem_deposit_word(1, dn_dt10_off + PRI_CMTW_STS, &word))
|
|
goto error;
|
|
dcnt = dn_out[dn_out_ptr].cnt;
|
|
if ((dn_out[dn_out_ptr].func & PRI_IND_FLG) == 0)
|
|
dcnt += dn_out[dn_out_ptr].dcnt;
|
|
/* Tell 10 something is ready */
|
|
if ((uptr->STATUS & DTE_SIND) != 0) {
|
|
dcnt = dn_out[dn_out_ptr].dcnt;
|
|
}
|
|
sim_debug(DEBUG_DATA, &dn_dev, "DTE: start: %012llo %o\n", word, dcnt);
|
|
word = (uint64)dcnt;
|
|
word |= (word << 18);
|
|
if (Mem_deposit_word(1, dn_dt10_off + PRI_CMTW_CNT, &word))
|
|
goto error;
|
|
for (i = 0; i < 8; i++)
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "EB word %o %012llo\n", i, M[eb_ptr + 0150+i]);
|
|
for (i = 0; i <200; i++) {
|
|
if (Mem_examine_word(1, i, &word))
|
|
break;
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN1 word %3o %012llo\n", i, word);
|
|
}
|
|
uptr->STATUS |= DTE_10DB;
|
|
set_interrupt(DTE_DEVNUM, uptr->STATUS);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Check for input from CTY and put on queue. */
|
|
t_stat dni_svc (UNIT *uptr)
|
|
{
|
|
int32 ch;
|
|
uint32 base = 0;
|
|
UNIT *optr = &dn_unit[0];
|
|
|
|
#if KI_22BIT
|
|
base = eb_ptr;
|
|
#endif
|
|
sim_clock_coschedule (uptr, tmxr_poll);
|
|
dn_input();
|
|
if ((optr->STATUS & (DTE_SEC)) == 0) {
|
|
dn_function(uptr); /* Process queue */
|
|
dn_start(optr);
|
|
}
|
|
|
|
|
|
#if 0
|
|
/* If we have room see if any new lines */
|
|
while (!full(&cty_in)) {
|
|
ch = sim_poll_kbd ();
|
|
if (ch & SCPE_KFLAG) {
|
|
ch = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (uptr->flags));
|
|
cty_in.buff[cty_in.in_ptr] =ch & 0377;
|
|
inci(&cty_in);
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "CTY char %o '%c'\n", ch,
|
|
((ch > 040 && ch < 0177)? ch: '.'));
|
|
} else
|
|
break;
|
|
}
|
|
|
|
/* If Monitor input, place in buffer */
|
|
if ((optr->STATUS & (DTE_SEC|DTE_MON)) == (DTE_SEC|DTE_MON) &&
|
|
not_empty(&cty_in) && M[SEC_DTMTI + base] == 0) {
|
|
ch = cty_in.buff[cty_in.out_ptr];
|
|
inco(&cty_in);
|
|
M[SEC_DTF11 + base] = ch;
|
|
M[SEC_DTMTI + base] = FMASK;
|
|
if (dn_dev.flags & TYPE_RSX20) {
|
|
uptr->STATUS |= DTE_10DB;
|
|
set_interrupt(DTE_DEVNUM, dn_unit[0].STATUS);
|
|
}
|
|
}
|
|
#endif
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Handle output of characters to CTY. Started whenever there is output pending */
|
|
t_stat dno_svc (UNIT *uptr)
|
|
{
|
|
#if 0
|
|
/* Flush out any pending CTY output */
|
|
while(not_empty(&cty_out)) {
|
|
char ch = cty_out.buff[cty_out.out_ptr];
|
|
if (ch != 0) {
|
|
if (sim_putchar_s(ch) != SCPE_OK) {
|
|
sim_activate(uptr, 1000);
|
|
return SCPE_OK;;
|
|
}
|
|
}
|
|
inco(&cty_out);
|
|
sim_debug(DEBUG_DETAIL, &dn_dev, "DN outch %o '%c'\n", ch,
|
|
((ch > 040 && ch < 0177)? ch: '.'));
|
|
}
|
|
cty_done++;
|
|
#endif
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* Handle FE timer interrupts. And keepalive counts */
|
|
t_stat
|
|
dnrtc_srv(UNIT * uptr)
|
|
{
|
|
UNIT *optr = &dn_unit[0];
|
|
|
|
sim_activate_after(uptr, 1000000/60);
|
|
|
|
/* Update out keep alive timer if in secondary protocol */
|
|
if ((optr->STATUS & DTE_SEC) == 0) {
|
|
int addr = 0154 + eb_ptr;
|
|
uint64 word;
|
|
|
|
(void)Mem_examine_word(1, dn_et11_off + PRI_CMTW_STS, &word);
|
|
addr = (M[addr+1] + dn_off + PRI_CMTW_KAC) & RMASK;
|
|
word = M[addr];
|
|
word = (word + 1) & FMASK;
|
|
M[addr] = word;
|
|
sim_debug(DEBUG_EXP, &dn_dev, "DN keepalive %06o %012llo %06o\n",
|
|
addr, word, optr->STATUS);
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
t_stat dn_reset (DEVICE *dptr)
|
|
{
|
|
dn_unit[0].STATUS = 0; //DTE_SEC;
|
|
dn_unit[1].STATUS = 0;
|
|
dn_unit[2].STATUS = 0;
|
|
dn_proc_num = 0;
|
|
dn_base = dn_proc_num + 1;
|
|
dn_off = 0;
|
|
dn_dt10_off = 16;
|
|
dn_et10_off = 050;
|
|
dn_et11_off = 033;
|
|
sim_activate(&dn_unit[2], 1000);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
t_stat
|
|
dn_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
DEVICE *dptr;
|
|
dptr = find_dev_from_unit (uptr);
|
|
if (dptr == NULL)
|
|
return SCPE_IERR;
|
|
dptr->flags &= ~DEV_M_OS;
|
|
dptr->flags |= val;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat
|
|
dn_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
DEVICE *dptr;
|
|
|
|
if (uptr == NULL)
|
|
return SCPE_IERR;
|
|
|
|
dptr = find_dev_from_unit(uptr);
|
|
if (dptr == NULL)
|
|
return SCPE_IERR;
|
|
fprintf (st, "%s", (dptr->flags & TYPE_RSX20) ? "RSX20" : "RSX10");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
t_stat dn_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
|
{
|
|
fprint_reg_help (st, &dn_dev);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
const char *dn_description (DEVICE *dptr)
|
|
{
|
|
return "DN Network interface";
|
|
}
|
|
|
|
|
|
#endif
|
|
#endif
|