KA10: Initial release of PDP10 KA/KI and PDP6 simulators.
This commit is contained in:
parent
461f2ea513
commit
90b7d2beac
37 changed files with 29808 additions and 0 deletions
392
PDP10/ka10_auxcpu.c
Normal file
392
PDP10/ka10_auxcpu.c
Normal file
|
@ -0,0 +1,392 @@
|
||||||
|
/* ka10_auxcpu.c: Auxiliary processor.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is a device which interfaces with an auxiliary processor
|
||||||
|
through shared memory and inter-processor interrupts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
#include "sim_tmxr.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_AUXCPU
|
||||||
|
#define NUM_DEVS_AUXCPU 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NUM_DEVS_AUXCPU > 0
|
||||||
|
#include <fcntl.h>
|
||||||
|
//#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* External bus interface. */
|
||||||
|
#define DATO 1
|
||||||
|
#define DATI 2
|
||||||
|
#define ACK 3
|
||||||
|
#define ERR 4
|
||||||
|
#define TIMEOUT 5
|
||||||
|
#define IRQ 6
|
||||||
|
|
||||||
|
/* Simulator time units for a Unibus memory cycle. */
|
||||||
|
#define AUXCPU_MEM_CYCLE 100
|
||||||
|
|
||||||
|
/* Interprocessor interrupt device. */
|
||||||
|
#define AUXCPU_DEVNUM 020
|
||||||
|
|
||||||
|
#define AUXCPU_POLL 1000
|
||||||
|
|
||||||
|
|
||||||
|
static int pia = 0;
|
||||||
|
static int status = 0;
|
||||||
|
|
||||||
|
static t_stat auxcpu_devio(uint32 dev, t_uint64 *data);
|
||||||
|
static t_stat auxcpu_svc (UNIT *uptr);
|
||||||
|
static t_stat auxcpu_reset (DEVICE *dptr);
|
||||||
|
static t_stat auxcpu_attach (UNIT *uptr, CONST char *ptr);
|
||||||
|
static t_stat auxcpu_detach (UNIT *uptr);
|
||||||
|
static t_stat auxcpu_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
|
static const char *auxcpu_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
UNIT auxcpu_unit[1] = {
|
||||||
|
{ UDATA (&auxcpu_svc, UNIT_IDLE|UNIT_ATTABLE, 0), 1000 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static REG auxcpu_reg[] = {
|
||||||
|
{ DRDATAD (POLL, auxcpu_unit[0].wait, 24, "poll interval"), PV_LEFT },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static MTAB auxcpu_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DBG_TRC 1
|
||||||
|
#define DBG_CMD 2
|
||||||
|
|
||||||
|
static DEBTAB auxcpu_debug[] = {
|
||||||
|
{"TRACE", DBG_TRC, "Routine trace"},
|
||||||
|
{"CMD", DBG_CMD, "Command Processing"},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE auxcpu_dev = {
|
||||||
|
"AUXCPU", auxcpu_unit, auxcpu_reg, auxcpu_mod,
|
||||||
|
1, 8, 16, 2, 8, 16,
|
||||||
|
NULL, /* examine */
|
||||||
|
NULL, /* deposit */
|
||||||
|
&auxcpu_reset, /* reset */
|
||||||
|
NULL, /* boot */
|
||||||
|
auxcpu_attach, /* attach */
|
||||||
|
auxcpu_detach, /* detach */
|
||||||
|
NULL, /* context */
|
||||||
|
DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX,
|
||||||
|
DBG_CMD, /* debug control */
|
||||||
|
auxcpu_debug, /* debug flags */
|
||||||
|
NULL, /* memory size chage */
|
||||||
|
NULL, /* logical name */
|
||||||
|
NULL, /* help */
|
||||||
|
&auxcpu_attach_help, /* attach help */
|
||||||
|
NULL, /* help context */
|
||||||
|
&auxcpu_description, /* description */
|
||||||
|
};
|
||||||
|
|
||||||
|
static TMLN auxcpu_ldsc; /* line descriptor */
|
||||||
|
static TMXR auxcpu_desc = { 1, 0, 0, &auxcpu_ldsc }; /* mux descriptor */
|
||||||
|
|
||||||
|
static t_stat auxcpu_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
sim_debug(DBG_TRC, dptr, "auxcpu_reset()\n");
|
||||||
|
|
||||||
|
auxcpu_unit[0].flags |= UNIT_ATTABLE | UNIT_IDLE;
|
||||||
|
auxcpu_desc.packet = TRUE;
|
||||||
|
auxcpu_desc.notelnet = TRUE;
|
||||||
|
auxcpu_desc.buffered = 2048;
|
||||||
|
|
||||||
|
if (auxcpu_unit[0].flags & UNIT_ATT)
|
||||||
|
sim_activate (&auxcpu_unit[0], 1000);
|
||||||
|
else
|
||||||
|
sim_cancel (&auxcpu_unit[0]);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat auxcpu_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (!cptr || !*cptr)
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (!(uptr->flags & UNIT_ATTABLE))
|
||||||
|
return SCPE_NOATT;
|
||||||
|
r = tmxr_attach_ex (&auxcpu_desc, uptr, cptr, FALSE);
|
||||||
|
if (r != SCPE_OK) /* error? */
|
||||||
|
return r;
|
||||||
|
sim_debug(DBG_TRC, &auxcpu_dev, "activate connection\n");
|
||||||
|
sim_activate (uptr, 10); /* start poll */
|
||||||
|
uptr->flags |= UNIT_ATT;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat auxcpu_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (!(uptr->flags & UNIT_ATT))
|
||||||
|
return SCPE_OK;
|
||||||
|
sim_cancel (uptr);
|
||||||
|
r = tmxr_detach (&auxcpu_desc, uptr);
|
||||||
|
uptr->flags &= ~UNIT_ATT;
|
||||||
|
free (uptr->filename);
|
||||||
|
uptr->filename = NULL;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build (unsigned char *request, unsigned char octet)
|
||||||
|
{
|
||||||
|
request[0]++;
|
||||||
|
request[request[0]] = octet & 0377;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat auxcpu_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
tmxr_poll_rx (&auxcpu_desc);
|
||||||
|
if (auxcpu_ldsc.rcve && !auxcpu_ldsc.conn) {
|
||||||
|
auxcpu_ldsc.rcve = 0;
|
||||||
|
tmxr_reset_ln (&auxcpu_ldsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If incoming interrput => status |= 010 */
|
||||||
|
if (status & 010)
|
||||||
|
set_interrupt(AUXCPU_DEVNUM, pia);
|
||||||
|
else
|
||||||
|
clr_interrupt(AUXCPU_DEVNUM);
|
||||||
|
|
||||||
|
if (tmxr_poll_conn(&auxcpu_desc) >= 0) {
|
||||||
|
sim_debug(DBG_CMD, &auxcpu_dev, "got connection\n");
|
||||||
|
auxcpu_ldsc.rcve = 1;
|
||||||
|
uptr->wait = AUXCPU_POLL;
|
||||||
|
}
|
||||||
|
sim_activate (uptr, uptr->wait);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat auxcpu_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
const char helpString[] =
|
||||||
|
/* The '*'s in the next line represent the standard text width of a help line */
|
||||||
|
/****************************************************************************/
|
||||||
|
" The %D device connects a secondary processor that is sharing memory with the.\n"
|
||||||
|
" primary.\n\n"
|
||||||
|
" The device must be attached to a receive port, this is done by using the\n"
|
||||||
|
" ATTACH command to specify the receive port number.\n"
|
||||||
|
"\n"
|
||||||
|
"+sim> ATTACH %U port\n"
|
||||||
|
"\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
return scp_help (st, dptr, uptr, flag, helpString, cptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *auxcpu_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Auxiliary processor";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int error (const char *message)
|
||||||
|
{
|
||||||
|
sim_debug (DBG_TRC, &auxcpu_dev, "%s\r\n", message);
|
||||||
|
sim_debug (DBG_TRC, &auxcpu_dev, "CLOSE\r\n");
|
||||||
|
auxcpu_ldsc.rcve = 0;
|
||||||
|
tmxr_reset_ln (&auxcpu_ldsc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int transaction (unsigned char *request, unsigned char *response)
|
||||||
|
{
|
||||||
|
const uint8 *auxcpu_request;
|
||||||
|
size_t size;
|
||||||
|
t_stat stat;
|
||||||
|
|
||||||
|
stat = tmxr_put_packet_ln (&auxcpu_ldsc, request + 1, (size_t)request[0]);
|
||||||
|
if (stat != SCPE_OK)
|
||||||
|
return error ("Write error in transaction");
|
||||||
|
|
||||||
|
do {
|
||||||
|
tmxr_poll_rx (&auxcpu_desc);
|
||||||
|
stat = tmxr_get_packet_ln (&auxcpu_ldsc, &auxcpu_request, &size);
|
||||||
|
} while (stat != SCPE_OK || size == 0);
|
||||||
|
|
||||||
|
if (size > 7)
|
||||||
|
return error ("Malformed transaction");
|
||||||
|
|
||||||
|
memcpy (response, auxcpu_request, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int auxcpu_read (int addr, t_uint64 *data)
|
||||||
|
{
|
||||||
|
unsigned char request[12];
|
||||||
|
unsigned char response[12];
|
||||||
|
|
||||||
|
sim_interval -= AUXCPU_MEM_CYCLE;
|
||||||
|
|
||||||
|
if ((auxcpu_unit[0].flags & UNIT_ATT) == 0) {
|
||||||
|
*data = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr &= 037777;
|
||||||
|
|
||||||
|
memset (request, 0, sizeof request);
|
||||||
|
build (request, DATI);
|
||||||
|
build (request, addr & 0377);
|
||||||
|
build (request, (addr >> 8) & 0377);
|
||||||
|
build (request, (addr >> 16) & 0377);
|
||||||
|
|
||||||
|
transaction (request, response);
|
||||||
|
|
||||||
|
switch (response[0])
|
||||||
|
{
|
||||||
|
case ACK:
|
||||||
|
*data = (t_uint64)response[1];
|
||||||
|
*data |= (t_uint64)response[2] << 8;
|
||||||
|
*data |= (t_uint64)response[3] << 16;
|
||||||
|
*data |= (t_uint64)response[4] << 24;
|
||||||
|
*data |= (t_uint64)response[5] << 32;
|
||||||
|
break;
|
||||||
|
case ERR:
|
||||||
|
fprintf (stderr, "AUXCPU: Read error %06o\r\n", addr);
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
case TIMEOUT:
|
||||||
|
fprintf (stderr, "AUXCPU: Read timeout %06o\r\n", addr);
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return error ("Protocol error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int auxcpu_write (int addr, t_uint64 data)
|
||||||
|
{
|
||||||
|
unsigned char request[12];
|
||||||
|
unsigned char response[12];
|
||||||
|
|
||||||
|
sim_interval -= AUXCPU_MEM_CYCLE;
|
||||||
|
|
||||||
|
if ((ten11_unit[0].flags & UNIT_ATT) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr &= 037777;
|
||||||
|
|
||||||
|
memset (request, 0, sizeof request);
|
||||||
|
build (request, DATO);
|
||||||
|
build (request, (addr) & 0377);
|
||||||
|
build (request, (addr >> 8) & 0377);
|
||||||
|
build (request, (addr >> 16) & 0377);
|
||||||
|
build (request, (data) & 0377);
|
||||||
|
build (request, (data >> 8) & 0377);
|
||||||
|
build (request, (data >> 16) & 0377);
|
||||||
|
build (request, (data >> 24) & 0377);
|
||||||
|
build (request, (data >> 32) & 0377);
|
||||||
|
|
||||||
|
transaction (request, response);
|
||||||
|
|
||||||
|
switch (response[0])
|
||||||
|
{
|
||||||
|
case ACK:
|
||||||
|
break;
|
||||||
|
case ERR:
|
||||||
|
fprintf (stderr, "AUXCPU: Write error %06o\r\n", addr);
|
||||||
|
break;
|
||||||
|
case TIMEOUT:
|
||||||
|
fprintf (stderr, "AUXCPU: Write timeout %06o\r\n", addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return error ("Protocol error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int auxcpu_interrupt (void)
|
||||||
|
{
|
||||||
|
unsigned char request[12];
|
||||||
|
unsigned char response[12];
|
||||||
|
memset (request, 0, sizeof request);
|
||||||
|
|
||||||
|
sim_debug(DEBUG_IRQ, &auxcpu_dev, "PDP-10 interrupting the PDP-6\n");
|
||||||
|
|
||||||
|
build (request, IRQ);
|
||||||
|
|
||||||
|
transaction (request, response);
|
||||||
|
|
||||||
|
switch (response[1])
|
||||||
|
{
|
||||||
|
case ACK:
|
||||||
|
break;
|
||||||
|
case ERR:
|
||||||
|
case TIMEOUT:
|
||||||
|
fprintf (stderr, "AUXCPU: Interrupt error or timeout\r\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return error ("Protocol error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat auxcpu_devio(uint32 dev, t_uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &auxcpu_dev;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case CONO:
|
||||||
|
sim_debug(DEBUG_CONO, &auxcpu_dev, "CONO %012llo\n", *data);
|
||||||
|
pia = *data & 7;
|
||||||
|
if (*data & 010)
|
||||||
|
{
|
||||||
|
// Clear interrupt from the PDP-6.
|
||||||
|
status &= ~010;
|
||||||
|
clr_interrupt(AUXCPU_DEVNUM);
|
||||||
|
}
|
||||||
|
if (*data & 020)
|
||||||
|
auxcpu_interrupt ();
|
||||||
|
break;
|
||||||
|
case CONI:
|
||||||
|
*data = (status & 010) | pia;
|
||||||
|
sim_debug(DEBUG_CONI, &auxcpu_dev, "CONI %012llo\n", *data);
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
*data = 0;
|
||||||
|
sim_debug(DEBUG_CONI, &auxcpu_dev, "DATAI %012llo\n", *data);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
sim_debug(DEBUG_CONI, &auxcpu_dev, "DATAO %012llo\n", *data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
551
PDP10/ka10_ch10.c
Normal file
551
PDP10/ka10_ch10.c
Normal file
|
@ -0,0 +1,551 @@
|
||||||
|
/* ka10_ch.c: CH10 Chaosnet interface.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2019, Richard Cornwell, original by Lars Brinkhoff.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHOR 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 the author shall not be
|
||||||
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
|
in this Software without prior written authorization from the author.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
#include "sim_tmxr.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_CH10
|
||||||
|
#define NUM_DEVS_CH10 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_CH10 > 0)
|
||||||
|
#define CH_DEVNUM 0470
|
||||||
|
|
||||||
|
/* CSR bits */
|
||||||
|
#define PIA 00000007LL /* Interrupt channel */
|
||||||
|
#define TXIE 00000010LL /* Transmit interrupt enable */
|
||||||
|
#define RXIE 00000020LL /* Receive interrupt enable */
|
||||||
|
#define SPY 00000040LL /* Spy */
|
||||||
|
#define LOOP 00000100LL /* Loop back */
|
||||||
|
#define SWAP 00000200LL /* Swap bytes */
|
||||||
|
#define HALF 00000400LL /* Halfword output */
|
||||||
|
#define TXD 00001000LL /* Transmit done */
|
||||||
|
#define RXD 00002000LL /* Receive done */
|
||||||
|
#define TXA 00004000LL /* Transmit abort */
|
||||||
|
#define CTX 00004000LL /* Clear transmitter */
|
||||||
|
#define LOST 00170000LL /* Lost count */
|
||||||
|
#define RESET 00010000LL /* Reset */
|
||||||
|
#define CRC 00200000LL /* CRC error */
|
||||||
|
#define WLE 00400000LL /* Word length error */
|
||||||
|
#define PLE 01000000LL /* Packet length error */
|
||||||
|
#define OVER 02000000LL /* Overrun */
|
||||||
|
|
||||||
|
#define STATUS_BITS (PIA|TXIE|RXIE|SPY|LOOP|SWAP|HALF|TXA|LOST|CRC|WLE|PLE|OVER)
|
||||||
|
|
||||||
|
BITFIELD ch10_csr_bits[] = {
|
||||||
|
BIT(PIA),
|
||||||
|
BIT(TXIE),
|
||||||
|
BIT(RXIE),
|
||||||
|
BIT(SPY),
|
||||||
|
BIT(LOOP),
|
||||||
|
BIT(SWAP),
|
||||||
|
BIT(HALF),
|
||||||
|
BIT(TXD),
|
||||||
|
BIT(RXD),
|
||||||
|
BIT(TXA),
|
||||||
|
BIT(CTX),
|
||||||
|
BITF(LOST,4),
|
||||||
|
BIT(CRC),
|
||||||
|
BIT(WLE),
|
||||||
|
BIT(PLE),
|
||||||
|
BIT(OVER),
|
||||||
|
ENDBITS
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CHUDP_HEADER 4
|
||||||
|
#define IOLN_CH 020
|
||||||
|
#define DBG_TRC 0x0001
|
||||||
|
#define DBG_REG 0x0002
|
||||||
|
#define DBG_PKT 0x0004
|
||||||
|
#define DBG_DAT 0x0008
|
||||||
|
#define DBG_INT 0x0010
|
||||||
|
#define DBG_ERR 0x0020
|
||||||
|
|
||||||
|
t_stat ch10_svc(UNIT *);
|
||||||
|
t_stat ch10_reset (DEVICE *);
|
||||||
|
t_stat ch10_attach (UNIT *, CONST char *);
|
||||||
|
t_stat ch10_detach (UNIT *);
|
||||||
|
t_stat ch10_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat ch10_show_peer (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
|
||||||
|
t_stat ch10_set_peer (UNIT* uptr, int32 val, CONST char* cptr, void* desc);
|
||||||
|
t_stat ch10_show_node (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
|
||||||
|
t_stat ch10_set_node (UNIT* uptr, int32 val, CONST char* cptr, void* desc);
|
||||||
|
t_stat ch10_help (FILE *, DEVICE *, UNIT *, int32, const char *);
|
||||||
|
t_stat ch10_help_attach (FILE *, DEVICE *, UNIT *, int32, const char *);
|
||||||
|
const char *ch10_description (DEVICE *);
|
||||||
|
|
||||||
|
static char peer[256];
|
||||||
|
int address;
|
||||||
|
static uint64 ch10_status;
|
||||||
|
static int rx_count;
|
||||||
|
static int tx_count;
|
||||||
|
static uint8 rx_buffer[512+100];
|
||||||
|
static uint8 tx_buffer[512+100];
|
||||||
|
|
||||||
|
TMLN ch10_lines[1] = { {0} };
|
||||||
|
TMXR ch10_tmxr = { 1, NULL, 0, ch10_lines};
|
||||||
|
|
||||||
|
UNIT ch10_unit[] = {
|
||||||
|
{UDATA (&ch10_svc, UNIT_IDLE|UNIT_ATTABLE, 0) },
|
||||||
|
};
|
||||||
|
|
||||||
|
REG ch10_reg[] = {
|
||||||
|
{ GRDATADF(CSR, ch10_status, 16, 16, 0, "Control and status", ch10_csr_bits), REG_FIT },
|
||||||
|
{ GRDATAD(RXCNT, rx_count, 16, 16, 0, "Receive word count"), REG_FIT|REG_RO},
|
||||||
|
{ GRDATAD(TXCNT, tx_count, 16, 16, 0, "Transmit word count"), REG_FIT|REG_RO},
|
||||||
|
{ BRDATAD(RXBUF, rx_buffer, 16, 8, sizeof rx_buffer, "Receive packet buffer"), REG_FIT},
|
||||||
|
{ BRDATAD(TXBUF, tx_buffer, 16, 8, sizeof tx_buffer, "Transmit packet buffer"), REG_FIT},
|
||||||
|
{ BRDATAD(PEER, peer, 16, 8, sizeof peer, "Network peer"), REG_HRO},
|
||||||
|
{ GRDATAD(NODE, address, 16, 16, 0, "Node address"), REG_HRO},
|
||||||
|
{ NULL } };
|
||||||
|
|
||||||
|
MTAB ch10_mod[] = {
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "PEER", "PEER",
|
||||||
|
&ch10_set_peer, &ch10_show_peer, NULL, "Remote host name and port" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "NODE", "NODE",
|
||||||
|
&ch10_set_node, &ch10_show_node, NULL, "Chaosnet node address" },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB ch10_dib = {CH_DEVNUM, 1, &ch10_devio, NULL};
|
||||||
|
|
||||||
|
DEBTAB ch10_debug[] = {
|
||||||
|
{ "TRC", DBG_TRC, "Detailed trace" },
|
||||||
|
{ "REG", DBG_REG, "Hardware registers" },
|
||||||
|
{ "PKT", DBG_PKT, "Packets" },
|
||||||
|
{ "DAT", DBG_DAT, "Packet data" },
|
||||||
|
{ "INT", DBG_INT, "Interrupts" },
|
||||||
|
{ "ERR", DBG_ERR, "Error conditions" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE ch10_dev = {
|
||||||
|
"CH", ch10_unit, ch10_reg, ch10_mod,
|
||||||
|
1, 8, 16, 1, 8, 16,
|
||||||
|
NULL, NULL, &ch10_reset,
|
||||||
|
NULL, &ch10_attach, &ch10_detach,
|
||||||
|
&ch10_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX,
|
||||||
|
0, ch10_debug, NULL, NULL, &ch10_help, &ch10_help_attach, NULL,
|
||||||
|
&ch10_description
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16 ch10_checksum (const uint8 *p, int count)
|
||||||
|
{
|
||||||
|
int32 sum = 0;
|
||||||
|
|
||||||
|
while (count > 1) {
|
||||||
|
sum += (p[0]<<8) | p[1];
|
||||||
|
p += 2;
|
||||||
|
count -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count > 0)
|
||||||
|
sum += p[0];
|
||||||
|
|
||||||
|
while (sum >> 16)
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
|
||||||
|
return (~sum) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ch10_test_int (void)
|
||||||
|
{
|
||||||
|
if ((ch10_status & (RXD|RXIE)) == (RXD|RXIE) ||
|
||||||
|
(ch10_status & (TXD|TXIE)) == (TXD|TXIE)) {
|
||||||
|
sim_debug (DBG_INT, &ch10_dev, "%s %s Interrupt\n",
|
||||||
|
ch10_status & RXD ? "RX" : "",
|
||||||
|
ch10_status & TXD ? "TX" : "");
|
||||||
|
set_interrupt(CH_DEVNUM, ch10_status & PIA);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
clr_interrupt(CH_DEVNUM);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch10_validate (const uint8 *p, int count)
|
||||||
|
{
|
||||||
|
uint16 chksum;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Packet opcode: %02x\n", p[0]);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "MBZ: %02x\n", p[1]);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Forwarding count: %02x\n", p[2] >> 4);
|
||||||
|
size = ((p[2] & 0xF) << 8) + p[3];
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Packet size: %03x\n", size);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Destination address: %o\n", (p[4] << 8) + p[5]);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Destination index: %02x\n", (p[6] << 8) + p[7]);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Source address: %o\n", (p[8] << 8) + p[9]);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Source index: %02x\n", (p[10] << 8) + p[11]);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Packet number: %02x\n", (p[12] << 8) + p[13]);
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Acknowledgement: %02x\n", (p[14] << 8) + p[15]);
|
||||||
|
|
||||||
|
if (p[1] != 0)
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "Bad packet\n");
|
||||||
|
|
||||||
|
chksum = ch10_checksum (p, count);
|
||||||
|
if (chksum != 0) {
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "Checksum error: %04x\n", chksum);
|
||||||
|
ch10_status |= CRC;
|
||||||
|
} else
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Checksum: %05o\n", chksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_transmit ()
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
t_stat r;
|
||||||
|
int i = CHUDP_HEADER + tx_count;
|
||||||
|
uint16 chk;
|
||||||
|
|
||||||
|
if (tx_count > (512 - CHUDP_HEADER)) {
|
||||||
|
sim_debug (DBG_PKT, &ch10_dev, "Pack size failed, %d bytes.\n", (int)tx_count);
|
||||||
|
ch10_status |= PLE;
|
||||||
|
return SCPE_INCOMP;
|
||||||
|
}
|
||||||
|
tx_buffer[i] = tx_buffer[8+CHUDP_HEADER];
|
||||||
|
tx_buffer[i+1] = tx_buffer[9+CHUDP_HEADER];
|
||||||
|
tx_count += 2;
|
||||||
|
chk = ch10_checksum(tx_buffer + CHUDP_HEADER, tx_count);
|
||||||
|
tx_buffer[i+2] = (chk >> 8) & 0xff;
|
||||||
|
tx_buffer[i+3] = chk & 0xff;
|
||||||
|
tx_count += 2;
|
||||||
|
|
||||||
|
tmxr_poll_tx (&ch10_tmxr);
|
||||||
|
len = CHUDP_HEADER + (size_t)tx_count;
|
||||||
|
r = tmxr_put_packet_ln (&ch10_lines[0], (const uint8 *)&tx_buffer, len);
|
||||||
|
if (r == SCPE_OK) {
|
||||||
|
sim_debug (DBG_PKT, &ch10_dev, "Sent UDP packet, %d bytes.\n", (int)len);
|
||||||
|
tmxr_poll_tx (&ch10_tmxr);
|
||||||
|
} else {
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "Sending UDP failed: %d.\n", r);
|
||||||
|
ch10_status |= OVER;
|
||||||
|
}
|
||||||
|
tx_count = 0;
|
||||||
|
ch10_test_int ();
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch10_receive (void)
|
||||||
|
{
|
||||||
|
size_t count;
|
||||||
|
const uint8 *p;
|
||||||
|
uint16 dest;
|
||||||
|
|
||||||
|
tmxr_poll_rx (&ch10_tmxr);
|
||||||
|
if (tmxr_get_packet_ln (&ch10_lines[0], &p, &count) != SCPE_OK) {
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "TMXR error receiving packet\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (p == NULL)
|
||||||
|
return;
|
||||||
|
dest = ((p[4+CHUDP_HEADER] & 0xff) << 8) + (p[5+CHUDP_HEADER] & 0xff);
|
||||||
|
|
||||||
|
sim_debug (DBG_PKT, &ch10_dev, "Received UDP packet, %d bytes for: %o\n", (int)count, dest);
|
||||||
|
/* Check if packet for us. */
|
||||||
|
if (dest != address && dest != 0 && (ch10_status & SPY) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((RXD & ch10_status) == 0) {
|
||||||
|
count = (count + 1) & 0776;
|
||||||
|
memcpy (rx_buffer + (512 - count), p, count);
|
||||||
|
rx_count = count;
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Rx count, %d\n", rx_count);
|
||||||
|
ch10_validate (p + CHUDP_HEADER, count - CHUDP_HEADER);
|
||||||
|
ch10_status |= RXD;
|
||||||
|
ch10_lines[0].rcve = FALSE;
|
||||||
|
sim_debug (DBG_TRC, &ch10_dev, "Rx off\n");
|
||||||
|
ch10_test_int ();
|
||||||
|
} else {
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "Lost packet\n");
|
||||||
|
if ((ch10_status & LOST) < LOST)
|
||||||
|
ch10_status += 01000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch10_clear (void)
|
||||||
|
{
|
||||||
|
ch10_status = TXD;
|
||||||
|
rx_count = 0;
|
||||||
|
tx_count = 0;
|
||||||
|
|
||||||
|
tx_buffer[0] = 1; /* CHUDP header */
|
||||||
|
tx_buffer[1] = 1;
|
||||||
|
tx_buffer[2] = 0;
|
||||||
|
tx_buffer[3] = 0;
|
||||||
|
ch10_lines[0].rcve = TRUE;
|
||||||
|
|
||||||
|
ch10_test_int ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch10_command (uint32 data)
|
||||||
|
{
|
||||||
|
if (data & RXD) {
|
||||||
|
sim_debug (DBG_REG, &ch10_dev, "Clear RX\n");
|
||||||
|
ch10_status &= ~RXD;
|
||||||
|
rx_count = 0;
|
||||||
|
ch10_lines[0].rcve = TRUE;
|
||||||
|
rx_count = 0;
|
||||||
|
}
|
||||||
|
if (data & RESET) {
|
||||||
|
/* Do this first so other bits can do their things. */
|
||||||
|
sim_debug (DBG_REG, &ch10_dev, "Reset\n");
|
||||||
|
ch10_clear ();
|
||||||
|
}
|
||||||
|
if (data & CTX) {
|
||||||
|
sim_debug (DBG_REG, &ch10_dev, "Clear TX\n");
|
||||||
|
tx_count = 0;
|
||||||
|
ch10_status |= TXD;
|
||||||
|
ch10_status &= ~TXA;
|
||||||
|
}
|
||||||
|
if (data & TXD) {
|
||||||
|
sim_debug (DBG_REG, &ch10_dev, "XMIT TX\n");
|
||||||
|
ch10_transmit();
|
||||||
|
ch10_status &= ~TXA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_devio(uint32 dev, uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &imx_dev;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case CONO:
|
||||||
|
sim_debug (DBG_REG, &ch10_dev, "CONO %012llo %012llo \n", *data, ch10_status);
|
||||||
|
ch10_command ((uint32)(*data & RMASK));
|
||||||
|
ch10_status &= ~STATUS_BITS;
|
||||||
|
ch10_status |= *data & STATUS_BITS;
|
||||||
|
ch10_test_int ();
|
||||||
|
break;
|
||||||
|
case CONI:
|
||||||
|
*data = ch10_status & (STATUS_BITS|TXD|RXD);
|
||||||
|
*data |= (uint64)address << 20;
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
ch10_status &= ~TXD;
|
||||||
|
if (tx_count < 512) {
|
||||||
|
int i = CHUDP_HEADER + tx_count;
|
||||||
|
if (ch10_status & SWAP) {
|
||||||
|
tx_buffer[i] = (*data >> 20) & 0xff;
|
||||||
|
tx_buffer[i+1] = (*data >> 28) & 0xff;
|
||||||
|
} else {
|
||||||
|
tx_buffer[i] = (*data >> 28) & 0xff;
|
||||||
|
tx_buffer[i+1] = (*data >> 20) & 0xff;
|
||||||
|
}
|
||||||
|
tx_count+=2;
|
||||||
|
if ((ch10_status & HALF) == 0) {
|
||||||
|
if (ch10_status & SWAP) {
|
||||||
|
tx_buffer[i+2] = (*data >> 4) & 0xff;
|
||||||
|
tx_buffer[i+3] = (*data >> 12) & 0xff;
|
||||||
|
} else {
|
||||||
|
tx_buffer[i+2] = (*data >> 12) & 0xff;
|
||||||
|
tx_buffer[i+3] = (*data >> 4) & 0xff;
|
||||||
|
}
|
||||||
|
tx_count+=2;
|
||||||
|
}
|
||||||
|
sim_debug (DBG_DAT, &ch10_dev, "Write buffer word %d:%02x %02x %02x %02x %012llo %012llo\n",
|
||||||
|
tx_count, tx_buffer[i], tx_buffer[i+1], tx_buffer[i+2], tx_buffer[i+3], *data, ch10_status);
|
||||||
|
return SCPE_OK;
|
||||||
|
} else {
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "Write buffer overflow\n");
|
||||||
|
ch10_status |= PLE;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
case DATAI:
|
||||||
|
if (rx_count == 0) {
|
||||||
|
*data = 0;
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "Read empty buffer\n");
|
||||||
|
} else {
|
||||||
|
int i = 512-rx_count;
|
||||||
|
ch10_status &= ~RXD;
|
||||||
|
if (ch10_status & SWAP) {
|
||||||
|
*data = ((uint64)(rx_buffer[i]) & 0xff) << 20;
|
||||||
|
*data |= ((uint64)(rx_buffer[i+1]) & 0xff) << 28;
|
||||||
|
*data |= ((uint64)(rx_buffer[i+2]) & 0xff) << 4;
|
||||||
|
*data |= ((uint64)(rx_buffer[i+3]) & 0xff) << 12;
|
||||||
|
} else {
|
||||||
|
*data = ((uint64)(rx_buffer[i]) & 0xff) << 28;
|
||||||
|
*data |= ((uint64)(rx_buffer[i+1]) & 0xff) << 20;
|
||||||
|
*data |= ((uint64)(rx_buffer[i+2]) & 0xff) << 12;
|
||||||
|
*data |= ((uint64)(rx_buffer[i+3]) & 0xff) << 4;
|
||||||
|
}
|
||||||
|
rx_count-=4;
|
||||||
|
sim_debug (DBG_DAT, &ch10_dev, "Read buffer word %d:%02x %02x %02x %02x %012llo %012llo\n",
|
||||||
|
rx_count, rx_buffer[i], rx_buffer[i+1], rx_buffer[i+2], rx_buffer[i+3], *data, ch10_status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
sim_clock_coschedule (uptr, 1000);
|
||||||
|
(void)tmxr_poll_conn (&ch10_tmxr);
|
||||||
|
if (ch10_lines[0].conn) {
|
||||||
|
ch10_receive ();
|
||||||
|
}
|
||||||
|
if (tx_count == 0)
|
||||||
|
ch10_status |= TXD;
|
||||||
|
ch10_test_int ();
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
char linkinfo[256];
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
ch10_dev.dctrl |= 0xF77F0000;
|
||||||
|
if (address == -1)
|
||||||
|
return sim_messagef (SCPE_2FARG, "Must set Chaosnet NODE address first \"SET CH NODE=val\"\n");
|
||||||
|
if (peer[0] == '\0')
|
||||||
|
return sim_messagef (SCPE_2FARG, "Must set Chaosnet PEER \"SET CH PEER=host:port\"\n");
|
||||||
|
|
||||||
|
snprintf (linkinfo, sizeof(linkinfo), "Buffer=%d,UDP,%s,PACKET,Connect=%s,Line=0",
|
||||||
|
(int)sizeof tx_buffer, cptr, peer);
|
||||||
|
r = tmxr_attach (&ch10_tmxr, uptr, linkinfo);
|
||||||
|
if (r != SCPE_OK) {
|
||||||
|
sim_debug (DBG_ERR, &ch10_dev, "TMXR error opening master\n");
|
||||||
|
return sim_messagef (r, "Error Opening: %s\n", peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uptr->filename = (char *)realloc (uptr->filename, 1 + strlen (cptr));
|
||||||
|
strcpy (uptr->filename, cptr);
|
||||||
|
sim_activate (uptr, 1000);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
sim_cancel (uptr);
|
||||||
|
tmxr_detach (&ch10_tmxr, uptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
ch10_clear ();
|
||||||
|
if (ch10_unit[0].flags & UNIT_ATT)
|
||||||
|
sim_activate (&ch10_unit[0], 100);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_show_peer (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
|
||||||
|
{
|
||||||
|
fprintf (st, "peer=%s", peer[0] ? peer : "unspecified");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_set_peer (UNIT* uptr, int32 val, CONST char* cptr, void* desc)
|
||||||
|
{
|
||||||
|
char host[256], port[256];
|
||||||
|
|
||||||
|
if ((cptr == NULL) || (*cptr == 0))
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (uptr->flags & UNIT_ATT)
|
||||||
|
return SCPE_ALATT;
|
||||||
|
if (sim_parse_addr (cptr, host, sizeof host, NULL, port, sizeof port, NULL, NULL))
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (host[0] == '\0')
|
||||||
|
return SCPE_ARG;
|
||||||
|
|
||||||
|
strncpy (peer, cptr, sizeof(peer) - 1);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_show_node (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
|
||||||
|
{
|
||||||
|
if (address == -1)
|
||||||
|
fprintf (st, "node=unspecified");
|
||||||
|
else
|
||||||
|
fprintf (st, "node=%o", address);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_set_node (UNIT* uptr, int32 val, CONST char* cptr, void* desc)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
if ((cptr == NULL) || (*cptr == 0))
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (uptr->flags & UNIT_ATT)
|
||||||
|
return SCPE_ALATT;
|
||||||
|
|
||||||
|
x = (int)get_uint (cptr, 8, 0177777, &r);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return SCPE_ARG;
|
||||||
|
|
||||||
|
address = x;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ch10_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "CH11 Chaosnet interface";
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "CH10 Chaosnet interface\n\n");
|
||||||
|
fprintf (st, "It's a network interface for MIT's Chaosnet. Options allow\n");
|
||||||
|
fprintf (st, "control of the node address and network peer. The node address must\n");
|
||||||
|
fprintf (st, "be a 16-bit octal number.\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprintf (st, "\nConfigured options and controller state can be displayed with:\n");
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprintf (st, "\nThe CH10 simulation will encapsulate Chaosnet packets in UDP or TCP.\n");
|
||||||
|
fprintf (st, "To access the network, the simulated Chaosnet interface must be attached\n");
|
||||||
|
fprintf (st, "to a network peer.\n\n");
|
||||||
|
ch10_help_attach (st, dptr, uptr, flag, cptr);
|
||||||
|
fprintf (st, "Software that runs on SIMH that supports this device include:\n");
|
||||||
|
fprintf (st, " - ITS, the PDP-10 Incompatible Timesharing System\n");
|
||||||
|
fprintf (st, "Outside SIMH, there's KLH10 and Lisp machine simulators. Various\n");
|
||||||
|
fprintf (st, "encapsulating transport mechanisms exist: UDP, IP, Ethernet.\n\n");
|
||||||
|
fprintf (st, "Documentation:\n");
|
||||||
|
fprintf (st, "https://lm-3.github.io/amber.html#Hardware-Programming-Documentation\n\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ch10_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "To configure CH10, first set the local Chaosnet node address, and\n");
|
||||||
|
fprintf (st, "the peer:\n\n");
|
||||||
|
fprintf (st, " sim> SET CH NODE=<octal address>\n");
|
||||||
|
fprintf (st, " sim> SET CH PEER=<remote host>:<remote port>\n\n");
|
||||||
|
fprintf (st, "Then, attach a local port. By default UDP is used:\n\n");
|
||||||
|
fprintf (st, " sim> ATTACH CH <local port>\n\n");
|
||||||
|
fprintf (st, "If TCP is desired, add \"TCP\":\n\n");
|
||||||
|
fprintf (st, " sim> ATTACH CH <local port>,TCP\n\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
98
PDP10/ka10_dkb.c
Normal file
98
PDP10/ka10_dkb.c
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* ka10_dkb.c:Stanford Microswitch scanner.
|
||||||
|
|
||||||
|
Copyright (c) 2013-2017, 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"
|
||||||
|
#ifndef NUM_DEVS_DKB
|
||||||
|
#define NUM_DEVS_DKB 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NUM_DEVS_DKB > 0
|
||||||
|
|
||||||
|
t_stat dkb_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
|
const char *dkb_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
#define DKB_DEVNUM 0310
|
||||||
|
|
||||||
|
#define STATUS u3
|
||||||
|
#define DATA u4
|
||||||
|
#define PIA u5
|
||||||
|
|
||||||
|
t_stat dkb_devio(uint32 dev, uint64 *data);
|
||||||
|
|
||||||
|
DIB dkb_dib = { DKB_DEVNUM, 1, dkb_devio, NULL};
|
||||||
|
|
||||||
|
UNIT dkb_unit[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
MTAB dkb_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dkb_dev = {
|
||||||
|
"DKB", dkb_unit, NULL, dkb_mod,
|
||||||
|
2, 10, 31, 1, 8, 8,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, &dkb_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS, 0, dev_debug,
|
||||||
|
NULL, NULL, &dkb_help, NULL, NULL, &dkb_description
|
||||||
|
};
|
||||||
|
|
||||||
|
int status;
|
||||||
|
t_stat dkb_devio(uint32 dev, uint64 *data) {
|
||||||
|
/* uint64 res; */
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = status;
|
||||||
|
sim_debug(DEBUG_CONI, &dkb_dev, "DKB %03o CONI %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
case CONO:
|
||||||
|
status = (int)(*data&7);
|
||||||
|
sim_debug(DEBUG_CONO, &dkb_dev, "DKB %03o CONO %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
sim_debug(DEBUG_DATAIO, &dkb_dev, "DKB %03o DATAI %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
sim_debug(DEBUG_DATAIO, &dkb_dev, "DKB %03o DATAO %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t_stat dkb_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dkb_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Console TTY Line";
|
||||||
|
}
|
||||||
|
#endif
|
391
PDP10/ka10_dpk.c
Normal file
391
PDP10/ka10_dpk.c
Normal file
|
@ -0,0 +1,391 @@
|
||||||
|
/* ka10_dpk.c: Systems Concepts DK-10, Datapoint kludge.
|
||||||
|
|
||||||
|
Copyright (c) 2018-2019, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
The Systems Concepts DK-10, also known as the Datapoint kludge, is
|
||||||
|
a device with 16 terminal ports. It's specific to the MIT AI lab
|
||||||
|
PDP-10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "sim_defs.h"
|
||||||
|
#include "sim_tmxr.h"
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#define DPK_NAME "DPK"
|
||||||
|
#define DPK_DEVNUM 0604
|
||||||
|
#define DPK_LINES 16
|
||||||
|
|
||||||
|
#define DPK_IEN 04000000 /* Interrupt enable. */
|
||||||
|
|
||||||
|
#define DPK_PIA 000000007 /* PI channel assignment */
|
||||||
|
#define DPK_IDONE 000000010 /* Input char available. */
|
||||||
|
#define DPK_NXM 000000020 /* NXM. */
|
||||||
|
#define DPK_PAR 000000040 /* Parity error. */
|
||||||
|
#define DPK_BUSY 000000100 /* Ouput line busy. */
|
||||||
|
#define DPK_IN 000000200 /* State of input line. */
|
||||||
|
#define DPK_ODONE 000000400 /* Output buffer done. */
|
||||||
|
#define DPK_OLINE 017000000 /* Line number, output. */
|
||||||
|
|
||||||
|
#define DPK_CONI_BITS (DPK_PIA | DPK_IDONE | DPK_PAR | DPK_NXM | \
|
||||||
|
DPK_BUSY | DPK_IN | DPK_ODONE | DPK_OLINE)
|
||||||
|
|
||||||
|
#define DPK_FN 000000700 /* Function. */
|
||||||
|
#define DPK_SET_ODONE 000000000 /* Set output done. */
|
||||||
|
#define DPK_OSTART 000000100 /* Start output. */
|
||||||
|
#define DPK_ISTOP 000000200 /* Stop input. */
|
||||||
|
#define DPK_ISTART 000000300 /* Start input. */
|
||||||
|
#define DPK_OSTOP 000000400 /* Stop output, clear output done. */
|
||||||
|
#define DPK_OSPEED 000000500 /* Set output speed, start output. */
|
||||||
|
#define DPK_ISPEED_STOP 000000600 /* Set input speed, stop input. */
|
||||||
|
#define DPK_ISPEED_START 000000700 /* Set input speed, start input. */
|
||||||
|
#define DPK_SPEED 000007000 /* Speed code. */
|
||||||
|
#define DPK_ILINE 000170000 /* Line number. */
|
||||||
|
#define DPK_MANY 000200000 /* Apply to selected line through highest. */
|
||||||
|
#define DPK_RESET 000400000 /* Master clear. */
|
||||||
|
|
||||||
|
#define PORT_OUTPUT 1
|
||||||
|
#define PORT_INPUT 2
|
||||||
|
|
||||||
|
static t_stat dpk_devio(uint32 dev, uint64 *data);
|
||||||
|
static t_stat dpk_svc (UNIT *uptr);
|
||||||
|
static t_stat dpk_reset (DEVICE *dptr);
|
||||||
|
static t_stat dpk_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
static t_stat dpk_detach (UNIT *uptr);
|
||||||
|
static const char *dpk_description (DEVICE *dptr);
|
||||||
|
static t_stat dpk_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr);
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
|
||||||
|
TMLN dpk_ldsc[DPK_LINES] = { 0 };
|
||||||
|
TMXR dpk_desc = { DPK_LINES, 0, 0, dpk_ldsc };
|
||||||
|
|
||||||
|
static int dpk_ien = 0;
|
||||||
|
static int dpk_base = 0;
|
||||||
|
static int dpk_status = 0;
|
||||||
|
static int dpk_port[16];
|
||||||
|
static int dpk_ibuf[16];
|
||||||
|
static int dpk_ird = 0;
|
||||||
|
static int dpk_iwr = 0;
|
||||||
|
|
||||||
|
UNIT dpk_unit[] = {
|
||||||
|
{UDATA(dpk_svc, TT_MODE_8B|UNIT_ATTABLE|UNIT_DISABLE, 0)}, /* 0 */
|
||||||
|
};
|
||||||
|
DIB dpk_dib = {DPK_DEVNUM, 1, &dpk_devio, NULL};
|
||||||
|
|
||||||
|
MTAB dpk_mod[] = {
|
||||||
|
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL, NULL, NULL, "7 bit mode" },
|
||||||
|
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL, NULL, NULL, "8 bit mode" },
|
||||||
|
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL, NULL, NULL, "7 bit mode - non printing suppressed" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
|
||||||
|
&tmxr_dscln, NULL, &dpk_desc, "Disconnect a specific line" },
|
||||||
|
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
|
||||||
|
NULL, &tmxr_show_summ, (void *) &dpk_desc, "Display a summary of line states" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &dpk_desc, "Display current connections" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &dpk_desc, "Display multiplexer statistics" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dpk_dev = {
|
||||||
|
DPK_NAME, dpk_unit, NULL, dpk_mod,
|
||||||
|
1, 8, 0, 1, 8, 36,
|
||||||
|
NULL, NULL, dpk_reset, NULL, dpk_attach, dpk_detach,
|
||||||
|
&dpk_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, dpk_help, NULL, NULL, dpk_description
|
||||||
|
};
|
||||||
|
|
||||||
|
static t_stat dpk_devio(uint32 dev, uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &dpk_dev;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case CONO|4:
|
||||||
|
sim_debug(DEBUG_CONO, &dpk_dev, "%012llo\n", *data);
|
||||||
|
port = (*data & DPK_ILINE) >> 12;
|
||||||
|
if (*data & DPK_RESET)
|
||||||
|
dpk_reset (&dpk_dev);
|
||||||
|
if (*data & DPK_IDONE) {
|
||||||
|
dpk_status &= ~DPK_IDONE;
|
||||||
|
dpk_iwr = dpk_ird = 0;
|
||||||
|
}
|
||||||
|
if (*data & DPK_PAR)
|
||||||
|
dpk_status &= ~DPK_PAR;
|
||||||
|
if (*data & DPK_NXM)
|
||||||
|
dpk_status &= ~DPK_NXM;
|
||||||
|
switch (*data & DPK_FN) {
|
||||||
|
case DPK_SET_ODONE:
|
||||||
|
dpk_status |= DPK_ODONE;
|
||||||
|
break;
|
||||||
|
case DPK_OSTART:
|
||||||
|
dpk_port[port] |= PORT_OUTPUT;
|
||||||
|
dpk_status &= ~DPK_ODONE;
|
||||||
|
break;
|
||||||
|
case DPK_ISTOP:
|
||||||
|
dpk_port[port] &= ~PORT_INPUT;
|
||||||
|
break;
|
||||||
|
case DPK_ISTART:
|
||||||
|
dpk_port[port] |= PORT_OUTPUT;
|
||||||
|
break;
|
||||||
|
case DPK_OSTOP:
|
||||||
|
dpk_port[port] &= ~PORT_OUTPUT;
|
||||||
|
dpk_status &= ~DPK_ODONE;
|
||||||
|
break;
|
||||||
|
case DPK_OSPEED:
|
||||||
|
sim_debug(DEBUG_CMD, &dpk_dev, "Set port %d output speed %lld\n",
|
||||||
|
port, (*data & DPK_SPEED) >> 9);
|
||||||
|
dpk_port[port] |= PORT_OUTPUT;
|
||||||
|
break;
|
||||||
|
case DPK_ISPEED_STOP:
|
||||||
|
dpk_port[port] &= ~PORT_INPUT;
|
||||||
|
goto ispeed;
|
||||||
|
case DPK_ISPEED_START:
|
||||||
|
dpk_port[port] |= PORT_INPUT;
|
||||||
|
ispeed:
|
||||||
|
sim_debug(DEBUG_CMD, &dpk_dev, "Set port %d input speed %lld\n",
|
||||||
|
port, (*data & DPK_SPEED) >> 9);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf (stderr, "Unknown function: %llo\n", *data);
|
||||||
|
exit (1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dpk_status &= ~DPK_PIA;
|
||||||
|
dpk_status |= *data & DPK_PIA;
|
||||||
|
break;
|
||||||
|
case CONI|4:
|
||||||
|
*data = dpk_status & DPK_CONI_BITS;
|
||||||
|
sim_debug(DEBUG_CONI, &dpk_dev, "%07llo\n", *data);
|
||||||
|
break;
|
||||||
|
case DATAO|4:
|
||||||
|
dpk_base = *data & 03777777;
|
||||||
|
if (*data & DPK_IEN)
|
||||||
|
dpk_ien = 1;
|
||||||
|
sim_debug(DEBUG_DATAIO, &dpk_dev, "DATAO %06llo\n", *data);
|
||||||
|
break;
|
||||||
|
case DATAI|4:
|
||||||
|
if (dpk_ird == dpk_iwr) {
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*data = dpk_ibuf[dpk_ird++];
|
||||||
|
dpk_ird &= 15;
|
||||||
|
sim_debug(DEBUG_DATAIO, &dpk_dev, "DATAI %06llo\n", *data);
|
||||||
|
if (dpk_ird == dpk_iwr) {
|
||||||
|
dpk_status &= ~DPK_IDONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dpk_ien && (dpk_status & (DPK_IDONE | DPK_ODONE)))
|
||||||
|
set_interrupt(DPK_DEVNUM, dpk_status & DPK_PIA);
|
||||||
|
else
|
||||||
|
clr_interrupt(DPK_DEVNUM);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note, the byte pointer used by the hardware has halfwords swapped. */
|
||||||
|
static int ildb (uint64 *pointer)
|
||||||
|
{
|
||||||
|
uint64 bp = *pointer;
|
||||||
|
int pos, ch, addr;
|
||||||
|
|
||||||
|
again:
|
||||||
|
pos = (bp >> 12) & 077;
|
||||||
|
pos -= 7;
|
||||||
|
addr = (bp >> 18) & 0777777;
|
||||||
|
if (pos < 0) {
|
||||||
|
pos = 36 - 7;
|
||||||
|
addr++;
|
||||||
|
addr &= 0777777;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (M[addr] & 1) {
|
||||||
|
bp = M[addr];
|
||||||
|
goto again;
|
||||||
|
} else
|
||||||
|
*pointer = ((uint64)addr << 18) | (pos << 12) | 7 << 6;
|
||||||
|
|
||||||
|
ch = (M[addr] >> pos) & 0177;
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dpk_output (int port, TMLN *lp)
|
||||||
|
{
|
||||||
|
uint64 count;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
if ((dpk_port[port] & PORT_OUTPUT) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (M[dpk_base + 2*port] == 0777777777777LL) {
|
||||||
|
dpk_port[port] &= ~PORT_OUTPUT;
|
||||||
|
dpk_status &= ~DPK_OLINE;
|
||||||
|
dpk_status |= port << 18;
|
||||||
|
dpk_status |= DPK_ODONE;
|
||||||
|
if (dpk_ien)
|
||||||
|
set_interrupt(DPK_DEVNUM, dpk_status & DPK_PIA);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = ildb (&M[dpk_base + 2*port + 1]);
|
||||||
|
ch = sim_tt_outcvt(ch & 0377, TT_GET_MODE (dpk_unit[0].flags));
|
||||||
|
tmxr_putc_ln (lp, ch);
|
||||||
|
|
||||||
|
count = M[dpk_base + 2*port] - 1;
|
||||||
|
M[dpk_base + 2*port] = count & 0777777777777LL;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat dpk_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
static int scan = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* 16 ports at 4800 baud, rounded up. */
|
||||||
|
sim_activate_after (uptr, 200);
|
||||||
|
|
||||||
|
i = tmxr_poll_conn (&dpk_desc);
|
||||||
|
if (i >= 0) {
|
||||||
|
dpk_ldsc[i].conn = 1;
|
||||||
|
dpk_ldsc[i].rcve = 1;
|
||||||
|
dpk_ldsc[i].xmte = 1;
|
||||||
|
sim_debug(DEBUG_CMD, &dpk_dev, "Connect %d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmxr_poll_rx (&dpk_desc);
|
||||||
|
tmxr_poll_tx (&dpk_desc);
|
||||||
|
|
||||||
|
for (i = 0; i < DPK_LINES; i++) {
|
||||||
|
/* Round robin scan 16 lines. */
|
||||||
|
scan = (scan + 1) & 017;
|
||||||
|
|
||||||
|
/* 1 means the line became ready since the last check. Ignore
|
||||||
|
-1 which means "still ready". */
|
||||||
|
if (tmxr_txdone_ln (&dpk_ldsc[scan])) {
|
||||||
|
if (dpk_output (scan, &dpk_ldsc[scan]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dpk_ldsc[scan].conn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tmxr_input_pending_ln (&dpk_ldsc[scan])) {
|
||||||
|
if ((dpk_port[scan] & PORT_INPUT) == 0)
|
||||||
|
continue;
|
||||||
|
dpk_ibuf[dpk_iwr++] = (scan << 18) | (tmxr_getc_ln (&dpk_ldsc[scan]) & 0177);
|
||||||
|
dpk_iwr &= 15;
|
||||||
|
dpk_status |= DPK_IDONE;
|
||||||
|
if (dpk_ien)
|
||||||
|
set_interrupt(DPK_DEVNUM, dpk_status & DPK_PIA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat dpk_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
sim_debug(DEBUG_CMD, &dpk_dev, "Reset\n");
|
||||||
|
if (dpk_unit->flags & UNIT_ATT)
|
||||||
|
sim_activate (dpk_unit, tmxr_poll);
|
||||||
|
else
|
||||||
|
sim_cancel (dpk_unit);
|
||||||
|
|
||||||
|
dpk_ien = 0;
|
||||||
|
dpk_base = 0;
|
||||||
|
dpk_status = 0;
|
||||||
|
dpk_ird = dpk_iwr = 0;
|
||||||
|
memset (dpk_port, 0, sizeof dpk_port);
|
||||||
|
clr_interrupt(DPK_DEVNUM);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat dpk_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat stat;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
stat = tmxr_attach (&dpk_desc, uptr, cptr);
|
||||||
|
for (i = 0; i < DPK_LINES; i++) {
|
||||||
|
dpk_ldsc[i].rcve = 0;
|
||||||
|
dpk_ldsc[i].xmte = 0;
|
||||||
|
/* Clear txdone so tmxr_txdone_ln will not return return true
|
||||||
|
on the first call. */
|
||||||
|
dpk_ldsc[i].txdone = 0;
|
||||||
|
}
|
||||||
|
if (stat == SCPE_OK)
|
||||||
|
sim_activate (uptr, tmxr_poll);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat dpk_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat stat = tmxr_detach (&dpk_desc, uptr);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < DPK_LINES; i++) {
|
||||||
|
dpk_ldsc[i].rcve = 0;
|
||||||
|
dpk_ldsc[i].xmte = 0;
|
||||||
|
}
|
||||||
|
dpk_status = 0;
|
||||||
|
sim_cancel (uptr);
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat dpk_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "DPK Datapoint kludge terminal multiplexer\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, "Terminals can be set to one of three modes: 7P, 7B, or 8B.\n\n");
|
||||||
|
fprintf (st, " mode input characters output characters\n\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 7B.\n\n");
|
||||||
|
fprintf (st, "Once DPK 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 DPK DISCONNECT command, or a DETACH DPK command.\n\n");
|
||||||
|
fprintf (st, "Other special commands:\n\n");
|
||||||
|
fprintf (st, " sim> SHOW DPK CONNECTIONS show current connections\n");
|
||||||
|
fprintf (st, " sim> SHOW DPK STATISTICS show statistics for active connections\n");
|
||||||
|
fprintf (st, " sim> SET DPKn DISCONNECT disconnects the specified line.\n");
|
||||||
|
fprint_reg_help (st, &dc_dev);
|
||||||
|
fprintf (st, "\nThe terminals do not support save and restore. All open connections\n");
|
||||||
|
fprintf (st, "are lost when the simulator shuts down or DPK is detached.\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *dpk_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Systems Concepts DK-10, Datapoint kludge";
|
||||||
|
}
|
118
PDP10/ka10_imx.c
Normal file
118
PDP10/ka10_imx.c
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/* ka10_imx.c: Input multplexor for A/D.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is a device which has 128 A/D channels. It's specific to the MIT
|
||||||
|
AI lab PDP-10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_IMX
|
||||||
|
#define NUM_DEVS_IMX 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_IMX > 0)
|
||||||
|
|
||||||
|
#define IMX_DEVNUM 0574
|
||||||
|
|
||||||
|
#define IMX_PIA 0000007
|
||||||
|
#define IMX_DONE 0000010
|
||||||
|
#define IMX_PACK 0000040
|
||||||
|
#define IMX_SEQUENCE 0000100
|
||||||
|
#define IMX_TEST 0000200
|
||||||
|
#define IMX_RATE 0377000
|
||||||
|
#define IMX_ASSIGNED 0400000000000LL
|
||||||
|
|
||||||
|
#define IMX_CONO (IMX_PIA | IMX_PACK | IMX_SEQUENCE | IMX_RATE)
|
||||||
|
#define IMX_CONI (IMX_PIA | IMX_DONE | IMX_PACK | IMX_SEQUENCE | IMX_TEST | IMX_ASSIGNED)
|
||||||
|
|
||||||
|
#define IMX_CHANNEL 0000177
|
||||||
|
|
||||||
|
t_stat imx_devio(uint32 dev, uint64 *data);
|
||||||
|
const char *imx_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
static uint64 status = IMX_ASSIGNED;
|
||||||
|
static int initial_channel = 0;
|
||||||
|
static int current_channel = 0;
|
||||||
|
|
||||||
|
UNIT imx_unit[] = {
|
||||||
|
{UDATA(NULL, UNIT_DISABLE, 0)}, /* 0 */
|
||||||
|
};
|
||||||
|
DIB imx_dib = {IMX_DEVNUM, 1, &imx_devio, NULL};
|
||||||
|
|
||||||
|
MTAB imx_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE imx_dev = {
|
||||||
|
"IMX", imx_unit, NULL, imx_mod,
|
||||||
|
1, 8, 0, 1, 8, 36,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
&imx_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, &imx_description
|
||||||
|
};
|
||||||
|
|
||||||
|
static int imx_sample (void)
|
||||||
|
{
|
||||||
|
int sample = 2048;
|
||||||
|
if (status & IMX_SEQUENCE)
|
||||||
|
current_channel = (current_channel + 1) & IMX_CHANNEL;
|
||||||
|
else
|
||||||
|
current_channel = initial_channel;
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat imx_devio(uint32 dev, uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &imx_dev;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case CONO|4:
|
||||||
|
status &= ~IMX_CONO;
|
||||||
|
status |= *data & IMX_CONO;
|
||||||
|
current_channel = initial_channel;
|
||||||
|
break;
|
||||||
|
case CONI|4:
|
||||||
|
status |= IMX_DONE;
|
||||||
|
*data = status & IMX_CONI;
|
||||||
|
break;
|
||||||
|
case DATAO|4:
|
||||||
|
initial_channel = *data & IMX_CHANNEL;
|
||||||
|
break;
|
||||||
|
case DATAI|4:
|
||||||
|
*data = imx_sample();
|
||||||
|
if (status & IMX_PACK) {
|
||||||
|
*data <<= 24;
|
||||||
|
*data |= imx_sample() << 12;
|
||||||
|
*data |= imx_sample();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *imx_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "A/D input multiplexor";
|
||||||
|
}
|
||||||
|
#endif
|
304
PDP10/ka10_mty.c
Normal file
304
PDP10/ka10_mty.c
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
/* ka10_tk10.c: MTY, Morton multiplex box: Terminal multiplexor.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is a device with 32 high-speed terminal lines. It's specific
|
||||||
|
to the MIT Mathlab and Dynamic Modeling PDP-10s.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "sim_defs.h"
|
||||||
|
#include "sim_tmxr.h"
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_MTY
|
||||||
|
#define NUM_DEVS_MTY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_MTY > 0)
|
||||||
|
|
||||||
|
#define MTY_NAME "MTY"
|
||||||
|
#define MTY_DEVNUM 0400
|
||||||
|
#define MTY_LINES 32
|
||||||
|
|
||||||
|
#define MTY_PIA 0000007 /* PI channel assignment */
|
||||||
|
#define MTY_RQINT 0000010 /* Request interrupt. */
|
||||||
|
#define MTY_ODONE 0000010 /* Output done. */
|
||||||
|
#define MTY_IDONE 0000040 /* Input done. */
|
||||||
|
#define MTY_STOP 0000200 /* Clear output done. */
|
||||||
|
#define MTY_LINE 0370000 /* Line number. */
|
||||||
|
|
||||||
|
#define MTY_DONE (MTY_IDONE | MTY_ODONE)
|
||||||
|
#define MTY_CONI_BITS (MTY_PIA | MTY_DONE | MTY_LINE)
|
||||||
|
#define MTY_CONO_BITS (MTY_PIA | MTY_LINE)
|
||||||
|
|
||||||
|
static t_stat mty_devio(uint32 dev, uint64 *data);
|
||||||
|
static t_stat mty_svc (UNIT *uptr);
|
||||||
|
static t_stat mty_reset (DEVICE *dptr);
|
||||||
|
static t_stat mty_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
static t_stat mty_detach (UNIT *uptr);
|
||||||
|
static const char *mty_description (DEVICE *dptr);
|
||||||
|
static t_stat mty_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr);
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
|
||||||
|
TMLN mty_ldsc[MTY_LINES] = { 0 };
|
||||||
|
TMXR mty_desc = { MTY_LINES, 0, 0, mty_ldsc };
|
||||||
|
|
||||||
|
static uint64 status = 0;
|
||||||
|
|
||||||
|
UNIT mty_unit[] = {
|
||||||
|
{UDATA(mty_svc, TT_MODE_7B|UNIT_ATTABLE|UNIT_DISABLE, 0)}, /* 0 */
|
||||||
|
};
|
||||||
|
DIB mty_dib = {MTY_DEVNUM, 1, &mty_devio, NULL};
|
||||||
|
|
||||||
|
MTAB mty_mod[] = {
|
||||||
|
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL, NULL, NULL, "7 bit mode" },
|
||||||
|
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL, NULL, NULL, "7 bit mode - non printing suppressed" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
|
||||||
|
&tmxr_dscln, NULL, &mty_desc, "Disconnect a specific line" },
|
||||||
|
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
|
||||||
|
NULL, &tmxr_show_summ, (void *) &mty_desc, "Display a summary of line states" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &mty_desc, "Display current connections" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &mty_desc, "Display multiplexer statistics" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE mty_dev = {
|
||||||
|
MTY_NAME, mty_unit, NULL, mty_mod,
|
||||||
|
1, 8, 0, 1, 8, 36,
|
||||||
|
NULL, NULL, mty_reset, NULL, mty_attach, mty_detach,
|
||||||
|
&mty_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, mty_help, NULL, NULL, mty_description
|
||||||
|
};
|
||||||
|
|
||||||
|
static t_stat mty_devio(uint32 dev, uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &mty_dev;
|
||||||
|
TMLN *lp;
|
||||||
|
int line;
|
||||||
|
uint64 word;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case CONO:
|
||||||
|
sim_debug(DEBUG_CONO, &mty_dev, "%06llo\n", *data);
|
||||||
|
status &= ~MTY_CONO_BITS;
|
||||||
|
status |= *data & MTY_CONO_BITS;
|
||||||
|
line = (status & MTY_LINE) >> 12;
|
||||||
|
if (*data & MTY_STOP) {
|
||||||
|
status &= ~MTY_ODONE;
|
||||||
|
/* Set txdone so future calls to tmxr_txdone_ln will
|
||||||
|
return -1 rather than 1. */
|
||||||
|
mty_ldsc[line].txdone = 1;
|
||||||
|
sim_debug(DEBUG_CMD, &mty_dev, "Clear output done line %d\n",
|
||||||
|
line);
|
||||||
|
}
|
||||||
|
if (*data & MTY_RQINT) {
|
||||||
|
status |= MTY_ODONE;
|
||||||
|
sim_debug(DEBUG_CMD, &mty_dev, "Request interrupt line %d\n",
|
||||||
|
line);
|
||||||
|
}
|
||||||
|
if ((*data & (MTY_STOP | MTY_RQINT)) == 0)
|
||||||
|
sim_debug(DEBUG_CMD, &mty_dev, "Select line %d\n",
|
||||||
|
line);
|
||||||
|
break;
|
||||||
|
case CONI:
|
||||||
|
*data = status & MTY_CONI_BITS;
|
||||||
|
sim_debug(DEBUG_CONI, &mty_dev, "%06llo\n", *data);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
line = (status & MTY_LINE) >> 12;
|
||||||
|
word = *data;
|
||||||
|
sim_debug(DEBUG_DATAIO, &mty_dev, "DATAO line %d -> %012llo\n",
|
||||||
|
line, *data);
|
||||||
|
lp = &mty_ldsc[line];
|
||||||
|
if (!mty_ldsc[line].conn)
|
||||||
|
/* If the line isn't connected, clear txdone to force
|
||||||
|
tmxr_txdone_ln to return 1 rather than -1. */
|
||||||
|
mty_ldsc[line].txdone = 0;
|
||||||
|
/* Write up to five characters extracted from a word. NUL can
|
||||||
|
only be in the first character. */
|
||||||
|
ch = (word >> 29) & 0177;
|
||||||
|
tmxr_putc_ln (lp, sim_tt_outcvt(ch, TT_GET_MODE (mty_unit[0].flags)));
|
||||||
|
while ((ch = (word >> 22) & 0177) != 0) {
|
||||||
|
tmxr_putc_ln (lp, sim_tt_outcvt(ch, TT_GET_MODE (mty_unit[0].flags)));
|
||||||
|
|
||||||
|
word <<= 7;
|
||||||
|
}
|
||||||
|
status &= ~MTY_ODONE;
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
line = (status & MTY_LINE) >> 12;
|
||||||
|
lp = &mty_ldsc[line];
|
||||||
|
*data = tmxr_getc_ln (lp) & 0177;
|
||||||
|
sim_debug(DEBUG_DATAIO, &mty_dev, "DATAI line %d -> %012llo\n",
|
||||||
|
line, *data);
|
||||||
|
status &= ~MTY_IDONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & MTY_DONE)
|
||||||
|
set_interrupt(MTY_DEVNUM, status & MTY_PIA);
|
||||||
|
else
|
||||||
|
clr_interrupt(MTY_DEVNUM);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat mty_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
static int scan = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* High speed device, poll every 0.1 ms. */
|
||||||
|
sim_activate_after (uptr, 100);
|
||||||
|
|
||||||
|
i = tmxr_poll_conn (&mty_desc);
|
||||||
|
if (i >= 0) {
|
||||||
|
mty_ldsc[i].conn = 1;
|
||||||
|
mty_ldsc[i].rcve = 1;
|
||||||
|
mty_ldsc[i].xmte = 1;
|
||||||
|
/* Set txdone so tmxr_txdone_ln will not return return 1 on
|
||||||
|
the first call after a new connection. */
|
||||||
|
mty_ldsc[i].txdone = 1;
|
||||||
|
sim_debug(DEBUG_CMD, &mty_dev, "Connect %d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmxr_poll_rx (&mty_desc);
|
||||||
|
tmxr_poll_tx (&mty_desc);
|
||||||
|
|
||||||
|
for (i = 0; i < MTY_LINES; i++) {
|
||||||
|
/* Round robin scan 32 lines. */
|
||||||
|
scan = (scan + 1) & 037;
|
||||||
|
|
||||||
|
/* 1 means the line became ready since the last check. Ignore
|
||||||
|
-1 which means "still ready". */
|
||||||
|
if (tmxr_txdone_ln (&mty_ldsc[scan]) == 1) {
|
||||||
|
sim_debug(DEBUG_DETAIL, &mty_dev, "Output ready line %d\n", scan);
|
||||||
|
status &= ~MTY_LINE;
|
||||||
|
status |= scan << 12;
|
||||||
|
status |= MTY_ODONE;
|
||||||
|
set_interrupt(MTY_DEVNUM, status & MTY_PIA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mty_ldsc[scan].conn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tmxr_input_pending_ln (&mty_ldsc[scan])) {
|
||||||
|
sim_debug(DEBUG_DETAIL, &mty_dev, "Input ready line %d\n", scan);
|
||||||
|
status &= ~MTY_LINE;
|
||||||
|
status |= scan << 12;
|
||||||
|
status |= MTY_IDONE;
|
||||||
|
set_interrupt(MTY_DEVNUM, status & MTY_PIA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat mty_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
sim_debug(DEBUG_CMD, &mty_dev, "Reset\n");
|
||||||
|
if (mty_unit->flags & UNIT_ATT)
|
||||||
|
sim_activate (mty_unit, tmxr_poll);
|
||||||
|
else
|
||||||
|
sim_cancel (mty_unit);
|
||||||
|
|
||||||
|
status = 0;
|
||||||
|
clr_interrupt(MTY_DEVNUM);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat mty_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat stat;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
stat = tmxr_attach (&mty_desc, uptr, cptr);
|
||||||
|
for (i = 0; i < MTY_LINES; i++) {
|
||||||
|
mty_ldsc[i].rcve = 0;
|
||||||
|
mty_ldsc[i].xmte = 0;
|
||||||
|
/* Set txdone so tmxr_txdone_ln will not return return 1 on
|
||||||
|
the first call. */
|
||||||
|
mty_ldsc[i].txdone = 1;
|
||||||
|
}
|
||||||
|
if (stat == SCPE_OK) {
|
||||||
|
status = 0;
|
||||||
|
sim_activate (uptr, tmxr_poll);
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat mty_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat stat = tmxr_detach (&mty_desc, uptr);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MTY_LINES; i++) {
|
||||||
|
mty_ldsc[i].rcve = 0;
|
||||||
|
mty_ldsc[i].xmte = 0;
|
||||||
|
}
|
||||||
|
status = 0;
|
||||||
|
sim_cancel (uptr);
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat mty_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "MTY Morton box terminal multiplexor\n\n");
|
||||||
|
fprintf (st, "The MTY supported 32 high-speed lines at up to 80 bits/second.\n");
|
||||||
|
fprintf (st, "this simulation.\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, "Terminals can be set to one of three modes: 7P, 7B, or 8B.\n\n");
|
||||||
|
fprintf (st, " mode input characters output characters\n\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 7B.\n\n");
|
||||||
|
fprintf (st, "Once MTY 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 MTY DISCONNECT command, or a DETACH MTY command.\n\n");
|
||||||
|
fprintf (st, "Other special commands:\n\n");
|
||||||
|
fprintf (st, " sim> SHOW MTY CONNECTIONS show current connections\n");
|
||||||
|
fprintf (st, " sim> SHOW MTY STATISTICS show statistics for active connections\n");
|
||||||
|
fprintf (st, " sim> SET MTYn DISCONNECT disconnects the specified line.\n");
|
||||||
|
fprint_reg_help (st, &dc_dev);
|
||||||
|
fprintf (st, "\nThe terminals do not support save and restore. All open connections\n");
|
||||||
|
fprintf (st, "are lost when the simulator shuts down or MTY is detached.\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *mty_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Morton box: Terminal multiplexor";
|
||||||
|
}
|
||||||
|
#endif
|
127
PDP10/ka10_pd.c
Normal file
127
PDP10/ka10_pd.c
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/* ka10_pd.c: DeCoriolis clock.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is a device which keeps track of the time and date. An access
|
||||||
|
will return the number of ticks since the beginning of the year.
|
||||||
|
There are 60 ticks per second. The device was made by Paul
|
||||||
|
DeCoriolis at MIT.
|
||||||
|
|
||||||
|
When used with a KL10, the clock was part of the KL-UDGE board
|
||||||
|
which could also provide a 60 Hz interrupt and set console lights.
|
||||||
|
This is not needed on a KA10, so it's not implemented here.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_PD
|
||||||
|
#define NUM_DEVS_PD 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_PD > 0)
|
||||||
|
|
||||||
|
#define PD_DEVNUM 0500
|
||||||
|
#define PD_OFF (1 << DEV_V_UF)
|
||||||
|
|
||||||
|
t_stat pd_devio(uint32 dev, uint64 *data);
|
||||||
|
const char *pd_description (DEVICE *dptr);
|
||||||
|
t_stat pd_set_on(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat pd_set_off(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat pd_show_on(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||||
|
|
||||||
|
UNIT pd_unit[] = {
|
||||||
|
{UDATA(NULL, UNIT_DISABLE, 0)}, /* 0 */
|
||||||
|
};
|
||||||
|
DIB pd_dib = {PD_DEVNUM, 1, &pd_devio, NULL};
|
||||||
|
|
||||||
|
MTAB pd_mod[] = {
|
||||||
|
{ MTAB_VDV, 0, "ON", "ON", pd_set_on, pd_show_on },
|
||||||
|
{ MTAB_VDV, PD_OFF, NULL, "OFF", pd_set_off },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE pd_dev = {
|
||||||
|
"PD", pd_unit, NULL, pd_mod,
|
||||||
|
1, 8, 0, 1, 8, 36,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
&pd_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, &pd_description
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint64 pd_ticks (void)
|
||||||
|
{
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm *x = localtime(&t);
|
||||||
|
uint64 seconds;
|
||||||
|
seconds = 86400ULL * x->tm_yday;
|
||||||
|
seconds += 3600ULL * x->tm_hour;
|
||||||
|
seconds += 60ULL * x->tm_min;
|
||||||
|
seconds += x->tm_sec;
|
||||||
|
// We could add individual ticks here, but there's no pressing need.
|
||||||
|
return 60ULL * seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat pd_devio(uint32 dev, uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &pd_dev;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case DATAI:
|
||||||
|
if (dptr->flags & PD_OFF)
|
||||||
|
*data = 0;
|
||||||
|
else
|
||||||
|
*data = pd_ticks();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *pd_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Paul DeCoriolis clock";
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat pd_set_on(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &pd_dev;
|
||||||
|
dptr->flags &= ~PD_OFF;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat pd_set_off(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &pd_dev;
|
||||||
|
dptr->flags |= PD_OFF;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat pd_show_on(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &pd_dev;
|
||||||
|
fprintf (st, "%s", (dptr->flags & PD_OFF) ? "off" : "on");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
2436
PDP10/ka10_pmp.c
Normal file
2436
PDP10/ka10_pmp.c
Normal file
File diff suppressed because it is too large
Load diff
397
PDP10/ka10_stk.c
Normal file
397
PDP10/ka10_stk.c
Normal file
|
@ -0,0 +1,397 @@
|
||||||
|
/* ka10_stk.c: Stanford keyboard.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is a device which interfaces with a Stanford keyboard. It's
|
||||||
|
specific to the MIT AI lab PDP-10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "sim_video.h"
|
||||||
|
#include "display/display.h"
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifdef USE_DISPLAY
|
||||||
|
#if NUM_DEVS_STK > 0
|
||||||
|
#define STK_DEVNUM 070
|
||||||
|
|
||||||
|
/* CONI/O bits. */
|
||||||
|
#define STK_PIA 0000007
|
||||||
|
#define STK_DONE 0000010
|
||||||
|
|
||||||
|
/* Bucky bits. */
|
||||||
|
#define SHFT 00100
|
||||||
|
#define CTRL 00200
|
||||||
|
#define TOP 00400
|
||||||
|
#define META 01000
|
||||||
|
|
||||||
|
static t_stat stk_svc (UNIT *uptr);
|
||||||
|
static t_stat stk_devio(uint32 dev, uint64 *data);
|
||||||
|
static t_stat stk_reset (DEVICE *dptr);
|
||||||
|
static const char *stk_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
static uint64 status = 0;
|
||||||
|
static int key_code = 0;
|
||||||
|
|
||||||
|
UNIT stk_unit[] = {
|
||||||
|
{UDATA(stk_svc, UNIT_DISABLE, 0)}, /* 0 */
|
||||||
|
};
|
||||||
|
DIB stk_dib = {STK_DEVNUM, 1, &stk_devio, NULL};
|
||||||
|
|
||||||
|
MTAB stk_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE stk_dev = {
|
||||||
|
"STK", stk_unit, NULL, stk_mod,
|
||||||
|
1, 8, 0, 1, 8, 36,
|
||||||
|
NULL, NULL, &stk_reset, NULL, NULL, NULL,
|
||||||
|
&stk_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, &stk_description
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Special key codes. */
|
||||||
|
#define CR 033
|
||||||
|
#define BKSL 034
|
||||||
|
#define LF 035
|
||||||
|
#define TAB 045
|
||||||
|
#define FF 046
|
||||||
|
#define VT 047
|
||||||
|
#define BS 074
|
||||||
|
#define ALT 077 /* Not sure if 42, 75, 76, or 77. */
|
||||||
|
|
||||||
|
/* This maps ASCII codes to Stanford key codes plus bucky bits. */
|
||||||
|
static int translate[] = {
|
||||||
|
0, CTRL|001,CTRL|002,CTRL|003,CTRL|004,CTRL|005,CTRL|006,CTRL|007,
|
||||||
|
CTRL|010,TAB, LF, VT, FF, CR, CTRL|016,CTRL|017,
|
||||||
|
CTRL|020,CTRL|021,CTRL|022,CTRL|023,CTRL|024,CTRL|025,CTRL|026,CTRL|027,
|
||||||
|
CTRL|030,CTRL|031,CTRL|032,ALT, CTRL|034,CTRL|035,0, CTRL|037,
|
||||||
|
' ', SHFT|',',TOP|031, TOP|022, SHFT|'6',SHFT|'7',TOP|024, TOP|011,
|
||||||
|
'(', ')', '*', '+', ',', '-', '.', '/',
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', ':', ';', TOP|004, TOP|010, TOP|006, TOP|'.',
|
||||||
|
TOP|005, SHFT|001,SHFT|002,SHFT|003,SHFT|004,SHFT|005,SHFT|006,SHFT|007,
|
||||||
|
SHFT|010,SHFT|011,SHFT|012,SHFT|013,SHFT|014,SHFT|015,SHFT|016,SHFT|017,
|
||||||
|
SHFT|020,SHFT|021,SHFT|022,SHFT|023,SHFT|024,SHFT|025,SHFT|026,SHFT|027,
|
||||||
|
SHFT|030,SHFT|031,SHFT|032,TOP|'(', BKSL, TOP|')', 0, TOP|'9',
|
||||||
|
TOP|025, 001, 002, 003, 004, 005, 006, 007,
|
||||||
|
010, 011, 012, 013, 014, 015, 016, 017,
|
||||||
|
020, 021, 022, 023, 024, 025, 026, 027,
|
||||||
|
030, 031, 032, TOP|017, SHFT|'+',TOP|020, SHFT|'8',BS
|
||||||
|
};
|
||||||
|
|
||||||
|
static int bucky = 0;
|
||||||
|
|
||||||
|
static int stk_modifiers (SIM_KEY_EVENT *kev)
|
||||||
|
{
|
||||||
|
if (kev->state == SIM_KEYPRESS_DOWN) {
|
||||||
|
switch (kev->key) {
|
||||||
|
case SIM_KEY_SHIFT_L:
|
||||||
|
case SIM_KEY_SHIFT_R:
|
||||||
|
bucky |= SHFT;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_CTRL_L:
|
||||||
|
case SIM_KEY_CTRL_R:
|
||||||
|
case SIM_KEY_CAPS_LOCK:
|
||||||
|
bucky |= CTRL;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_WIN_L:
|
||||||
|
case SIM_KEY_WIN_R:
|
||||||
|
bucky |= TOP;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_ALT_L:
|
||||||
|
case SIM_KEY_ALT_R:
|
||||||
|
bucky |= META;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (kev->state == SIM_KEYPRESS_UP) {
|
||||||
|
switch (kev->key) {
|
||||||
|
case SIM_KEY_SHIFT_L:
|
||||||
|
case SIM_KEY_SHIFT_R:
|
||||||
|
bucky &= ~SHFT;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_CTRL_L:
|
||||||
|
case SIM_KEY_CTRL_R:
|
||||||
|
case SIM_KEY_CAPS_LOCK:
|
||||||
|
bucky &= ~CTRL;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_WIN_L:
|
||||||
|
case SIM_KEY_WIN_R:
|
||||||
|
bucky &= ~TOP;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_ALT_L:
|
||||||
|
case SIM_KEY_ALT_R:
|
||||||
|
bucky &= ~META;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stk_keys (SIM_KEY_EVENT *kev)
|
||||||
|
{
|
||||||
|
if (kev->state == SIM_KEYPRESS_UP)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (kev->key) {
|
||||||
|
case SIM_KEY_0:
|
||||||
|
key_code = bucky | '+';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_1:
|
||||||
|
key_code = bucky | '1';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_2:
|
||||||
|
key_code = bucky | '2';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_3:
|
||||||
|
key_code = bucky | '3';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_4:
|
||||||
|
key_code = bucky | '4';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_5:
|
||||||
|
key_code = bucky | '5';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_6:
|
||||||
|
key_code = bucky | '6';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_7:
|
||||||
|
key_code = bucky | '7';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_8:
|
||||||
|
key_code = bucky | '8';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_9:
|
||||||
|
key_code = bucky | '9';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_A:
|
||||||
|
key_code = bucky | 001;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_B:
|
||||||
|
key_code = bucky | 002;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_C:
|
||||||
|
key_code = bucky | 003;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_D:
|
||||||
|
key_code = bucky | 004;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_E:
|
||||||
|
key_code = bucky | 005;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_F:
|
||||||
|
key_code = bucky | 006;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_G:
|
||||||
|
key_code = bucky | 007;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_H:
|
||||||
|
key_code = bucky | 010;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_I:
|
||||||
|
key_code = bucky | 011;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_J:
|
||||||
|
key_code = bucky | 012;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_K:
|
||||||
|
key_code = bucky | 013;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_L:
|
||||||
|
key_code = bucky | 014;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_M:
|
||||||
|
key_code = bucky | 015;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_N:
|
||||||
|
key_code = bucky | 016;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_O:
|
||||||
|
key_code = bucky | 017;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_P:
|
||||||
|
key_code = bucky | 020;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_Q:
|
||||||
|
key_code = bucky | 021;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_R:
|
||||||
|
key_code = bucky | 022;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_S:
|
||||||
|
key_code = bucky | 023;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_T:
|
||||||
|
key_code = bucky | 024;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_U:
|
||||||
|
key_code = bucky | 025;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_V:
|
||||||
|
key_code = bucky | 026;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_W:
|
||||||
|
key_code = bucky | 027;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_X:
|
||||||
|
key_code = bucky | 030;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_Y:
|
||||||
|
key_code = bucky | 031;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_Z:
|
||||||
|
key_code = bucky | 032;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_BACKQUOTE:
|
||||||
|
key_code = bucky | '0';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_MINUS:
|
||||||
|
key_code = bucky | '-';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_EQUALS:
|
||||||
|
key_code = bucky | '*';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_LEFT_BRACKET:
|
||||||
|
key_code = bucky | '(';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_RIGHT_BRACKET:
|
||||||
|
key_code = bucky | ')';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_SEMICOLON:
|
||||||
|
key_code = bucky | ';';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_SINGLE_QUOTE:
|
||||||
|
key_code = bucky | ':';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_BACKSLASH:
|
||||||
|
key_code = bucky | BKSL;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_LEFT_BACKSLASH:
|
||||||
|
key_code = bucky | BKSL;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_COMMA:
|
||||||
|
key_code = bucky | ',';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_PERIOD:
|
||||||
|
key_code = bucky | '.';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_SLASH:
|
||||||
|
key_code = bucky | '/';
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_ESC:
|
||||||
|
key_code = bucky | ALT;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_BACKSPACE:
|
||||||
|
case SIM_KEY_DELETE:
|
||||||
|
key_code = bucky | BS;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_TAB:
|
||||||
|
key_code = bucky | TAB;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_ENTER:
|
||||||
|
key_code = bucky | CR;
|
||||||
|
return 1;
|
||||||
|
case SIM_KEY_SPACE:
|
||||||
|
key_code = bucky | ' ';
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stk_keyboard (SIM_KEY_EVENT *kev)
|
||||||
|
{
|
||||||
|
if (stk_modifiers (kev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (stk_keys (kev)) {
|
||||||
|
status |= STK_DONE;
|
||||||
|
set_interrupt(STK_DEVNUM, status & STK_PIA);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat stk_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int c = SCPE_OK;
|
||||||
|
|
||||||
|
#ifdef USE_DISPLAY
|
||||||
|
if (display_last_char) {
|
||||||
|
c = display_last_char | SCPE_KFLAG;
|
||||||
|
display_last_char = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (c & SCPE_KFLAG) {
|
||||||
|
key_code = translate[c & 0177];
|
||||||
|
status |= STK_DONE;
|
||||||
|
set_interrupt(STK_DEVNUM, status & STK_PIA);
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_activate (uptr, 100000);
|
||||||
|
|
||||||
|
if (c & SCPE_KFLAG)
|
||||||
|
return SCPE_OK;
|
||||||
|
else
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat stk_devio(uint32 dev, uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &stk_dev;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case CONO:
|
||||||
|
status &= ~STK_PIA;
|
||||||
|
status |= *data & STK_PIA;
|
||||||
|
if (status & STK_PIA)
|
||||||
|
sim_activate (stk_unit, 1);
|
||||||
|
else
|
||||||
|
sim_cancel (stk_unit);
|
||||||
|
break;
|
||||||
|
case CONI:
|
||||||
|
*data = status;
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
status &= ~STK_DONE;
|
||||||
|
clr_interrupt(STK_DEVNUM);
|
||||||
|
*data = key_code;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat stk_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
vid_display_kb_event_process = stk_keyboard;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *stk_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Stanford keyboard";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
417
PDP10/ka10_ten11.c
Normal file
417
PDP10/ka10_ten11.c
Normal file
|
@ -0,0 +1,417 @@
|
||||||
|
/* ka10_ten11.c: Rubin 10-11 interface.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is a device which interfaces with eight Unibuses. It's
|
||||||
|
specific to the MIT AI lab PDP-10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
#include "sim_tmxr.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_TEN11
|
||||||
|
#define NUM_DEVS_TEN11 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_TEN11 > 0)
|
||||||
|
#include <fcntl.h>
|
||||||
|
//#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
//#include <sys/socket.h>
|
||||||
|
//#include <netinet/in.h>
|
||||||
|
//#include <netinet/tcp.h>
|
||||||
|
//#include <arpa/inet.h>
|
||||||
|
|
||||||
|
/* Rubin 10-11 pager. */
|
||||||
|
static uint64 ten11_pager[256];
|
||||||
|
|
||||||
|
/* Physical address of 10-11 control page. */
|
||||||
|
#define T11CPA 03776000
|
||||||
|
|
||||||
|
/* Bits in a 10-11 page table entry. */
|
||||||
|
#define T11VALID (0400000000000LL)
|
||||||
|
#define T11WRITE (0200000000000LL)
|
||||||
|
#define T11PDP11 (0003400000000LL)
|
||||||
|
#define T11ADDR (0000377776000LL)
|
||||||
|
#define T11LIMIT (0000000001777LL)
|
||||||
|
|
||||||
|
/* External Unibus interface. */
|
||||||
|
#define DATO 1
|
||||||
|
#define DATI 2
|
||||||
|
#define ACK 3
|
||||||
|
#define ERR 4
|
||||||
|
#define TIMEOUT 5
|
||||||
|
|
||||||
|
#define TEN11_POLL 100
|
||||||
|
|
||||||
|
/* Simulator time units for a Unibus memory cycle. */
|
||||||
|
#define UNIBUS_MEM_CYCLE 100
|
||||||
|
|
||||||
|
|
||||||
|
static t_stat ten11_svc (UNIT *uptr);
|
||||||
|
static t_stat ten11_reset (DEVICE *dptr);
|
||||||
|
static t_stat ten11_attach (UNIT *uptr, CONST char *ptr);
|
||||||
|
static t_stat ten11_detach (UNIT *uptr);
|
||||||
|
static t_stat ten11_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
|
static const char *ten11_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
UNIT ten11_unit[1] = {
|
||||||
|
{ UDATA (&ten11_svc, UNIT_IDLE|UNIT_ATTABLE, 0), 1000 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static REG ten11_reg[] = {
|
||||||
|
{ DRDATAD (POLL, ten11_unit[0].wait, 24, "poll interval"), PV_LEFT },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static MTAB ten11_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DBG_TRC 1
|
||||||
|
#define DBG_CMD 2
|
||||||
|
|
||||||
|
static DEBTAB ten11_debug[] = {
|
||||||
|
{"TRACE", DBG_TRC, "Routine trace"},
|
||||||
|
{"CMD", DBG_CMD, "Command Processing"},
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE ten11_dev = {
|
||||||
|
"TEN11", ten11_unit, ten11_reg, ten11_mod,
|
||||||
|
1, 8, 16, 2, 8, 16,
|
||||||
|
NULL, /* examine */
|
||||||
|
NULL, /* deposit */
|
||||||
|
&ten11_reset, /* reset */
|
||||||
|
NULL, /* boot */
|
||||||
|
ten11_attach, /* attach */
|
||||||
|
ten11_detach, /* detach */
|
||||||
|
NULL, /* context */
|
||||||
|
DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX,
|
||||||
|
DBG_CMD, /* debug control */
|
||||||
|
ten11_debug, /* debug flags */
|
||||||
|
NULL, /* memory size chage */
|
||||||
|
NULL, /* logical name */
|
||||||
|
NULL, /* help */
|
||||||
|
&ten11_attach_help, /* attach help */
|
||||||
|
NULL, /* help context */
|
||||||
|
&ten11_description, /* description */
|
||||||
|
};
|
||||||
|
|
||||||
|
static TMLN ten11_ldsc; /* line descriptor */
|
||||||
|
static TMXR ten11_desc = { 1, 0, 0, &ten11_ldsc }; /* mux descriptor */
|
||||||
|
|
||||||
|
static t_stat ten11_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
sim_debug(DBG_TRC, dptr, "ten11_reset()\n");
|
||||||
|
|
||||||
|
ten11_unit[0].flags |= UNIT_ATTABLE | UNIT_IDLE;
|
||||||
|
ten11_desc.packet = TRUE;
|
||||||
|
ten11_desc.notelnet = TRUE;
|
||||||
|
ten11_desc.buffered = 2048;
|
||||||
|
|
||||||
|
if (ten11_unit[0].flags & UNIT_ATT)
|
||||||
|
sim_activate (&ten11_unit[0], 1000);
|
||||||
|
else
|
||||||
|
sim_cancel (&ten11_unit[0]);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat ten11_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (!cptr || !*cptr)
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (!(uptr->flags & UNIT_ATTABLE))
|
||||||
|
return SCPE_NOATT;
|
||||||
|
r = tmxr_attach_ex (&ten11_desc, uptr, cptr, FALSE);
|
||||||
|
if (r != SCPE_OK) /* error? */
|
||||||
|
return r;
|
||||||
|
sim_debug(DBG_TRC, &ten11_dev, "activate connection\n");
|
||||||
|
sim_activate (uptr, 10); /* start poll */
|
||||||
|
uptr->flags |= UNIT_ATT;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat ten11_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (!(uptr->flags & UNIT_ATT))
|
||||||
|
return SCPE_OK;
|
||||||
|
sim_cancel (uptr);
|
||||||
|
r = tmxr_detach (&ten11_desc, uptr);
|
||||||
|
uptr->flags &= ~UNIT_ATT;
|
||||||
|
free (uptr->filename);
|
||||||
|
uptr->filename = NULL;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build (unsigned char *request, unsigned char octet)
|
||||||
|
{
|
||||||
|
request[0]++;
|
||||||
|
request[request[0]] = octet;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat ten11_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
tmxr_poll_rx (&ten11_desc);
|
||||||
|
if (ten11_ldsc.rcve && !ten11_ldsc.conn) {
|
||||||
|
ten11_ldsc.rcve = 0;
|
||||||
|
tmxr_reset_ln (&ten11_ldsc);
|
||||||
|
}
|
||||||
|
if (tmxr_poll_conn(&ten11_desc) >= 0) {
|
||||||
|
sim_debug(DBG_CMD, &ten11_dev, "got connection\n");
|
||||||
|
ten11_ldsc.rcve = 1;
|
||||||
|
uptr->wait = TEN11_POLL;
|
||||||
|
}
|
||||||
|
sim_activate (uptr, uptr->wait);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat ten11_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
const char helpString[] =
|
||||||
|
/* The '*'s in the next line represent the standard text width of a help line */
|
||||||
|
/****************************************************************************/
|
||||||
|
" The %D device is an implementation of the Rubin PDP-10 to PDP-11 interface\n"
|
||||||
|
" facility. This allows a PDP 10 system to reach into a PDP-11 simulator\n"
|
||||||
|
" and modify or access the contents of the PDP-11 memory.\n\n"
|
||||||
|
" The device must be attached to a receive port, this is done by using the\n"
|
||||||
|
" ATTACH command to specify the receive port number.\n"
|
||||||
|
"\n"
|
||||||
|
"+sim> ATTACH %U port\n"
|
||||||
|
"\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
return scp_help (st, dptr, uptr, flag, helpString, cptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *ten11_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Rubin PDP-10 to PDP-11 interface";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int error (const char *message)
|
||||||
|
{
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev, "%s\r\n", message);
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev, "CLOSE\r\n");
|
||||||
|
ten11_ldsc.rcve = 0;
|
||||||
|
tmxr_reset_ln (&ten11_ldsc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int transaction (unsigned char *request, unsigned char *response)
|
||||||
|
{
|
||||||
|
const uint8 *ten11_request;
|
||||||
|
size_t size;
|
||||||
|
t_stat stat;
|
||||||
|
|
||||||
|
stat = tmxr_put_packet_ln (&ten11_ldsc, request + 1, (size_t)request[0]);
|
||||||
|
if (stat != SCPE_OK)
|
||||||
|
return error ("Write error in transaction");
|
||||||
|
|
||||||
|
do {
|
||||||
|
tmxr_poll_rx (&ten11_desc);
|
||||||
|
stat = tmxr_get_packet_ln (&ten11_ldsc, &ten11_request, &size);
|
||||||
|
} while (stat != SCPE_OK || size == 0);
|
||||||
|
|
||||||
|
if (size > 7)
|
||||||
|
return error ("Malformed transaction");
|
||||||
|
|
||||||
|
memcpy (response, ten11_request, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_word (int addr, int *data)
|
||||||
|
{
|
||||||
|
unsigned char request[8];
|
||||||
|
unsigned char response[8];
|
||||||
|
|
||||||
|
sim_interval -= UNIBUS_MEM_CYCLE;
|
||||||
|
|
||||||
|
if ((ten11_unit[0].flags & UNIT_ATT) == 0) {
|
||||||
|
*data = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (request, 0, sizeof request);
|
||||||
|
build (request, DATI);
|
||||||
|
build (request, (addr >> 16) & 0377);
|
||||||
|
build (request, (addr >> 8) & 0377);
|
||||||
|
build (request, (addr) & 0377);
|
||||||
|
|
||||||
|
transaction (request, response);
|
||||||
|
|
||||||
|
switch (response[0])
|
||||||
|
{
|
||||||
|
case ACK:
|
||||||
|
*data = response[2];
|
||||||
|
*data |= response[1] << 8;
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev, "Read word %06o\n", *data);
|
||||||
|
break;
|
||||||
|
case ERR:
|
||||||
|
fprintf (stderr, "TEN11: Read error %06o\r\n", addr);
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
case TIMEOUT:
|
||||||
|
fprintf (stderr, "TEN11: Read timeout %06o\r\n", addr);
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return error ("Protocol error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ten11_read (int addr, uint64 *data)
|
||||||
|
{
|
||||||
|
int offset = addr & 01777;
|
||||||
|
int word1, word2;
|
||||||
|
|
||||||
|
if (addr >= T11CPA) {
|
||||||
|
/* Accessing the control page. */
|
||||||
|
if (offset >= 0400) {
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev,
|
||||||
|
"Control page read NXM: %o @ %o\n",
|
||||||
|
offset, PC);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*data = ten11_pager[offset];
|
||||||
|
} else {
|
||||||
|
/* Accessing a memory page. */
|
||||||
|
int page = (addr >> 10) & 0377;
|
||||||
|
uint64 mapping = ten11_pager[page];
|
||||||
|
int unibus, uaddr, limit;
|
||||||
|
|
||||||
|
limit = mapping & T11LIMIT;
|
||||||
|
if ((mapping & T11VALID) == 0 || offset > limit) {
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev,
|
||||||
|
"(%o) %07o >= 4,,000000 / %llo / %o > %o\n",
|
||||||
|
page, addr, (mapping & T11VALID), offset, limit);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unibus = (mapping & T11PDP11) >> 26;
|
||||||
|
uaddr = ((mapping & T11ADDR) >> 10) + offset;
|
||||||
|
uaddr <<= 2;
|
||||||
|
|
||||||
|
read_word (uaddr, &word1);
|
||||||
|
read_word (uaddr + 2, &word2);
|
||||||
|
*data = ((uint64)word1 << 20) | (word2 << 4);
|
||||||
|
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev,
|
||||||
|
"Read: (%o) %06o -> %012llo\n",
|
||||||
|
unibus, uaddr, *data);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_word (int addr, uint16 data)
|
||||||
|
{
|
||||||
|
unsigned char request[8];
|
||||||
|
unsigned char response[8];
|
||||||
|
|
||||||
|
sim_interval -= UNIBUS_MEM_CYCLE;
|
||||||
|
|
||||||
|
if ((ten11_unit[0].flags & UNIT_ATT) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (request, 0, sizeof request);
|
||||||
|
build (request, DATO);
|
||||||
|
build (request, (addr >> 16) & 0377);
|
||||||
|
build (request, (addr >> 8) & 0377);
|
||||||
|
build (request, (addr) & 0377);
|
||||||
|
build (request, (data >> 8) & 0377);
|
||||||
|
build (request, (data) & 0377);
|
||||||
|
|
||||||
|
transaction (request, response);
|
||||||
|
|
||||||
|
switch (response[0])
|
||||||
|
{
|
||||||
|
case ACK:
|
||||||
|
break;
|
||||||
|
case ERR:
|
||||||
|
fprintf (stderr, "TEN11: Write error %06o\r\n", addr);
|
||||||
|
break;
|
||||||
|
case TIMEOUT:
|
||||||
|
fprintf (stderr, "TEN11: Write timeout %06o\r\n", addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return error ("Protocol error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ten11_write (int addr, uint64 data)
|
||||||
|
{
|
||||||
|
int offset = addr & 01777;
|
||||||
|
|
||||||
|
if (addr >= T11CPA) {
|
||||||
|
/* Accessing the control page. */
|
||||||
|
if (offset >= 0400) {
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev,
|
||||||
|
"Control page write NXM: %o @ %o\n",
|
||||||
|
offset, PC);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ten11_pager[offset] = data;
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev,
|
||||||
|
"Page %03o: %s %s (%llo) %06llo/%04llo\n",
|
||||||
|
offset,
|
||||||
|
(data & T11VALID) ? "V" : "I",
|
||||||
|
(data & T11WRITE) ? "RW" : "R",
|
||||||
|
(data & T11PDP11) >> 26,
|
||||||
|
(data & T11ADDR) >> 10,
|
||||||
|
(data & T11LIMIT));
|
||||||
|
} else {
|
||||||
|
/* Accessing a memory page. */
|
||||||
|
int page = (addr >> 10) & 0377;
|
||||||
|
uint64 mapping = ten11_pager[page];
|
||||||
|
int unibus, uaddr, limit;
|
||||||
|
limit = mapping & T11LIMIT;
|
||||||
|
if ((mapping & T11VALID) == 0 || offset > limit) {
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev,
|
||||||
|
"(%o) %07o >= 4,,000000 / %llo / %o > %o\n",
|
||||||
|
page, addr, (mapping & T11VALID), offset, limit);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
unibus = (mapping & T11PDP11) >> 26;
|
||||||
|
uaddr = ((mapping & T11ADDR) >> 10) + offset;
|
||||||
|
uaddr <<= 2;
|
||||||
|
sim_debug (DBG_TRC, &ten11_dev,
|
||||||
|
"Write: (%o) %06o <- %012llo\n",
|
||||||
|
unibus, uaddr, data);
|
||||||
|
|
||||||
|
if ((data & 010) == 0)
|
||||||
|
write_word (uaddr, (data >> 20) & 0177777);
|
||||||
|
if ((data & 004) == 0)
|
||||||
|
write_word (uaddr + 2, (data >> 4) & 0177777);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
329
PDP10/ka10_tk10.c
Normal file
329
PDP10/ka10_tk10.c
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
/* ka10_tk10.c: Knight kludge, TTY scanner.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is a device with 16 terminal ports. It's specific to the MIT
|
||||||
|
AI lab and Dynamic Modeling PDP-10s.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "sim_defs.h"
|
||||||
|
#include "sim_tmxr.h"
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_TK10
|
||||||
|
#define NUM_DEVS_TK10 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_TK10 > 0)
|
||||||
|
|
||||||
|
#define TK10_NAME "TK"
|
||||||
|
#define TK10_DEVNUM 0600 /* Also known as NTY. */
|
||||||
|
#define TK10_LINES 16
|
||||||
|
|
||||||
|
#define TK10_PIA 0000007 /* PI channel assignment */
|
||||||
|
#define TK10_RQINT 0000010 /* Request interrupt. */
|
||||||
|
#define TK10_ODONE 0000020 /* Done flag on typeout. */
|
||||||
|
#define TK10_STOP 0000020 /* Stop interrupting. */
|
||||||
|
#define TK10_IDONE 0000040 /* Done flag on input. */
|
||||||
|
#define TK10_TYI 0007400 /* Input TTY. */
|
||||||
|
#define TK10_TYO 0170000 /* Output TTY. */
|
||||||
|
#define TK10_INT 0200000 /* Interrupt. */
|
||||||
|
#define TK10_CLEAR 0200000 /* Clear interrupt. */
|
||||||
|
#define TK10_SELECT 0400000 /* Select line. */
|
||||||
|
#define TK10_GO 0 /* 0400000 Scanning. */
|
||||||
|
|
||||||
|
#define TK10_CONI_BITS (TK10_PIA | TK10_INT | TK10_TYI | TK10_GO | \
|
||||||
|
TK10_ODONE | TK10_IDONE)
|
||||||
|
|
||||||
|
static t_stat tk10_devio(uint32 dev, uint64 *data);
|
||||||
|
static t_stat tk10_svc (UNIT *uptr);
|
||||||
|
static t_stat tk10_reset (DEVICE *dptr);
|
||||||
|
static t_stat tk10_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
static t_stat tk10_detach (UNIT *uptr);
|
||||||
|
static const char *tk10_description (DEVICE *dptr);
|
||||||
|
static t_stat tk10_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr);
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
|
||||||
|
TMLN tk10_ldsc[TK10_LINES] = { 0 };
|
||||||
|
TMXR tk10_desc = { TK10_LINES, 0, 0, tk10_ldsc };
|
||||||
|
|
||||||
|
static uint64 status = 0;
|
||||||
|
|
||||||
|
UNIT tk10_unit[] = {
|
||||||
|
{UDATA(tk10_svc, TT_MODE_7B|UNIT_ATTABLE|UNIT_DISABLE, 0)}, /* 0 */
|
||||||
|
};
|
||||||
|
DIB tk10_dib = {TK10_DEVNUM, 1, &tk10_devio, NULL};
|
||||||
|
|
||||||
|
MTAB tk10_mod[] = {
|
||||||
|
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL, NULL, NULL, "7 bit mode" },
|
||||||
|
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL, NULL, NULL, "8 bit mode" },
|
||||||
|
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL, NULL, NULL, "7 bit mode - non printing suppressed" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
|
||||||
|
&tmxr_dscln, NULL, &tk10_desc, "Disconnect a specific line" },
|
||||||
|
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
|
||||||
|
NULL, &tmxr_show_summ, (void *) &tk10_desc, "Display a summary of line states" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &tk10_desc, "Display current connections" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &tk10_desc, "Display multiplexer statistics" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE tk10_dev = {
|
||||||
|
TK10_NAME, tk10_unit, NULL, tk10_mod,
|
||||||
|
1, 8, 0, 1, 8, 36,
|
||||||
|
NULL, NULL, tk10_reset, NULL, tk10_attach, tk10_detach,
|
||||||
|
&tk10_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, tk10_help, NULL, NULL, tk10_description
|
||||||
|
};
|
||||||
|
|
||||||
|
static t_stat tk10_devio(uint32 dev, uint64 *data)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = &tk10_dev;
|
||||||
|
TMLN *lp;
|
||||||
|
int port;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
switch(dev & 07) {
|
||||||
|
case CONO:
|
||||||
|
sim_debug(DEBUG_CONO, &tk10_dev, "%06llo\n", *data);
|
||||||
|
if (*data & TK10_CLEAR) {
|
||||||
|
status &= ~TK10_INT;
|
||||||
|
status |= TK10_GO;
|
||||||
|
sim_debug(DEBUG_CMD, &tk10_dev, "Clear interrupt\n");
|
||||||
|
}
|
||||||
|
if (*data & TK10_STOP) {
|
||||||
|
status &= ~TK10_ODONE;
|
||||||
|
if (!(status & TK10_IDONE))
|
||||||
|
status &= ~TK10_INT;
|
||||||
|
/* Set txdone so future calls to tmxr_txdone_ln will
|
||||||
|
return -1 rather than 1. */
|
||||||
|
tk10_ldsc[(status & TK10_TYO) >> 12].txdone = 1;
|
||||||
|
sim_debug(DEBUG_CMD, &tk10_dev, "Clear output done port %lld\n",
|
||||||
|
(status & TK10_TYO) >> 12);
|
||||||
|
}
|
||||||
|
if (*data & TK10_RQINT) {
|
||||||
|
status &= ~TK10_TYI;
|
||||||
|
status |= ((status & TK10_TYO) >> 4) | TK10_ODONE | TK10_INT;
|
||||||
|
sim_debug(DEBUG_CMD, &tk10_dev, "Request interrupt port %lld\n",
|
||||||
|
(status & TK10_TYO) >> 12);
|
||||||
|
}
|
||||||
|
if (*data & TK10_SELECT) {
|
||||||
|
status &= ~TK10_TYO;
|
||||||
|
status |= ((*data) & TK10_TYO);
|
||||||
|
sim_debug(DEBUG_DETAIL, &tk10_dev, "Select port %lld\n",
|
||||||
|
(status & TK10_TYO) >> 12);
|
||||||
|
}
|
||||||
|
status &= ~TK10_PIA;
|
||||||
|
status |= *data & TK10_PIA;
|
||||||
|
break;
|
||||||
|
case CONI:
|
||||||
|
*data = status & TK10_CONI_BITS;
|
||||||
|
sim_debug(DEBUG_CONI, &tk10_dev, "%06llo\n", *data);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
port = (status & TK10_TYO) >> 12;
|
||||||
|
sim_debug(DEBUG_DATAIO, &tk10_dev, "DATAO port %d -> %012llo\n",
|
||||||
|
port, *data);
|
||||||
|
lp = &tk10_ldsc[port];
|
||||||
|
ch = sim_tt_outcvt(*data & 0377, TT_GET_MODE (tk10_unit[0].flags));
|
||||||
|
if (!tk10_ldsc[port].conn)
|
||||||
|
/* If the port isn't connected, clear txdone to force
|
||||||
|
tmxr_txdone_ln to return 1 rather than -1. */
|
||||||
|
tk10_ldsc[port].txdone = 0;
|
||||||
|
tmxr_putc_ln (lp, ch);
|
||||||
|
status &= ~TK10_ODONE;
|
||||||
|
if (!(status & TK10_IDONE)) {
|
||||||
|
status &= ~TK10_INT;
|
||||||
|
status |= TK10_GO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
port = (status & TK10_TYO) >> 12;
|
||||||
|
lp = &tk10_ldsc[port];
|
||||||
|
*data = tmxr_getc_ln (lp);
|
||||||
|
sim_debug(DEBUG_DATAIO, &tk10_dev, "DATAI port %d -> %012llo\n",
|
||||||
|
port, *data);
|
||||||
|
status &= ~TK10_IDONE;
|
||||||
|
if (!(status & TK10_ODONE)) {
|
||||||
|
status &= ~TK10_INT;
|
||||||
|
status |= TK10_GO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & TK10_INT)
|
||||||
|
set_interrupt(TK10_DEVNUM, status & TK10_PIA);
|
||||||
|
else
|
||||||
|
clr_interrupt(TK10_DEVNUM);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat tk10_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
static int scan = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Slow hardware only supported 300 baud teletypes. */
|
||||||
|
sim_activate_after (uptr, 2083);
|
||||||
|
|
||||||
|
i = tmxr_poll_conn (&tk10_desc);
|
||||||
|
if (i >= 0) {
|
||||||
|
tk10_ldsc[i].conn = 1;
|
||||||
|
tk10_ldsc[i].rcve = 1;
|
||||||
|
tk10_ldsc[i].xmte = 1;
|
||||||
|
/* Set txdone so tmxr_txdone_ln will not return return 1 on
|
||||||
|
the first call after a new connection. */
|
||||||
|
tk10_ldsc[i].txdone = 1;
|
||||||
|
sim_debug(DEBUG_CMD, &tk10_dev, "Connect %d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* The GO bit is not yet properly modeled. */
|
||||||
|
if (!(status & TK10_GO))
|
||||||
|
return SCPE_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tmxr_poll_rx (&tk10_desc);
|
||||||
|
tmxr_poll_tx (&tk10_desc);
|
||||||
|
|
||||||
|
for (i = 0; i < TK10_LINES; i++) {
|
||||||
|
/* Round robin scan 16 lines. */
|
||||||
|
scan = (scan + 1) & 017;
|
||||||
|
|
||||||
|
/* 1 means the line became ready since the last check. Ignore
|
||||||
|
-1 which means "still ready". */
|
||||||
|
if (tmxr_txdone_ln (&tk10_ldsc[scan]) == 1) {
|
||||||
|
sim_debug(DEBUG_DETAIL, &tk10_dev, "Output ready port %d\n", scan);
|
||||||
|
status &= ~TK10_TYI;
|
||||||
|
status |= scan << 8;
|
||||||
|
status |= TK10_INT;
|
||||||
|
status &= ~TK10_GO;
|
||||||
|
status |= TK10_ODONE;
|
||||||
|
set_interrupt(TK10_DEVNUM, status & TK10_PIA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tk10_ldsc[scan].conn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tmxr_input_pending_ln (&tk10_ldsc[scan])) {
|
||||||
|
sim_debug(DEBUG_DETAIL, &tk10_dev, "Input ready port %d\n", scan);
|
||||||
|
status &= ~TK10_TYI;
|
||||||
|
status |= scan << 8;
|
||||||
|
status |= TK10_INT;
|
||||||
|
status &= ~TK10_GO;
|
||||||
|
status |= TK10_IDONE;
|
||||||
|
set_interrupt(TK10_DEVNUM, status & TK10_PIA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat tk10_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
sim_debug(DEBUG_CMD, &tk10_dev, "Reset\n");
|
||||||
|
if (tk10_unit->flags & UNIT_ATT)
|
||||||
|
sim_activate (tk10_unit, tmxr_poll);
|
||||||
|
else
|
||||||
|
sim_cancel (tk10_unit);
|
||||||
|
|
||||||
|
status = 0;
|
||||||
|
clr_interrupt(TK10_DEVNUM);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat tk10_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat stat;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
stat = tmxr_attach (&tk10_desc, uptr, cptr);
|
||||||
|
for (i = 0; i < TK10_LINES; i++) {
|
||||||
|
tk10_ldsc[i].rcve = 0;
|
||||||
|
tk10_ldsc[i].xmte = 0;
|
||||||
|
/* Set txdone so tmxr_txdone_ln will not return return 1 on
|
||||||
|
the first call. */
|
||||||
|
tk10_ldsc[i].txdone = 1;
|
||||||
|
}
|
||||||
|
if (stat == SCPE_OK) {
|
||||||
|
status = TK10_GO;
|
||||||
|
sim_activate (uptr, tmxr_poll);
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat tk10_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat stat = tmxr_detach (&tk10_desc, uptr);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < TK10_LINES; i++) {
|
||||||
|
tk10_ldsc[i].rcve = 0;
|
||||||
|
tk10_ldsc[i].xmte = 0;
|
||||||
|
}
|
||||||
|
status = 0;
|
||||||
|
sim_cancel (uptr);
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat tk10_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "TK10 Knight kludge TTY scanner\n\n");
|
||||||
|
fprintf (st, "The TK10 supported 8 or 16 lines, but only the latter is supported by\n");
|
||||||
|
fprintf (st, "this simulation.\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, "Terminals can be set to one of three modes: 7P, 7B, or 8B.\n\n");
|
||||||
|
fprintf (st, " mode input characters output characters\n\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 7B.\n\n");
|
||||||
|
fprintf (st, "Once TK10 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 TK10 DISCONNECT command, or a DETACH TK10 command.\n\n");
|
||||||
|
fprintf (st, "Other special commands:\n\n");
|
||||||
|
fprintf (st, " sim> SHOW TK10 CONNECTIONS show current connections\n");
|
||||||
|
fprintf (st, " sim> SHOW TK10 STATISTICS show statistics for active connections\n");
|
||||||
|
fprintf (st, " sim> SET TK10n DISCONNECT disconnects the specified line.\n");
|
||||||
|
fprint_reg_help (st, &dc_dev);
|
||||||
|
fprintf (st, "\nThe terminals do not support save and restore. All open connections\n");
|
||||||
|
fprintf (st, "are lost when the simulator shuts down or TK10 is detached.\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *tk10_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Knight kludge: TTY scanner";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
260
PDP10/kx10_cp.c
Normal file
260
PDP10/kx10_cp.c
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
/* ka10_cp.c: PDP10 Card Punch
|
||||||
|
|
||||||
|
Copyright (c) 2016-2017, 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.
|
||||||
|
|
||||||
|
This is the standard card punch.
|
||||||
|
|
||||||
|
These units each buffer one record in local memory and signal
|
||||||
|
ready when the buffer is full or empty. The channel must be
|
||||||
|
ready to recieve/transmit data when they are activated since
|
||||||
|
they will transfer their block during chan_cmd. All data is
|
||||||
|
transmitted as BCD characters.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
#include "sim_card.h"
|
||||||
|
#include "sim_defs.h"
|
||||||
|
#if (NUM_DEVS_CP > 0)
|
||||||
|
|
||||||
|
#define UNIT_CDP UNIT_ATTABLE | UNIT_DISABLE | MODE_029
|
||||||
|
|
||||||
|
#define CP_DEVNUM 0110
|
||||||
|
|
||||||
|
|
||||||
|
/* std devices. data structures
|
||||||
|
|
||||||
|
cp_dev Card Punch device descriptor
|
||||||
|
cp_unit Card Punch unit descriptor
|
||||||
|
cp_reg Card Punch register list
|
||||||
|
cp_mod Card Punch modifiers list
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* CONO Bits */
|
||||||
|
#define SET_DATA_REQ 0000010
|
||||||
|
#define CLR_DATA_REQ 0000020
|
||||||
|
#define SET_PUNCH_ON 0000040
|
||||||
|
#define CLR_END_CARD 0000100
|
||||||
|
#define EN_END_CARD 0000200
|
||||||
|
#define DIS_END_CARD 0000400
|
||||||
|
#define CLR_ERROR 0001000
|
||||||
|
#define EN_TROUBLE 0002000
|
||||||
|
#define DIS_TROUBLE 0004000
|
||||||
|
#define EJECT 0010000 /* Finish punch and eject */
|
||||||
|
#define OFFSET_CARD 0040000 /* Offset card stack */
|
||||||
|
#define CLR_PUNCH 0100000 /* Clear Trouble, Error, End */
|
||||||
|
|
||||||
|
/* CONI Bits */
|
||||||
|
#define PIA 0000007
|
||||||
|
#define DATA_REQ 0000010
|
||||||
|
#define PUNCH_ON 0000040
|
||||||
|
#define END_CARD 0000100 /* Eject or column 80 */
|
||||||
|
#define END_CARD_EN 0000200
|
||||||
|
#define CARD_IN_PUNCH 0000400 /* Card ready to punch */
|
||||||
|
#define ERROR 0001000 /* Punch error */
|
||||||
|
#define TROUBLE_EN 0002000
|
||||||
|
#define TROUBLE 0004000 /* Bit 18,22,23, or 21 */
|
||||||
|
#define EJECT_FAIL 0010000 /* Could not eject card 23 */
|
||||||
|
#define PICK_FAIL 0020000 /* Could not pick up card 22 */
|
||||||
|
#define NEED_OPR 0040000 /* Hopper empty, chip full 21 */
|
||||||
|
#define HOPPER_LOW 0100000 /* less 200 cards 20 */
|
||||||
|
#define TEST 0400000 /* In test mode 18 */
|
||||||
|
|
||||||
|
#define STATUS u3
|
||||||
|
#define COL u4
|
||||||
|
|
||||||
|
t_stat cp_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat cp_srv(UNIT *);
|
||||||
|
t_stat cp_reset(DEVICE *);
|
||||||
|
t_stat cp_attach(UNIT *, CONST char *);
|
||||||
|
t_stat cp_detach(UNIT *);
|
||||||
|
t_stat cp_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||||||
|
const char *cp_description(DEVICE *dptr);
|
||||||
|
uint16 cp_buffer[80];
|
||||||
|
|
||||||
|
|
||||||
|
DIB cp_dib = { CP_DEVNUM, 1, cp_devio, NULL};
|
||||||
|
|
||||||
|
UNIT cp_unit = {UDATA(cp_srv, UNIT_CDP, 0), 600 };
|
||||||
|
|
||||||
|
MTAB cp_mod[] = {
|
||||||
|
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||||
|
&sim_card_set_fmt, &sim_card_show_fmt, NULL},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
REG cp_reg[] = {
|
||||||
|
{BRDATA(BUFF, cp_buffer, 16, 16, sizeof(cp_buffer)), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE cp_dev = {
|
||||||
|
"CP", &cp_unit, cp_reg, cp_mod,
|
||||||
|
NUM_DEVS_CP, 8, 15, 1, 8, 8,
|
||||||
|
NULL, NULL, NULL, NULL, &cp_attach, &cp_detach,
|
||||||
|
&cp_dib, DEV_DISABLE | DEV_DEBUG | DEV_CARD, 0, crd_debug,
|
||||||
|
NULL, NULL, &cp_help, NULL, NULL, &cp_description
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Card punch routine
|
||||||
|
*/
|
||||||
|
|
||||||
|
t_stat cp_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &cp_unit;
|
||||||
|
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = uptr->STATUS;
|
||||||
|
sim_debug(DEBUG_CONI, &cp_dev, "CP: CONI %012llo\n", *data);
|
||||||
|
break;
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_debug(DEBUG_CONO, &cp_dev, "CP: CONO %012llo\n", *data);
|
||||||
|
uptr->STATUS &= ~PIA;
|
||||||
|
uptr->STATUS |= *data & PIA;
|
||||||
|
if (*data & CLR_PUNCH) {
|
||||||
|
uptr->STATUS &= ~(TROUBLE|ERROR|END_CARD|END_CARD_EN|TROUBLE_EN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*data & SET_DATA_REQ) {
|
||||||
|
uptr->STATUS |= DATA_REQ;
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
}
|
||||||
|
if (*data & CLR_DATA_REQ)
|
||||||
|
uptr->STATUS &= ~DATA_REQ;
|
||||||
|
if (*data & CLR_END_CARD)
|
||||||
|
uptr->STATUS &= ~END_CARD;
|
||||||
|
if (*data & EN_END_CARD)
|
||||||
|
uptr->STATUS |= END_CARD_EN;
|
||||||
|
if (*data & DIS_END_CARD)
|
||||||
|
uptr->STATUS &= ~END_CARD_EN;
|
||||||
|
if (*data & EN_TROUBLE)
|
||||||
|
uptr->STATUS |= TROUBLE_EN;
|
||||||
|
if (*data & DIS_TROUBLE)
|
||||||
|
uptr->STATUS &= ~TROUBLE_EN;
|
||||||
|
if (*data & EJECT && uptr->STATUS & CARD_IN_PUNCH) {
|
||||||
|
uptr->COL = 80;
|
||||||
|
uptr->STATUS &= ~DATA_REQ;
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
}
|
||||||
|
if ((uptr->STATUS & (TROUBLE|TROUBLE_EN)) == (TROUBLE|TROUBLE_EN))
|
||||||
|
set_interrupt(CP_DEVNUM, uptr->STATUS);
|
||||||
|
if ((uptr->STATUS & (END_CARD|END_CARD_EN)) == (END_CARD|END_CARD_EN))
|
||||||
|
set_interrupt(CP_DEVNUM, uptr->STATUS);
|
||||||
|
if (*data & PUNCH_ON) {
|
||||||
|
uptr->STATUS |= PUNCH_ON;
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
cp_buffer[uptr->COL++] = *data & 0xfff;
|
||||||
|
uptr->STATUS &= ~DATA_REQ;
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_debug(DEBUG_DATAIO, &cp_dev, "CP: DATAO %012llo %d\n", *data,
|
||||||
|
uptr->COL);
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle transfer of data for card punch */
|
||||||
|
t_stat
|
||||||
|
cp_srv(UNIT *uptr) {
|
||||||
|
|
||||||
|
if (uptr->STATUS & PUNCH_ON) {
|
||||||
|
|
||||||
|
uptr->STATUS |= CARD_IN_PUNCH;
|
||||||
|
if (uptr->STATUS & DATA_REQ) {
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (uptr->COL < 80) {
|
||||||
|
if ((uptr->STATUS & DATA_REQ) == 0) {
|
||||||
|
uptr->STATUS |= DATA_REQ;
|
||||||
|
set_interrupt(CP_DEVNUM, uptr->STATUS);
|
||||||
|
}
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
uptr->COL = 0;
|
||||||
|
uptr->STATUS &= ~(PUNCH_ON|CARD_IN_PUNCH);
|
||||||
|
uptr->STATUS |= END_CARD;
|
||||||
|
switch(sim_punch_card(uptr, cp_buffer)) {
|
||||||
|
case CDSE_EOF:
|
||||||
|
case CDSE_EMPTY:
|
||||||
|
uptr->STATUS |= PICK_FAIL|TROUBLE;
|
||||||
|
break;
|
||||||
|
/* If we get here, something is wrong */
|
||||||
|
case CDSE_ERROR:
|
||||||
|
uptr->STATUS |= EJECT_FAIL|TROUBLE;
|
||||||
|
break;
|
||||||
|
case CDSE_OK:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((uptr->STATUS & (TROUBLE|TROUBLE_EN)) == (TROUBLE|TROUBLE_EN))
|
||||||
|
set_interrupt(CP_DEVNUM, uptr->STATUS);
|
||||||
|
if (uptr->STATUS & END_CARD_EN)
|
||||||
|
set_interrupt(CP_DEVNUM, uptr->STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
cp_attach(UNIT * uptr, CONST char *file)
|
||||||
|
{
|
||||||
|
return sim_card_attach(uptr, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
cp_detach(UNIT * uptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (uptr->STATUS & CARD_IN_PUNCH)
|
||||||
|
sim_punch_card(uptr, cp_buffer);
|
||||||
|
return sim_card_detach(uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
cp_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Card Punch\n\n");
|
||||||
|
sim_card_attach_help(st, dptr, uptr, flag, cptr);
|
||||||
|
fprint_set_help(st, dptr);
|
||||||
|
fprint_show_help(st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
cp_description(DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Card Punch";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
6353
PDP10/kx10_cpu.c
Normal file
6353
PDP10/kx10_cpu.c
Normal file
File diff suppressed because it is too large
Load diff
305
PDP10/kx10_cr.c
Normal file
305
PDP10/kx10_cr.c
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
/* ka10_cr.c: PDP10 Card reader.
|
||||||
|
|
||||||
|
Copyright (c) 2016-2017, 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.
|
||||||
|
|
||||||
|
This is the standard card reader.
|
||||||
|
|
||||||
|
These units each buffer one record in local memory and signal
|
||||||
|
ready when the buffer is full or empty. The channel must be
|
||||||
|
ready to recieve/transmit data when they are activated since
|
||||||
|
they will transfer their block during chan_cmd. All data is
|
||||||
|
transmitted as BCD characters.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
#include "sim_card.h"
|
||||||
|
#include "sim_defs.h"
|
||||||
|
#if (NUM_DEVS_CR > 0)
|
||||||
|
|
||||||
|
#define UNIT_CDR UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | MODE_029
|
||||||
|
|
||||||
|
#define CR_DEVNUM 0150
|
||||||
|
|
||||||
|
|
||||||
|
/* std devices. data structures
|
||||||
|
|
||||||
|
cr_dev Card Reader device descriptor
|
||||||
|
cr_unit Card Reader unit descriptor
|
||||||
|
cr_reg Card Reader register list
|
||||||
|
cr_mod Card Reader modifiers list
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* CONO Bits */
|
||||||
|
#define PIA 0000007
|
||||||
|
#define CLR_DRDY 0000010 /* Clear data ready */
|
||||||
|
#define CLR_END_CARD 0000020 /* Clear end of card */
|
||||||
|
#define CLR_EOF 0000040 /* Clear end of File Flag */
|
||||||
|
#define EN_READY 0000100 /* Enable ready irq */
|
||||||
|
#define CLR_DATA_MISS 0000200 /* Clear data miss */
|
||||||
|
#define EN_TROUBLE 0000400 /* Enable trouble IRQ */
|
||||||
|
#define READ_CARD 0001000 /* Read card */
|
||||||
|
#define OFFSET_CARD 0004000
|
||||||
|
#define CLR_READER 0010000 /* Clear reader */
|
||||||
|
/* CONI Bits */
|
||||||
|
#define DATA_RDY 00000010 /* Data ready */
|
||||||
|
#define END_CARD 00000020 /* End of card */
|
||||||
|
#define END_FILE 00000040 /* End of file */
|
||||||
|
#define RDY_READ 00000100 /* Ready to read */
|
||||||
|
#define DATA_MISS 00000200 /* Data missed */
|
||||||
|
#define TROUBLE 00000400 /* Trouble */
|
||||||
|
#define READING 00001000 /* Reading card */
|
||||||
|
#define HOPPER_EMPTY 00002000
|
||||||
|
#define CARD_IN_READ 00004000 /* Card in reader */
|
||||||
|
#define STOP 00010000
|
||||||
|
#define MOTION_ERROR 00020000
|
||||||
|
#define CELL_ERROR 00040000
|
||||||
|
#define PICK_ERROR 00100000
|
||||||
|
#define RDY_READ_EN 00200000
|
||||||
|
#define TROUBLE_EN 00400000
|
||||||
|
|
||||||
|
#define STATUS u3
|
||||||
|
#define COL u4
|
||||||
|
#define DATA u5
|
||||||
|
|
||||||
|
#define CARD_RDY(u) (sim_card_input_hopper_count(u) > 0 || \
|
||||||
|
sim_card_eof(u) == 1)
|
||||||
|
|
||||||
|
t_stat cr_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat cr_srv(UNIT *);
|
||||||
|
t_stat cr_reset(DEVICE *);
|
||||||
|
t_stat cr_attach(UNIT *, CONST char *);
|
||||||
|
t_stat cr_detach(UNIT *);
|
||||||
|
t_stat cr_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||||||
|
const char *cr_description(DEVICE *dptr);
|
||||||
|
uint16 cr_buffer[80];
|
||||||
|
|
||||||
|
DIB cr_dib = { CR_DEVNUM, 1, cr_devio, NULL};
|
||||||
|
|
||||||
|
UNIT cr_unit = {
|
||||||
|
UDATA(cr_srv, UNIT_CDR, 0), 300,
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB cr_mod[] = {
|
||||||
|
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||||
|
&sim_card_set_fmt, &sim_card_show_fmt, NULL},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
REG cr_reg[] = {
|
||||||
|
{BRDATA(BUFF, cr_buffer, 16, 16, sizeof(cr_buffer)), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DEVICE cr_dev = {
|
||||||
|
"CR", &cr_unit, cr_reg, cr_mod,
|
||||||
|
NUM_DEVS_CR, 8, 15, 1, 8, 8,
|
||||||
|
NULL, NULL, NULL, NULL, &cr_attach, &cr_detach,
|
||||||
|
&cr_dib, DEV_DISABLE | DEV_DEBUG | DEV_CARD, 0, crd_debug,
|
||||||
|
NULL, NULL, &cr_help, NULL, NULL, &cr_description
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device entry points for card reader.
|
||||||
|
*/
|
||||||
|
t_stat cr_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &cr_unit;
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
if (uptr->flags & UNIT_ATT &&
|
||||||
|
(uptr->STATUS & (TROUBLE|READING|CARD_IN_READ|END_CARD)) == 0 &&
|
||||||
|
CARD_RDY(uptr)) {
|
||||||
|
uptr->STATUS |= RDY_READ;
|
||||||
|
}
|
||||||
|
*data = uptr->STATUS;
|
||||||
|
sim_debug(DEBUG_CONI, &cr_dev, "CR: CONI %012llo\n", *data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_debug(DEBUG_CONO, &cr_dev, "CR: CONO %012llo\n", *data);
|
||||||
|
if (*data & CLR_READER) {
|
||||||
|
uptr->STATUS = 0;
|
||||||
|
if (!CARD_RDY(uptr))
|
||||||
|
uptr->STATUS |= END_FILE;
|
||||||
|
sim_cancel(uptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->STATUS &= ~(PIA);
|
||||||
|
uptr->STATUS |= *data & PIA;
|
||||||
|
uptr->STATUS &= ~(*data & (CLR_DRDY|CLR_END_CARD|CLR_EOF|CLR_DATA_MISS));
|
||||||
|
if (*data & EN_TROUBLE)
|
||||||
|
uptr->STATUS |= TROUBLE_EN;
|
||||||
|
if (*data & EN_READY)
|
||||||
|
uptr->STATUS |= RDY_READ_EN;
|
||||||
|
if (uptr->flags & UNIT_ATT && *data & READ_CARD) {
|
||||||
|
uptr->STATUS |= READING;
|
||||||
|
uptr->STATUS &= ~(CARD_IN_READ|RDY_READ|DATA_RDY);
|
||||||
|
uptr->COL = 0;
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (CARD_RDY(uptr))
|
||||||
|
uptr->STATUS |= RDY_READ;
|
||||||
|
else
|
||||||
|
uptr->STATUS |= STOP;
|
||||||
|
if (uptr->STATUS & RDY_READ_EN && uptr->STATUS & RDY_READ)
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
if (uptr->STATUS & TROUBLE_EN && uptr->STATUS & TROUBLE)
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
if (uptr->STATUS & DATA_RDY) {
|
||||||
|
*data = uptr->DATA;
|
||||||
|
sim_debug(DEBUG_DATAIO, &cr_dev, "CR: DATAI %012llo\n", *data);
|
||||||
|
uptr->STATUS &= ~DATA_RDY;
|
||||||
|
} else
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle transfer of data for card reader */
|
||||||
|
t_stat
|
||||||
|
cr_srv(UNIT *uptr) {
|
||||||
|
|
||||||
|
/* Read in card, ready to read next one set IRQ */
|
||||||
|
if (uptr->flags & UNIT_ATT /*&& uptr->STATUS & END_CARD*/) {
|
||||||
|
if ((uptr->STATUS & (READING|CARD_IN_READ|RDY_READ)) == 0 &&
|
||||||
|
(CARD_RDY(uptr))) {
|
||||||
|
sim_debug(DEBUG_EXP, &cr_dev, "CR: card ready %d\n",
|
||||||
|
sim_card_input_hopper_count(uptr));
|
||||||
|
uptr->STATUS |= RDY_READ; /* INdicate ready to start reading */
|
||||||
|
if (uptr->STATUS & RDY_READ_EN)
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if new card requested. */
|
||||||
|
if ((uptr->STATUS & (READING|CARD_IN_READ)) == READING) {
|
||||||
|
uptr->STATUS &= ~(END_CARD|RDY_READ);
|
||||||
|
switch(sim_read_card(uptr, cr_buffer)) {
|
||||||
|
case CDSE_EOF:
|
||||||
|
sim_debug(DEBUG_EXP, &cr_dev, "CR: card eof\n");
|
||||||
|
uptr->STATUS &= ~(CARD_IN_READ|READING);
|
||||||
|
uptr->STATUS |= END_FILE;
|
||||||
|
if (sim_card_input_hopper_count(uptr) != 0)
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
case CDSE_EMPTY:
|
||||||
|
sim_debug(DEBUG_EXP, &cr_dev, "CR: card empty\n");
|
||||||
|
uptr->STATUS &= ~(CARD_IN_READ|READING);
|
||||||
|
uptr->STATUS |= HOPPER_EMPTY|TROUBLE|STOP;
|
||||||
|
if (uptr->STATUS & TROUBLE_EN)
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
case CDSE_ERROR:
|
||||||
|
sim_debug(DEBUG_EXP, &cr_dev, "CR: card error\n");
|
||||||
|
uptr->STATUS &= ~(CARD_IN_READ|READING);
|
||||||
|
uptr->STATUS |= TROUBLE|PICK_ERROR|STOP;
|
||||||
|
if (uptr->STATUS & TROUBLE_EN)
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
case CDSE_OK:
|
||||||
|
sim_debug(DEBUG_EXP, &cr_dev, "CR: card ok\n");
|
||||||
|
uptr->STATUS |= CARD_IN_READ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->COL = 0;
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy next column over */
|
||||||
|
if (uptr->STATUS & CARD_IN_READ) {
|
||||||
|
if (uptr->COL >= 80) {
|
||||||
|
uptr->STATUS &= ~(CARD_IN_READ|READING);
|
||||||
|
uptr->STATUS |= END_CARD;
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
uptr->DATA = cr_buffer[uptr->COL++];
|
||||||
|
if (uptr->STATUS & DATA_RDY) {
|
||||||
|
uptr->STATUS |= DATA_MISS;
|
||||||
|
}
|
||||||
|
uptr->STATUS |= DATA_RDY;
|
||||||
|
sim_debug(DEBUG_DATA, &cr_dev, "CR Char > %d %03x\n", uptr->COL, uptr->DATA);
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
sim_activate(uptr, uptr->wait);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
cr_attach(UNIT * uptr, CONST char *file)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
if ((uptr->STATUS & (READING|CARD_IN_READ)) == 0) {
|
||||||
|
uptr->STATUS |= RDY_READ;
|
||||||
|
uptr->STATUS &= ~(HOPPER_EMPTY|STOP|TROUBLE|CELL_ERROR|PICK_ERROR);
|
||||||
|
if (uptr->STATUS & RDY_READ_EN)
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
cr_detach(UNIT * uptr)
|
||||||
|
{
|
||||||
|
if (uptr->flags & UNIT_ATT) {
|
||||||
|
uptr->STATUS |= TROUBLE|HOPPER_EMPTY;
|
||||||
|
if (uptr->STATUS & TROUBLE_EN)
|
||||||
|
set_interrupt(CR_DEVNUM, uptr->STATUS);
|
||||||
|
}
|
||||||
|
uptr->STATUS &= ~ RDY_READ;
|
||||||
|
return sim_card_detach(uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
cr_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Card Reader\n\n");
|
||||||
|
sim_card_attach_help(st, dptr, uptr, flag, cptr);
|
||||||
|
fprint_set_help(st, dptr);
|
||||||
|
fprint_show_help(st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
cr_description(DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Card Reader";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
219
PDP10/kx10_cty.c
Normal file
219
PDP10/kx10_cty.c
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
/* ka10_cty.c: KA-10 front end (console terminal) simulator
|
||||||
|
|
||||||
|
Copyright (c) 2013-2017, 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"
|
||||||
|
#if PDP6 | KA | KI
|
||||||
|
#define UNIT_DUMMY (1 << UNIT_V_UF)
|
||||||
|
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
t_stat ctyi_svc (UNIT *uptr);
|
||||||
|
t_stat ctyo_svc (UNIT *uptr);
|
||||||
|
t_stat cty_reset (DEVICE *dptr);
|
||||||
|
t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
|
const char *cty_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
/* CTY data structures
|
||||||
|
|
||||||
|
cty_dev CTY device descriptor
|
||||||
|
cty_unit CTY unit descriptor
|
||||||
|
cty_reg CTY register list
|
||||||
|
*/
|
||||||
|
#define TEL_RDY 0010
|
||||||
|
#define TEL_BSY 0020
|
||||||
|
#define KEY_RDY 0040
|
||||||
|
#define KEY_BSY 0100
|
||||||
|
#define KEY_TST 04000
|
||||||
|
#define CTY_DEVNUM 0120
|
||||||
|
|
||||||
|
#define STATUS u3
|
||||||
|
#define DATA u4
|
||||||
|
#define PIA u5
|
||||||
|
|
||||||
|
t_stat cty_devio(uint32 dev, uint64 *data);
|
||||||
|
|
||||||
|
DIB cty_dib = { CTY_DEVNUM, 1, cty_devio, NULL};
|
||||||
|
|
||||||
|
UNIT cty_unit[] = {
|
||||||
|
{ UDATA (&ctyo_svc, TT_MODE_7B, 0), 10000 },
|
||||||
|
{ UDATA (&ctyi_svc, TT_MODE_7B|UNIT_IDLE, 0), 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
MTAB cty_mod[] = {
|
||||||
|
{ UNIT_DUMMY, 0, NULL, "STOP", &cty_stop_os },
|
||||||
|
{ TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode },
|
||||||
|
{ TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
|
||||||
|
{ TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
|
||||||
|
{ TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE cty_dev = {
|
||||||
|
"CTY", cty_unit, NULL, cty_mod,
|
||||||
|
2, 10, 31, 1, 8, 8,
|
||||||
|
NULL, NULL, &cty_reset,
|
||||||
|
NULL, NULL, NULL, &cty_dib, DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &cty_help, NULL, NULL, &cty_description
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat cty_devio(uint32 dev, uint64 *data) {
|
||||||
|
uint64 res;
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
res = cty_unit[0].PIA | (cty_unit[0].STATUS & (TEL_RDY | TEL_BSY));
|
||||||
|
res |= cty_unit[1].STATUS & (KEY_RDY | KEY_BSY);
|
||||||
|
res |= cty_unit[0].STATUS & KEY_TST;
|
||||||
|
*data = res;
|
||||||
|
sim_debug(DEBUG_CONI, &cty_dev, "CTY %03o CONI %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
case CONO:
|
||||||
|
res = *data;
|
||||||
|
cty_unit[0].PIA = res & 07;
|
||||||
|
cty_unit[1].PIA = res & 07;
|
||||||
|
cty_unit[0].PIA &= ~(KEY_TST);
|
||||||
|
cty_unit[0].STATUS &= ~((res >> 4) & (TEL_RDY | TEL_BSY));
|
||||||
|
cty_unit[0].STATUS |= (res & (TEL_RDY | TEL_BSY | KEY_TST));
|
||||||
|
cty_unit[1].STATUS &= ~((res >> 4) & (KEY_RDY | KEY_BSY));
|
||||||
|
cty_unit[1].STATUS |= (res & (KEY_RDY | KEY_BSY));
|
||||||
|
if ((cty_unit[0].STATUS & TEL_RDY) || (cty_unit[1].STATUS & KEY_RDY))
|
||||||
|
set_interrupt(dev, cty_unit[0].PIA);
|
||||||
|
else
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_debug(DEBUG_CONO, &cty_dev, "CTY %03o CONO %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
res = cty_unit[1].DATA & 0xff;
|
||||||
|
cty_unit[1].STATUS &= ~KEY_RDY;
|
||||||
|
if ((cty_unit[0].STATUS & TEL_RDY) == 0)
|
||||||
|
clr_interrupt(dev);
|
||||||
|
*data = res;
|
||||||
|
sim_debug(DEBUG_DATAIO, &cty_dev, "CTY %03o DATAI %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
cty_unit[0].DATA = *data & 0x7f;
|
||||||
|
cty_unit[0].STATUS &= ~TEL_RDY;
|
||||||
|
cty_unit[0].STATUS |= TEL_BSY;
|
||||||
|
if ((cty_unit[1].STATUS & KEY_RDY) == 0)
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_activate(&cty_unit[0], cty_unit[0].wait);
|
||||||
|
sim_debug(DEBUG_DATAIO, &cty_dev, "CTY %03o DATAO %06o\n", dev, (uint32)*data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t_stat ctyo_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
int32 ch;
|
||||||
|
|
||||||
|
if (uptr->DATA != 0) {
|
||||||
|
ch = sim_tt_outcvt ( uptr->DATA, TT_GET_MODE (uptr->flags)) ;
|
||||||
|
if ((r = sim_putchar_s (ch)) != SCPE_OK) { /* output; error? */
|
||||||
|
sim_activate (uptr, uptr->wait); /* try again */
|
||||||
|
return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uptr->STATUS &= ~TEL_BSY;
|
||||||
|
uptr->STATUS |= TEL_RDY;
|
||||||
|
set_interrupt(CTY_DEVNUM, uptr->PIA);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ctyi_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int32 ch;
|
||||||
|
|
||||||
|
sim_clock_coschedule (uptr, tmxr_poll);
|
||||||
|
/* continue poll */
|
||||||
|
if ((ch = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
|
||||||
|
return ch;
|
||||||
|
if (ch & SCPE_BREAK) /* ignore break */
|
||||||
|
return SCPE_OK;
|
||||||
|
uptr->DATA = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (uptr->flags));
|
||||||
|
uptr->DATA = ch & 0177;
|
||||||
|
uptr->STATUS |= KEY_RDY;
|
||||||
|
set_interrupt(CTY_DEVNUM, uptr->PIA);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset */
|
||||||
|
|
||||||
|
t_stat cty_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
cty_unit[0].STATUS &= ~(TEL_RDY | TEL_BSY);
|
||||||
|
cty_unit[1].STATUS &= ~(KEY_RDY | KEY_BSY);
|
||||||
|
clr_interrupt(CTY_DEVNUM);
|
||||||
|
sim_clock_coschedule (&cty_unit[1], tmxr_poll);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop operating system */
|
||||||
|
|
||||||
|
t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
M[CTY_SWITCH] = 1; /* tell OS to stop */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
cty_unit[0].flags = (cty_unit[0].flags & ~TT_MODE) | val;
|
||||||
|
cty_unit[1].flags = (cty_unit[1].flags & ~TT_MODE) | val;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "To stop the cpu use the command:\n\n");
|
||||||
|
fprintf (st, " sim> SET CTY STOP\n\n");
|
||||||
|
fprintf (st, "This will write a 1 to location %03o, causing TOPS10 to stop\n\n", CTY_SWITCH);
|
||||||
|
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
|
||||||
|
fprintf (st, " mode input characters output characters\n\n");
|
||||||
|
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
|
||||||
|
fprintf (st, " to upper case, high-order bit cleared,\n");
|
||||||
|
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
|
||||||
|
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
|
||||||
|
fprintf (st, " non-printing characters suppressed\n");
|
||||||
|
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
|
||||||
|
fprintf (st, " 8B no changes no changes\n\n");
|
||||||
|
fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n");
|
||||||
|
fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n");
|
||||||
|
fprint_reg_help (st, &cty_dev);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cty_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Console TTY Line";
|
||||||
|
}
|
||||||
|
#endif
|
579
PDP10/kx10_dc.c
Normal file
579
PDP10/kx10_dc.c
Normal file
|
@ -0,0 +1,579 @@
|
||||||
|
/* ka10_dc.c: PDP-10 DC10 communication server simulator
|
||||||
|
|
||||||
|
Copyright (c) 2011-2017, 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"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_DC
|
||||||
|
#define NUM_DEVS_DC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DC > 0)
|
||||||
|
|
||||||
|
#define DC_DEVNUM 0240
|
||||||
|
|
||||||
|
#define DC10_LINES 8
|
||||||
|
#define DC10_MLINES 32
|
||||||
|
|
||||||
|
#define STATUS u3
|
||||||
|
|
||||||
|
#define DTS_LINE 007700 /* Scanner line number in STATUS */
|
||||||
|
#define PI_CHN 000007 /* IN STATUS. */
|
||||||
|
#define RCV_PI 000010 /* IN STATUS. */
|
||||||
|
#define XMT_PI 000020 /* IN STATUS. */
|
||||||
|
#define DTR_DIS 000040 /* DTR FLAG */
|
||||||
|
#define RST_SCN 000010 /* CONO */
|
||||||
|
#define DTR_SET 000020 /* CONO */
|
||||||
|
#define CLR_SCN 000040 /* CONO */
|
||||||
|
|
||||||
|
#define DATA 0000377
|
||||||
|
#define FLAG 0000400 /* Recieve data/ transmit disable */
|
||||||
|
#define LINE 0000077 /* Line number in Left */
|
||||||
|
#define LFLAG 0000100 /* Direct line number flag */
|
||||||
|
|
||||||
|
/* DC10E flags */
|
||||||
|
#define CTS 0000004 /* Clear to send */
|
||||||
|
#define RES_DET 0000002 /* Ring detect */
|
||||||
|
#define DLO 0000040 /* (ACU) Data line occupied */
|
||||||
|
#define PND 0000020 /* (ACU) Present next digit */
|
||||||
|
#define ACR 0000010 /* (ACU) Abandon Call and retry */
|
||||||
|
#define CRQ 0000040 /* (ACU) Call Request */
|
||||||
|
#define DPR 0000020 /* (ACU) Digit Presented */
|
||||||
|
#define NB 0000017 /* (ACU) Number */
|
||||||
|
#define OFF_HOOK 0000100 /* Off Hook (CD) */
|
||||||
|
#define CAUSE_PI 0000200 /* Cause PI */
|
||||||
|
|
||||||
|
uint64 dc_l_status; /* Line status */
|
||||||
|
int dc_l_count = 0; /* Scan counter */
|
||||||
|
int dc_modem = DC10_MLINES; /* Modem base address */
|
||||||
|
uint8 dcix_buf[DC10_MLINES] = { 0 }; /* Input buffers */
|
||||||
|
uint8 dcox_buf[DC10_MLINES] = { 0 }; /* Output buffers */
|
||||||
|
TMLN dc_ldsc[DC10_MLINES] = { 0 }; /* Line descriptors */
|
||||||
|
TMXR dc_desc = { DC10_LINES, 0, 0, dc_ldsc };
|
||||||
|
uint32 tx_enable, rx_rdy; /* Flags */
|
||||||
|
uint32 dc_enable; /* Enable line */
|
||||||
|
uint32 dc_ring; /* Connection pending */
|
||||||
|
uint32 rx_conn; /* Connection flags */
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
|
||||||
|
t_stat dc_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat dc_svc (UNIT *uptr);
|
||||||
|
t_stat dc_doscan (UNIT *uptr);
|
||||||
|
t_stat dc_reset (DEVICE *dptr);
|
||||||
|
t_stat dc_set_modem (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dc_show_modem (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||||
|
t_stat dc_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dc_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dc_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dc_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||||
|
t_stat dc_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
t_stat dc_detach (UNIT *uptr);
|
||||||
|
t_stat dc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *dc_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
/* DC10 data structures
|
||||||
|
|
||||||
|
dc_dev DC10 device descriptor
|
||||||
|
dc_unit DC10 unit descriptor
|
||||||
|
dc_reg DC10 register list
|
||||||
|
*/
|
||||||
|
|
||||||
|
DIB dc_dib = { DC_DEVNUM, 1, &dc_devio, NULL };
|
||||||
|
|
||||||
|
UNIT dc_unit = {
|
||||||
|
UDATA (&dc_svc, TT_MODE_7B+UNIT_IDLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT
|
||||||
|
};
|
||||||
|
|
||||||
|
REG dc_reg[] = {
|
||||||
|
{ DRDATA (TIME, dc_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||||
|
{ DRDATA (STATUS, dc_unit.STATUS, 18), PV_LEFT },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB dc_mod[] = {
|
||||||
|
{ TT_MODE, TT_MODE_KSR, "KSR", "KSR", 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_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
|
||||||
|
&tmxr_dscln, NULL, &dc_desc, "Disconnect a specific line" },
|
||||||
|
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
|
||||||
|
NULL, &tmxr_show_summ, (void *) &dc_desc, "Display a summary of line states" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &dc_desc, "Display current connections" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &dc_desc, "Display multiplexer statistics" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "LINES", "LINES=n",
|
||||||
|
&dc_setnl, &tmxr_show_lines, (void *) &dc_desc, "Set number of lines" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "MODEM", "MODEM=n",
|
||||||
|
&dc_set_modem, &dc_show_modem, (void *)&dc_modem, "Set modem offset" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NC, 0, NULL, "LOG=n=file",
|
||||||
|
&dc_set_log, NULL, (void *)&dc_desc },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "NOLOG",
|
||||||
|
&dc_set_nolog, NULL, (void *)&dc_desc, "Disable logging on designated line" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "LOG", NULL,
|
||||||
|
NULL, &dc_show_log, (void *)&dc_desc, "Display logging for all lines" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dc_dev = {
|
||||||
|
"DC", &dc_unit, dc_reg, dc_mod,
|
||||||
|
1, 10, 31, 1, 8, 8,
|
||||||
|
&tmxr_ex, &tmxr_dep, &dc_reset,
|
||||||
|
NULL, &dc_attach, &dc_detach,
|
||||||
|
&dc_dib, DEV_NET | DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &dc_help, NULL, NULL, &dc_description
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* IOT routine */
|
||||||
|
t_stat dc_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &dc_unit;
|
||||||
|
TMLN *lp;
|
||||||
|
int ln;
|
||||||
|
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
/* Check if we might have any interrupts pending */
|
||||||
|
if ((uptr->STATUS & (RCV_PI|XMT_PI)) == 0)
|
||||||
|
dc_doscan(uptr);
|
||||||
|
*data = uptr->STATUS & (PI_CHN|RCV_PI|XMT_PI);
|
||||||
|
sim_debug(DEBUG_CONI, &dc_dev, "DC %03o CONI %06o PC=%o\n",
|
||||||
|
dev, (uint32)*data, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
/* Set PI */
|
||||||
|
uptr->STATUS &= ~PI_CHN;
|
||||||
|
uptr->STATUS |= PI_CHN & *data;
|
||||||
|
if (*data & RST_SCN)
|
||||||
|
dc_l_count = 0;
|
||||||
|
if (*data & DTR_SET)
|
||||||
|
uptr->STATUS |= DTR_SET;
|
||||||
|
if (*data & CLR_SCN) {
|
||||||
|
uptr->STATUS &= PI_CHN;
|
||||||
|
for (ln = 0; ln < dc_desc.lines; ln++) {
|
||||||
|
lp = &dc_ldsc[ln];
|
||||||
|
if (lp->conn) {
|
||||||
|
tmxr_linemsg (lp, "\r\nLine Hangup\r\n");
|
||||||
|
tmxr_reset_ln(lp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx_enable = 0;
|
||||||
|
dc_enable = 0;
|
||||||
|
rx_rdy = 0; /* Flags */
|
||||||
|
rx_conn = 0;
|
||||||
|
dc_ring = 0;
|
||||||
|
dc_l_status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_debug(DEBUG_CONO, &dc_dev, "DC %03o CONO %06o PC=%06o\n",
|
||||||
|
dev, (uint32)*data, PC);
|
||||||
|
dc_doscan(uptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
if (*data & (LFLAG << 18))
|
||||||
|
ln = (*data >> 18) & 077;
|
||||||
|
else
|
||||||
|
ln = dc_l_count;
|
||||||
|
if (ln >= dc_modem) {
|
||||||
|
if (*data & CAUSE_PI)
|
||||||
|
dc_l_status |= (1LL << ln);
|
||||||
|
else
|
||||||
|
dc_l_status &= ~(1LL << ln);
|
||||||
|
ln -= dc_modem;
|
||||||
|
sim_debug(DEBUG_DETAIL, &dc_dev, "DC line modem %d %03o\n",
|
||||||
|
ln, (uint32)(*data & 0777));
|
||||||
|
if ((*data & OFF_HOOK) == 0) {
|
||||||
|
uint32 mask = ~(1 << ln);
|
||||||
|
rx_rdy &= mask;
|
||||||
|
tx_enable &= mask;
|
||||||
|
dc_enable &= mask;
|
||||||
|
lp = &dc_ldsc[ln];
|
||||||
|
if (rx_conn & (1 << ln) && lp->conn) {
|
||||||
|
sim_debug(DEBUG_DETAIL, &dc_dev, "DC line hangup %d\n", ln);
|
||||||
|
tmxr_linemsg (lp, "\r\nLine Hangup\r\n");
|
||||||
|
tmxr_reset_ln(lp);
|
||||||
|
rx_conn &= mask;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sim_debug(DEBUG_DETAIL, &dc_dev, "DC line off-hook %d\n", ln);
|
||||||
|
dc_enable |= 1<<ln;
|
||||||
|
if (dc_ring & (1 << ln)) {
|
||||||
|
dc_l_status |= (1LL << (ln + dc_modem));
|
||||||
|
dc_ring &= ~(1 << ln);
|
||||||
|
rx_conn |= (1 << ln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ln < dc_desc.lines) {
|
||||||
|
lp = &dc_ldsc[ln];
|
||||||
|
if (*data & FLAG) {
|
||||||
|
tx_enable &= ~(1 << ln);
|
||||||
|
dc_l_status &= ~(1LL << ln);
|
||||||
|
} else if (lp->conn) {
|
||||||
|
int32 ch = *data & DATA;
|
||||||
|
ch = sim_tt_outcvt(ch, TT_GET_MODE (dc_unit.flags) | TTUF_KSR);
|
||||||
|
tmxr_putc_ln (lp, ch);
|
||||||
|
if (lp->xmte)
|
||||||
|
tx_enable |= (1 << ln);
|
||||||
|
else
|
||||||
|
tx_enable &= ~(1 << ln);
|
||||||
|
dc_l_status |= (1LL << ln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dc_doscan(uptr);
|
||||||
|
sim_debug(DEBUG_DATAIO, &dc_dev, "DC %03o DATO %012llo PC=%06o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
ln = dc_l_count;
|
||||||
|
*data = (uint64)(ln) << 18;
|
||||||
|
if (ln >= dc_modem) {
|
||||||
|
dc_l_status &= ~(1LL << ln);
|
||||||
|
ln = ln - dc_modem;
|
||||||
|
lp = &dc_ldsc[ln];
|
||||||
|
if (dc_enable & (1 << ln))
|
||||||
|
*data |= FLAG|OFF_HOOK;
|
||||||
|
if (rx_conn & (1 << ln) && lp->conn)
|
||||||
|
*data |= FLAG|CTS;
|
||||||
|
if (dc_ring & (1 << ln))
|
||||||
|
*data |= FLAG|RES_DET;
|
||||||
|
} else if (ln < dc_desc.lines) {
|
||||||
|
/* Nothing happens if no recieve data, which is transmit ready */
|
||||||
|
lp = &dc_ldsc[ln];
|
||||||
|
if (tmxr_rqln (lp) > 0) {
|
||||||
|
int32 ch = tmxr_getc_ln (lp);
|
||||||
|
if (ch & SCPE_BREAK) /* break? */
|
||||||
|
ch = 0;
|
||||||
|
else
|
||||||
|
ch = sim_tt_inpcvt (ch, TT_GET_MODE(dc_unit.flags) | TTUF_KSR);
|
||||||
|
*data |= FLAG | (uint64)(ch & DATA);
|
||||||
|
}
|
||||||
|
if (tmxr_rqln (lp) > 0) {
|
||||||
|
rx_rdy |= 1 << ln;
|
||||||
|
dc_l_status |= (1LL << ln);
|
||||||
|
} else {
|
||||||
|
rx_rdy &= ~(1 << ln);
|
||||||
|
dc_l_status &= ~(1LL << ln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dc_doscan(uptr);
|
||||||
|
sim_debug(DEBUG_DATAIO, &dc_dev, "DC %03o DATI %012llo PC=%06o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Unit service */
|
||||||
|
|
||||||
|
t_stat dc_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int32 ln;
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
|
ln = tmxr_poll_conn (&dc_desc); /* look for connect */
|
||||||
|
if (ln >= 0) { /* got one? rcv enb*/
|
||||||
|
dc_ldsc[ln].rcve = 1;
|
||||||
|
dc_ring |= (1 << ln);
|
||||||
|
dc_l_status |= (1LL << (ln + dc_modem)); /* Flag modem line */
|
||||||
|
sim_debug(DEBUG_DETAIL, &dc_dev, "DC line connect %d\n", ln);
|
||||||
|
}
|
||||||
|
tmxr_poll_tx(&dc_desc);
|
||||||
|
tmxr_poll_rx(&dc_desc);
|
||||||
|
for (ln = 0; ln < dc_desc.lines; ln++) {
|
||||||
|
/* Check if buffer empty */
|
||||||
|
if (dc_ldsc[ln].xmte && ((dc_l_status & (1ll << ln)) != 0)) {
|
||||||
|
tx_enable |= 1 << ln;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check to see if any pending data for this line */
|
||||||
|
if (tmxr_rqln(&dc_ldsc[ln]) > 0) {
|
||||||
|
rx_rdy |= (1 << ln);
|
||||||
|
dc_l_status |= (1LL << ln); /* Flag line */
|
||||||
|
sim_debug(DEBUG_DETAIL, &dc_dev, "DC recieve %d\n", ln);
|
||||||
|
}
|
||||||
|
/* Check if disconnect */
|
||||||
|
if ((rx_conn & (1 << ln)) != 0 && dc_ldsc[ln].conn == 0) {
|
||||||
|
rx_conn &= ~(1 << ln);
|
||||||
|
dc_l_status |= (1LL << (ln + dc_modem)); /* Flag modem line */
|
||||||
|
sim_debug(DEBUG_DETAIL, &dc_dev, "DC line disconnect %d\n", ln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If any pending status request, raise the PI signal */
|
||||||
|
if (dc_l_status)
|
||||||
|
set_interrupt(DC_DEVNUM, uptr->STATUS);
|
||||||
|
sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan to see if something to do */
|
||||||
|
t_stat dc_doscan (UNIT *uptr) {
|
||||||
|
int32 lmask;
|
||||||
|
|
||||||
|
uptr->STATUS &= ~(RCV_PI|XMT_PI);
|
||||||
|
clr_interrupt(DC_DEVNUM);
|
||||||
|
for (;dc_l_status != 0; dc_l_count++) {
|
||||||
|
dc_l_count &= 077;
|
||||||
|
/* Check if we found it */
|
||||||
|
if (dc_l_status & (1LL << dc_l_count)) {
|
||||||
|
/* Check if modem control or data line */
|
||||||
|
if (dc_l_count >= dc_modem) {
|
||||||
|
uptr->STATUS |= RCV_PI;
|
||||||
|
} else {
|
||||||
|
/* Must be data line */
|
||||||
|
lmask = 1 << dc_l_count;
|
||||||
|
if (rx_rdy & lmask)
|
||||||
|
uptr->STATUS |= RCV_PI;
|
||||||
|
if (tx_enable & lmask)
|
||||||
|
uptr->STATUS |= XMT_PI;
|
||||||
|
}
|
||||||
|
/* Stop scanner */
|
||||||
|
set_interrupt(DC_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset routine */
|
||||||
|
|
||||||
|
t_stat dc_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (dc_unit.flags & UNIT_ATT) /* if attached, */
|
||||||
|
sim_activate (&dc_unit, tmxr_poll); /* activate */
|
||||||
|
else
|
||||||
|
sim_cancel (&dc_unit); /* else stop */
|
||||||
|
tx_enable = 0;
|
||||||
|
rx_rdy = 0; /* Flags */
|
||||||
|
rx_conn = 0;
|
||||||
|
dc_l_status = 0;
|
||||||
|
dc_l_count = 0;
|
||||||
|
dc_unit.STATUS = 0;
|
||||||
|
clr_interrupt(DC_DEVNUM);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SET BUFFER processor */
|
||||||
|
|
||||||
|
t_stat dc_set_modem (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
int32 modem;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
modem = (int32) get_uint (cptr, 10, 32, &r);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (modem < 0 || modem >= (DC10_MLINES * 2))
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (modem < dc_desc.lines)
|
||||||
|
return SCPE_ARG;
|
||||||
|
if ((modem % 8) == 0) {
|
||||||
|
dc_modem = modem;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SHOW BUFFER processor */
|
||||||
|
|
||||||
|
t_stat dc_show_modem (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
|
{
|
||||||
|
fprintf (st, "modem=%d ", dc_modem);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SET LINES processor */
|
||||||
|
|
||||||
|
t_stat dc_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
int32 newln, i, t;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
newln = (int32) get_uint (cptr, 10, DC10_MLINES, &r);
|
||||||
|
if ((r != SCPE_OK) || (newln == dc_desc.lines))
|
||||||
|
return r;
|
||||||
|
if (newln > dc_modem)
|
||||||
|
return SCPE_ARG;
|
||||||
|
if ((newln == 0) || (newln >= DC10_MLINES) || (newln % 8) != 0)
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (newln < dc_desc.lines) {
|
||||||
|
for (i = newln, t = 0; i < dc_desc.lines; i++)
|
||||||
|
t = t | dc_ldsc[i].conn;
|
||||||
|
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
|
||||||
|
return SCPE_OK;
|
||||||
|
for (i = newln; i < dc_desc.lines; i++) {
|
||||||
|
if (dc_ldsc[i].conn) {
|
||||||
|
tmxr_linemsg (&dc_ldsc[i], "\r\nOperator disconnected line\r\n");
|
||||||
|
tmxr_send_buffered_data (&dc_ldsc[i]);
|
||||||
|
}
|
||||||
|
tmxr_detach_ln (&dc_ldsc[i]); /* completely reset line */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dc_desc.lines < newln)
|
||||||
|
memset (dc_ldsc + dc_desc.lines, 0, sizeof(*dc_ldsc)*(newln-dc_desc.lines));
|
||||||
|
dc_desc.lines = newln;
|
||||||
|
return dc_reset (&dc_dev); /* setup lines and auto config */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SET LOG processor */
|
||||||
|
|
||||||
|
t_stat dc_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
char gbuf[CBUFSIZE];
|
||||||
|
int32 ln;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
cptr = get_glyph (cptr, gbuf, '=');
|
||||||
|
if ((cptr == NULL) || (*cptr == 0) || (gbuf[0] == 0))
|
||||||
|
return SCPE_ARG;
|
||||||
|
ln = (int32) get_uint (gbuf, 10, dc_desc.lines, &r);
|
||||||
|
if ((r != SCPE_OK) || (ln >= dc_desc.lines))
|
||||||
|
return SCPE_ARG;
|
||||||
|
return tmxr_set_log (NULL, ln, cptr, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SET NOLOG processor */
|
||||||
|
|
||||||
|
t_stat dc_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
int32 ln;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
ln = (int32) get_uint (cptr, 10, dc_desc.lines, &r);
|
||||||
|
if ((r != SCPE_OK) || (ln >= dc_desc.lines))
|
||||||
|
return SCPE_ARG;
|
||||||
|
return tmxr_set_nolog (NULL, ln, NULL, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SHOW LOG processor */
|
||||||
|
|
||||||
|
t_stat dc_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < dc_desc.lines; i++) {
|
||||||
|
fprintf (st, "line %d: ", i);
|
||||||
|
tmxr_show_log (st, NULL, i, desc);
|
||||||
|
fprintf (st, "\n");
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Attach routine */
|
||||||
|
|
||||||
|
t_stat dc_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat reason;
|
||||||
|
|
||||||
|
reason = tmxr_attach (&dc_desc, uptr, cptr);
|
||||||
|
if (reason != SCPE_OK)
|
||||||
|
return reason;
|
||||||
|
sim_activate (uptr, tmxr_poll);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detach routine */
|
||||||
|
|
||||||
|
t_stat dc_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
t_stat reason;
|
||||||
|
reason = tmxr_detach (&dc_desc, uptr);
|
||||||
|
for (i = 0; i < dc_desc.lines; i++)
|
||||||
|
dc_ldsc[i].rcve = 0;
|
||||||
|
sim_cancel (uptr);
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat dc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "DC10E Terminal Interfaces\n\n");
|
||||||
|
fprintf (st, "The DC10 supported up to 8 blocks of 8 lines. Modem control was on a seperate\n");
|
||||||
|
fprintf (st, "line. The simulator supports this by setting modem control to a fixed offset\n");
|
||||||
|
fprintf (st, "from the given line. The number of lines is specified with a SET command:\n\n");
|
||||||
|
fprintf (st, " sim> SET DC LINES=n set number of additional lines to n [8-32]\n\n");
|
||||||
|
fprintf (st, "Lines must be set in multiples of 8.\n");
|
||||||
|
fprintf (st, "The default offset for modem lines is 32. This can be changed with\n\n");
|
||||||
|
fprintf (st, " sim> SET DC MODEM=n set offset for modem control to n [8-32]\n\n");
|
||||||
|
fprintf (st, "Modem control must be set larger then the number of lines\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.\n");
|
||||||
|
fprintf (st, "Finally, each line supports output logging. The SET DCn LOG command enables\n");
|
||||||
|
fprintf (st, "logging on a line:\n\n");
|
||||||
|
fprintf (st, " sim> SET DCn LOG=filename log output of line n to filename\n\n");
|
||||||
|
fprintf (st, "The SET DCn NOLOG command disables logging and closes the open log file,\n");
|
||||||
|
fprintf (st, "if any.\n\n");
|
||||||
|
fprintf (st, "Once DC 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 DC DISCONNECT command, or a DETACH DC command.\n\n");
|
||||||
|
fprintf (st, "Other special commands:\n\n");
|
||||||
|
fprintf (st, " sim> SHOW DC CONNECTIONS show current connections\n");
|
||||||
|
fprintf (st, " sim> SHOW DC STATISTICS show statistics for active connections\n");
|
||||||
|
fprintf (st, " sim> SET DCn DISCONNECT disconnects the specified line.\n");
|
||||||
|
fprint_reg_help (st, &dc_dev);
|
||||||
|
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 DC is detached.\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dc_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "DC10E asynchronous line interface";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
492
PDP10/kx10_defs.h
Normal file
492
PDP10/kx10_defs.h
Normal file
|
@ -0,0 +1,492 @@
|
||||||
|
/* ka10_defs.h: PDP-10 simulator definitions
|
||||||
|
|
||||||
|
Copyright (c) 2011-2017, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _KA10_DEFS_H_
|
||||||
|
#define _KA10_DEFS_H_ 0
|
||||||
|
|
||||||
|
#include "sim_defs.h" /* simulator defns */
|
||||||
|
|
||||||
|
#if defined(USE_ADDR64)
|
||||||
|
#error "PDP-10 does not support 64b addresses!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PDP6
|
||||||
|
#define PDP6 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KA
|
||||||
|
#define KA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KI
|
||||||
|
#define KI 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KLA
|
||||||
|
#define KLA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KLB
|
||||||
|
#define KLB 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KL /* Either KL10A or KL10B */
|
||||||
|
#define KL (KLA+KLB)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (PDP6 + KA + KI + KL) != 1
|
||||||
|
#error "Please define only one type of CPU"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KI_22BIT
|
||||||
|
#define KI_22BIT KI|KL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Support for ITS Pager */
|
||||||
|
#ifndef ITS
|
||||||
|
#define ITS KA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Support for TENEX Pager */
|
||||||
|
#ifndef BBN
|
||||||
|
#define BBN KA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Support for WAITS mods */
|
||||||
|
#ifndef WAITS
|
||||||
|
#define WAITS KA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PDP6_DEV /* Include PDP6 devices */
|
||||||
|
#define PDP6_DEV PDP6|WAITS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* MPX interrupt multiplexer for ITS systems */
|
||||||
|
#define MPX_DEV ITS
|
||||||
|
|
||||||
|
/* Digital Equipment Corporation's 36b family had six implementations:
|
||||||
|
|
||||||
|
name mips comments
|
||||||
|
|
||||||
|
PDP-6 0.25 Original 36b implementation, 1964
|
||||||
|
KA10 0.38 First PDP-10, flip chips, 1967
|
||||||
|
KI10 0.72 First paging system, flip chip + MSI, 1972
|
||||||
|
KL10 1.8 First ECL system, ECL 10K, 1975
|
||||||
|
KL10B 1.8 Expanded addressing, ECL 10K, 1978
|
||||||
|
KS10 0.3 Last 36b system, 2901 based, 1979
|
||||||
|
|
||||||
|
In addition, it ran four major (incompatible) operating systems:
|
||||||
|
|
||||||
|
name company comments
|
||||||
|
|
||||||
|
TOPS-10 DEC Original timesharing system
|
||||||
|
ITS MIT "Incompatible Timesharing System"
|
||||||
|
TENEX BBN ARPA-sponsored, became
|
||||||
|
TOPS-20 DEC Commercial version of TENEX
|
||||||
|
|
||||||
|
All of the implementations differ from one another, in instruction set,
|
||||||
|
I/O structure, and memory management. Further, each of the operating
|
||||||
|
systems customized the microcode of the paging systems (KI10, KL10, KS10)
|
||||||
|
for additional instructions and specialized memory management. As a
|
||||||
|
result, there is no "reference implementation" for the 36b family that
|
||||||
|
will run all programs and all operating systems. The conditionalization
|
||||||
|
and generality needed to support the full matrix of models and operating
|
||||||
|
systems, and to support 36b hardware on 32b data types, is beyond the
|
||||||
|
scope of this project.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Abort codes, used to sort out longjmp's back to the main loop
|
||||||
|
Codes > 0 are simulator stop codes
|
||||||
|
Codes < 0 are internal aborts
|
||||||
|
Code = 0 stops execution for an interrupt check
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef t_uint64 uint64;
|
||||||
|
|
||||||
|
#define STOP_HALT 1 /* halted */
|
||||||
|
#define STOP_IBKPT 2 /* breakpoint */
|
||||||
|
|
||||||
|
/* Debuging controls */
|
||||||
|
#define DEBUG_CMD 0x0000001 /* Show device commands */
|
||||||
|
#define DEBUG_DATA 0x0000002 /* Show data transfers */
|
||||||
|
#define DEBUG_DETAIL 0x0000004 /* Show details */
|
||||||
|
#define DEBUG_EXP 0x0000008 /* Show error conditions */
|
||||||
|
#define DEBUG_CONI 0x0000020 /* Show CONI instructions */
|
||||||
|
#define DEBUG_CONO 0x0000040 /* Show CONO instructions */
|
||||||
|
#define DEBUG_DATAIO 0x0000100 /* Show DATAI/O instructions */
|
||||||
|
#define DEBUG_IRQ 0x0000200 /* Show IRQ requests */
|
||||||
|
|
||||||
|
extern DEBTAB dev_debug[];
|
||||||
|
extern DEBTAB crd_debug[];
|
||||||
|
|
||||||
|
/* Operating system flags, kept in cpu_unit.flags */
|
||||||
|
|
||||||
|
#define Q_IDLE (sim_idle_enab)
|
||||||
|
|
||||||
|
/* Device information block */
|
||||||
|
#define LMASK 00777777000000LL
|
||||||
|
#define RMASK 00000000777777LL
|
||||||
|
#define FMASK 00777777777777LL
|
||||||
|
#define CMASK 00377777777777LL
|
||||||
|
#define SMASK 00400000000000LL
|
||||||
|
#define C1 01000000000000LL
|
||||||
|
#define RSIGN 00000000400000LL
|
||||||
|
#define PMASK 00007777777777LL
|
||||||
|
#define XMASK 03777777777777LL
|
||||||
|
#define EMASK 00777000000000LL
|
||||||
|
#define MMASK 00000777777777LL
|
||||||
|
#define BIT1 00200000000000LL
|
||||||
|
#define BIT7 00002000000000LL
|
||||||
|
#define BIT8 00001000000000LL
|
||||||
|
#define BIT9 00000400000000LL
|
||||||
|
#define BIT10 00000200000000LL
|
||||||
|
#define BIT10_35 00000377777777LL
|
||||||
|
#define MANT 00000777777777LL
|
||||||
|
#define EXPO 00377000000000LL
|
||||||
|
#define FPHBIT 01000000000000000000000LL
|
||||||
|
#define FPSBIT 00400000000000000000000LL
|
||||||
|
#define FPNBIT 00200000000000000000000LL
|
||||||
|
#define FP1BIT 00100000000000000000000LL
|
||||||
|
#define FPFMASK 01777777777777777777777LL
|
||||||
|
#define FPRMASK 00000000000177777777777LL
|
||||||
|
#define FPMMASK 00000000000077777777777LL
|
||||||
|
#define FPRBIT2 00000000000100000000000LL
|
||||||
|
#define FPRBIT1 00000000000200000000000LL
|
||||||
|
|
||||||
|
#define CM(x) (FMASK ^ (x))
|
||||||
|
|
||||||
|
#define INST_V_OP 27 /* opcode */
|
||||||
|
#define INST_M_OP 0777
|
||||||
|
#define INST_V_DEV 26
|
||||||
|
#define INST_M_DEV 0177 /* device */
|
||||||
|
#define INST_V_AC 23 /* AC */
|
||||||
|
#define INST_M_AC 017
|
||||||
|
#define INST_V_IND 22 /* indirect */
|
||||||
|
#define INST_IND (1 << INST_V_IND)
|
||||||
|
#define INST_V_XR 18 /* index */
|
||||||
|
#define INST_M_XR 017
|
||||||
|
#define OP_JRST 0254 /* JRST */
|
||||||
|
#define OP_JUMPA 0324 /* JUMPA */
|
||||||
|
#define AC_XPCW 07 /* XPCW */
|
||||||
|
#define OP_JSR 0264 /* JSR */
|
||||||
|
#define GET_OP(x) ((int32) (((x) >> INST_V_OP) & INST_M_OP))
|
||||||
|
#define GET_DEV(x) ((int32) (((x) >> INST_V_DEV) & INST_M_DEV))
|
||||||
|
#define GET_AC(x) ((int32) (((x) >> INST_V_AC) & INST_M_AC))
|
||||||
|
#define TST_IND(x) ((x) & INST_IND)
|
||||||
|
#define GET_XR(x) ((int32) (((x) >> INST_V_XR) & INST_M_XR))
|
||||||
|
#define GET_ADDR(x) ((uint32) ((x) & RMASK))
|
||||||
|
#define LRZ(x) (((x) >> 18) & RMASK)
|
||||||
|
#define JRST1 (((uint64)OP_JRST << 27) + 1)
|
||||||
|
|
||||||
|
#if PDP6
|
||||||
|
#define NODIV 000000
|
||||||
|
#define FLTUND 000000
|
||||||
|
#else
|
||||||
|
#define NODIV 000001 /* 000040 */
|
||||||
|
#define FLTUND 000002 /* 000100 */
|
||||||
|
#endif
|
||||||
|
#if KI|KL
|
||||||
|
#define TRP1 000004 /* 000200 */
|
||||||
|
#define TRP2 000010 /* 000400 */
|
||||||
|
#define ADRFLT 000020 /* 001000 */
|
||||||
|
#define PUBLIC 000040 /* 002000 */
|
||||||
|
#else
|
||||||
|
#define TRP1 000000
|
||||||
|
#define TRP2 000000
|
||||||
|
#define ADRFLT 000000
|
||||||
|
#define PUBLIC 000000
|
||||||
|
#endif
|
||||||
|
#ifdef BBN
|
||||||
|
#define EXJSYS 000040 /* 002000 */
|
||||||
|
#endif
|
||||||
|
#define USERIO 000100 /* 004000 */
|
||||||
|
#define USER 000200 /* 010000 */
|
||||||
|
#define BYTI 000400 /* 020000 */
|
||||||
|
#if PDP6
|
||||||
|
#define FLTOVR 010000
|
||||||
|
#define PCHNG 001000 /* 040000 */
|
||||||
|
#else
|
||||||
|
#define FLTOVR 001000 /* 040000 */
|
||||||
|
#define PCHNG 000000
|
||||||
|
#endif
|
||||||
|
#define CRY1 002000 /* 100000 */
|
||||||
|
#define CRY0 004000 /* 200000 */
|
||||||
|
#define OVR 010000 /* 400000 */
|
||||||
|
#if KI|KL
|
||||||
|
#define PRV_PUB 020000 /* Overflow in excutive mode */
|
||||||
|
#else
|
||||||
|
#define PRV_PUB 000000 /* Not on KA or PDP6 */
|
||||||
|
#endif
|
||||||
|
#ifdef ITS
|
||||||
|
#ifdef PURE
|
||||||
|
#undef PURE
|
||||||
|
#endif
|
||||||
|
#define ONEP 000010 /* 000400 */
|
||||||
|
#define PURE 000040 /* 002000 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DATAI 00
|
||||||
|
#define DATAO 01
|
||||||
|
#define CONI 02
|
||||||
|
#define CONO 03
|
||||||
|
|
||||||
|
#define CTY_SWITCH 030
|
||||||
|
|
||||||
|
#if KI_22BIT|KI
|
||||||
|
#define MAXMEMSIZE 4096 * 1024
|
||||||
|
#else
|
||||||
|
#if PDP6
|
||||||
|
#define MAXMEMSIZE 256 * 1024
|
||||||
|
#else
|
||||||
|
#define MAXMEMSIZE 1024 * 1024
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#define MEMSIZE (cpu_unit[0].capac)
|
||||||
|
|
||||||
|
#define ICWA 0000000000776
|
||||||
|
#if KI_22BIT
|
||||||
|
#define AMASK 00000017777777LL
|
||||||
|
#define WMASK 0037777LL
|
||||||
|
#define CSHIFT 22
|
||||||
|
#else
|
||||||
|
#define AMASK RMASK
|
||||||
|
#define WMASK RMASK
|
||||||
|
#define CSHIFT 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define API_MASK 0000000007
|
||||||
|
#define PI_ENABLE 0000000010 /* Clear DONE */
|
||||||
|
#define BUSY 0000000020 /* STOP */
|
||||||
|
#define CCW_COMP 0000000040 /* Write Final CCW */
|
||||||
|
|
||||||
|
#if KI
|
||||||
|
#define DEF_SERIAL 514 /* Default DEC test machine */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BBN
|
||||||
|
#define BBN_PAGE 0000017777777LL
|
||||||
|
#define BBN_TRPPG 0000017000000LL
|
||||||
|
#define BBN_SPT 0000017777000LL
|
||||||
|
#define BBN_PN 0000000000777LL
|
||||||
|
#define BBN_ACC 0000040000000LL
|
||||||
|
#define BBN_TRP1 0000100000000LL
|
||||||
|
#define BBN_TRP 0000200000000LL
|
||||||
|
#define BBN_TRPMOD 0000400000000LL
|
||||||
|
#define BBN_TRPUSR 0001000000000LL
|
||||||
|
#define BBN_EXEC 0020000000000LL
|
||||||
|
#define BBN_WRITE 0040000000000LL
|
||||||
|
#define BBN_READ 0100000000000LL
|
||||||
|
#define BBN_MERGE 0161740000000LL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Flags for CPU unit */
|
||||||
|
#define UNIT_V_MSIZE (UNIT_V_UF + 0)
|
||||||
|
#define UNIT_MSIZE (0177 << UNIT_V_MSIZE)
|
||||||
|
#define UNIT_V_MAOFF (UNIT_V_MSIZE + 8)
|
||||||
|
#define UNIT_V_PAGE (UNIT_V_MAOFF + 1)
|
||||||
|
#define UNIT_MAOFF (1 << UNIT_V_MAOFF)
|
||||||
|
#define UNIT_TWOSEG (1 << UNIT_V_PAGE)
|
||||||
|
#define UNIT_ITSPAGE (2 << UNIT_V_PAGE)
|
||||||
|
#define UNIT_BBNPAGE (4 << UNIT_V_PAGE)
|
||||||
|
#define UNIT_M_PAGE (007 << UNIT_V_PAGE)
|
||||||
|
#define UNIT_V_WAITS (UNIT_V_PAGE + 3)
|
||||||
|
#define UNIT_M_WAITS (1 << UNIT_V_WAITS)
|
||||||
|
#define UNIT_WAITS (UNIT_M_WAITS) /* Support for WAITS xct and fix */
|
||||||
|
#define UNIT_V_MPX (UNIT_V_WAITS + 1)
|
||||||
|
#define UNIT_M_MPX (1 << UNIT_V_MPX)
|
||||||
|
#define UNIT_MPX (UNIT_M_MPX) /* MPX Device for ITS */
|
||||||
|
|
||||||
|
|
||||||
|
#if MPX_DEV
|
||||||
|
extern void set_interrupt_mpx(int dev, int lvl, int mpx);
|
||||||
|
#else
|
||||||
|
#define set_interrupt_mpx(d,l,m) set_interrupt(d,l)
|
||||||
|
#endif
|
||||||
|
extern void set_interrupt(int dev, int lvl);
|
||||||
|
extern void clr_interrupt(int dev);
|
||||||
|
extern void check_apr_irq();
|
||||||
|
extern int check_irq_level();
|
||||||
|
extern void restore_pi_hold();
|
||||||
|
extern void set_pi_hold();
|
||||||
|
extern UNIT cpu_unit[];
|
||||||
|
extern UNIT ten11_unit[];
|
||||||
|
extern UNIT auxcpu_unit[];
|
||||||
|
extern DEVICE cpu_dev;
|
||||||
|
extern DEVICE cty_dev;
|
||||||
|
extern DEVICE mt_dev;
|
||||||
|
extern DEVICE dpa_dev;
|
||||||
|
extern DEVICE dpb_dev;
|
||||||
|
extern DEVICE dpc_dev;
|
||||||
|
extern DEVICE dpd_dev;
|
||||||
|
extern DEVICE imp_dev;
|
||||||
|
extern DEVICE rpa_dev;
|
||||||
|
extern DEVICE rpb_dev;
|
||||||
|
extern DEVICE rpc_dev;
|
||||||
|
extern DEVICE rpd_dev;
|
||||||
|
extern DEVICE rsa_dev;
|
||||||
|
extern DEVICE tua_dev;
|
||||||
|
extern DEVICE lpt_dev;
|
||||||
|
extern DEVICE ptp_dev;
|
||||||
|
extern DEVICE ptr_dev;
|
||||||
|
extern DEVICE cr_dev;
|
||||||
|
extern DEVICE cp_dev;
|
||||||
|
extern DEVICE rca_dev;
|
||||||
|
extern DEVICE rcb_dev;
|
||||||
|
extern DEVICE dc_dev;
|
||||||
|
extern DEVICE dt_dev;
|
||||||
|
extern DEVICE pmp_dev;
|
||||||
|
extern DEVICE dk_dev;
|
||||||
|
extern DEVICE pd_dev;
|
||||||
|
extern DEVICE dpy_dev;
|
||||||
|
extern DEVICE imx_dev;
|
||||||
|
extern DEVICE imp_dev;
|
||||||
|
extern DEVICE ch10_dev;
|
||||||
|
extern DEVICE stk_dev;
|
||||||
|
extern DEVICE tk10_dev;
|
||||||
|
extern DEVICE mty_dev;
|
||||||
|
extern DEVICE ten11_dev;
|
||||||
|
extern DEVICE dkb_dev;
|
||||||
|
extern DEVICE auxcpu_dev;
|
||||||
|
extern DEVICE dpk_dev;
|
||||||
|
extern DEVICE wcnsls_dev; /* MIT Spacewar Consoles */
|
||||||
|
extern DEVICE dct_dev; /* PDP6 devices. */
|
||||||
|
extern DEVICE dtc_dev;
|
||||||
|
extern DEVICE mtc_dev;
|
||||||
|
extern DEVICE dsk_dev;
|
||||||
|
extern DEVICE dcs_dev;
|
||||||
|
|
||||||
|
extern t_stat (*dev_tab[128])(uint32 dev, t_uint64 *data);
|
||||||
|
|
||||||
|
#define VEC_DEVMAX 8 /* max device vec */
|
||||||
|
|
||||||
|
/* Device context block */
|
||||||
|
struct pdp_dib {
|
||||||
|
uint32 dev_num; /* device address */
|
||||||
|
uint32 num_devs; /* length */
|
||||||
|
t_stat (*io)(uint32 dev, t_uint64 *data);
|
||||||
|
int (*irq)(uint32 dev, int addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RH10_DEV 01000
|
||||||
|
struct rh_dev {
|
||||||
|
uint32 dev_num;
|
||||||
|
DEVICE *dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct pdp_dib DIB;
|
||||||
|
|
||||||
|
|
||||||
|
/* DF10 Interface */
|
||||||
|
struct df10 {
|
||||||
|
uint32 status;
|
||||||
|
uint32 cia;
|
||||||
|
uint32 ccw;
|
||||||
|
uint32 wcr;
|
||||||
|
uint32 cda;
|
||||||
|
uint32 devnum;
|
||||||
|
t_uint64 buf;
|
||||||
|
uint8 nxmerr;
|
||||||
|
uint8 ccw_comp;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
void df10_setirq(struct df10 *df) ;
|
||||||
|
void df10_writecw(struct df10 *df) ;
|
||||||
|
void df10_finish_op(struct df10 *df, int flags) ;
|
||||||
|
void df10_setup(struct df10 *df, uint32 addr);
|
||||||
|
int df10_fetch(struct df10 *df);
|
||||||
|
int df10_read(struct df10 *df);
|
||||||
|
int df10_write(struct df10 *df);
|
||||||
|
#if PDP6_DEV
|
||||||
|
int dct_read(int u, t_uint64 *data, int c);
|
||||||
|
int dct_write(int u, t_uint64 *data, int c);
|
||||||
|
int dct_is_connect(int u);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ten11_read (int addr, t_uint64 *data);
|
||||||
|
int ten11_write (int addr, t_uint64 data);
|
||||||
|
|
||||||
|
/* Console lights. */
|
||||||
|
extern void ka10_lights_init (void);
|
||||||
|
extern void ka10_lights_main (t_uint64);
|
||||||
|
extern void ka10_lights_set_aux (int);
|
||||||
|
extern void ka10_lights_clear_aux (int);
|
||||||
|
|
||||||
|
int auxcpu_read (int addr, t_uint64 *);
|
||||||
|
int auxcpu_write (int addr, t_uint64);
|
||||||
|
|
||||||
|
/* I/O system parameters */
|
||||||
|
#define NUM_DEVS_LP 1
|
||||||
|
#define NUM_DEVS_PT 1
|
||||||
|
#define NUM_DEVS_CR 1
|
||||||
|
#define NUM_DEVS_CP 1
|
||||||
|
#define NUM_DEVS_DPY USE_DISPLAY
|
||||||
|
#define NUM_DEVS_WCNSLS USE_DISPLAY
|
||||||
|
#if PDP6_DEV
|
||||||
|
#define NUM_DEVS_DTC 1
|
||||||
|
#define NUM_DEVS_DCT 2
|
||||||
|
#define NUM_DEVS_MTC 1
|
||||||
|
#define NUM_DEVS_DSK 1
|
||||||
|
#define NUM_DEVS_DCS 1
|
||||||
|
#endif
|
||||||
|
#if !PDP6
|
||||||
|
#define NUM_DEVS_DC 1
|
||||||
|
#define NUM_DEVS_MT 1
|
||||||
|
#define NUM_DEVS_RC 1
|
||||||
|
#define NUM_DEVS_DT 1
|
||||||
|
#define NUM_DEVS_DK 1
|
||||||
|
#define NUM_DEVS_DP 2
|
||||||
|
#define NUM_DEVS_RP 4
|
||||||
|
#define NUM_DEVS_RS 1
|
||||||
|
#define NUM_DEVS_TU 1
|
||||||
|
#define NUM_DEVS_PMP WAITS
|
||||||
|
#define NUM_DEVS_DKB WAITS
|
||||||
|
#define NUM_DEVS_PD ITS
|
||||||
|
#define NUM_DEVS_IMX ITS
|
||||||
|
#define NUM_DEVS_STK ITS
|
||||||
|
#define NUM_DEVS_TK10 ITS
|
||||||
|
#define NUM_DEVS_MTY ITS
|
||||||
|
#define NUM_DEVS_TEN11 ITS
|
||||||
|
#define NUM_DEVS_AUXCPU ITS
|
||||||
|
#define NUM_DEVS_IMP 1
|
||||||
|
#define NUM_DEVS_CH10 ITS
|
||||||
|
#define NUM_DEVS_DPK ITS
|
||||||
|
#endif
|
||||||
|
/* Global data */
|
||||||
|
|
||||||
|
|
||||||
|
extern t_bool sim_idle_enab;
|
||||||
|
extern struct rh_dev rh[];
|
||||||
|
extern t_uint64 M[MAXMEMSIZE];
|
||||||
|
extern t_uint64 FM[];
|
||||||
|
extern uint32 PC;
|
||||||
|
extern uint32 FLAGS;
|
||||||
|
|
||||||
|
#endif
|
139
PDP10/kx10_df.c
Normal file
139
PDP10/kx10_df.c
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/* ka10_df.c: DF10 common routines.
|
||||||
|
|
||||||
|
Copyright (c) 2015-2017, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
void df10_setirq(struct df10 *df) {
|
||||||
|
df->status |= PI_ENABLE;
|
||||||
|
set_interrupt(df->devnum, df->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void df10_writecw(struct df10 *df) {
|
||||||
|
df->status |= 1 << df->ccw_comp;
|
||||||
|
if (df->wcr != 0)
|
||||||
|
df->cda++;
|
||||||
|
M[df->cia|1] = ((uint64)(df->ccw & WMASK) << CSHIFT) | ((uint64)(df->cda) & AMASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void df10_finish_op(struct df10 *df, int flags) {
|
||||||
|
df->status &= ~BUSY;
|
||||||
|
df->status |= flags;
|
||||||
|
df10_writecw(df);
|
||||||
|
df10_setirq(df);
|
||||||
|
}
|
||||||
|
|
||||||
|
void df10_setup(struct df10 *df, uint32 addr) {
|
||||||
|
df->cia = addr & ICWA;
|
||||||
|
df->ccw = df->cia;
|
||||||
|
df->wcr = 0;
|
||||||
|
df->status |= BUSY;
|
||||||
|
df->status &= ~(1 << df->ccw_comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int df10_fetch(struct df10 *df) {
|
||||||
|
uint64 data;
|
||||||
|
if (df->ccw > MEMSIZE) {
|
||||||
|
df10_finish_op(df, df->nxmerr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
data = M[df->ccw];
|
||||||
|
while((data & (WMASK << CSHIFT)) == 0) {
|
||||||
|
if ((data & AMASK) == 0 || (uint32)(data & AMASK) == df->ccw) {
|
||||||
|
df10_finish_op(df,0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
df->ccw = (uint32)(data & AMASK);
|
||||||
|
if (df->ccw > MEMSIZE) {
|
||||||
|
df10_finish_op(df, 1<<df->nxmerr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
data = M[df->ccw];
|
||||||
|
}
|
||||||
|
#if KA & ITS
|
||||||
|
if (cpu_unit[0].flags & UNIT_ITSPAGE) {
|
||||||
|
df->wcr = (uint32)((data >> CSHIFT) & 0077777) | 0700000;
|
||||||
|
df->cda = (uint32)(data & RMASK);
|
||||||
|
df->cda |= (uint32)((data >> 15) & 00000007000000LL) ^ 07000000;
|
||||||
|
df->ccw = (uint32)((df->ccw + 1) & AMASK);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
df->wcr = (uint32)((data >> CSHIFT) & WMASK);
|
||||||
|
df->cda = (uint32)(data & AMASK);
|
||||||
|
df->ccw = (uint32)((df->ccw + 1) & AMASK);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int df10_read(struct df10 *df) {
|
||||||
|
uint64 data;
|
||||||
|
if (df->wcr == 0) {
|
||||||
|
if (!df10_fetch(df))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
df->wcr = (uint32)((df->wcr + 1) & WMASK);
|
||||||
|
if (df->cda != 0) {
|
||||||
|
if (df->cda > MEMSIZE) {
|
||||||
|
df10_finish_op(df, 1<<df->nxmerr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#if KA & ITS
|
||||||
|
if (cpu_unit[0].flags & UNIT_ITSPAGE)
|
||||||
|
df->cda = (uint32)((df->cda + 1) & RMASK) | (df->cda & 07000000);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
df->cda = (uint32)((df->cda + 1) & AMASK);
|
||||||
|
data = M[df->cda];
|
||||||
|
} else {
|
||||||
|
data = 0;
|
||||||
|
}
|
||||||
|
df->buf = data;
|
||||||
|
if (df->wcr == 0) {
|
||||||
|
return df10_fetch(df);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int df10_write(struct df10 *df) {
|
||||||
|
if (df->wcr == 0) {
|
||||||
|
if (!df10_fetch(df))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
df->wcr = (uint32)((df->wcr + 1) & WMASK);
|
||||||
|
if (df->cda != 0) {
|
||||||
|
if (df->cda > MEMSIZE) {
|
||||||
|
df10_finish_op(df, 1<<df->nxmerr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#if KA & ITS
|
||||||
|
if (cpu_unit[0].flags & UNIT_ITSPAGE)
|
||||||
|
df->cda = (uint32)((df->cda + 1) & RMASK) | (df->cda & 07000000);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
df->cda = (uint32)((df->cda + 1) & AMASK);
|
||||||
|
M[df->cda] = df->buf;
|
||||||
|
}
|
||||||
|
if (df->wcr == 0) {
|
||||||
|
return df10_fetch(df);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
220
PDP10/kx10_dk.c
Normal file
220
PDP10/kx10_dk.c
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
/* ka10_dk.c: PDP-10 DK subsystem simulator
|
||||||
|
|
||||||
|
Copyright (c) 2013-2017, 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 <time.h>
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_DK
|
||||||
|
#define NUM_DEVS_DK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DK > 0)
|
||||||
|
|
||||||
|
#define DK_DEVNUM 070
|
||||||
|
#define STAT_REG u3
|
||||||
|
#define CLK_REG u4
|
||||||
|
#define INT_REG u5
|
||||||
|
#define CLK_TIM u6
|
||||||
|
|
||||||
|
/* CONO */
|
||||||
|
#define PIA 000007
|
||||||
|
#define CLK_CLR_FLG 000010 /* Clear Clock flag */
|
||||||
|
#define CLK_CLR_OVF 000020 /* Clear OVFL flag */
|
||||||
|
#define CLK_SET_EN 000040 /* Enable Clock */
|
||||||
|
#define CLK_CLR_EN 000100 /* Disable Clock */
|
||||||
|
#define CLK_SET_PI 000200 /* Set PI Control Flip-Flop */
|
||||||
|
#define CLK_CLR_PI 000400 /* Clear PI Control Flip-Flop */
|
||||||
|
#define CLK_GEN_CLR 001000 /* Clear control */
|
||||||
|
#define CLK_ADD_ONE 002000 /* Bump clock */
|
||||||
|
#define CLK_SET_FLG 004000 /* Set Clock Flag */
|
||||||
|
#define CLK_SET_OVF 010000 /* Set OVFL Flag */
|
||||||
|
|
||||||
|
/* CONI */
|
||||||
|
#define CLK_FLG 000010
|
||||||
|
#define CLK_OVF 000020
|
||||||
|
#define CLK_EN 000040
|
||||||
|
#define CLK_PI 000200
|
||||||
|
#define CLK_EXT 001000
|
||||||
|
|
||||||
|
t_stat dk_devio(uint32 dev, uint64 *data);
|
||||||
|
void dk_test (UNIT *uptr);
|
||||||
|
t_stat dk_svc (UNIT *uptr);
|
||||||
|
const char *dk_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
DIB dk_dib[] = {
|
||||||
|
{ DK_DEVNUM, 1, &dk_devio, NULL },
|
||||||
|
{ DK_DEVNUM + 4, 1, &dk_devio, NULL}};
|
||||||
|
|
||||||
|
UNIT dk_unit[] = {
|
||||||
|
{UDATA (&dk_svc, UNIT_IDLE, 0) },
|
||||||
|
#if (NUM_DEVS_DK > 1)
|
||||||
|
{UDATA (&dk_svc, UNIT_IDLE, 0) },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dk_dev = {
|
||||||
|
"DK", dk_unit, NULL, NULL,
|
||||||
|
NUM_DEVS_DK, 0, 0, 0, 0, 0,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
&dk_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, &dk_description
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat dk_devio(uint32 dev, uint64 *data) {
|
||||||
|
int unit = (dev - DK_DEVNUM) >> 2;
|
||||||
|
UNIT *uptr;
|
||||||
|
double us;
|
||||||
|
int32 t;
|
||||||
|
|
||||||
|
if (unit < 0 || unit >= NUM_DEVS_DK)
|
||||||
|
return SCPE_OK;
|
||||||
|
uptr = &dk_unit[unit];
|
||||||
|
switch (dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = (uint64)(uptr->STAT_REG);
|
||||||
|
*data |= ((uint64)uptr->INT_REG) << 18;
|
||||||
|
sim_debug(DEBUG_CONI, &dk_dev, "DK %03o CONI %06o PC=%o %06o\n",
|
||||||
|
dev, (uint32)*data, PC, uptr->CLK_REG);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
/* Adjust U3 */
|
||||||
|
clr_interrupt(dev);
|
||||||
|
uptr->STAT_REG &= ~07;
|
||||||
|
if (*data & CLK_GEN_CLR) {
|
||||||
|
uptr->CLK_REG = 0;
|
||||||
|
uptr->STAT_REG = 0;
|
||||||
|
sim_cancel(uptr);
|
||||||
|
}
|
||||||
|
uptr->STAT_REG |= (uint32)(*data & 07);
|
||||||
|
|
||||||
|
if (*data & CLK_ADD_ONE) {
|
||||||
|
if ((uptr->STAT_REG & CLK_EN) == 0) {
|
||||||
|
uptr->CLK_REG++;
|
||||||
|
dk_test(uptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*data & CLK_SET_EN)
|
||||||
|
uptr->STAT_REG |= CLK_EN;
|
||||||
|
if (*data & CLK_CLR_EN)
|
||||||
|
uptr->STAT_REG &= ~CLK_EN;
|
||||||
|
if (*data & CLK_SET_OVF)
|
||||||
|
uptr->STAT_REG |= CLK_OVF;
|
||||||
|
if (*data & CLK_CLR_OVF)
|
||||||
|
uptr->STAT_REG &= ~CLK_OVF;
|
||||||
|
if (*data & CLK_SET_FLG)
|
||||||
|
uptr->STAT_REG |= CLK_FLG;
|
||||||
|
if (*data & CLK_CLR_FLG)
|
||||||
|
uptr->STAT_REG &= ~CLK_FLG;
|
||||||
|
if (*data & CLK_SET_PI)
|
||||||
|
uptr->STAT_REG |= CLK_PI;
|
||||||
|
if (*data & CLK_CLR_PI)
|
||||||
|
uptr->STAT_REG &= ~CLK_PI;
|
||||||
|
|
||||||
|
if ((uptr->STAT_REG & CLK_EN) != 0 &&
|
||||||
|
(uptr->STAT_REG & (CLK_FLG|CLK_OVF))) {
|
||||||
|
set_interrupt(dev, uptr->STAT_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_clock:
|
||||||
|
if (sim_is_active(uptr)) { /* Save current clock time */
|
||||||
|
us = sim_activate_time_usecs(uptr);
|
||||||
|
uptr->CLK_REG += uptr->CLK_TIM - (uint32)(us / 10.0);
|
||||||
|
sim_cancel(uptr);
|
||||||
|
}
|
||||||
|
if (uptr->INT_REG == uptr->CLK_REG) {
|
||||||
|
uptr->STAT_REG |= CLK_FLG;
|
||||||
|
set_interrupt(dev, uptr->STAT_REG);
|
||||||
|
}
|
||||||
|
if (uptr->STAT_REG & CLK_EN) {
|
||||||
|
if (uptr->INT_REG < uptr->CLK_REG) /* Count until overflow */
|
||||||
|
uptr->CLK_TIM = 01000000;
|
||||||
|
else
|
||||||
|
uptr->CLK_TIM = uptr->INT_REG;
|
||||||
|
t = uptr->CLK_TIM - uptr->CLK_REG;
|
||||||
|
us = (double)(t) * 10.0;
|
||||||
|
sim_activate_after_d(uptr, us);
|
||||||
|
} else {
|
||||||
|
sim_cancel(uptr);
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_CONO, &dk_dev, "DK %03o CONO %06o PC=%06o %06o\n",
|
||||||
|
dev, (uint32)*data, PC, uptr->STAT_REG);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
uptr->INT_REG = (uint32)(*data & RMASK);
|
||||||
|
sim_debug(DEBUG_DATAIO, &dk_dev, "DK %03o DATO %012llo PC=%06o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
goto set_clock;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
if (sim_is_active(uptr)) { /* Save current clock time */
|
||||||
|
double us = sim_activate_time_usecs(uptr);
|
||||||
|
uptr->CLK_REG += uptr->CLK_TIM - (uint32)(us / 10.0);
|
||||||
|
sim_cancel(uptr);
|
||||||
|
}
|
||||||
|
*data = (uint64)(uptr->CLK_REG);
|
||||||
|
sim_debug(DEBUG_DATAIO, &dk_dev, "DK %03o DATI %012llo PC=%06o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
goto set_clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bump counter by 1 */
|
||||||
|
void dk_test (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int dev;
|
||||||
|
if (uptr->CLK_REG & (~RMASK))
|
||||||
|
uptr->STAT_REG |= CLK_OVF;
|
||||||
|
uptr->CLK_REG &= RMASK;
|
||||||
|
if (uptr->INT_REG == uptr->CLK_REG)
|
||||||
|
uptr->STAT_REG |= CLK_FLG;
|
||||||
|
if (uptr->STAT_REG & (CLK_FLG|CLK_OVF)) {
|
||||||
|
dev = ((uptr - dk_unit) << 2) + DK_DEVNUM;
|
||||||
|
set_interrupt(dev, uptr->STAT_REG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timer service - */
|
||||||
|
t_stat dk_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
uptr->CLK_REG = uptr->CLK_TIM;
|
||||||
|
dk_test (uptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dk_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "DK10 Timer module";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
999
PDP10/kx10_dp.c
Normal file
999
PDP10/kx10_dp.c
Normal file
|
@ -0,0 +1,999 @@
|
||||||
|
/* ka10_dp.c: Dec Data Products Disk Drive.
|
||||||
|
|
||||||
|
Copyright (c) 2013-2017, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_DP
|
||||||
|
#define NUM_DEVS_DP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DP > 0)
|
||||||
|
|
||||||
|
#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF)
|
||||||
|
#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define RP_NUMWD 128 /* 36bit words/sec */
|
||||||
|
#define DP_DEVNUM 0250 /* First device number */
|
||||||
|
#define NUM_UNITS_DP 8
|
||||||
|
|
||||||
|
/* Flags in the unit flags word */
|
||||||
|
|
||||||
|
#define DEV_WHDR (1 << DEV_V_UF) /* Enable write headers */
|
||||||
|
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||||
|
#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
|
||||||
|
#define UNIT_M_DTYPE 3
|
||||||
|
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||||
|
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
|
||||||
|
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
|
||||||
|
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||||
|
|
||||||
|
/* Parameters in the unit descriptor */
|
||||||
|
|
||||||
|
#define CUR_CYL u3 /* current cylinder */
|
||||||
|
#define DATAPTR u4 /* data pointer */
|
||||||
|
#define UFLAGS u5 /* Function */
|
||||||
|
#define STATUS u6 /* Drive status */
|
||||||
|
#define SECT_CNT up7 /* Sector counter */
|
||||||
|
#define CONTROL 007
|
||||||
|
#define CMD_MASK 070
|
||||||
|
#define SEEK_DONE 0100 /* Seek finished */
|
||||||
|
#define SEEK_STATE 0200 /* Seek in progress */
|
||||||
|
#define DONE 0400 /* Done bit */
|
||||||
|
|
||||||
|
|
||||||
|
/* CONI/CONO Flags */
|
||||||
|
#define SUF_ERR 0000000000100LL
|
||||||
|
#define SEC_ERR 0000000000200LL
|
||||||
|
#define ILL_CMD 0000000000400LL
|
||||||
|
#define ILL_WR 0000000001000LL
|
||||||
|
#define NOT_RDY 0000000002000LL /* Clear CXR */
|
||||||
|
#define PRT_ERR 0000000004000LL /* 14-17 Clear CCPE, DSPE, DISK WDPE, CDPE */
|
||||||
|
#define NXM_ERR 0000000010000LL
|
||||||
|
#define SLW_CHN 0000000020000LL
|
||||||
|
#define SRC_ERR 0000000040000LL
|
||||||
|
#define PWR_FAIL_10 0000000100000LL
|
||||||
|
#define END_CYL 0000000200000LL /* No effect */
|
||||||
|
#define SRC_DONE 0000000400000LL /* No effect */
|
||||||
|
#define DSK_PRTY 0000001000000LL /* No effect */
|
||||||
|
#define CHN_PRTY 0000002000000LL /* No effect */
|
||||||
|
#define SEC_PRTY 0000004000000LL /* No effect */
|
||||||
|
#define CCW_PRTY 0000010000000LL /* No effect */
|
||||||
|
#define B22_FLAG 0000020000000LL
|
||||||
|
|
||||||
|
#define CLRMSK 0000000177710LL
|
||||||
|
#define CLRMSK2 0000176000000LL
|
||||||
|
|
||||||
|
/* DATAO */
|
||||||
|
#define DWPE_STOP 0000000001000LL
|
||||||
|
#define SPARE 0000000002000LL
|
||||||
|
#define DSPE_STOP 0000000004000LL
|
||||||
|
#define SECTOR 0000000170000LL
|
||||||
|
#define CYL256 0000000200000LL
|
||||||
|
#define SURFACE 0000017400000LL
|
||||||
|
#define CYL 0007760000000LL
|
||||||
|
#define DRIVE 0070000000000LL
|
||||||
|
#define OP 0700000000000LL
|
||||||
|
|
||||||
|
#define RD 0
|
||||||
|
#define WR 1
|
||||||
|
#define RV 2
|
||||||
|
#define WH 3
|
||||||
|
#define SK 4
|
||||||
|
#define CL 5
|
||||||
|
#define NO 6
|
||||||
|
#define RC 7
|
||||||
|
|
||||||
|
/* DATAI Flags */
|
||||||
|
#define ATTN 0000000000776LL
|
||||||
|
#define DEFECT 0000000001000LL
|
||||||
|
#define SEL_RP03 0000000002000LL
|
||||||
|
#define SEL_CYL256 0000000004000LL
|
||||||
|
#define SEL_SPARE 0000000010000LL
|
||||||
|
#define SEL_SEC 0000000760000LL
|
||||||
|
#define WR_HD_LK 0000001000000LL
|
||||||
|
#define RD_ONLY 0000002000000LL
|
||||||
|
#define NO_DRIVE 0000004000000LL
|
||||||
|
#define FILE_UNSAFE 0000010000000LL
|
||||||
|
#define DRV_ONLINE 0000020000000LL
|
||||||
|
#define ON_CYL 0000040000000LL
|
||||||
|
#define SEEK_INC 0000100000000LL
|
||||||
|
#define SEL_CYL 0077600000000LL
|
||||||
|
#define SEL_DRIVE 0700000000000LL
|
||||||
|
|
||||||
|
#define RP01_DTYPE 0
|
||||||
|
#define RP01_SECT 5
|
||||||
|
#define RP01_SURF 10
|
||||||
|
#define RP01_CYL 203
|
||||||
|
#define RP01_DEV 0
|
||||||
|
#define RP01_SIZE (RP01_SECT * RP01_SURF * RP01_CYL * RP_NUMWD)
|
||||||
|
|
||||||
|
#define RP02_DTYPE 1
|
||||||
|
#define RP02_SECT 10
|
||||||
|
#define RP02_SURF 20
|
||||||
|
#define RP02_CYL 203
|
||||||
|
#define RP02_DEV 0
|
||||||
|
#define RP02_SIZE (RP02_SECT * RP02_SURF * RP02_CYL * RP_NUMWD)
|
||||||
|
|
||||||
|
#define RP03_DTYPE 2
|
||||||
|
#define RP03_SECT 10
|
||||||
|
#define RP03_SURF 20
|
||||||
|
#define RP03_CYL 406
|
||||||
|
#define RP03_DEV 1
|
||||||
|
#define RP03_SIZE (RP03_SECT * RP03_SURF * RP03_CYL * RP_NUMWD)
|
||||||
|
|
||||||
|
struct drvtyp {
|
||||||
|
int32 sect; /* sectors */
|
||||||
|
int32 surf; /* surfaces */
|
||||||
|
int32 cyl; /* cylinders */
|
||||||
|
int32 size; /* #blocks */
|
||||||
|
int32 devtype; /* device type */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drvtyp dp_drv_tab[] = {
|
||||||
|
{ RP01_SECT, RP01_SURF, RP01_CYL, RP01_SIZE, RP01_DTYPE},
|
||||||
|
{ RP02_SECT, RP02_SURF, RP02_CYL, RP02_SIZE, RP02_DTYPE},
|
||||||
|
{ RP03_SECT, RP03_SURF, RP03_CYL, RP03_SIZE, RP03_DTYPE},
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct df10 dp_df10[NUM_DEVS_DP];
|
||||||
|
uint32 dp_cur_unit[NUM_DEVS_DP];
|
||||||
|
uint64 dp_buf[NUM_DEVS_DP][RP_NUMWD];
|
||||||
|
int readin_flag = 0;
|
||||||
|
|
||||||
|
t_stat dp_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat dp_svc(UNIT *);
|
||||||
|
t_stat dp_boot(int32, DEVICE *);
|
||||||
|
void dp_ini(UNIT *, t_bool);
|
||||||
|
t_stat dp_reset(DEVICE *);
|
||||||
|
t_stat dp_attach(UNIT *, CONST char *);
|
||||||
|
t_stat dp_detach(UNIT *);
|
||||||
|
t_stat dp_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dp_set_hdr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dp_show_hdr(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||||
|
t_stat dp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *dp_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
UNIT dp_unit[] = {
|
||||||
|
/* Controller 1 */
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DP > 1)
|
||||||
|
/* Controller 2 */
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
#if (NUM_DEVS_DP > 2)
|
||||||
|
/* Controller 3 */
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
#if (NUM_DEVS_DP > 3)
|
||||||
|
/* Controller 4 */
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
{ UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RP03_DTYPE << UNIT_V_DTYPE), RP03_SIZE) },
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB dp_dib[] = {
|
||||||
|
{DP_DEVNUM+000, 1, &dp_devio, NULL},
|
||||||
|
{DP_DEVNUM+004, 1, &dp_devio, NULL},
|
||||||
|
{DP_DEVNUM+010, 1, &dp_devio, NULL},
|
||||||
|
{DP_DEVNUM+014, 1, &dp_devio, NULL}};
|
||||||
|
|
||||||
|
|
||||||
|
MTAB dp_mod[] = {
|
||||||
|
{UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||||||
|
{UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL},
|
||||||
|
{MTAB_XTD|MTAB_VDV, 0, NULL, "NOHEADERS",
|
||||||
|
&dp_set_hdr, &dp_show_hdr, NULL, "Disable header writing"},
|
||||||
|
{MTAB_XTD|MTAB_VDV, DEV_WHDR, "write header", "HEADERS",
|
||||||
|
&dp_set_hdr, &dp_show_hdr, NULL, "Enable header writing"},
|
||||||
|
{UNIT_DTYPE, (RP03_DTYPE << UNIT_V_DTYPE), "RP03", "RP03", &dp_set_type },
|
||||||
|
{UNIT_DTYPE, (RP02_DTYPE << UNIT_V_DTYPE), "RP02", "RP02", &dp_set_type },
|
||||||
|
{UNIT_DTYPE, (RP01_DTYPE << UNIT_V_DTYPE), "RP01", "RP01", &dp_set_type },
|
||||||
|
{0},
|
||||||
|
};
|
||||||
|
|
||||||
|
REG dpa_reg[] = {
|
||||||
|
{BRDATA(BUFF, &dp_buf[0][0], 16, 64, RP_NUMWD), REG_HRO},
|
||||||
|
{BRDATA(UNIT, &dp_cur_unit[0], 16, 8, 1), REG_HRO},
|
||||||
|
{FLDATA(READIN, readin_flag, 0), REG_HRO},
|
||||||
|
{ORDATA(STATUS, dp_df10[0].status, 18), REG_RO},
|
||||||
|
{ORDATA(CIA, dp_df10[0].cia, 18)},
|
||||||
|
{ORDATA(CCW, dp_df10[0].ccw, 18)},
|
||||||
|
{ORDATA(WCR, dp_df10[0].wcr, 18)},
|
||||||
|
{ORDATA(CDA, dp_df10[0].cda, 18)},
|
||||||
|
{ORDATA(DEVNUM, dp_df10[0].devnum, 9), REG_HRO},
|
||||||
|
{ORDATA(BUF, dp_df10[0].buf, 36), REG_HRO},
|
||||||
|
{ORDATA(NXM, dp_df10[0].nxmerr, 8), REG_HRO},
|
||||||
|
{ORDATA(COMP, dp_df10[0].ccw_comp, 8), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dpa_dev = {
|
||||||
|
"DPA", dp_unit, dpa_reg, dp_mod,
|
||||||
|
NUM_UNITS_DP, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &dp_reset, &dp_boot, &dp_attach, &dp_detach,
|
||||||
|
&dp_dib[0], DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &dp_help, NULL, NULL, &dp_description
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DP > 1)
|
||||||
|
REG dpb_reg[] = {
|
||||||
|
{BRDATA(BUFF, &dp_buf[1][0], 16, 64, RP_NUMWD), REG_HRO},
|
||||||
|
{BRDATA(DF10, &dp_cur_unit[1], 16, 8, 1), REG_HRO},
|
||||||
|
{ORDATA(STATUS, dp_df10[1].status, 18), REG_RO},
|
||||||
|
{ORDATA(CIA, dp_df10[1].cia, 18)},
|
||||||
|
{ORDATA(CCW, dp_df10[1].ccw, 18)},
|
||||||
|
{ORDATA(WCR, dp_df10[1].wcr, 18)},
|
||||||
|
{ORDATA(CDA, dp_df10[1].cda, 18)},
|
||||||
|
{ORDATA(DEVNUM, dp_df10[1].devnum, 9), REG_HRO},
|
||||||
|
{ORDATA(BUF, dp_df10[1].buf, 36), REG_HRO},
|
||||||
|
{ORDATA(NXM, dp_df10[1].nxmerr, 8), REG_HRO},
|
||||||
|
{ORDATA(COMP, dp_df10[1].ccw_comp, 8), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dpb_dev = {
|
||||||
|
"DPB", &dp_unit[010], dpb_reg, dp_mod,
|
||||||
|
NUM_UNITS_DP, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &dp_reset, &dp_boot, &dp_attach, &dp_detach,
|
||||||
|
&dp_dib[1], DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &dp_help, NULL, NULL, &dp_description
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DP > 2)
|
||||||
|
REG dpc_reg[] = {
|
||||||
|
{BRDATA(BUFF, &dp_buf[2][0], 16, 64, RP_NUMWD), REG_HRO},
|
||||||
|
{BRDATA(DF10, &dp_cur_unit[2], 16, 8, 1), REG_HRO},
|
||||||
|
{ORDATA(STATUS, dp_df10[2].status, 18), REG_RO},
|
||||||
|
{ORDATA(CIA, dp_df10[2].cia, 18)},
|
||||||
|
{ORDATA(CCW, dp_df10[2].ccw, 18)},
|
||||||
|
{ORDATA(WCR, dp_df10[2].wcr, 18)},
|
||||||
|
{ORDATA(CDA, dp_df10[2].cda, 18)},
|
||||||
|
{ORDATA(DEVNUM, dp_df10[2].devnum, 9), REG_HRO},
|
||||||
|
{ORDATA(BUF, dp_df10[2].buf, 36), REG_HRO},
|
||||||
|
{ORDATA(NXM, dp_df10[2].nxmerr, 8), REG_HRO},
|
||||||
|
{ORDATA(COMP, dp_df10[2].ccw_comp, 8), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dpc_dev = {
|
||||||
|
"DPC", &dp_unit[020], dpc_reg, dp_mod,
|
||||||
|
NUM_UNITS_DP, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &dp_reset, &dp_boot, &dp_attach, &dp_detach,
|
||||||
|
&dp_dib[2], DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &dp_help, NULL, NULL, &dp_description
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DP > 3)
|
||||||
|
REG dpd_reg[] = {
|
||||||
|
{BRDATA(BUFF, &dp_buf[3][0], 16, 64, RP_NUMWD), REG_HRO},
|
||||||
|
{BRDATA(DF10, &dp_cur_unit[3], 16, 8, 1), REG_HRO},
|
||||||
|
{ORDATA(STATUS, dp_df10[3].status, 18), REG_RO},
|
||||||
|
{ORDATA(CIA, dp_df10[3].cia, 18)},
|
||||||
|
{ORDATA(CCW, dp_df10[3].ccw, 18)},
|
||||||
|
{ORDATA(WCR, dp_df10[3].wcr, 18)},
|
||||||
|
{ORDATA(CDA, dp_df10[3].cda, 18)},
|
||||||
|
{ORDATA(DEVNUM, dp_df10[3].devnum, 9), REG_HRO},
|
||||||
|
{ORDATA(BUF, dp_df10[3].buf, 36), REG_HRO},
|
||||||
|
{ORDATA(NXM, dp_df10[3].nxmerr, 8), REG_HRO},
|
||||||
|
{ORDATA(COMP, dp_df10[3].ccw_comp, 8), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dpd_dev = {
|
||||||
|
"DPD", &dp_unit[030], dpd_reg, dp_mod,
|
||||||
|
NUM_UNITS_DP, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &dp_reset, &dp_boot, &dp_attach, &dp_detach,
|
||||||
|
&dp_dib[3], DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &dp_help, NULL, NULL, &dp_description
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEVICE *dp_devs[] = {
|
||||||
|
&dpa_dev,
|
||||||
|
#if (NUM_DEVS_DP > 1)
|
||||||
|
&dpb_dev,
|
||||||
|
#if (NUM_DEVS_DP > 2)
|
||||||
|
&dpc_dev,
|
||||||
|
#if (NUM_DEVS_DP > 3)
|
||||||
|
&dpd_dev,
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
t_stat dp_devio(uint32 dev, uint64 *data) {
|
||||||
|
uint64 res;
|
||||||
|
int ctlr = (dev - DP_DEVNUM) >> 2;
|
||||||
|
struct df10 *df10;
|
||||||
|
DEVICE *dptr;
|
||||||
|
UNIT *uptr;
|
||||||
|
int unit;
|
||||||
|
int cyl;
|
||||||
|
int tmp;
|
||||||
|
static int sect_count;
|
||||||
|
|
||||||
|
if (ctlr < 0 || ctlr >= NUM_DEVS_DP)
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
df10 = &dp_df10[ctlr];
|
||||||
|
dptr = dp_devs[ctlr];
|
||||||
|
unit = dp_cur_unit[ctlr];
|
||||||
|
uptr = &dp_unit[(ctlr * NUM_UNITS_DP) + unit];
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = (uint64)(df10->status | uptr->STATUS);
|
||||||
|
#if KI_22BIT
|
||||||
|
*data |= B22_FLAG;
|
||||||
|
#endif
|
||||||
|
sim_debug(DEBUG_CONI, dptr, "DP %03o CONI %012llo %d PC=%o\n", dev,
|
||||||
|
*data, ctlr, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
df10->status &= ~07LL;
|
||||||
|
df10->status |= *data & 07LL;
|
||||||
|
if (*data & BUSY) {
|
||||||
|
/* Stop controller */
|
||||||
|
sim_cancel(uptr);
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
df10_finish_op(df10, 0);
|
||||||
|
}
|
||||||
|
/* Clear flags */
|
||||||
|
uptr->STATUS &= ~(*data & CLRMSK);
|
||||||
|
if (*data & PRT_ERR)
|
||||||
|
uptr->STATUS &= ~(CLRMSK2);
|
||||||
|
if (*data & CCW_COMP) {
|
||||||
|
df10_writecw(df10);
|
||||||
|
df10->status &= ~CCW_COMP;
|
||||||
|
}
|
||||||
|
if (*data & PI_ENABLE) {
|
||||||
|
uptr->UFLAGS &= ~DONE;
|
||||||
|
/* Check if any drives still reporting seek done */
|
||||||
|
tmp = 1;
|
||||||
|
uptr = &dp_unit[ctlr * NUM_UNITS_DP];
|
||||||
|
for(unit = 0; unit < NUM_UNITS_DP; unit++) {
|
||||||
|
if (uptr->UFLAGS & SEEK_DONE) {
|
||||||
|
tmp = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr++;
|
||||||
|
}
|
||||||
|
if (tmp)
|
||||||
|
df10->status &= ~PI_ENABLE;
|
||||||
|
else
|
||||||
|
df10_setirq(df10);
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_CONO, dptr, "DP %03o CONO %06o %d PC=%o %06o\n", dev,
|
||||||
|
(uint32)*data, ctlr, PC, df10->status);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
res = (uint64)(unit) << 33;
|
||||||
|
if ((dptr->flags & DEV_WHDR) == 0)
|
||||||
|
res |= WR_HD_LK; /* Can't write headers. */
|
||||||
|
if (dp_drv_tab[GET_DTYPE(uptr->flags)].devtype == RP03_DTYPE)
|
||||||
|
res |= SEL_RP03;
|
||||||
|
if (uptr->flags & UNIT_DIS) {
|
||||||
|
res |= NO_DRIVE;
|
||||||
|
} else if (uptr->flags & UNIT_ATT) {
|
||||||
|
res |= DRV_ONLINE;
|
||||||
|
cyl = uptr->CUR_CYL;
|
||||||
|
res |= ((uint64)(cyl & 0377)) << 25;
|
||||||
|
if (cyl & 0400)
|
||||||
|
res |= SEL_CYL256;
|
||||||
|
if (sect_count > 20)
|
||||||
|
sect_count = 0;
|
||||||
|
res |= SEL_SEC & (uint64)(sect_count << 13);
|
||||||
|
sect_count++;
|
||||||
|
if ((uptr->UFLAGS & SEEK_STATE) == 0)
|
||||||
|
res |= ON_CYL;
|
||||||
|
if (uptr->flags & UNIT_WPRT)
|
||||||
|
res |= RD_ONLY|WR_HD_LK;
|
||||||
|
}
|
||||||
|
uptr = &dp_unit[ctlr * NUM_UNITS_DP];
|
||||||
|
for(unit = 0; unit < NUM_UNITS_DP; unit++) {
|
||||||
|
if (uptr->UFLAGS & SEEK_DONE)
|
||||||
|
res |= 0400>>unit;
|
||||||
|
uptr++;
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr, "DP %03o DATI %012llo %d PC=%o F=%o %o\n",
|
||||||
|
dev, res, ctlr, PC, uptr->UFLAGS, sect_count);
|
||||||
|
*data = res;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr, "DP %03o DATO %012llo, %d PC=%o\n",
|
||||||
|
dev, *data, ctlr, PC);
|
||||||
|
if (df10->status & BUSY) {
|
||||||
|
uptr->STATUS |= ILL_CMD;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
clr_interrupt(dev);
|
||||||
|
df10->status &= ~(PI_ENABLE|CCW_COMP);
|
||||||
|
unit = (*data >> 30) & 07;
|
||||||
|
dp_cur_unit[ctlr] = unit;
|
||||||
|
uptr = &dp_unit[(ctlr * NUM_UNITS_DP) + unit];
|
||||||
|
if ((uptr->STATUS & NOT_RDY) == 0) {
|
||||||
|
uptr->STATUS &= ~(SUF_ERR|SEC_ERR|SRC_ERR|NXM_ERR|ILL_WR|
|
||||||
|
NO_DRIVE|NOT_RDY|ILL_CMD|END_CYL|SRC_DONE);
|
||||||
|
}
|
||||||
|
cyl = ((*data >> 22) & 0377);
|
||||||
|
if (*data & CYL256)
|
||||||
|
cyl += 0400;
|
||||||
|
tmp = (*data >> 33) & 07;
|
||||||
|
switch(tmp) {
|
||||||
|
case WH:
|
||||||
|
if ((dptr->flags & DEV_WHDR) == 0) {
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
uptr->STATUS |= ILL_WR;
|
||||||
|
df10_setirq(df10);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
*data &= ~SECTOR; /* Clear sector */
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
|
case WR:
|
||||||
|
if (uptr->flags & UNIT_WPRT) {
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
uptr->STATUS |= ILL_WR;
|
||||||
|
df10_setirq(df10);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
|
case RD:
|
||||||
|
case RV:
|
||||||
|
if (uptr->flags & UNIT_DIS) {
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
uptr->STATUS |= NO_DRIVE;
|
||||||
|
df10_setirq(df10);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
uptr->STATUS |= NOT_RDY;
|
||||||
|
df10_setirq(df10);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
uptr->UFLAGS = ((*data & (SURFACE|SECTOR)) >> 3) | (cyl << 20)
|
||||||
|
| (tmp << 3) | ctlr;
|
||||||
|
uptr->DATAPTR = 0; /* Set no data */
|
||||||
|
CLR_BUF(uptr);
|
||||||
|
df10_setup(df10, (uint32)*data);
|
||||||
|
uptr->STATUS |= BUSY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RC:
|
||||||
|
cyl = 0;
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
|
case SK:
|
||||||
|
uptr->STATUS |= NOT_RDY;
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
return SCPE_OK;
|
||||||
|
uptr->UFLAGS = (cyl << 20) | (tmp<<3) | ctlr | SEEK_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CL:
|
||||||
|
uptr->UFLAGS &= ~DONE;
|
||||||
|
uptr = &dp_unit[ctlr * NUM_UNITS_DP];
|
||||||
|
for(unit = 0; unit < NUM_UNITS_DP; unit++) {
|
||||||
|
if (*data & (0400 >> unit))
|
||||||
|
uptr->UFLAGS &= ~(SEEK_DONE);
|
||||||
|
uptr++;
|
||||||
|
}
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
|
case NO:
|
||||||
|
tmp = 0;
|
||||||
|
uptr = &dp_unit[ctlr * NUM_UNITS_DP];
|
||||||
|
for(unit = 0; unit < NUM_UNITS_DP; unit++) {
|
||||||
|
if (uptr->UFLAGS & SEEK_DONE) {
|
||||||
|
tmp = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr++;
|
||||||
|
}
|
||||||
|
if (tmp) {
|
||||||
|
df10_setirq(df10);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
sim_activate(uptr, 150);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat dp_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int dtype = GET_DTYPE(uptr->flags);
|
||||||
|
int ctlr = uptr->UFLAGS & 03;
|
||||||
|
int cmd = (uptr->UFLAGS & 070) >> 3;
|
||||||
|
int sect = (uptr->UFLAGS >> 9);
|
||||||
|
int surf = (sect >> 5) & 037;
|
||||||
|
int cyl = (uptr->UFLAGS >> 20) & 0777;
|
||||||
|
DEVICE *dptr = dp_devs[ctlr];
|
||||||
|
struct df10 *df10 = &dp_df10[ctlr];
|
||||||
|
int diff, diffs, wc;
|
||||||
|
int r;
|
||||||
|
sect &= 017;
|
||||||
|
|
||||||
|
switch(cmd) {
|
||||||
|
case WR:
|
||||||
|
case RV:
|
||||||
|
case RD:
|
||||||
|
/* Cylinder, Surface, Sector all ok */
|
||||||
|
if (BUF_EMPTY(uptr)) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr,
|
||||||
|
"DP %d cmd=%o cyl=%d (%o) sect=%d surf=%d %d\n",
|
||||||
|
ctlr, uptr->UFLAGS, cyl, cyl, sect, surf,uptr->CUR_CYL);
|
||||||
|
uptr->STATUS |= SRC_DONE;
|
||||||
|
if (uptr->STATUS & END_CYL) {
|
||||||
|
if (cmd == WR) {
|
||||||
|
if(df10_read(df10))
|
||||||
|
df10_read(df10);
|
||||||
|
}
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
df10_finish_op(df10, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (sect >= dp_drv_tab[dtype].sect) {
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
uptr->STATUS |= SEC_ERR;
|
||||||
|
}
|
||||||
|
if (surf >= dp_drv_tab[dtype].surf) {
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
uptr->STATUS |= SUF_ERR;
|
||||||
|
}
|
||||||
|
if (cyl != uptr->CUR_CYL) {
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
uptr->STATUS |= SRC_ERR;
|
||||||
|
}
|
||||||
|
if ((uptr->STATUS & BUSY) == 0) {
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
df10_finish_op(df10, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (cmd != WR) {
|
||||||
|
/* Read the block */
|
||||||
|
int da = ((cyl * dp_drv_tab[dtype].surf + surf)
|
||||||
|
* dp_drv_tab[dtype].sect + sect) * RP_NUMWD;
|
||||||
|
(void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
wc = sim_fread (&dp_buf[ctlr][0], sizeof(uint64), RP_NUMWD,
|
||||||
|
uptr->fileref);
|
||||||
|
for (; wc < RP_NUMWD; wc++)
|
||||||
|
dp_buf[ctlr][wc] = 0;
|
||||||
|
uptr->hwmark = RP_NUMWD;
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
sect = sect + 1;
|
||||||
|
if (sect >= dp_drv_tab[dtype].sect) {
|
||||||
|
sect = 0;
|
||||||
|
surf = surf + 1;
|
||||||
|
if (surf >= dp_drv_tab[dtype].surf) {
|
||||||
|
uptr->STATUS |= END_CYL;
|
||||||
|
} else {
|
||||||
|
uptr->UFLAGS &= ~(01757000);
|
||||||
|
uptr->UFLAGS |= (surf << 14);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uptr->UFLAGS &= ~(017000);
|
||||||
|
uptr->UFLAGS |= (sect << 9);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
uptr->hwmark = 0;
|
||||||
|
}
|
||||||
|
sim_activate(uptr, 50);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
switch(cmd) {
|
||||||
|
case WR:
|
||||||
|
r = df10_read(df10);
|
||||||
|
if (r)
|
||||||
|
uptr->hwmark = uptr->DATAPTR;
|
||||||
|
dp_buf[ctlr][uptr->DATAPTR] = df10->buf;
|
||||||
|
break;
|
||||||
|
case RV:
|
||||||
|
case RD:
|
||||||
|
df10->buf = dp_buf[ctlr][uptr->DATAPTR];
|
||||||
|
r = df10_write(df10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "Xfer %d %08o %012llo %08o\n",
|
||||||
|
uptr->DATAPTR, df10->cda, df10->buf, df10->wcr);
|
||||||
|
uptr->DATAPTR++;
|
||||||
|
if (uptr->DATAPTR >= RP_NUMWD || r == 0 ) {
|
||||||
|
if (cmd == WR) {
|
||||||
|
int da = ((cyl * dp_drv_tab[dtype].surf + surf)
|
||||||
|
* dp_drv_tab[dtype].sect + sect) * RP_NUMWD;
|
||||||
|
/* write block the block */
|
||||||
|
for (; uptr->DATAPTR < RP_NUMWD; uptr->DATAPTR++)
|
||||||
|
dp_buf[ctlr][uptr->DATAPTR] = 0;
|
||||||
|
(void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
wc = sim_fwrite(&dp_buf[ctlr][0],sizeof(uint64), RP_NUMWD,
|
||||||
|
uptr->fileref);
|
||||||
|
uptr->STATUS |= SRC_DONE;
|
||||||
|
sect = sect + 1;
|
||||||
|
if (sect >= dp_drv_tab[dtype].sect) {
|
||||||
|
sect = 0;
|
||||||
|
surf = surf + 1;
|
||||||
|
if (surf >= dp_drv_tab[dtype].surf) {
|
||||||
|
uptr->STATUS |= END_CYL;
|
||||||
|
} else {
|
||||||
|
uptr->UFLAGS &= ~(01757 << 9);
|
||||||
|
uptr->UFLAGS |= (surf << 14);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uptr->UFLAGS &= ~(017 << 9);
|
||||||
|
uptr->UFLAGS |= (sect << 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
CLR_BUF(uptr);
|
||||||
|
}
|
||||||
|
if (r)
|
||||||
|
sim_activate(uptr, 25);
|
||||||
|
else {
|
||||||
|
uptr->STATUS &= ~(SRC_DONE|END_CYL|BUSY);
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WH:
|
||||||
|
/* Cylinder, Surface, Sector all ok */
|
||||||
|
if (BUF_EMPTY(uptr)) {
|
||||||
|
if (uptr->DATAPTR == 0)
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr,
|
||||||
|
"DP %d cmd=%o cyl=%d (%o) sect=%d surf=%d %d\n",
|
||||||
|
ctlr, uptr->UFLAGS, cyl, cyl, sect, surf,uptr->CUR_CYL);
|
||||||
|
uptr->STATUS |= SRC_DONE;
|
||||||
|
if (uptr->STATUS & END_CYL) {
|
||||||
|
if(df10_read(df10))
|
||||||
|
df10_read(df10);
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
df10_finish_op(df10, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (sect >= dp_drv_tab[dtype].sect) {
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
uptr->STATUS |= SEC_ERR;
|
||||||
|
}
|
||||||
|
if (surf >= dp_drv_tab[dtype].surf) {
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
uptr->STATUS |= SUF_ERR;
|
||||||
|
}
|
||||||
|
if (cyl != uptr->CUR_CYL) {
|
||||||
|
uptr->STATUS &= ~BUSY;
|
||||||
|
uptr->STATUS |= SRC_ERR;
|
||||||
|
}
|
||||||
|
if ((uptr->STATUS & BUSY) == 0) {
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
df10_finish_op(df10, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
r = df10_read(df10);
|
||||||
|
uptr->DATAPTR++;
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "Xfer h%d %012llo\n",
|
||||||
|
uptr->DATAPTR, df10->buf);
|
||||||
|
if (uptr->DATAPTR == 36) {
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
uptr->hwmark = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = df10_read(df10);
|
||||||
|
if (r)
|
||||||
|
uptr->hwmark = uptr->DATAPTR;
|
||||||
|
dp_buf[ctlr][uptr->DATAPTR] = (df10->buf << 1) & FMASK;
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "Xfer %d %012llo\n",
|
||||||
|
uptr->DATAPTR, df10->buf);
|
||||||
|
uptr->DATAPTR++;
|
||||||
|
if (uptr->DATAPTR >= RP_NUMWD || r == 0 ) {
|
||||||
|
int da = ((cyl * dp_drv_tab[dtype].surf + surf)
|
||||||
|
* dp_drv_tab[dtype].sect + sect) * RP_NUMWD;
|
||||||
|
/* write block the block */
|
||||||
|
for (; uptr->DATAPTR < RP_NUMWD; uptr->DATAPTR++)
|
||||||
|
dp_buf[ctlr][uptr->DATAPTR] = 0;
|
||||||
|
(void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
wc = sim_fwrite(&dp_buf[ctlr][0],sizeof(uint64), RP_NUMWD,
|
||||||
|
uptr->fileref);
|
||||||
|
uptr->STATUS |= SRC_DONE;
|
||||||
|
sect = sect + 1;
|
||||||
|
if (sect >= dp_drv_tab[dtype].sect) {
|
||||||
|
uptr->STATUS |= END_CYL;
|
||||||
|
} else {
|
||||||
|
uptr->UFLAGS &= ~(017 << 9);
|
||||||
|
uptr->UFLAGS |= (sect << 9);
|
||||||
|
}
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
CLR_BUF(uptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r)
|
||||||
|
sim_activate(uptr, 25);
|
||||||
|
else {
|
||||||
|
uptr->STATUS &= ~(SRC_DONE|END_CYL|BUSY);
|
||||||
|
uptr->UFLAGS |= DONE;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CL:
|
||||||
|
case NO:
|
||||||
|
return SCPE_OK;
|
||||||
|
case RC:
|
||||||
|
case SK:
|
||||||
|
if(uptr->UFLAGS & SEEK_STATE) {
|
||||||
|
diff = cyl - uptr->CUR_CYL;
|
||||||
|
diffs = (diff < 0) ? -1 : 1;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DP Seek %d %d %d %d\n",
|
||||||
|
ctlr, cyl, uptr->CUR_CYL, diff);
|
||||||
|
if (diff == 0) {
|
||||||
|
uptr->UFLAGS |= SEEK_DONE;
|
||||||
|
uptr->UFLAGS &= ~SEEK_STATE;
|
||||||
|
uptr->STATUS &= ~(NOT_RDY);
|
||||||
|
if ((df10->status & BUSY) == 0)
|
||||||
|
df10_setirq(df10);
|
||||||
|
} else if (diff < 10 && diff > -10) {
|
||||||
|
uptr->CUR_CYL += diffs;
|
||||||
|
if (uptr->CUR_CYL < 0) {
|
||||||
|
uptr->UFLAGS |= SEEK_DONE;
|
||||||
|
uptr->UFLAGS &= ~SEEK_STATE;
|
||||||
|
uptr->STATUS &= ~(NOT_RDY);
|
||||||
|
uptr->CUR_CYL = 0;
|
||||||
|
if ((df10->status & BUSY) == 0)
|
||||||
|
df10_setirq(df10);
|
||||||
|
} else if (uptr->CUR_CYL > dp_drv_tab[dtype].cyl) {
|
||||||
|
uptr->UFLAGS |= SEEK_DONE;
|
||||||
|
uptr->UFLAGS &= ~SEEK_STATE;
|
||||||
|
uptr->STATUS &= ~(NOT_RDY);
|
||||||
|
uptr->CUR_CYL = dp_drv_tab[dtype].cyl;
|
||||||
|
if ((df10->status & BUSY) == 0)
|
||||||
|
df10_setirq(df10);
|
||||||
|
} else
|
||||||
|
sim_activate(uptr, 500);
|
||||||
|
} else if (diff > 100 || diff < -100) {
|
||||||
|
uptr->CUR_CYL += diffs * 100;
|
||||||
|
sim_activate(uptr, 4000);
|
||||||
|
} else {
|
||||||
|
uptr->CUR_CYL += diffs * 10;
|
||||||
|
sim_activate(uptr, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dp_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (uptr == NULL) return SCPE_IERR;
|
||||||
|
for (i = 0; dp_drv_tab[i].sect != 0; i++) {
|
||||||
|
if (GET_DTYPE(val) == dp_drv_tab[i].devtype) {
|
||||||
|
uptr->flags &= ~(UNIT_DTYPE);
|
||||||
|
uptr->flags |= val;
|
||||||
|
uptr->capac = dp_drv_tab[i].size;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_IERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dp_set_hdr(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_WHDR;
|
||||||
|
dptr->flags |= val;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat dp_show_hdr (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 & DEV_WHDR) ? "HEADERS" : "NOHEADERS");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dp_reset(DEVICE * dptr)
|
||||||
|
{
|
||||||
|
int unit;
|
||||||
|
int ctlr;
|
||||||
|
UNIT *uptr = dptr->units;
|
||||||
|
for(unit = 0; unit < NUM_UNITS_DP; unit++) {
|
||||||
|
uptr->UFLAGS = 0;
|
||||||
|
uptr->STATUS = 0;
|
||||||
|
uptr->CUR_CYL = 0;
|
||||||
|
uptr++;
|
||||||
|
}
|
||||||
|
for (ctlr = 0; ctlr < NUM_DEVS_DP; ctlr++) {
|
||||||
|
dp_df10[ctlr].status = 0;
|
||||||
|
dp_df10[ctlr].devnum = dp_dib[ctlr].dev_num;
|
||||||
|
dp_df10[ctlr].nxmerr = 12;
|
||||||
|
dp_df10[ctlr].ccw_comp = 5;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boot from given device */
|
||||||
|
t_stat
|
||||||
|
dp_boot(int32 unit_num, DEVICE * dptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &dptr->units[unit_num];
|
||||||
|
uint32 addr;
|
||||||
|
uint32 ptr;
|
||||||
|
int sect;
|
||||||
|
int wc;
|
||||||
|
|
||||||
|
addr = (MEMSIZE - 512) & RMASK;
|
||||||
|
for (sect = 4; sect <= 7; sect++) {
|
||||||
|
(void)sim_fseek(uptr->fileref, (sect * RP_NUMWD) * sizeof(uint64), SEEK_SET);
|
||||||
|
(void)sim_fread (&dp_buf[0][0], sizeof(uint64), RP_NUMWD, uptr->fileref);
|
||||||
|
ptr = 0;
|
||||||
|
for(wc = RP_NUMWD; wc > 0; wc--)
|
||||||
|
M[addr++] = dp_buf[0][ptr++];
|
||||||
|
}
|
||||||
|
PC = (MEMSIZE - 512) & RMASK;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device attach */
|
||||||
|
|
||||||
|
t_stat dp_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
DEVICE *dptr;
|
||||||
|
DIB *dib;
|
||||||
|
int ctlr;
|
||||||
|
|
||||||
|
uptr->capac = dp_drv_tab[GET_DTYPE (uptr->flags)].size;
|
||||||
|
r = attach_unit (uptr, cptr);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
dptr = find_dev_from_unit(uptr);
|
||||||
|
if (dptr == 0)
|
||||||
|
return SCPE_OK;
|
||||||
|
dib = (DIB *) dptr->ctxt;
|
||||||
|
ctlr = dib->dev_num & 014;
|
||||||
|
uptr->CUR_CYL = 0;
|
||||||
|
uptr->UFLAGS = (NO << 3) | SEEK_DONE | (ctlr >> 2);
|
||||||
|
dp_df10[ctlr].status |= PI_ENABLE;
|
||||||
|
set_interrupt(DP_DEVNUM + (ctlr), dp_df10[ctlr >> 2].status);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device detach */
|
||||||
|
|
||||||
|
t_stat dp_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
if (!(uptr->flags & UNIT_ATT)) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
|
if (sim_is_active (uptr)) /* unit active? */
|
||||||
|
sim_cancel (uptr); /* cancel operation */
|
||||||
|
return detach_unit (uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat dp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "RP10 RP01/2/3 Disk Pack Drives (DP)\n\n");
|
||||||
|
fprintf (st, "The DP controller implements the RP10 disk drives. RP\n");
|
||||||
|
fprintf (st, "options include the ability to set units write enabled or write locked, to\n");
|
||||||
|
fprintf (st, "set the drive type to one of three disk types.\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n");
|
||||||
|
fprintf (st, "The RP device supports the BOOT command.\n");
|
||||||
|
fprint_reg_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dp_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "RP10 disk controller";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
442
PDP10/kx10_dpy.c
Normal file
442
PDP10/kx10_dpy.c
Normal file
|
@ -0,0 +1,442 @@
|
||||||
|
/* ka10_dpy.c: 340 display subsystem simulator w/ PDP-6 344 interface!
|
||||||
|
|
||||||
|
Copyright (c) 2018, Philip L. Budne
|
||||||
|
|
||||||
|
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
|
||||||
|
PHILIP BUDNE 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 Philip Budne 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE!!! Currently only supports 340 display using the type 344 interface
|
||||||
|
* for PDP-6 described in
|
||||||
|
* http://www.bitsavers.org/pdf/dec/graphics/H-340_Type_340_Precision_Incremental_CRT_System_Nov64.pdf
|
||||||
|
*
|
||||||
|
* 340C was used in the PDP-10 VB10C display system
|
||||||
|
* http://bitsavers.informatik.uni-stuttgart.de/pdf/dec/pdp10/periph/VB10C_Interactive_Graphics_Terminal_Jul70.pdf
|
||||||
|
* "The basic hardware system consists of a 340/C display connected
|
||||||
|
* directly to PDP-1O memory through a special memory channel. Several
|
||||||
|
* important features included in the VB-10/C display are memory
|
||||||
|
* protection and relocation, slave mode operation, raster mode, and
|
||||||
|
* subroutining."
|
||||||
|
*
|
||||||
|
* reading 6.03 VBCSER
|
||||||
|
* http://pdp-10.trailing-edge.com/dec-10-omona-u-mc9/01/vbcser.mac.html
|
||||||
|
* There appear to be differences in the DIS (130) CONI/O bits:
|
||||||
|
* CONI
|
||||||
|
* 47400 are "DISPLAY INTERRUPT" bits
|
||||||
|
* 45000 are "ILLEGAL ADDRESS OR EDGE FLAG" (same VE/HE??)
|
||||||
|
* 40000 is "ILLEGAL ADDR"
|
||||||
|
* 2000 is LP HIT (same)
|
||||||
|
* 400 is STOP (same
|
||||||
|
* CONO
|
||||||
|
* 20000 "lock display out of memory"
|
||||||
|
* 100 init? (same)
|
||||||
|
* 40 "clear flags"
|
||||||
|
* 20 "resume" (stored @DISIN4)
|
||||||
|
* 7 PI channel?
|
||||||
|
* DISCON = CHAN + 140 (continue?)
|
||||||
|
* *NO* DATAO or BLKO to device 130!
|
||||||
|
*
|
||||||
|
* It appears that the reloc/protect mechanism is on I/O device 134.
|
||||||
|
* (referred to by number, not symbol!)
|
||||||
|
* DATAO sets reloc/protect, start addr
|
||||||
|
* possibly:
|
||||||
|
* high order 8 protection bits are left justified in left half
|
||||||
|
* high order 8 relocation bits are left justified in right half
|
||||||
|
*
|
||||||
|
* Other PDP-6/10 display interfaces:
|
||||||
|
*
|
||||||
|
* http://bitsavers.trailing-edge.com/pdf/dec/graphics/348_Manual_1964.pdf
|
||||||
|
* Type 348 interface to Type 30A or 30E displays.
|
||||||
|
* "To the display, the interface looks like a PDP-1 computer"
|
||||||
|
*
|
||||||
|
* Also VP10/VR30 (phone book p. 487):
|
||||||
|
* control word format:
|
||||||
|
* INTENSITY(*),,0 ("4 dimmest, thru 13 brightest" default is 10)
|
||||||
|
* YPOS,,XPOS (10 bit positions)
|
||||||
|
*
|
||||||
|
* (*)6.03 DISSER.MAC says:
|
||||||
|
* ONLY FOR VP10 and TYPE 30.
|
||||||
|
* N IS 3 BITS WIDE FOR 30, 2 BITS WIDE FOR VP10.
|
||||||
|
*
|
||||||
|
* 348 manual p.10 says: "The three flip-flops are treated as a two bit
|
||||||
|
* signed binary number. Negative numbers are in two's complement form.
|
||||||
|
* The most negative number (100) will produce the least intensity.
|
||||||
|
* The largest positive number (011) results in the greatest intensity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_DPY
|
||||||
|
#define NUM_DEVS_DPY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DPY > 0)
|
||||||
|
#include "display/type340.h"
|
||||||
|
#include "display/display.h"
|
||||||
|
|
||||||
|
#define DPY_DEVNUM 0130
|
||||||
|
|
||||||
|
#define RRZ(W) ((W) & RMASK)
|
||||||
|
#define XWD(L,R) ((((uint64)(L))<<18)|((uint64)(R)))
|
||||||
|
|
||||||
|
#if PDP6 | KA | KI
|
||||||
|
extern uint64 SW; /* switch register */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* number of (real?) microseconds between svc calls
|
||||||
|
* used to age display, poll for WS events
|
||||||
|
* and delay "data" interrupt
|
||||||
|
* (VB10C could steal cycles)
|
||||||
|
*/
|
||||||
|
#define DPY_CYCLE_US 50
|
||||||
|
|
||||||
|
/*
|
||||||
|
* number of DPY_CYCLES to delay int
|
||||||
|
* too small and host CPU doesn't run enough!
|
||||||
|
*/
|
||||||
|
#define INT_COUNT (500/DPY_CYCLE_US)
|
||||||
|
|
||||||
|
#define STAT_REG u3
|
||||||
|
#define INT_COUNTDOWN u4
|
||||||
|
#define XPOS us9 /* from LP hit */
|
||||||
|
#define YPOS us10 /* from LP hit */
|
||||||
|
|
||||||
|
/* STAT_REG */
|
||||||
|
#define STAT_VALID 01000000 /* internal: invisible to PDP-10 */
|
||||||
|
|
||||||
|
/* CONI/CONO */
|
||||||
|
/* http://www.bitsavers.org/pdf/dec/graphics/H-340_Type_340_Precision_Incremental_CRT_System_Nov64.pdf p 2-14 */
|
||||||
|
#define CONO_MASK 0000077 /* bits changed by CONO */
|
||||||
|
#define CONI_MASK 0007677 /* bits read by CONI */
|
||||||
|
|
||||||
|
#define CONI_INT_SPEC 0007400 /* I- "special conditions" */
|
||||||
|
#define CONI_INT_VE 0004000 /* I- b24: VER EDGE */
|
||||||
|
#define CONI_INT_LP 0002000 /* I- b25: LIGHT PEN */
|
||||||
|
#define CONI_INT_HE 0001000 /* I- b26: HOR EDGE */
|
||||||
|
#define CONI_INT_SI 0000400 /* I- b27: STOP INT */
|
||||||
|
#define CONI_INT_DONE 0000200 /* I- b28: done with second half */
|
||||||
|
#define CONO_INIT 0000100 /* -O b29: init display */
|
||||||
|
#define CONX_SC 0000070 /* IO special channel */
|
||||||
|
#define CONX_DC 0000007 /* IO data channel */
|
||||||
|
|
||||||
|
#define CONX_SC_SHIFT 3
|
||||||
|
#define CONX_DC_SHIFT 0
|
||||||
|
|
||||||
|
/* make sure ST340_XXX bits match CONI_INT_XXX bits */
|
||||||
|
#if (ST340_VEDGE^CONI_INT_VE)|(ST340_LPHIT^CONI_INT_LP)|(ST340_HEDGE^CONI_INT_HE)|(ST340_STOP_INT^CONI_INT_SI)
|
||||||
|
#error ST340 bits do not match CONI_INT bits!!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
t_stat dpy_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat dpy_svc (UNIT *uptr);
|
||||||
|
t_stat dpy_reset (DEVICE *dptr);
|
||||||
|
const char *dpy_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
DIB dpy_dib[] = {
|
||||||
|
{ DPY_DEVNUM, 1, &dpy_devio, NULL }};
|
||||||
|
|
||||||
|
UNIT dpy_unit[] = {
|
||||||
|
{ UDATA (&dpy_svc, UNIT_IDLE, DPY_CYCLE_US) }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UPTR(UNIT) (dpy_unit+(UNIT))
|
||||||
|
|
||||||
|
DEVICE dpy_dev = {
|
||||||
|
"DPY", dpy_unit, NULL, NULL,
|
||||||
|
NUM_DEVS_DPY, 0, 0, 0, 0, 0,
|
||||||
|
NULL, NULL, dpy_reset,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
&dpy_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, &dpy_description
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *dpy_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Type 340 Display on Type 344 interface";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* until it's done just one place! */
|
||||||
|
static void dpy_set_int_done(UNIT *uptr)
|
||||||
|
{
|
||||||
|
uptr->STAT_REG |= CONI_INT_DONE;
|
||||||
|
uptr->INT_COUNTDOWN = INT_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return true if display not stopped */
|
||||||
|
int dpy_update_status (UNIT *uptr, ty340word status, int done)
|
||||||
|
{
|
||||||
|
int running = !(status & ST340_STOPPED);
|
||||||
|
|
||||||
|
/* sub in lastest bits from display */
|
||||||
|
uptr->STAT_REG &= ~CONI_INT_SPEC;
|
||||||
|
uptr->STAT_REG |= status & CONI_INT_SPEC;
|
||||||
|
|
||||||
|
/* data interrupt sent from svc routine, so CPU can run */
|
||||||
|
if (done && running) {
|
||||||
|
/* XXX also set in "rfd" callback: decide! */
|
||||||
|
dpy_set_int_done(uptr);
|
||||||
|
}
|
||||||
|
if (uptr->STAT_REG & CONI_INT_SPEC) {
|
||||||
|
uint32 sc = uptr->STAT_REG & CONX_SC;
|
||||||
|
if (sc) { /* PI channel set? */
|
||||||
|
set_interrupt(DPY_DEVNUM, sc >> CONX_SC_SHIFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat dpy_devio(uint32 dev, uint64 *data) {
|
||||||
|
int unit = (dev - DPY_DEVNUM) >> 2;
|
||||||
|
UNIT *uptr;
|
||||||
|
int32 inst;
|
||||||
|
|
||||||
|
if (unit < 0 || unit >= NUM_DEVS_DPY)
|
||||||
|
return SCPE_OK;
|
||||||
|
uptr = UPTR(unit);
|
||||||
|
|
||||||
|
if (!(uptr->STAT_REG & STAT_VALID)) {
|
||||||
|
dpy_update_status(uptr, ty340_status(), 0);
|
||||||
|
sim_activate_after(uptr, DPY_CYCLE_US);
|
||||||
|
uptr->STAT_REG |= STAT_VALID;
|
||||||
|
uptr->INT_COUNTDOWN = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = (uint64)(uptr->STAT_REG & CONI_MASK);
|
||||||
|
/*
|
||||||
|
* MIT AI only, See Hardware Memo 1
|
||||||
|
* https://github.com/larsbrinkhoff/its-archives/blob/master/ailab/ITS_Hardware_Memo_1.pdf
|
||||||
|
* Set sign bit if device assigned to this CPU (KA or PDP-6)
|
||||||
|
* (Thanks to Lars for figuring this out!)
|
||||||
|
*/
|
||||||
|
*data |= SMASK; /* always assigned to us */
|
||||||
|
sim_debug(DEBUG_CONI, &dpy_dev, "DPY %03o CONI PC=%06o %012llo\n",
|
||||||
|
dev, PC, *data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
uptr->STAT_REG &= ~CONO_MASK;
|
||||||
|
uptr->STAT_REG |= *data & CONO_MASK;
|
||||||
|
if (*data & CONO_INIT)
|
||||||
|
dpy_update_status( uptr, ty340_reset(&dpy_dev), 1);
|
||||||
|
sim_debug(DEBUG_CONO, &dpy_dev, "DPY %03o CONO %06o PC=%06o %06o\n",
|
||||||
|
dev, (uint32)*data, PC, uptr->STAT_REG & ~STAT_VALID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
uptr->STAT_REG &= ~CONI_INT_DONE;
|
||||||
|
uptr->INT_COUNTDOWN = 0;
|
||||||
|
|
||||||
|
/* if fed using BLKO from interrupt vector, PC will be wrong! */
|
||||||
|
sim_debug(DEBUG_DATAIO, &dpy_dev, "DPY %03o DATO %012llo PC=%06o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
|
||||||
|
inst = (uint32)LRZ(*data);
|
||||||
|
if (dpy_update_status(uptr, ty340_instruction(inst), 0)) {
|
||||||
|
/* still running */
|
||||||
|
inst = (uint32)RRZ(*data);
|
||||||
|
dpy_update_status(uptr, ty340_instruction(inst), 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
*data = XWD(uptr->YPOS, uptr->XPOS);
|
||||||
|
sim_debug(DEBUG_DATAIO, &dpy_dev, "DPY %03o DATI %06o,,%06o PC=%06o\n",
|
||||||
|
dev, uptr->YPOS, uptr->XPOS, PC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timer service - */
|
||||||
|
t_stat dpy_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
sim_activate_after(uptr, DPY_CYCLE_US); /* requeue! */
|
||||||
|
|
||||||
|
display_age(DPY_CYCLE_US, 0); /* age the display */
|
||||||
|
|
||||||
|
if (uptr->INT_COUNTDOWN && --uptr->INT_COUNTDOWN == 0) {
|
||||||
|
if (uptr->STAT_REG & CONI_INT_DONE) { /* delayed int? */
|
||||||
|
uint32 dc = uptr->STAT_REG & CONX_DC;
|
||||||
|
if (dc) { /* PI channel set? */
|
||||||
|
set_interrupt(DPY_DEVNUM, dc>>CONX_DC_SHIFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset routine */
|
||||||
|
|
||||||
|
t_stat dpy_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
if (!(dptr->flags & DEV_DIS)) {
|
||||||
|
display_reset();
|
||||||
|
ty340_reset(dptr);
|
||||||
|
}
|
||||||
|
sim_cancel (&dpy_unit[0]); /* deactivate unit */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* callbacks from type340.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* not used with Type 344 interface */
|
||||||
|
ty340word
|
||||||
|
ty340_fetch(ty340word addr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not used with Type 344 interface */
|
||||||
|
void
|
||||||
|
ty340_store(ty340word addr, ty340word value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ty340_lp_int(ty340word x, ty340word y)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* real hardware pauses display until the CPU reads out coords
|
||||||
|
* w/ DATAI which then continues the display
|
||||||
|
*/
|
||||||
|
dpy_unit[0].XPOS = x;
|
||||||
|
dpy_unit[0].YPOS = y;
|
||||||
|
dpy_update_status(dpy_unit, ty340_status(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ty340_rfd(void) { /* request for data */
|
||||||
|
#ifdef TY340_NODISPLAY
|
||||||
|
puts("ty340_rfd");
|
||||||
|
#endif
|
||||||
|
dpy_set_int_done(dpy_unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cpu_get_switches(unsigned long *p1, unsigned long *p2) {
|
||||||
|
#if PDP6 | KA | KI
|
||||||
|
*p1 = LRZ(SW);
|
||||||
|
*p2 = RRZ(SW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cpu_set_switches(unsigned long w1, unsigned long w2) {
|
||||||
|
#if PDP6 | KA | KI
|
||||||
|
SW = XWD(w1,w2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MIT Spacewar console switches
|
||||||
|
* WCNSLS is the mnemonic defined/used in the SPCWAR sources
|
||||||
|
*/
|
||||||
|
#if NUM_DEVS_WCNSLS > 0
|
||||||
|
#define WCNSLS_DEVNUM 0420
|
||||||
|
|
||||||
|
t_stat wcnsls_devio(uint32 dev, uint64 *data);
|
||||||
|
const char *wcnsls_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
DIB wcnsls_dib[] = {
|
||||||
|
{ WCNSLS_DEVNUM, 1, &wcnsls_devio, NULL }};
|
||||||
|
|
||||||
|
UNIT wcnsls_unit[] = {
|
||||||
|
{ UDATA (NULL, UNIT_IDLE, 0) }};
|
||||||
|
|
||||||
|
DEVICE wcnsls_dev = {
|
||||||
|
"WCNSLS", wcnsls_unit, NULL, NULL,
|
||||||
|
NUM_DEVS_WCNSLS, 0, 0, 0, 0, 0,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
&wcnsls_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, &wcnsls_description
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *wcnsls_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "MIT Spacewar Consoles";
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat wcnsls_devio(uint32 dev, uint64 *data) {
|
||||||
|
uint64 switches;
|
||||||
|
|
||||||
|
switch (dev & 3) {
|
||||||
|
case CONO:
|
||||||
|
/* CONO WCNSLS,40 ;enable spacewar consoles */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
switches = 0777777777777LL; /* 1 is off */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* map 32-bit "spacewar_switches" value to what PDP-6/10 game expects
|
||||||
|
* (four 9-bit bytes)
|
||||||
|
*/
|
||||||
|
/* bits inside the bytes */
|
||||||
|
#define CCW 0400 /* counter clockwise (L) */
|
||||||
|
#define CW 0200 /* clockwise (R) */
|
||||||
|
#define THRUST 0100
|
||||||
|
#define HYPER 040
|
||||||
|
#define FIRE 020
|
||||||
|
|
||||||
|
/* shift values for the players' bytes */
|
||||||
|
#define UR 0 /* upper right: enterprise "top plug" */
|
||||||
|
#define LR 9 /* lower right: klingon "second plug" */
|
||||||
|
#define LL 18 /* lower left: thin ship "third plug" */
|
||||||
|
#define UL 27 /* upper left: fat ship "bottom plug" */
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#define DEBUGSW(X) (void)0
|
||||||
|
#else
|
||||||
|
#define DEBUGSW(X) printf X
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SWSW(UC, LC, BIT, POS36, FUNC36) \
|
||||||
|
if (spacewar_switches & BIT) { \
|
||||||
|
switches &= ~(((uint64)FUNC36)<<POS36); \
|
||||||
|
DEBUGSW(("mapping %#o %s %s to %03o<<%d\r\n", \
|
||||||
|
(uint32)BIT, #POS36, #FUNC36, FUNC36, POS36)); \
|
||||||
|
}
|
||||||
|
SPACEWAR_SWITCHES;
|
||||||
|
#undef SWSW
|
||||||
|
|
||||||
|
if (spacewar_switches)
|
||||||
|
DEBUGSW(("in %#lo out %#llo\r\n", spacewar_switches, switches));
|
||||||
|
|
||||||
|
*data = switches;
|
||||||
|
sim_debug(DEBUG_DATAIO, &wcnsls_dev, "WCNSLS %03o DATI %012llo PC=%06o\n",
|
||||||
|
dev, switches, PC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
1266
PDP10/kx10_dt.c
Normal file
1266
PDP10/kx10_dt.c
Normal file
File diff suppressed because it is too large
Load diff
2186
PDP10/kx10_imp.c
Normal file
2186
PDP10/kx10_imp.c
Normal file
File diff suppressed because it is too large
Load diff
170
PDP10/kx10_lights.c
Normal file
170
PDP10/kx10_lights.c
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/* ka10_lights.c: KA10 console lights.
|
||||||
|
|
||||||
|
Copyright (c) 2018, Lars Brinkhoff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libusb-1.0/libusb.h>
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
static libusb_device_handle *lights_handle = NULL;
|
||||||
|
static uint64 lights_main = 0;
|
||||||
|
static int lights_aux = 0;
|
||||||
|
|
||||||
|
static void ka10_lights_latch (void)
|
||||||
|
{
|
||||||
|
unsigned char buffer[8];
|
||||||
|
|
||||||
|
if (lights_handle == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer[0] = (lights_main >> 32) & 0377;
|
||||||
|
buffer[1] = (lights_main >> 24) & 0377;
|
||||||
|
buffer[2] = (lights_main >> 16) & 0377;
|
||||||
|
buffer[3] = (lights_main >> 8) & 0377;
|
||||||
|
buffer[4] = lights_main & 0377;
|
||||||
|
|
||||||
|
buffer[5] = (lights_aux << 4) & 0340;
|
||||||
|
buffer[6] = 0;
|
||||||
|
buffer[7] = 0;
|
||||||
|
|
||||||
|
libusb_control_transfer(lights_handle,
|
||||||
|
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
|
||||||
|
LIBUSB_REQUEST_SET_CONFIGURATION,
|
||||||
|
0x0000,
|
||||||
|
0,
|
||||||
|
buffer,
|
||||||
|
sizeof buffer,
|
||||||
|
5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ka10_lights_main (uint64 data)
|
||||||
|
{
|
||||||
|
lights_main = data;
|
||||||
|
ka10_lights_latch ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ka10_lights_set_aux (int n)
|
||||||
|
{
|
||||||
|
lights_aux |= 1 << n;
|
||||||
|
ka10_lights_latch ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ka10_lights_clear_aux (int n)
|
||||||
|
{
|
||||||
|
lights_aux &= ~(1 << n);
|
||||||
|
ka10_lights_latch ();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USB_CFG_VENDOR_ID 0xc0, 0x16
|
||||||
|
#define USB_CFG_DEVICE_ID 0xdf, 0x05
|
||||||
|
#define USB_CFG_DEVICE_NAME 'P','a','n','d','a',' ','D','i','s','p','l','a','y',
|
||||||
|
#define USB_CFG_DEVICE_NAME_LEN 13
|
||||||
|
|
||||||
|
static libusb_device_handle *get_panda_handle(libusb_device **devs)
|
||||||
|
{
|
||||||
|
libusb_device *dev;
|
||||||
|
libusb_device_handle *handle = NULL;
|
||||||
|
int i = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
int found = 0;
|
||||||
|
int openable = 0;
|
||||||
|
|
||||||
|
unsigned char prod[256];
|
||||||
|
char devname[USB_CFG_DEVICE_NAME_LEN] = {USB_CFG_DEVICE_NAME};
|
||||||
|
|
||||||
|
unsigned char rawVid[2] = {USB_CFG_VENDOR_ID};
|
||||||
|
unsigned char rawPid[2] = {USB_CFG_DEVICE_ID};
|
||||||
|
|
||||||
|
int vid = rawVid[0] + 256 * rawVid[1];
|
||||||
|
int pid = rawPid[0] + 256 * rawPid[1];
|
||||||
|
|
||||||
|
|
||||||
|
while ((dev = devs[i++]) != NULL) {
|
||||||
|
struct libusb_device_descriptor desc;
|
||||||
|
libusb_get_device_descriptor(dev, &desc); /* this always succeeds */
|
||||||
|
// Do the VID and PID match?
|
||||||
|
if (desc.idVendor == vid && desc.idProduct == pid) {
|
||||||
|
found = 1;
|
||||||
|
r = libusb_open(dev, &handle);
|
||||||
|
// If we can't open it, keep trying.
|
||||||
|
// There may be a device with the same pid and vid but not a Panda Display
|
||||||
|
if (r < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
openable = 1;
|
||||||
|
r = libusb_get_string_descriptor_ascii(handle, desc.iProduct, prod, sizeof prod);
|
||||||
|
if (r < 0) {
|
||||||
|
libusb_close(handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// Here we have something that matches the free
|
||||||
|
// VID and PID offered by Objective Development.
|
||||||
|
// Now we need to Check device name to see if it
|
||||||
|
// really is a Panda Display.
|
||||||
|
if ((0 == strncmp((char *)prod, devname, USB_CFG_DEVICE_NAME_LEN)) &&
|
||||||
|
(desc.idVendor == vid) &&
|
||||||
|
(desc.idProduct == pid)) {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
libusb_close(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
if (openable)
|
||||||
|
sim_messagef (SCPE_NOFNC, "Found USB device matching 16c0:05df, but it isn't a Panda Display\n");
|
||||||
|
else
|
||||||
|
sim_messagef (SCPE_NOFNC, "Found something that might be a Panda Display, but couldn't open it.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ka10_lights_init (void)
|
||||||
|
{
|
||||||
|
libusb_device **devs;
|
||||||
|
libusb_context *ctx = NULL;
|
||||||
|
ssize_t cnt;
|
||||||
|
int r, i, pos;
|
||||||
|
|
||||||
|
if (lights_handle != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
r = libusb_init(&ctx);
|
||||||
|
if (r < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cnt = libusb_get_device_list(ctx, &devs);
|
||||||
|
if (cnt < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lights_handle = get_panda_handle(devs);
|
||||||
|
if (lights_handle == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (libusb_kernel_driver_active(lights_handle, 0) == 1)
|
||||||
|
libusb_detach_kernel_driver(lights_handle, 0);
|
||||||
|
|
||||||
|
r = libusb_claim_interface(lights_handle, 0);
|
||||||
|
if(r < 0)
|
||||||
|
return;
|
||||||
|
}
|
408
PDP10/kx10_lp.c
Normal file
408
PDP10/kx10_lp.c
Normal file
|
@ -0,0 +1,408 @@
|
||||||
|
/* ka10_lp.c: PDP-10 line printer simulator
|
||||||
|
|
||||||
|
Copyright (c) 2011-2017, 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 <ctype.h>
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_LP
|
||||||
|
#define NUM_DEVS_LP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_LP > 0)
|
||||||
|
|
||||||
|
#define LP_DEVNUM 0124
|
||||||
|
#define STATUS u3
|
||||||
|
#define COL u4
|
||||||
|
#define POS u5
|
||||||
|
#define LINE u6
|
||||||
|
|
||||||
|
#define UNIT_V_CT (UNIT_V_UF + 0)
|
||||||
|
#define UNIT_UC (1 << UNIT_V_CT)
|
||||||
|
#define UNIT_UTF8 (2 << UNIT_V_CT)
|
||||||
|
#define UNIT_CT (3 << UNIT_V_CT)
|
||||||
|
|
||||||
|
#define PI_DONE 000007
|
||||||
|
#define PI_ERROR 000070
|
||||||
|
#define DONE_FLG 000100
|
||||||
|
#define BUSY_FLG 000200
|
||||||
|
#define ERR_FLG 000400
|
||||||
|
#define CLR_LPT 002000
|
||||||
|
#define C96 002000
|
||||||
|
#define C128 004000
|
||||||
|
#define DEL_FLG 0100000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t_stat lpt_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat lpt_svc (UNIT *uptr);
|
||||||
|
t_stat lpt_reset (DEVICE *dptr);
|
||||||
|
t_stat lpt_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
t_stat lpt_detach (UNIT *uptr);
|
||||||
|
t_stat lpt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *lpt_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
char lpt_buffer[134 * 3];
|
||||||
|
uint8 lpt_chbuf[5]; /* Read in Character buffers */
|
||||||
|
|
||||||
|
/* LPT data structures
|
||||||
|
|
||||||
|
lpt_dev LPT device descriptor
|
||||||
|
lpt_unit LPT unit descriptor
|
||||||
|
lpt_reg LPT register list
|
||||||
|
*/
|
||||||
|
|
||||||
|
DIB lpt_dib = { LP_DEVNUM, 1, &lpt_devio, NULL };
|
||||||
|
|
||||||
|
UNIT lpt_unit = {
|
||||||
|
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), 100
|
||||||
|
};
|
||||||
|
|
||||||
|
REG lpt_reg[] = {
|
||||||
|
{ DRDATA (STATUS, lpt_unit.STATUS, 18), PV_LEFT | REG_UNIT },
|
||||||
|
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT | REG_UNIT },
|
||||||
|
{ BRDATA(BUFF, lpt_buffer, 16, 8, sizeof(lpt_buffer)), REG_HRO},
|
||||||
|
{ BRDATA(CBUFF, lpt_chbuf, 16, 8, sizeof(lpt_chbuf)), REG_HRO},
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB lpt_mod[] = {
|
||||||
|
{UNIT_CT, 0, "Lower case", "LC", NULL},
|
||||||
|
{UNIT_CT, UNIT_UC, "Upper case", "UC", NULL},
|
||||||
|
{UNIT_CT, UNIT_UTF8, "UTF8 ouput", "UTF8", NULL},
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE lpt_dev = {
|
||||||
|
"LPT", &lpt_unit, lpt_reg, lpt_mod,
|
||||||
|
1, 10, 31, 1, 8, 8,
|
||||||
|
NULL, NULL, &lpt_reset,
|
||||||
|
NULL, &lpt_attach, &lpt_detach,
|
||||||
|
&lpt_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &lpt_help, NULL, NULL, &lpt_description
|
||||||
|
};
|
||||||
|
|
||||||
|
/* IOT routine */
|
||||||
|
|
||||||
|
t_stat lpt_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &lpt_unit;
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = uptr->STATUS & (PI_DONE|PI_ERROR|DONE_FLG|BUSY_FLG|ERR_FLG);
|
||||||
|
if ((uptr->flags & UNIT_UC) == 0)
|
||||||
|
*data |= C96;
|
||||||
|
if ((uptr->flags & UNIT_UTF8) == 0)
|
||||||
|
*data |= C128;
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
*data |= ERR_FLG;
|
||||||
|
sim_debug(DEBUG_CONI, &lpt_dev, "LP CONI %012llo PC=%06o\n", *data, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_debug(DEBUG_CONO, &lpt_dev, "LP CONO %012llo PC=%06o\n", *data, PC);
|
||||||
|
uptr->STATUS &= ~0777;
|
||||||
|
uptr->STATUS |= ((PI_DONE|PI_ERROR|DONE_FLG|BUSY_FLG|CLR_LPT) & *data);
|
||||||
|
if (*data & CLR_LPT) {
|
||||||
|
uptr->STATUS &= ~DONE_FLG;
|
||||||
|
uptr->STATUS |= BUSY_FLG;
|
||||||
|
sim_activate (&lpt_unit, lpt_unit.wait);
|
||||||
|
}
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
|
uptr->STATUS |= ERR_FLG;
|
||||||
|
set_interrupt(dev, (uptr->STATUS >> 3));
|
||||||
|
}
|
||||||
|
if ((uptr->STATUS & DONE_FLG) != 0)
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
if ((uptr->STATUS & DONE_FLG) != 0) {
|
||||||
|
int i, j;
|
||||||
|
for (j = 0, i = 29; i > 0; i-=7)
|
||||||
|
lpt_chbuf[j++] = ((uint8)(*data >> i)) & 0x7f;
|
||||||
|
uptr->STATUS &= ~DONE_FLG;
|
||||||
|
uptr->STATUS |= BUSY_FLG;
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_activate (&lpt_unit, lpt_unit.wait);
|
||||||
|
sim_debug(DEBUG_DATAIO, &lpt_dev, "LP DATO %012llo PC=%06o\n", *data, PC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lpt_printline(UNIT *uptr, int nl) {
|
||||||
|
int trim = 0;
|
||||||
|
/* Trim off trailing blanks */
|
||||||
|
while (uptr->COL >= 0 && lpt_buffer[uptr->POS - 1] == ' ') {
|
||||||
|
uptr->COL--;
|
||||||
|
uptr->POS--;
|
||||||
|
trim = 1;
|
||||||
|
}
|
||||||
|
lpt_buffer[uptr->POS] = '\0';
|
||||||
|
sim_debug(DEBUG_DETAIL, &lpt_dev, "LP output %d %d [%s]\n", uptr->COL, nl, lpt_buffer);
|
||||||
|
/* Stick a carraige return and linefeed as needed */
|
||||||
|
if (uptr->COL != 0 || trim)
|
||||||
|
lpt_buffer[uptr->POS++] = '\r';
|
||||||
|
if (nl) {
|
||||||
|
lpt_buffer[uptr->POS++] = '\n';
|
||||||
|
uptr->LINE++;
|
||||||
|
}
|
||||||
|
sim_fwrite(&lpt_buffer, 1, uptr->POS, uptr->fileref);
|
||||||
|
uptr->COL = 0;
|
||||||
|
uptr->POS = 0;
|
||||||
|
if (ferror (uptr->fileref)) { /* error? */
|
||||||
|
perror ("LPT I/O error");
|
||||||
|
clearerr (uptr->fileref);
|
||||||
|
uptr->STATUS |= ERR_FLG;
|
||||||
|
set_interrupt(LP_DEVNUM, (uptr->STATUS >> 3));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 utf_code[32] = {
|
||||||
|
0x0000, /* Dot */
|
||||||
|
0x2193, /* Down arrow */
|
||||||
|
0x237a, /* APL Alpha */
|
||||||
|
0x03b2, /* Beta */
|
||||||
|
0x039b, /* Lambda */
|
||||||
|
0x2510, /* Box light down and left */
|
||||||
|
0x03b5, /* Epsilon */
|
||||||
|
0x03d6, /* Pi */
|
||||||
|
0x03bb, /* Lambda */
|
||||||
|
0x221d, /* proportional */
|
||||||
|
0x222b, /* Integral */
|
||||||
|
0x00b1, /* Plus minus */
|
||||||
|
0x2295, /* Circle plus */
|
||||||
|
0x221e, /* Infinity */
|
||||||
|
0x2202, /* Partial derivitive */
|
||||||
|
0x2282, /* Subset of */
|
||||||
|
0x2283, /* Superset of */
|
||||||
|
0x2229, /* Intersection */
|
||||||
|
0x222a, /* union */
|
||||||
|
0x2200, /* For all */
|
||||||
|
0x2203, /* Exists */
|
||||||
|
0x2295, /* Circle plus */
|
||||||
|
0x2194, /* Left right arrow */
|
||||||
|
0x2227, /* Logical and */
|
||||||
|
0x2192, /* Rightwards arror */
|
||||||
|
0x2014, /* Em dash */
|
||||||
|
0x2260, /* Not equal */
|
||||||
|
0x2264, /* Less than or equal */
|
||||||
|
0x2265, /* Greater than or equal */
|
||||||
|
0x2261, /* Identical too */
|
||||||
|
0x2228 /* Logical or */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Unit service */
|
||||||
|
void
|
||||||
|
lpt_output(UNIT *uptr, char c) {
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return;
|
||||||
|
if ((uptr->flags & UNIT_UC) && (c & 0140) == 0140)
|
||||||
|
c &= 0137;
|
||||||
|
if ((uptr->flags & UNIT_UTF8) && c < 040) {
|
||||||
|
uint16 u = utf_code[c & 0x1f];
|
||||||
|
if (u > 0x7ff) {
|
||||||
|
lpt_buffer[uptr->POS++] = 0xe0 + ((u >> 12) & 0xf);
|
||||||
|
lpt_buffer[uptr->POS++] = 0x80 + ((u >> 6) & 0x3f);
|
||||||
|
lpt_buffer[uptr->POS++] = 0x80 + (u & 0x3f);
|
||||||
|
} else if (u > 0x7f) {
|
||||||
|
lpt_buffer[uptr->POS++] = 0xc0 + ((u >> 6) & 0x3f);
|
||||||
|
lpt_buffer[uptr->POS++] = 0x80 + (u & 0x3f);
|
||||||
|
} else {
|
||||||
|
lpt_buffer[uptr->POS++] = u & 0x7f;
|
||||||
|
}
|
||||||
|
uptr->COL++;
|
||||||
|
} else if (c >= 040) {
|
||||||
|
lpt_buffer[uptr->POS++] = c;
|
||||||
|
uptr->COL++;
|
||||||
|
}
|
||||||
|
if (uptr->COL == 132)
|
||||||
|
lpt_printline(uptr, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat lpt_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
int pos;
|
||||||
|
int cpos;
|
||||||
|
|
||||||
|
if ((uptr->flags & DONE_FLG) != 0) {
|
||||||
|
set_interrupt(LP_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
|
uptr->STATUS |= ERR_FLG;
|
||||||
|
set_interrupt(LP_DEVNUM, (uptr->STATUS >> 3));
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uptr->STATUS & CLR_LPT) {
|
||||||
|
for (pos = 0; pos < uptr->COL; lpt_buffer[pos++] = ' ');
|
||||||
|
uptr->POS = uptr->COL;
|
||||||
|
lpt_printline(uptr, 0);
|
||||||
|
uptr->STATUS &= ~(DEL_FLG|ERR_FLG|BUSY_FLG|CLR_LPT);
|
||||||
|
uptr->STATUS |= DONE_FLG;
|
||||||
|
set_interrupt(LP_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cpos = 0; cpos < 5; cpos++) {
|
||||||
|
c = lpt_chbuf[cpos];
|
||||||
|
if (uptr->STATUS & DEL_FLG) {
|
||||||
|
lpt_output(uptr, c);
|
||||||
|
uptr->STATUS &= ~DEL_FLG;
|
||||||
|
} else if (c == 0177) { /* Check for DEL Character */
|
||||||
|
uptr->STATUS |= DEL_FLG;
|
||||||
|
} else if (c < 040) { /* Control character */
|
||||||
|
switch(c) {
|
||||||
|
case 011: /* Horizontal tab, space to 8'th column */
|
||||||
|
lpt_output(uptr, ' ');
|
||||||
|
while ((uptr->COL & 07) != 0)
|
||||||
|
lpt_output(uptr, ' ');
|
||||||
|
break;
|
||||||
|
case 015: /* Carriage return, print line */
|
||||||
|
lpt_printline(uptr, 0);
|
||||||
|
break;
|
||||||
|
case 012: /* Line feed, print line, space one line */
|
||||||
|
lpt_printline(uptr, 1);
|
||||||
|
uptr->LINE++;
|
||||||
|
break;
|
||||||
|
case 014: /* Form feed, skip to top of page */
|
||||||
|
lpt_printline(uptr, 0);
|
||||||
|
sim_fwrite("\014", 1, 1, uptr->fileref);
|
||||||
|
uptr->LINE = 0;
|
||||||
|
break;
|
||||||
|
case 013: /* Vertical tab, Skip mod 20 */
|
||||||
|
lpt_printline(uptr, 1);
|
||||||
|
while((uptr->LINE % 20) != 0) {
|
||||||
|
sim_fwrite("\r\n", 1, 2, uptr->fileref);
|
||||||
|
uptr->LINE++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 020: /* Skip even lines */
|
||||||
|
lpt_printline(uptr, 1);
|
||||||
|
while((uptr->LINE % 2) != 0) {
|
||||||
|
sim_fwrite("\r\n", 1, 2, uptr->fileref);
|
||||||
|
uptr->LINE++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 021: /* Skip third lines */
|
||||||
|
lpt_printline(uptr, 1);
|
||||||
|
while((uptr->LINE % 3) != 0) {
|
||||||
|
sim_fwrite("\r\n", 1, 2, uptr->fileref);
|
||||||
|
uptr->LINE++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 022: /* Skip one line */
|
||||||
|
lpt_printline(uptr, 1);
|
||||||
|
sim_fwrite("\r\n", 1, 2, uptr->fileref);
|
||||||
|
uptr->LINE+=2;
|
||||||
|
break;
|
||||||
|
case 023: /* Skip every 10 lines */
|
||||||
|
lpt_printline(uptr, 1);
|
||||||
|
while((uptr->LINE % 10) != 0) {
|
||||||
|
sim_fwrite("\r\n", 1, 2, uptr->fileref);
|
||||||
|
uptr->LINE++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: /* Ignore */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lpt_output(uptr, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uptr->STATUS &= ~BUSY_FLG;
|
||||||
|
uptr->STATUS |= DONE_FLG;
|
||||||
|
set_interrupt(LP_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset routine */
|
||||||
|
|
||||||
|
t_stat lpt_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &lpt_unit;
|
||||||
|
uptr->POS = 0;
|
||||||
|
uptr->COL = 0;
|
||||||
|
uptr->LINE = 1;
|
||||||
|
uptr->STATUS = DONE_FLG;
|
||||||
|
clr_interrupt(LP_DEVNUM);
|
||||||
|
sim_cancel (&lpt_unit); /* deactivate unit */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach routine */
|
||||||
|
|
||||||
|
t_stat lpt_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat reason;
|
||||||
|
|
||||||
|
reason = attach_unit (uptr, cptr);
|
||||||
|
uptr->STATUS &= ~ERR_FLG;
|
||||||
|
clr_interrupt(LP_DEVNUM);
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detach routine */
|
||||||
|
|
||||||
|
t_stat lpt_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
uptr->STATUS |= ERR_FLG;
|
||||||
|
set_interrupt(LP_DEVNUM, uptr->STATUS >> 3);
|
||||||
|
return detach_unit (uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat lpt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Line Printer (LPT)\n\n");
|
||||||
|
fprintf (st, "The line printer (LPT) writes data to a disk file. The POS register specifies\n");
|
||||||
|
fprintf (st, "the number of the next data item to be written. Thus, by changing POS, the\n");
|
||||||
|
fprintf (st, "user can backspace or advance the printer.\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprint_reg_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *lpt_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "LP10 line printer" ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1063
PDP10/kx10_mt.c
Normal file
1063
PDP10/kx10_mt.c
Normal file
File diff suppressed because it is too large
Load diff
422
PDP10/kx10_pt.c
Normal file
422
PDP10/kx10_pt.c
Normal file
|
@ -0,0 +1,422 @@
|
||||||
|
/* ka10_pt.c: PDP-10 reader/punch simulator
|
||||||
|
|
||||||
|
Copyright (c) 2011-2017, 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"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_PT
|
||||||
|
#define NUM_DEVS_PT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_PT > 0)
|
||||||
|
|
||||||
|
#define PP_DEVNUM 0100
|
||||||
|
#define PR_DEVNUM 0104
|
||||||
|
#define STATUS u3
|
||||||
|
#define CHR u4
|
||||||
|
#define CHL u5
|
||||||
|
|
||||||
|
#define PI_DONE 000007
|
||||||
|
#define DONE_FLG 000010
|
||||||
|
#define BUSY_FLG 000020
|
||||||
|
#define BIN_FLG 000040
|
||||||
|
#define NO_TAPE_PP 000100
|
||||||
|
#if PDP6
|
||||||
|
#define TAPE_PR 000000
|
||||||
|
#else
|
||||||
|
#define TAPE_PR 000400
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
t_stat ptp_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat ptp_svc (UNIT *uptr);
|
||||||
|
t_stat ptp_reset (DEVICE *dptr);
|
||||||
|
t_stat ptp_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
t_stat ptp_detach (UNIT *uptr);
|
||||||
|
t_stat ptp_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr);
|
||||||
|
const char *ptp_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
t_stat ptr_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat ptr_svc (UNIT *uptr);
|
||||||
|
t_stat ptr_boot(int32 unit_num, DEVICE * dptr);
|
||||||
|
t_stat ptr_reset (DEVICE *dptr);
|
||||||
|
t_stat ptr_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
t_stat ptr_detach (UNIT *uptr);
|
||||||
|
t_stat ptr_help (FILE *st, DEVICE *dptr, UNIT *uptr,
|
||||||
|
int32 flag, const char *cptr);
|
||||||
|
const char *ptr_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
|
||||||
|
DIB ptp_dib = { PP_DEVNUM, 1, &ptp_devio, NULL };
|
||||||
|
|
||||||
|
UNIT ptp_unit = {
|
||||||
|
UDATA (&ptp_svc, UNIT_ATTABLE+UNIT_TEXT, 0), 10000
|
||||||
|
};
|
||||||
|
|
||||||
|
REG ptp_reg[] = {
|
||||||
|
{ DRDATA (STATUS, ptp_unit.STATUS, 18), PV_LEFT | REG_UNIT},
|
||||||
|
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT | REG_UNIT},
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB ptp_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE ptp_dev = {
|
||||||
|
"PTP", &ptp_unit, ptp_reg, ptp_mod,
|
||||||
|
1, 10, 31, 1, 8, 8,
|
||||||
|
NULL, NULL, &ptp_reset, NULL, &ptp_attach, &ptp_detach,
|
||||||
|
&ptp_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &ptp_help, NULL, NULL, &ptp_description
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB ptr_dib = { PR_DEVNUM, 1, &ptr_devio, NULL };
|
||||||
|
|
||||||
|
UNIT ptr_unit = {
|
||||||
|
UDATA (&ptr_svc, UNIT_ATTABLE+UNIT_TEXT, 0), 10000
|
||||||
|
};
|
||||||
|
|
||||||
|
REG ptr_reg[] = {
|
||||||
|
{ DRDATA (STATUS, ptr_unit.STATUS, 18), PV_LEFT | REG_UNIT},
|
||||||
|
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT | REG_UNIT},
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB ptr_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE ptr_dev = {
|
||||||
|
"PTR", &ptr_unit, ptr_reg, ptr_mod,
|
||||||
|
1, 10, 31, 1, 8, 8,
|
||||||
|
NULL, NULL, &ptr_reset, &ptr_boot, &ptr_attach, &ptr_detach,
|
||||||
|
&ptr_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &ptr_help, NULL, NULL, &ptr_description
|
||||||
|
};
|
||||||
|
|
||||||
|
/* IOT routine */
|
||||||
|
|
||||||
|
t_stat ptp_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &ptp_unit;
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = uptr->STATUS;
|
||||||
|
#if WAITS
|
||||||
|
/* The NXM stop switch is always off */
|
||||||
|
if (cpu_unit[0].flags & UNIT_WAITS)
|
||||||
|
*data |= 0200;
|
||||||
|
#endif
|
||||||
|
sim_debug(DEBUG_CONI, &ptp_dev, "PP: CONI %012llo\n\r", *data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
uptr->STATUS = (PI_DONE|DONE_FLG|BUSY_FLG|BIN_FLG) & *data;
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
uptr->STATUS |= NO_TAPE_PP;
|
||||||
|
if (uptr->STATUS & BUSY_FLG) {
|
||||||
|
uptr->CHR = 0;
|
||||||
|
sim_activate (&ptp_unit, ptp_unit.wait);
|
||||||
|
}
|
||||||
|
if (uptr->STATUS & DONE_FLG)
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
sim_debug(DEBUG_CONO, &ptp_dev, "PP: CONO %012llo\n\r", *data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
if ((uptr->STATUS & BUSY_FLG) == 0) {
|
||||||
|
uptr->CHR = *data & 00377;
|
||||||
|
if (uptr->STATUS & BIN_FLG) {
|
||||||
|
uptr->CHR &= 077;
|
||||||
|
uptr->CHR |= 0200;
|
||||||
|
}
|
||||||
|
uptr->STATUS |= BUSY_FLG;
|
||||||
|
uptr->STATUS &= ~DONE_FLG;
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_activate (&ptp_unit, ptp_unit.wait);
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DATAIO, &ptp_dev, "PP: DATAO %012llo\n\r", *data);
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
*data = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Unit service */
|
||||||
|
t_stat ptp_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
uptr->STATUS &= ~BUSY_FLG;
|
||||||
|
uptr->STATUS |= DONE_FLG;
|
||||||
|
set_interrupt(PP_DEVNUM, uptr->STATUS & 7);
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
|
uptr->STATUS |= NO_TAPE_PP;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
fputc (uptr->CHR, uptr->fileref); /* print char */
|
||||||
|
uptr->pos = ftell (uptr->fileref);
|
||||||
|
if (ferror (uptr->fileref)) { /* error? */
|
||||||
|
perror ("PTP I/O error");
|
||||||
|
clearerr (uptr->fileref);
|
||||||
|
return SCPE_IOERR;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset routine */
|
||||||
|
|
||||||
|
t_stat ptp_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &ptp_unit;
|
||||||
|
uptr->CHR = 0;
|
||||||
|
uptr->CHL = 0;
|
||||||
|
uptr->STATUS = 0;
|
||||||
|
clr_interrupt(PP_DEVNUM);
|
||||||
|
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach routine */
|
||||||
|
|
||||||
|
t_stat ptp_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat reason;
|
||||||
|
|
||||||
|
reason = attach_unit (uptr, cptr);
|
||||||
|
uptr->STATUS &= ~NO_TAPE_PP;
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detach routine */
|
||||||
|
|
||||||
|
t_stat ptp_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
uptr->STATUS |= NO_TAPE_PP;
|
||||||
|
return detach_unit (uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t_stat ptr_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &ptr_unit;
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = uptr->STATUS;
|
||||||
|
sim_debug(DEBUG_CONI, &ptr_dev, "PT: CONI %012llo\n\r", *data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
uptr->STATUS = (PI_DONE|DONE_FLG|BUSY_FLG|BIN_FLG) & *data;
|
||||||
|
if ((uptr->flags & UNIT_ATT))
|
||||||
|
uptr->STATUS |= TAPE_PR;
|
||||||
|
if (uptr->STATUS & BUSY_FLG) {
|
||||||
|
uptr->CHR = 0;
|
||||||
|
uptr->CHL = 0;
|
||||||
|
sim_activate (&ptr_unit, ptr_unit.wait);
|
||||||
|
}
|
||||||
|
if (uptr->STATUS & DONE_FLG)
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
sim_debug(DEBUG_CONO, &ptr_dev, "PT: CONO %012llo\n\r", *data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
if ((uptr->STATUS & DONE_FLG)) {
|
||||||
|
*data = ((uint64)uptr->CHL) << 18;
|
||||||
|
*data |= ((uint64)uptr->CHR);
|
||||||
|
uptr->STATUS &= ~DONE_FLG;
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_activate (&ptr_unit, ptr_unit.wait);
|
||||||
|
}
|
||||||
|
uptr->STATUS |= BUSY_FLG;
|
||||||
|
sim_debug(DEBUG_DATAIO, &ptr_dev, "PT: DATAI %012llo\n\r", *data);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unit service */
|
||||||
|
t_stat ptr_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int32 temp;
|
||||||
|
uint64 word;
|
||||||
|
int count = (uptr->STATUS & BIN_FLG) ? 6 : 1;
|
||||||
|
|
||||||
|
uptr->STATUS &= ~BUSY_FLG;
|
||||||
|
uptr->STATUS |= DONE_FLG;
|
||||||
|
set_interrupt(PR_DEVNUM, uptr->STATUS);
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
|
word = 0;
|
||||||
|
while (count > 0) {
|
||||||
|
if ((temp = getc (uptr->fileref)) == EOF) {
|
||||||
|
if (feof (uptr->fileref)) {
|
||||||
|
uptr->STATUS &= ~TAPE_PR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uptr->STATUS & BIN_FLG) {
|
||||||
|
if (temp & 0200) {
|
||||||
|
word <<= 6;
|
||||||
|
word |= (uint64)(temp & 077);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
word |= (uint64)(temp);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uptr->CHL = (word >> 18) & RMASK;
|
||||||
|
uptr->CHR = word & RMASK;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64
|
||||||
|
ptr_read_word(UNIT *uptr) {
|
||||||
|
int i, ch;
|
||||||
|
uint64 word = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < 6;) {
|
||||||
|
if ((ch = getc (uptr->fileref)) == EOF)
|
||||||
|
return word;
|
||||||
|
if (ch & 0200) {
|
||||||
|
word <<= 6;
|
||||||
|
word |= (uint64)(ch & 077);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boot from given device */
|
||||||
|
t_stat
|
||||||
|
ptr_boot(int32 unit_num, DEVICE * dptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &dptr->units[unit_num];
|
||||||
|
uint64 word;
|
||||||
|
int wc, addr;
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
return SCPE_UNATT; /* attached? */
|
||||||
|
|
||||||
|
word = ptr_read_word(uptr);
|
||||||
|
wc = (word >> 18) & RMASK;
|
||||||
|
addr = word & RMASK;
|
||||||
|
while (wc != 0) {
|
||||||
|
wc = (wc + 1) & RMASK;
|
||||||
|
addr = (addr + 1) & RMASK;
|
||||||
|
word = ptr_read_word(uptr);
|
||||||
|
if (addr < 020)
|
||||||
|
FM[addr] = word;
|
||||||
|
else
|
||||||
|
M[addr] = word;
|
||||||
|
}
|
||||||
|
if (addr < 020)
|
||||||
|
FM[addr] = word;
|
||||||
|
else
|
||||||
|
M[addr] = word;
|
||||||
|
uptr->STATUS = BUSY_FLG|BIN_FLG|TAPE_PR;
|
||||||
|
uptr->CHR = 0;
|
||||||
|
uptr->CHL = 0;
|
||||||
|
sim_activate (&ptr_unit, ptr_unit.wait);
|
||||||
|
PC = word & RMASK;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Reset routine */
|
||||||
|
|
||||||
|
t_stat ptr_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &ptr_unit;
|
||||||
|
uptr->CHR = 0;
|
||||||
|
uptr->CHL = 0;
|
||||||
|
uptr->STATUS = 0;
|
||||||
|
clr_interrupt(PR_DEVNUM);
|
||||||
|
sim_cancel (&ptr_unit); /* deactivate unit */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach routine */
|
||||||
|
|
||||||
|
t_stat ptr_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat reason;
|
||||||
|
|
||||||
|
reason = attach_unit (uptr, cptr);
|
||||||
|
uptr->STATUS |= TAPE_PR;
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detach routine */
|
||||||
|
|
||||||
|
t_stat ptr_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
uptr->STATUS &= ~TAPE_PR;
|
||||||
|
return detach_unit (uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ptr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Paper Tape Reader (PTR)\n\n");
|
||||||
|
fprintf (st, "The paper tape reader (PTR) reads data from a disk file. The POS register\n");
|
||||||
|
fprintf (st, "specifies the number of the next data item to be read. Thus, by changing\n");
|
||||||
|
fprintf (st, "POS, the user can backspace or advance the reader.\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprint_reg_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ptr_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "paper tape reader";
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat ptp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Paper Tape Punch (PTP)\n\n");
|
||||||
|
fprintf (st, "The paper tape punch (PTP) writes data to a disk file. The POS register\n");
|
||||||
|
fprintf (st, "specifies the number of the next data item to be written. Thus, by changing\n");
|
||||||
|
fprintf (st, "POS, the user can backspace or advance the punch.\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprint_reg_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ptp_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "paper tape punch";
|
||||||
|
}
|
||||||
|
#endif
|
574
PDP10/kx10_rc.c
Normal file
574
PDP10/kx10_rc.c
Normal file
|
@ -0,0 +1,574 @@
|
||||||
|
/* ka10_rc.c: RC10 Disk Controller.
|
||||||
|
|
||||||
|
Copyright (c) 2013-2017, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_RC
|
||||||
|
#define NUM_DEVS_RC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_RC > 0)
|
||||||
|
|
||||||
|
#define RC_DEVNUM 0170 /* 0174 */
|
||||||
|
#define NUM_UNITS_RC 4
|
||||||
|
|
||||||
|
/* Flags in the unit flags word */
|
||||||
|
|
||||||
|
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||||
|
#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
|
||||||
|
#define UNIT_M_DTYPE 1
|
||||||
|
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||||
|
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
|
||||||
|
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
|
||||||
|
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||||
|
|
||||||
|
/* Parameters in the unit descriptor */
|
||||||
|
|
||||||
|
#define CUR_CYL u3 /* current cylinder */
|
||||||
|
#define DATAPTR u4 /* data pointer */
|
||||||
|
#define UFLAGS u5 /* Function */
|
||||||
|
|
||||||
|
|
||||||
|
#define DISK_SEL 0600000000000LL
|
||||||
|
#define TRACK 0177600000000LL
|
||||||
|
#define SEGMENT 0000177000000LL
|
||||||
|
#define INIT_PAR 0000000770000LL /* Read */
|
||||||
|
#define DPE_STOP 0000000004000LL
|
||||||
|
#define CPE_STOP 0000000002000LL
|
||||||
|
#define WRITE 0000000001000LL
|
||||||
|
#define EPAR 0000000000001LL
|
||||||
|
#define SEC_SEL 0000000001400LL /* Read */
|
||||||
|
#define SECT_CNT 0000000000377LL /* Read */
|
||||||
|
|
||||||
|
#define PI 0000007
|
||||||
|
#define WCW 0000040
|
||||||
|
#define SEC_SCTR 0600000
|
||||||
|
|
||||||
|
#define RST_MSK 0000000177710LL /* CONO reset bits */
|
||||||
|
#define B22_FLAG 0040000000000LL /* 22 bit controller. */
|
||||||
|
#define MAINT_SEG 0010000000000LL
|
||||||
|
#define PRTLT 0004000000000LL /* Protected area less then bounds */
|
||||||
|
#define STS 0003777000000LL
|
||||||
|
#define SCRCHCMP 0000000400000LL /* Tranfer in progress. */
|
||||||
|
#define S_ERROR 0000000200000LL /* Segment not found */
|
||||||
|
#define DSK_DES_E 0000000100000LL /* Duplicate disk */
|
||||||
|
#define TRK_SEL_E 0000000040000LL /* Track not BCD number */
|
||||||
|
#define NOT_RDY 0000000020000LL /* Drive not ready */
|
||||||
|
#define PSW_FAIL 0000000010000LL /* Power supply fail */
|
||||||
|
#define DSK_PAR_E 0000000004000LL /* Disk Parity Error */
|
||||||
|
#define CH_PAR_D 0000000002000LL /* Channel Data Parity Error */
|
||||||
|
#define CH_PAR_C 0000000001000LL /* Channel Control Parity Error */
|
||||||
|
#define NXM_ERR 0000000000400LL /* Non existant memory */
|
||||||
|
#define ILL_WR 0000000000200LL /* Write to protected area */
|
||||||
|
#define OVRRUN 0000000000100LL /* Over run */
|
||||||
|
|
||||||
|
#define RD10_DTYPE 0
|
||||||
|
#define RD10_WDS 32
|
||||||
|
#define RD10_SEGS 80
|
||||||
|
#define RD10_CYL 200
|
||||||
|
#define RD10_SIZE (RD10_SEGS * RD10_CYL * RD10_WDS)
|
||||||
|
|
||||||
|
#define RM10_DTYPE 1
|
||||||
|
#define RM10_WDS 64
|
||||||
|
#define RM10_SEGS 60
|
||||||
|
#define RM10_CYL 90
|
||||||
|
#define RM10_SIZE (RM10_SEGS * RM10_CYL * RM10_WDS)
|
||||||
|
|
||||||
|
struct drvtyp {
|
||||||
|
int32 wd_seg; /* Number of words per segment */
|
||||||
|
int32 seg; /* segments */
|
||||||
|
int32 cyl; /* cylinders */
|
||||||
|
int32 size; /* #blocks */
|
||||||
|
int32 devtype; /* device type */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drvtyp rc_drv_tab[] = {
|
||||||
|
{ RD10_WDS, RD10_SEGS, RD10_CYL, RD10_SIZE, RD10_DTYPE},
|
||||||
|
{ RM10_WDS, RM10_SEGS, RM10_CYL, RM10_SIZE, RM10_DTYPE},
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct df10 rc_df10[NUM_DEVS_RC];
|
||||||
|
uint64 rc_buf[NUM_DEVS_RC][RM10_WDS];
|
||||||
|
uint32 rc_ipr[NUM_DEVS_RC];
|
||||||
|
|
||||||
|
t_stat rc_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat rc_svc(UNIT *);
|
||||||
|
t_stat rc_boot(int32, DEVICE *);
|
||||||
|
void rc_ini(UNIT *, t_bool);
|
||||||
|
t_stat rc_reset(DEVICE *);
|
||||||
|
t_stat rc_attach(UNIT *, CONST char *);
|
||||||
|
t_stat rc_detach(UNIT *);
|
||||||
|
t_stat rc_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat rc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *rc_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
|
||||||
|
UNIT rc_unit[] = {
|
||||||
|
/* Controller 1 */
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
|
||||||
|
#if (NUM_DEVS_RC > 1)
|
||||||
|
/* Controller 2 */
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
{ UDATA (&rc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+(RD10_DTYPE << UNIT_V_DTYPE), RD10_SIZE) },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB rc_dib[] = {
|
||||||
|
{RC_DEVNUM+000, 1, &rc_devio, NULL},
|
||||||
|
{RC_DEVNUM+004, 1, &rc_devio, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB rc_mod[] = {
|
||||||
|
{UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||||||
|
{UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL},
|
||||||
|
{UNIT_DTYPE, (RD10_DTYPE << UNIT_V_DTYPE), "RD10", "RD10", &rc_set_type },
|
||||||
|
{UNIT_DTYPE, (RM10_DTYPE << UNIT_V_DTYPE), "RM10", "RM10", &rc_set_type },
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
REG rca_reg[] = {
|
||||||
|
{BRDATA(BUFF, &rc_buf[0][0], 16, 64, RM10_WDS), REG_HRO},
|
||||||
|
{ORDATA(IPR, rc_ipr[0], 2), REG_HRO},
|
||||||
|
{ORDATA(STATUS, rc_df10[0].status, 18), REG_RO},
|
||||||
|
{ORDATA(CIA, rc_df10[0].cia, 18)},
|
||||||
|
{ORDATA(CCW, rc_df10[0].ccw, 18)},
|
||||||
|
{ORDATA(WCR, rc_df10[0].wcr, 18)},
|
||||||
|
{ORDATA(CDA, rc_df10[0].cda, 18)},
|
||||||
|
{ORDATA(DEVNUM, rc_df10[0].devnum, 9), REG_HRO},
|
||||||
|
{ORDATA(BUF, rc_df10[0].buf, 36), REG_HRO},
|
||||||
|
{ORDATA(NXM, rc_df10[0].nxmerr, 8), REG_HRO},
|
||||||
|
{ORDATA(COMP, rc_df10[0].ccw_comp, 8), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE rca_dev = {
|
||||||
|
"FHA", rc_unit, rca_reg, rc_mod,
|
||||||
|
NUM_UNITS_RC, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &rc_reset, &rc_boot, &rc_attach, &rc_detach,
|
||||||
|
&rc_dib[0], DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &rc_help, NULL, NULL, &rc_description
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (NUM_DEVS_RC > 1)
|
||||||
|
REG rcb_reg[] = {
|
||||||
|
{BRDATA(BUFF, &rc_buf[1][0], 16, 64, RM10_WDS), REG_HRO},
|
||||||
|
{ORDATA(IPR, rc_ipr[1], 2), REG_HRO},
|
||||||
|
{ORDATA(STATUS, rc_df10[1].status, 18), REG_RO},
|
||||||
|
{ORDATA(CIA, rc_df10[1].cia, 18)},
|
||||||
|
{ORDATA(CCW, rc_df10[1].ccw, 18)},
|
||||||
|
{ORDATA(WCR, rc_df10[1].wcr, 18)},
|
||||||
|
{ORDATA(CDA, rc_df10[1].cda, 18)},
|
||||||
|
{ORDATA(DEVNUM, rc_df10[1].devnum, 9), REG_HRO},
|
||||||
|
{ORDATA(BUF, rc_df10[1].buf, 36), REG_HRO},
|
||||||
|
{ORDATA(NXM, rc_df10[1].nxmerr, 8), REG_HRO},
|
||||||
|
{ORDATA(COMP, rc_df10[1].ccw_comp, 8), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE rcb_dev = {
|
||||||
|
"FHB", &rc_unit[010], rcb_reg, rc_mod,
|
||||||
|
NUM_UNITS_RC, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &rc_reset, &rc_boot, &rc_attach, &rc_detach,
|
||||||
|
&rc_dib[1], DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &rc_help, NULL, NULL, &rc_description
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEVICE *rc_devs[] = {
|
||||||
|
&rca_dev,
|
||||||
|
#if (NUM_DEVS_RC > 1)
|
||||||
|
&rcb_dev,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
t_stat rc_devio(uint32 dev, uint64 *data) {
|
||||||
|
int ctlr = (dev - RC_DEVNUM) >> 2;
|
||||||
|
struct df10 *df10;
|
||||||
|
UNIT *uptr;
|
||||||
|
DEVICE *dptr;
|
||||||
|
int unit;
|
||||||
|
int tmp;
|
||||||
|
int drv;
|
||||||
|
int cyl;
|
||||||
|
int dtype;
|
||||||
|
|
||||||
|
if (ctlr < 0 || ctlr >= NUM_DEVS_RC)
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
df10 = &rc_df10[ctlr];
|
||||||
|
dptr = rc_devs[ctlr];
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = df10->status;
|
||||||
|
#if KI_22BIT
|
||||||
|
*data |= B22_FLAG;
|
||||||
|
#endif
|
||||||
|
*data |= PRTLT;
|
||||||
|
sim_debug(DEBUG_CONI, dptr, "HK %03o CONI %06o PC=%o\n", dev,
|
||||||
|
(uint32)*data, PC);
|
||||||
|
break;
|
||||||
|
case CONO:
|
||||||
|
if (*data & PI_ENABLE)
|
||||||
|
df10->status &= ~(PI_ENABLE);
|
||||||
|
clr_interrupt(dev);
|
||||||
|
df10->status &= ~07;
|
||||||
|
df10->status |= *data & 07;
|
||||||
|
df10->status &= ~(RST_MSK & *data);
|
||||||
|
if ((*data & BUSY) != 0) {
|
||||||
|
unit = rc_ipr[ctlr] & 3;
|
||||||
|
drv = unit + (ctlr * NUM_UNITS_RC);
|
||||||
|
uptr = &rc_unit[drv];
|
||||||
|
if ((df10->status & BUSY) != 0) {
|
||||||
|
sim_cancel(uptr);
|
||||||
|
df10_finish_op(df10, 0);
|
||||||
|
} else {
|
||||||
|
df10->status &= ~BUSY;
|
||||||
|
df10_setirq(df10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc_ipr[ctlr] &= ~SEC_SCTR;
|
||||||
|
rc_ipr[ctlr] |= *data & SEC_SCTR;
|
||||||
|
|
||||||
|
if ((df10->status & BUSY) != 0 && (*data & CCW_COMP) != 0) {
|
||||||
|
df10_writecw(df10);
|
||||||
|
} else
|
||||||
|
df10->status &= ~CCW_COMP;
|
||||||
|
sim_debug(DEBUG_CONO, dptr, "HK %03o CONO %06o PC=%o %06o\n", dev,
|
||||||
|
(uint32)*data, PC, df10->status);
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
*data = rc_ipr[ctlr];
|
||||||
|
unit = (rc_ipr[ctlr] & SEC_SCTR) >> 16;
|
||||||
|
uptr = &rc_unit[(ctlr * NUM_UNITS_RC) + unit];
|
||||||
|
*data |= (uptr->UFLAGS >> 3) & 0177;
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr, "HK %03o DATI %012llo PC=%o F=%o\n",
|
||||||
|
dev, *data, PC, uptr->UFLAGS);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr, "HK %03o DATO %012llo, PC=%o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
if (df10->status & BUSY) {
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
df10->status &= ~(PI_ENABLE|S_ERROR);
|
||||||
|
clr_interrupt(RC_DEVNUM + (ctlr * 4));
|
||||||
|
rc_ipr[ctlr] &= ~(INIT_PAR|3);
|
||||||
|
rc_ipr[ctlr] |= *data & INIT_PAR;
|
||||||
|
unit = (*data >> 34) & 03;
|
||||||
|
rc_ipr[ctlr] |= unit;
|
||||||
|
drv = unit + (ctlr * NUM_UNITS_RC);
|
||||||
|
uptr = &rc_unit[drv];
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
|
df10->status &= ~BUSY;
|
||||||
|
df10->status |= NOT_RDY;
|
||||||
|
df10_setirq(df10);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if ((uptr->flags & UNIT_WPRT) && *data & WRITE) {
|
||||||
|
df10->status &= ~BUSY;
|
||||||
|
df10->status |= ILL_WR;
|
||||||
|
df10_setirq(df10);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
df10_setup(df10, (uint32)*data);
|
||||||
|
tmp = (uint32)(*data >> 15) & ~07;
|
||||||
|
cyl = (tmp >> 10) & 0777;
|
||||||
|
if (((cyl & 017) > 9) || (((cyl >> 4) & 017) > 9)) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d non-bcd cyl %02x\n",
|
||||||
|
ctlr, cyl);
|
||||||
|
df10_finish_op(df10, TRK_SEL_E);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
cyl = (((cyl >> 4) & 017) * 10) + (cyl & 017) +
|
||||||
|
((cyl & 0x100) ? 100 : 0);
|
||||||
|
dtype = GET_DTYPE(uptr->flags);
|
||||||
|
if (cyl >= rc_drv_tab[dtype].cyl) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d invalid cyl %d %d\n",
|
||||||
|
ctlr, cyl, rc_drv_tab[dtype].cyl);
|
||||||
|
df10_finish_op(df10, TRK_SEL_E);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
cyl = (tmp >> 3) & 0177;
|
||||||
|
if ((cyl & 017) > 9) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d non-bcd seg %02x\n",
|
||||||
|
ctlr, cyl);
|
||||||
|
df10_finish_op(df10, TRK_SEL_E);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
uptr->UFLAGS = tmp | ((*data & WRITE) != 0) | (ctlr << 1);
|
||||||
|
uptr->DATAPTR = -1; /* Set no data */
|
||||||
|
if ((*data & WRITE) != 0)
|
||||||
|
(void)df10_read(df10);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d cyl %o\n", ctlr, uptr->UFLAGS);
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat rc_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int dtype = GET_DTYPE(uptr->flags);
|
||||||
|
int ctlr = (uptr->UFLAGS >> 1) & 03;
|
||||||
|
int seg = (uptr->UFLAGS >> 3) & 0177;
|
||||||
|
int cyl = (uptr->UFLAGS >> 10) & 0777;
|
||||||
|
int wr = (uptr->UFLAGS & 1);
|
||||||
|
int seg_size = rc_drv_tab[dtype].wd_seg;
|
||||||
|
struct df10 *df10 = &rc_df10[ctlr];
|
||||||
|
int tmp, wc;
|
||||||
|
DEVICE *dptr;
|
||||||
|
t_stat err, r;
|
||||||
|
|
||||||
|
dptr = rc_devs[ctlr];
|
||||||
|
/* Check if we need to seek */
|
||||||
|
if (uptr->DATAPTR == -1) {
|
||||||
|
cyl = (((cyl >> 4) & 017) * 10) + (cyl & 017) +
|
||||||
|
((cyl & 0x100) ? 100 : 0);
|
||||||
|
if (cyl >= rc_drv_tab[dtype].cyl) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d invalid cyl %d %d %o\n",
|
||||||
|
ctlr, cyl, rc_drv_tab[dtype].cyl, uptr->UFLAGS);
|
||||||
|
df10_finish_op(df10, TRK_SEL_E);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
/* Convert segment from BCD to binary */
|
||||||
|
if ((seg & 017) > 10) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d non-bcd seg %02x %d %o\n",
|
||||||
|
ctlr, seg, rc_drv_tab[dtype].seg, uptr->UFLAGS);
|
||||||
|
df10_finish_op(df10, S_ERROR);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
seg = (((seg >> 4) & 07) * 10) + (seg & 017);
|
||||||
|
if (seg >= rc_drv_tab[dtype].seg) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d invalid sec %d %d %o\n",
|
||||||
|
ctlr, seg, rc_drv_tab[dtype].seg, uptr->UFLAGS);
|
||||||
|
df10_finish_op(df10, S_ERROR);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
/* Check if reading */
|
||||||
|
if (!wr) {
|
||||||
|
/* Read the block */
|
||||||
|
int da;
|
||||||
|
da = ((cyl * rc_drv_tab[dtype].seg) + seg) * seg_size;
|
||||||
|
err = sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
wc = sim_fread (&rc_buf[ctlr][0], sizeof(uint64),
|
||||||
|
seg_size, uptr->fileref);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d Read %d %d %d %x\n",
|
||||||
|
ctlr, da, cyl, seg, uptr->UFLAGS << 1 );
|
||||||
|
for (; wc < seg_size; wc++)
|
||||||
|
rc_buf[ctlr][wc] = 0;
|
||||||
|
}
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
df10->status |= SCRCHCMP;
|
||||||
|
}
|
||||||
|
if (wr) {
|
||||||
|
rc_buf[ctlr][uptr->DATAPTR] = df10->buf;
|
||||||
|
r = df10_read(df10);
|
||||||
|
} else {
|
||||||
|
df10->buf = rc_buf[ctlr][uptr->DATAPTR];
|
||||||
|
r = df10_write(df10);
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "Xfer %d %012llo %06o %06o\n", uptr->DATAPTR, df10->buf,
|
||||||
|
df10->wcr, df10->cda);
|
||||||
|
|
||||||
|
uptr->DATAPTR++;
|
||||||
|
if (uptr->DATAPTR >= seg_size || r == 0 ) {
|
||||||
|
/* Check if writing */
|
||||||
|
df10->status &= ~SCRCHCMP;
|
||||||
|
seg = (((seg >> 4) & 017) * 10) + (seg & 017);
|
||||||
|
cyl = (((cyl >> 4) & 017) * 10) + (cyl & 017) +
|
||||||
|
((cyl & 0x100) ? 100 : 0);
|
||||||
|
if (wr) {
|
||||||
|
int da;
|
||||||
|
|
||||||
|
while(uptr->DATAPTR < seg_size) {
|
||||||
|
rc_buf[ctlr][uptr->DATAPTR] = 0;
|
||||||
|
uptr->DATAPTR++;
|
||||||
|
}
|
||||||
|
da = ((cyl * rc_drv_tab[dtype].seg) + seg) * seg_size;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "HK %d Write %d %d %d %x %d\n",
|
||||||
|
ctlr, da, cyl, seg, uptr->UFLAGS << 1, uptr->DATAPTR );
|
||||||
|
err = sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
wc = sim_fwrite(&rc_buf[ctlr][0],sizeof(uint64),
|
||||||
|
seg_size, uptr->fileref);
|
||||||
|
}
|
||||||
|
uptr->DATAPTR = -1;
|
||||||
|
seg++;
|
||||||
|
if (seg >= rc_drv_tab[dtype].seg) {
|
||||||
|
seg = 0;
|
||||||
|
cyl++;
|
||||||
|
if (cyl >= rc_drv_tab[dtype].cyl)
|
||||||
|
cyl = 0;
|
||||||
|
}
|
||||||
|
/* Convert seg back to bcd */
|
||||||
|
tmp = seg % 10;
|
||||||
|
seg /= 10;
|
||||||
|
seg <<= 4;
|
||||||
|
seg += tmp;
|
||||||
|
wr = 0;
|
||||||
|
if (cyl >= 100) {
|
||||||
|
wr = 0x100;
|
||||||
|
cyl -= 100;
|
||||||
|
}
|
||||||
|
tmp = (cyl % 10);
|
||||||
|
cyl /= 10;
|
||||||
|
cyl <<= 4;
|
||||||
|
cyl += wr + tmp;
|
||||||
|
uptr->UFLAGS = (uptr->UFLAGS & 7) + (seg << 3) + (cyl << 10);
|
||||||
|
}
|
||||||
|
if ((df10->status & PI_ENABLE) == 0) {
|
||||||
|
sim_activate(uptr, 20);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
rc_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (uptr == NULL) return SCPE_IERR;
|
||||||
|
for (i = 0; rc_drv_tab[i].wd_seg != 0; i++) {
|
||||||
|
if ((val >> UNIT_V_DTYPE) == rc_drv_tab[i].devtype) {
|
||||||
|
uptr->capac = rc_drv_tab[i].size;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_IERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
rc_reset(DEVICE * dptr)
|
||||||
|
{
|
||||||
|
int unit;
|
||||||
|
int ctlr;
|
||||||
|
UNIT *uptr = dptr->units;
|
||||||
|
for(unit = 0; unit < NUM_UNITS_RC; unit++) {
|
||||||
|
uptr->UFLAGS = 0;
|
||||||
|
uptr->CUR_CYL = 0;
|
||||||
|
uptr++;
|
||||||
|
}
|
||||||
|
for (ctlr = 0; ctlr < NUM_DEVS_RC; ctlr++) {
|
||||||
|
rc_ipr[ctlr] = 0;
|
||||||
|
rc_df10[ctlr].status = 0;
|
||||||
|
rc_df10[ctlr].devnum = rc_dib[ctlr].dev_num;
|
||||||
|
rc_df10[ctlr].nxmerr = 8;
|
||||||
|
rc_df10[ctlr].ccw_comp = 5;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boot from given device */
|
||||||
|
t_stat
|
||||||
|
rc_boot(int32 unit_num, DEVICE * dptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &dptr->units[unit_num];
|
||||||
|
int dtype = GET_DTYPE(uptr->flags);
|
||||||
|
uint32 addr;
|
||||||
|
int wc;
|
||||||
|
int wps;
|
||||||
|
int seg;
|
||||||
|
int sect;
|
||||||
|
uint32 ptr;
|
||||||
|
|
||||||
|
addr = (MEMSIZE - 512) & RMASK;
|
||||||
|
wps = rc_drv_tab[dtype].wd_seg;
|
||||||
|
for (sect = 4; sect <= 7; sect++) {
|
||||||
|
seg = (sect * 128) / wps;
|
||||||
|
(void)sim_fseek(uptr->fileref, (seg * wps) * sizeof(uint64), SEEK_SET);
|
||||||
|
(void)sim_fread (&rc_buf[0][0], sizeof(uint64), wps, uptr->fileref);
|
||||||
|
ptr = 0;
|
||||||
|
for(wc = wps; wc > 0; wc--) {
|
||||||
|
M[addr++] = rc_buf[0][ptr++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PC = (MEMSIZE - 512) & RMASK;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device attach */
|
||||||
|
|
||||||
|
t_stat rc_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
uptr->capac = rc_drv_tab[GET_DTYPE (uptr->flags)].size;
|
||||||
|
r = attach_unit (uptr, cptr);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
uptr->CUR_CYL = 0;
|
||||||
|
uptr->UFLAGS = 0;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device detach */
|
||||||
|
|
||||||
|
t_stat rc_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
if (!(uptr->flags & UNIT_ATT)) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
|
if (sim_is_active (uptr)) /* unit active? */
|
||||||
|
sim_cancel (uptr); /* cancel operation */
|
||||||
|
return detach_unit (uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat rc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "RD10/RM10 Disk Pack Drives (RC)\n\n");
|
||||||
|
fprintf (st, "The RC controller implements the RC-10 disk controller that talked\n");
|
||||||
|
fprintf (st, "to either RD10 mountable pack or RM10 drum drives.\n");
|
||||||
|
fprintf (st, "Options include the ability to set units write enabled or write locked, to\n");
|
||||||
|
fprintf (st, "set the drive type to one of two disk types\n\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n");
|
||||||
|
fprintf (st, "The RC device supports the BOOT command.\n");
|
||||||
|
fprint_reg_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *rc_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "RD10/RM10 disk controller";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1350
PDP10/kx10_rp.c
Normal file
1350
PDP10/kx10_rp.c
Normal file
File diff suppressed because it is too large
Load diff
948
PDP10/kx10_rs.c
Normal file
948
PDP10/kx10_rs.c
Normal file
|
@ -0,0 +1,948 @@
|
||||||
|
/* ka10_rs.c: Dec RH10 RS04
|
||||||
|
|
||||||
|
Copyright (c) 2017, 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 PURSOSE 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_RS
|
||||||
|
#define NUM_DEVS_RS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_RS > 0)
|
||||||
|
|
||||||
|
#define RS_NUMWD 128 /* 36bit words/sec */
|
||||||
|
#define NUM_UNITS_RS 8
|
||||||
|
|
||||||
|
/* Flags in the unit flags word */
|
||||||
|
|
||||||
|
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||||
|
#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
|
||||||
|
#define UNIT_M_DTYPE 7
|
||||||
|
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||||
|
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
|
||||||
|
#define DTYPE(x) (((x) & UNIT_M_DTYPE) << UNIT_V_DTYPE)
|
||||||
|
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
|
||||||
|
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||||
|
#define CNTRL_V_CTYPE (UNIT_V_UF + 4)
|
||||||
|
#define CNTRL_M_CTYPE 7
|
||||||
|
#define GET_CNTRL(x) (((x) >> CNTRL_V_CTYPE) & CNTRL_M_CTYPE)
|
||||||
|
#define CNTRL(x) (((x) & CNTRL_M_CTYPE) << CNTRL_V_CTYPE)
|
||||||
|
|
||||||
|
/* Parameters in the unit descriptor */
|
||||||
|
|
||||||
|
|
||||||
|
/* CONI Flags */
|
||||||
|
#define IADR_ATTN 0000000000040LL /* Interrupt on attention */
|
||||||
|
#define IARD_RAE 0000000000100LL /* Interrupt on register access error */
|
||||||
|
#define DIB_CBOV 0000000000200LL /* Control bus overrun */
|
||||||
|
#define CXR_PS_FAIL 0000000002000LL /* Power supply fail (not implemented) */
|
||||||
|
#define CXR_ILC 0000000004000LL /* Illegal function code */
|
||||||
|
#define CR_DRE 0000000010000LL /* Or Data and Control Timeout */
|
||||||
|
#define DTC_OVER 0000000020000LL /* DF10 did not supply word on time (not implemented) */
|
||||||
|
#define CCW_COMP_1 0000000040000LL /* Control word written. */
|
||||||
|
#define CXR_CHAN_ER 0000000100000LL /* Channel Error */
|
||||||
|
#define CXR_EXC 0000000200000LL /* Error in drive transfer */
|
||||||
|
#define CXR_DBPE 0000000400000LL /* Device Parity error (not implemented) */
|
||||||
|
#define CXR_NXM 0000001000000LL /* Channel non-existent memory (not implemented) */
|
||||||
|
#define CXR_CWPE 0000002000000LL /* Channel Control word parity error (not implemented) */
|
||||||
|
#define CXR_CDPE 0000004000000LL /* Channel Data Parity Error (not implemented) */
|
||||||
|
#define CXR_SD_RAE 0000200000000LL /* Register access error */
|
||||||
|
#define CXR_ILFC 0000400000000LL /* Illegal CXR function code */
|
||||||
|
#define B22_FLAG 0004000000000LL /* 22 bit channel */
|
||||||
|
#define CC_CHAN_PLS 0010000000000LL /* Channel transfer pulse (not implemented) */
|
||||||
|
#define CC_CHAN_ACT 0020000000000LL /* Channel in use */
|
||||||
|
#define CC_INH 0040000000000LL /* Disconnect channel */
|
||||||
|
#define CB_FULL 0200000000000LL /* Set when channel buffer is full (not implemented) */
|
||||||
|
#define AR_FULL 0400000000000LL /* Set when AR is full (not implemented) */
|
||||||
|
|
||||||
|
/* CONO Flags */
|
||||||
|
#define ATTN_EN 0000000000040LL /* enable attention interrupt. */
|
||||||
|
#define REA_EN 0000000000100LL /* enable register error interrupt */
|
||||||
|
#define CBOV_CLR 0000000000200LL /* Clear CBOV */
|
||||||
|
#define CONT_RESET 0000000002000LL /* Clear All error bits */
|
||||||
|
#define ILC_CLR 0000000004000LL /* Clear ILC and SD RAE */
|
||||||
|
#define DRE_CLR 0000000010000LL /* Clear CR_CBTO and CR_DBTO */
|
||||||
|
#define OVER_CLR 0000000020000LL /* Clear DTC overrun */
|
||||||
|
#define WRT_CW 0000000040000LL /* Write control word */
|
||||||
|
#define CHN_CLR 0000000100000LL /* Clear Channel Error */
|
||||||
|
#define DR_EXC_CLR 0000000200000LL /* Clear DR_EXC */
|
||||||
|
#define DBPE_CLR 0000000400000LL /* Clear CXR_DBPE */
|
||||||
|
|
||||||
|
/* DATAO/DATAI */
|
||||||
|
#define CR_REG 0770000000000LL /* Register number */
|
||||||
|
#define LOAD_REG 0004000000000LL /* Load register */
|
||||||
|
#define CR_MAINT_MODE 0000100000000LL /* Maint mode... not implemented */
|
||||||
|
#define CR_DRIVE 0000007000000LL
|
||||||
|
#define CR_GEN_EVD 0000000400000LL /* Enable Parity */
|
||||||
|
#define CR_DXES 0000000200000LL /* Disable DXES errors */
|
||||||
|
#define CR_INAD 0000000077600LL
|
||||||
|
#define CR_WTEVM 0000000000100LL /* Verify Parity */
|
||||||
|
#define CR_FUNC 0000000000076LL
|
||||||
|
#define CR_GO 0000000000001LL
|
||||||
|
|
||||||
|
#define IRQ_VECT 0000000000177LL /* Interupt vector */
|
||||||
|
#define IRQ_KI10 0000002000000LL
|
||||||
|
#define IRQ_KA10 0000001000000LL
|
||||||
|
|
||||||
|
#define CMD u3
|
||||||
|
/* u3 low */
|
||||||
|
/* RSC - 00 - control */
|
||||||
|
|
||||||
|
#define CS1_GO CR_GO /* go */
|
||||||
|
#define CS1_V_FNC 1 /* function pos */
|
||||||
|
#define CS1_M_FNC 037 /* function mask */
|
||||||
|
#define CS1_FNC (CS1_M_FNC << CS1_V_FNC)
|
||||||
|
#define FNC_NOP 000 /* no operation */
|
||||||
|
#define FNC_DCLR 004 /* drive clear */
|
||||||
|
#define FNC_PRESET 010 /* read-in preset */
|
||||||
|
#define FNC_SEARCH 014 /* search */
|
||||||
|
#define FNC_XFER 024 /* >=? data xfr */
|
||||||
|
#define FNC_WCHK 024 /* write check */
|
||||||
|
#define FNC_WRITE 030 /* write */
|
||||||
|
#define FNC_READ 034 /* read */
|
||||||
|
#define CS1_DVA 0004000 /* drive avail NI */
|
||||||
|
#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
|
||||||
|
|
||||||
|
/* u3 low */
|
||||||
|
/* RSDS - 01 - drive status */
|
||||||
|
|
||||||
|
#define DS_VV 0000000 /* volume valid */
|
||||||
|
#define DS_DRY 0000200 /* drive ready */
|
||||||
|
#define DS_DPR 0000400 /* drive present */
|
||||||
|
#define DS_PGM 0001000 /* programable NI */
|
||||||
|
#define DS_LST 0002000 /* last sector */
|
||||||
|
#define DS_WRL 0004000 /* write locked */
|
||||||
|
#define DS_MOL 0010000 /* medium online */
|
||||||
|
#define DS_PIP 0020000 /* pos in progress */
|
||||||
|
#define DS_ERR 0040000 /* error */
|
||||||
|
#define DS_ATA 0100000 /* attention active */
|
||||||
|
#define DS_MBZ 0000076
|
||||||
|
|
||||||
|
/* u3 high */
|
||||||
|
/* RSER1 - 02 - error status 1 */
|
||||||
|
|
||||||
|
#define ER1_ILF 0000001 /* illegal func */
|
||||||
|
#define ER1_ILR 0000002 /* illegal register */
|
||||||
|
#define ER1_RMR 0000004 /* reg mod refused */
|
||||||
|
#define ER1_PAR 0000010 /* parity err */
|
||||||
|
#define ER1_FER 0000020 /* format err NI */
|
||||||
|
#define ER1_WCF 0000040 /* write clk fail NI */
|
||||||
|
#define ER1_ECH 0000100 /* ECC hard err NI */
|
||||||
|
#define ER1_HCE 0000200 /* hdr comp err NI */
|
||||||
|
#define ER1_HCR 0000400 /* hdr CRC err NI */
|
||||||
|
#define ER1_AOE 0001000 /* addr ovflo err */
|
||||||
|
#define ER1_IAE 0002000 /* invalid addr err */
|
||||||
|
#define ER1_WLE 0004000 /* write lock err */
|
||||||
|
#define ER1_DTE 0010000 /* drive time err NI */
|
||||||
|
#define ER1_OPI 0020000 /* op incomplete */
|
||||||
|
#define ER1_UNS 0040000 /* drive unsafe */
|
||||||
|
#define ER1_DCK 0100000 /* data check NI */
|
||||||
|
|
||||||
|
/* RSMR - 03 - maintenace register */
|
||||||
|
|
||||||
|
/* RSAS - 04 - attention summary */
|
||||||
|
|
||||||
|
#define AS_U0 0000001 /* unit 0 flag */
|
||||||
|
|
||||||
|
#define DA u4
|
||||||
|
/* u4 high */
|
||||||
|
/* RSDC - 05 - desired sector */
|
||||||
|
|
||||||
|
#define DA_V_SC 0 /* sector pos */
|
||||||
|
#define DA_M_SC 077 /* sector mask */
|
||||||
|
#define DA_V_SF 6 /* track pos */
|
||||||
|
#define DA_M_SF 077 /* track mask */
|
||||||
|
#define DA_MBZ 0170000
|
||||||
|
#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC)
|
||||||
|
#define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF)
|
||||||
|
|
||||||
|
/* RSDT - 06 - drive type */
|
||||||
|
|
||||||
|
/* RSLA - 07 - look ahead register */
|
||||||
|
|
||||||
|
#define LA_V_SC 6 /* sector pos */
|
||||||
|
|
||||||
|
#define GET_DA(c,d) (((GET_SF (c)) * rs_drv_tab[d].sect) + GET_SC (c))
|
||||||
|
|
||||||
|
#define DATAPTR u6
|
||||||
|
|
||||||
|
/* This controller supports many different disk drive types. These drives
|
||||||
|
are operated in 576 bytes/sector (128 36b words/sector) mode, which gives
|
||||||
|
them somewhat different geometry from the PDP-11 variants:
|
||||||
|
|
||||||
|
type #sectors/ #surfaces/
|
||||||
|
surface cylinder
|
||||||
|
|
||||||
|
RS03 32 64
|
||||||
|
RS04 32 64
|
||||||
|
|
||||||
|
In theory, each drive can be a different type. The size field in
|
||||||
|
each unit selects the drive capacity for each drive and thus the
|
||||||
|
drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RS03_DTYPE 0
|
||||||
|
#define RS03_SECT 64
|
||||||
|
#define RS03_SURF 32
|
||||||
|
#define RS03_DEV 020002
|
||||||
|
#define RS03_SIZE (RS03_SECT * RS03_SURF * RS_NUMWD)
|
||||||
|
|
||||||
|
#define RS04_DTYPE 1
|
||||||
|
#define RS04_SECT 64
|
||||||
|
#define RS04_SURF 32
|
||||||
|
#define RS04_DEV 020003
|
||||||
|
#define RS04_SIZE (RS04_SECT * RS04_SURF * RS_NUMWD)
|
||||||
|
|
||||||
|
|
||||||
|
struct drvtyp {
|
||||||
|
int32 sect; /* sectors */
|
||||||
|
int32 surf; /* surfaces */
|
||||||
|
int32 size; /* #blocks */
|
||||||
|
int32 devtype; /* device type */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drvtyp rs_drv_tab[] = {
|
||||||
|
{ RS03_SECT, RS03_SURF, RS03_SIZE, RS03_DEV },
|
||||||
|
{ RS04_SECT, RS04_SURF, RS04_SIZE, RS04_DEV },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct df10 rs_df10[NUM_DEVS_RS];
|
||||||
|
uint32 rs_xfer_drive[NUM_DEVS_RS];
|
||||||
|
uint64 rs_buf[NUM_DEVS_RS][RS_NUMWD];
|
||||||
|
int rs_reg[NUM_DEVS_RS];
|
||||||
|
int rs_ivect[NUM_DEVS_RS];
|
||||||
|
int rs_imode[NUM_DEVS_RS];
|
||||||
|
int rs_drive[NUM_DEVS_RS];
|
||||||
|
int rs_rae[NUM_DEVS_RS];
|
||||||
|
int rs_attn[NUM_DEVS_RS];
|
||||||
|
extern int readin_flag;
|
||||||
|
|
||||||
|
t_stat rs_devio(uint32 dev, uint64 *data);
|
||||||
|
int rs_devirq(uint32 dev, int addr);
|
||||||
|
void rs_write(int ctlr, int unit, int reg, uint32 data);
|
||||||
|
uint32 rs_read(int ctlr, int unit, int reg);
|
||||||
|
t_stat rs_svc(UNIT *);
|
||||||
|
t_stat rs_boot(int32, DEVICE *);
|
||||||
|
void rs_ini(UNIT *, t_bool);
|
||||||
|
t_stat rs_reset(DEVICE *);
|
||||||
|
t_stat rs_attach(UNIT *, CONST char *);
|
||||||
|
t_stat rs_detach(UNIT *);
|
||||||
|
t_stat rs_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat rs_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *rs_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
|
||||||
|
UNIT rs_unit[] = {
|
||||||
|
/* Controller 1 */
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
{ UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||||
|
UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) },
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB rs_dib[] = {
|
||||||
|
{RH10_DEV, 1, &rs_devio, &rs_devirq}
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB rs_mod[] = {
|
||||||
|
{UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||||||
|
{UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL},
|
||||||
|
{UNIT_DTYPE, (RS03_DTYPE << UNIT_V_DTYPE), "RS03", "RS03", &rs_set_type },
|
||||||
|
{UNIT_DTYPE, (RS04_DTYPE << UNIT_V_DTYPE), "RS04", "RS04", &rs_set_type },
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
REG rsa_reg[] = {
|
||||||
|
{ORDATA(IVECT, rs_ivect[0], 18)},
|
||||||
|
{FLDATA(IMODE, rs_imode[0], 0)},
|
||||||
|
{ORDATA(XFER, rs_xfer_drive[0], 3), REG_HRO},
|
||||||
|
{ORDATA(DRIVE, rs_drive[0], 3), REG_HRO},
|
||||||
|
{ORDATA(REG, rs_reg[0], 6), REG_RO},
|
||||||
|
{ORDATA(RAE, rs_rae[0], 8), REG_RO},
|
||||||
|
{ORDATA(ATTN, rs_attn[0], 8), REG_RO},
|
||||||
|
{FLDATA(READIN, readin_flag, 0), REG_HRO},
|
||||||
|
{ORDATA(STATUS, rs_df10[0].status, 18), REG_RO},
|
||||||
|
{ORDATA(CIA, rs_df10[0].cia, 18)},
|
||||||
|
{ORDATA(CCW, rs_df10[0].ccw, 18)},
|
||||||
|
{ORDATA(WCR, rs_df10[0].wcr, 18)},
|
||||||
|
{ORDATA(CDA, rs_df10[0].cda, 18)},
|
||||||
|
{ORDATA(DEVNUM, rs_df10[0].devnum, 9), REG_HRO},
|
||||||
|
{ORDATA(BUF, rs_df10[0].buf, 36), REG_HRO},
|
||||||
|
{ORDATA(NXM, rs_df10[0].nxmerr, 8), REG_HRO},
|
||||||
|
{ORDATA(COMP, rs_df10[0].ccw_comp, 8), REG_HRO},
|
||||||
|
{BRDATA(BUFF, &rs_buf[0][0], 16, 64, RS_NUMWD), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE rsa_dev = {
|
||||||
|
"FSA", rs_unit, rsa_reg, rs_mod,
|
||||||
|
NUM_UNITS_RS, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &rs_reset, &rs_boot, &rs_attach, &rs_detach,
|
||||||
|
&rs_dib[0], DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
|
||||||
|
NULL, NULL, &rs_help, NULL, NULL, &rs_description
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE *rs_devs[] = {
|
||||||
|
&rsa_dev,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
t_stat rs_devio(uint32 dev, uint64 *data) {
|
||||||
|
int ctlr = -1;
|
||||||
|
DEVICE *dptr = NULL;
|
||||||
|
struct df10 *df10;
|
||||||
|
int drive;
|
||||||
|
|
||||||
|
for (drive = 0; rh[drive].dev_num != 0; drive++) {
|
||||||
|
if (rh[drive].dev_num == (dev & 0774)) {
|
||||||
|
dptr = rh[drive].dev;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dptr == NULL)
|
||||||
|
return SCPE_OK;
|
||||||
|
ctlr = GET_CNTRL(dptr->units[0].flags);
|
||||||
|
df10 = &rs_df10[ctlr];
|
||||||
|
df10->devnum = dev;
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = df10->status & ~(IADR_ATTN|IARD_RAE);
|
||||||
|
if (rs_attn[ctlr] != 0 && (df10->status & IADR_ATTN))
|
||||||
|
*data |= IADR_ATTN;
|
||||||
|
if (rs_rae[ctlr] != 0 && (df10->status & IARD_RAE))
|
||||||
|
*data |= IARD_RAE;
|
||||||
|
#if KI_22BIT
|
||||||
|
*data |= B22_FLAG;
|
||||||
|
#endif
|
||||||
|
sim_debug(DEBUG_CONI, dptr, "RS %03o CONI %06o PC=%o %o\n",
|
||||||
|
dev, (uint32)*data, PC, rs_attn[ctlr]);
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
df10->status &= ~(07LL|IADR_ATTN|IARD_RAE);
|
||||||
|
df10->status |= *data & (07LL|IADR_ATTN|IARD_RAE);
|
||||||
|
/* Clear flags */
|
||||||
|
if (*data & CONT_RESET) {
|
||||||
|
UNIT *uptr=dptr->units;
|
||||||
|
for(drive = 0; drive < NUM_UNITS_RS; drive++, uptr++) {
|
||||||
|
uptr->CMD &= DS_MOL|DS_WRL|DS_DPR|DS_DRY|DS_VV|076;
|
||||||
|
uptr->DA &= 003400177777;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR))
|
||||||
|
df10->status &= ~(*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR));
|
||||||
|
if (*data & OVER_CLR)
|
||||||
|
df10->status &= ~(DTC_OVER);
|
||||||
|
if (*data & CBOV_CLR)
|
||||||
|
df10->status &= ~(DIB_CBOV);
|
||||||
|
if (*data & CXR_ILC)
|
||||||
|
df10->status &= ~(CXR_ILFC|CXR_SD_RAE);
|
||||||
|
if (*data & WRT_CW)
|
||||||
|
df10_writecw(df10);
|
||||||
|
if (*data & PI_ENABLE)
|
||||||
|
df10->status &= ~PI_ENABLE;
|
||||||
|
if (df10->status & PI_ENABLE)
|
||||||
|
set_interrupt(dev, df10->status);
|
||||||
|
if ((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0)
|
||||||
|
set_interrupt(dev, df10->status);
|
||||||
|
sim_debug(DEBUG_CONO, dptr, "RS %03o CONO %06o %d PC=%06o %06o\n",
|
||||||
|
dev, (uint32)*data, ctlr, PC, df10->status);
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
*data = 0;
|
||||||
|
if (df10->status & BUSY && rs_reg[ctlr] != 04) {
|
||||||
|
df10->status |= CC_CHAN_ACT;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (rs_reg[ctlr] == 040) {
|
||||||
|
*data = (uint64)(rs_read(ctlr, rs_drive[ctlr], 0) & 077);
|
||||||
|
*data |= ((uint64)(df10->cia)) << 6;
|
||||||
|
*data |= ((uint64)(rs_xfer_drive[ctlr])) << 18;
|
||||||
|
} else if (rs_reg[ctlr] == 044) {
|
||||||
|
*data = (uint64)rs_ivect[ctlr];
|
||||||
|
if (rs_imode[ctlr])
|
||||||
|
*data |= IRQ_KI10;
|
||||||
|
else
|
||||||
|
*data |= IRQ_KA10;
|
||||||
|
} else if (rs_reg[ctlr] == 054) {
|
||||||
|
*data = (uint64)(rs_rae[ctlr]);
|
||||||
|
} else if ((rs_reg[ctlr] & 040) == 0) {
|
||||||
|
int parity;
|
||||||
|
|
||||||
|
*data = (uint64)(rs_read(ctlr, rs_drive[ctlr], rs_reg[ctlr]) & 0177777);
|
||||||
|
parity = (int)((*data >> 8) ^ *data);
|
||||||
|
parity = (parity >> 4) ^ parity;
|
||||||
|
parity = (parity >> 2) ^ parity;
|
||||||
|
parity = ((parity >> 1) ^ parity) & 1;
|
||||||
|
*data |= ((uint64)(parity ^ 1)) << 17;
|
||||||
|
*data |= ((uint64)(rs_drive[ctlr])) << 18;
|
||||||
|
}
|
||||||
|
*data |= ((uint64)(rs_reg[ctlr])) << 30;
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr, "RS %03o DATI %012llo, %d %d PC=%06o\n",
|
||||||
|
dev, *data, ctlr, rs_drive[ctlr], PC);
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr, "RS %03o DATO %012llo, %d PC=%06o %06o\n",
|
||||||
|
dev, *data, ctlr, PC, df10->status);
|
||||||
|
rs_reg[ctlr] = ((int)(*data >> 30)) & 077;
|
||||||
|
if (rs_reg[ctlr] < 040 && rs_reg[ctlr] != 04) {
|
||||||
|
rs_drive[ctlr] = (int)(*data >> 18) & 07;
|
||||||
|
}
|
||||||
|
if (*data & LOAD_REG) {
|
||||||
|
if (rs_reg[ctlr] == 040) {
|
||||||
|
if ((*data & 1) == 0) {
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (df10->status & BUSY) {
|
||||||
|
df10->status |= CC_CHAN_ACT;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
df10->status &= ~(1 << df10->ccw_comp);
|
||||||
|
df10->status &= ~PI_ENABLE;
|
||||||
|
if (((*data >> 1) & 077) < FNC_XFER) {
|
||||||
|
df10->status |= CXR_ILC;
|
||||||
|
df10_setirq(df10);
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr,
|
||||||
|
"RS %03o command abort %012llo, %d[%d] PC=%06o %06o\n",
|
||||||
|
dev, *data, ctlr, rs_drive[ctlr], PC, df10->status);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start command */
|
||||||
|
df10_setup(df10, (uint32)(*data >> 6));
|
||||||
|
rs_xfer_drive[ctlr] = (int)(*data >> 18) & 07;
|
||||||
|
rs_write(ctlr, rs_drive[ctlr], 0, (uint32)(*data & 077));
|
||||||
|
sim_debug(DEBUG_DATAIO, dptr,
|
||||||
|
"RS %03o command %012llo, %d[%d] PC=%06o %06o\n",
|
||||||
|
dev, *data, ctlr, rs_drive[ctlr], PC, df10->status);
|
||||||
|
} else if (rs_reg[ctlr] == 044) {
|
||||||
|
/* Set KI10 Irq vector */
|
||||||
|
rs_ivect[ctlr] = (int)(*data & IRQ_VECT);
|
||||||
|
rs_imode[ctlr] = (*data & IRQ_KI10) != 0;
|
||||||
|
} else if (rs_reg[ctlr] == 050) {
|
||||||
|
; /* Diagnostic access to mass bus. */
|
||||||
|
} else if (rs_reg[ctlr] == 054) {
|
||||||
|
/* clear flags */
|
||||||
|
rs_rae[ctlr] &= ~(*data & 0377);
|
||||||
|
if (rs_rae[ctlr] == 0)
|
||||||
|
clr_interrupt(dev);
|
||||||
|
} else if ((rs_reg[ctlr] & 040) == 0) {
|
||||||
|
rs_drive[ctlr] = (int)(*data >> 18) & 07;
|
||||||
|
/* Check if access error */
|
||||||
|
if (rs_rae[ctlr] & (1 << rs_drive[ctlr])) {
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
rs_drive[ctlr] = (int)(*data >> 18) & 07;
|
||||||
|
rs_write(ctlr, rs_drive[ctlr], rs_reg[ctlr] & 037,
|
||||||
|
(int)(*data & 0777777));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
return SCPE_OK; /* Unreached */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle KI and KL style interrupt vectors */
|
||||||
|
int
|
||||||
|
rs_devirq(uint32 dev, int addr) {
|
||||||
|
DEVICE *dptr = NULL;
|
||||||
|
int drive;
|
||||||
|
|
||||||
|
for (drive = 0; rh[drive].dev_num != 0; drive++) {
|
||||||
|
if (rh[drive].dev_num == (dev & 0774)) {
|
||||||
|
dptr = rh[drive].dev;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dptr != NULL) {
|
||||||
|
drive = GET_CNTRL(dptr->units[0].flags);
|
||||||
|
return (rs_imode[drive] ? rs_ivect[drive] : addr);
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rs_write(int ctlr, int unit, int reg, uint32 data) {
|
||||||
|
int i;
|
||||||
|
DEVICE *dptr = rs_devs[ctlr];
|
||||||
|
struct df10 *df10 = &rs_df10[ctlr];
|
||||||
|
UNIT *uptr = &dptr->units[unit];
|
||||||
|
|
||||||
|
if ((uptr->CMD & CR_GO) && reg != 04) {
|
||||||
|
uptr->CMD |= (ER1_RMR << 16)|DS_ERR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(reg) {
|
||||||
|
case 000: /* control */
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o %d Status=%06o\n", unit, ctlr, uptr->CMD);
|
||||||
|
/* Set if drive not writable */
|
||||||
|
if (uptr->flags & UNIT_WLK)
|
||||||
|
uptr->CMD |= DS_WRL;
|
||||||
|
/* If drive not ready don't do anything */
|
||||||
|
if ((uptr->CMD & DS_DRY) == 0) {
|
||||||
|
uptr->CMD |= (ER1_RMR << 16)|DS_ERR;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o %d busy\n", unit, ctlr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Check if GO bit set */
|
||||||
|
if ((data & 1) == 0) {
|
||||||
|
uptr->CMD &= ~076;
|
||||||
|
uptr->CMD |= data & 076;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o %d no go\n", unit, ctlr);
|
||||||
|
return; /* No, nop */
|
||||||
|
}
|
||||||
|
uptr->CMD &= DS_ATA|DS_VV|DS_DPR|DS_MOL|DS_WRL;
|
||||||
|
uptr->CMD |= data & 076;
|
||||||
|
switch (GET_FNC(data)) {
|
||||||
|
case FNC_NOP:
|
||||||
|
uptr->CMD |= DS_DRY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FNC_SEARCH: /* search */
|
||||||
|
case FNC_WCHK: /* write check */
|
||||||
|
case FNC_WRITE: /* write */
|
||||||
|
case FNC_READ: /* read */
|
||||||
|
uptr->CMD |= DS_PIP|CR_GO;
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FNC_PRESET: /* read-in preset */
|
||||||
|
uptr->DA = 0;
|
||||||
|
if ((uptr->flags & UNIT_ATT) != 0)
|
||||||
|
uptr->CMD |= DS_VV;
|
||||||
|
uptr->CMD |= DS_DRY;
|
||||||
|
df10_setirq(df10);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FNC_DCLR: /* drive clear */
|
||||||
|
uptr->CMD |= DS_DRY;
|
||||||
|
uptr->CMD &= ~(DS_ATA|CR_GO);
|
||||||
|
rs_attn[ctlr] = 0;
|
||||||
|
clr_interrupt(df10->devnum);
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (rs_unit[(ctlr * 8) + i].CMD & DS_ATA)
|
||||||
|
rs_attn[ctlr] = 1;
|
||||||
|
}
|
||||||
|
if ((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0)
|
||||||
|
df10_setirq(df10);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
uptr->CMD |= DS_DRY|DS_ERR|DS_ATA;
|
||||||
|
uptr->CMD |= (ER1_ILF << 16);
|
||||||
|
if ((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0)
|
||||||
|
df10_setirq(df10);
|
||||||
|
}
|
||||||
|
if (uptr->CMD & CR_GO)
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o AStatus=%06o\n", unit, uptr->CMD);
|
||||||
|
return;
|
||||||
|
case 001: /* status */
|
||||||
|
break;
|
||||||
|
case 002: /* error register 1 */
|
||||||
|
uptr->CMD &= 0177777;
|
||||||
|
uptr->CMD |= data << 16;
|
||||||
|
if (data != 0)
|
||||||
|
uptr->CMD |= DS_ERR;
|
||||||
|
break;
|
||||||
|
case 003: /* maintenance */
|
||||||
|
break;
|
||||||
|
case 004: /* atten summary */
|
||||||
|
rs_attn[ctlr] = 0;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (data & (1<<i))
|
||||||
|
rs_unit[(ctlr * 8) + i].CMD &= ~DS_ATA;
|
||||||
|
if (rs_unit[(ctlr * 8) + i].CMD & DS_ATA)
|
||||||
|
rs_attn[ctlr] = 1;
|
||||||
|
}
|
||||||
|
clr_interrupt(df10->devnum);
|
||||||
|
if (((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0) ||
|
||||||
|
(df10->status & PI_ENABLE))
|
||||||
|
df10_setirq(df10);
|
||||||
|
break;
|
||||||
|
case 005: /* sector/track */
|
||||||
|
uptr->DA = data & 0177777;
|
||||||
|
break;
|
||||||
|
case 006: /* drive type */
|
||||||
|
case 007: /* look ahead */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
uptr->CMD |= (ER1_ILR<<16)|DS_ERR;
|
||||||
|
rs_rae[ctlr] &= ~(1<<unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
rs_read(int ctlr, int unit, int reg) {
|
||||||
|
DEVICE *dptr = rs_devs[ctlr];
|
||||||
|
struct df10 *df10 = &rs_df10[ctlr];
|
||||||
|
UNIT *uptr = &dptr->units[unit];
|
||||||
|
uint32 temp = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0 && reg != 04) { /* not attached? */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(reg) {
|
||||||
|
case 000: /* control */
|
||||||
|
temp = uptr->CMD & 077;
|
||||||
|
if (uptr->flags & UNIT_ATT)
|
||||||
|
temp |= CS1_DVA;
|
||||||
|
if ((df10->status & BUSY) == 0 && (uptr->CMD & CR_GO) == 0)
|
||||||
|
temp |= CS1_GO;
|
||||||
|
break;
|
||||||
|
case 001: /* status */
|
||||||
|
temp = uptr->CMD & 0177700;
|
||||||
|
break;
|
||||||
|
case 002: /* error register 1 */
|
||||||
|
temp = (uptr->CMD >> 16) & 0177777;
|
||||||
|
break;
|
||||||
|
case 004: /* atten summary */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (rs_unit[(ctlr * 8) + i].CMD & DS_ATA) {
|
||||||
|
temp |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 005: /* sector/track */
|
||||||
|
temp = uptr->DA & 0177777;
|
||||||
|
break;
|
||||||
|
case 006: /* drive type */
|
||||||
|
temp = rs_drv_tab[GET_DTYPE(uptr->flags)].devtype;
|
||||||
|
break;
|
||||||
|
case 003: /* maintenance */
|
||||||
|
case 007: /* look ahead */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
uptr->CMD |= (ER1_ILR<<16);
|
||||||
|
rs_rae[ctlr] &= ~(1<<unit);
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat rs_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int dtype = GET_DTYPE(uptr->flags);
|
||||||
|
int ctlr = GET_CNTRL(uptr->flags);
|
||||||
|
int unit;
|
||||||
|
DEVICE *dptr;
|
||||||
|
struct df10 *df;
|
||||||
|
int da;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
/* Find dptr, and df10 */
|
||||||
|
dptr = rs_devs[ctlr];
|
||||||
|
unit = uptr - dptr->units;
|
||||||
|
df = &rs_df10[ctlr];
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
|
||||||
|
uptr->CMD |= (ER1_UNS << 16) | DS_ATA|DS_ERR; /* set drive error */
|
||||||
|
df->status &= ~BUSY;
|
||||||
|
df10_setirq(df);
|
||||||
|
return (SCPE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if seeking */
|
||||||
|
if (uptr->CMD & DS_PIP) {
|
||||||
|
uptr->CMD &= ~DS_PIP;
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (GET_FNC(uptr->CMD)) {
|
||||||
|
case FNC_NOP:
|
||||||
|
case FNC_DCLR: /* drive clear */
|
||||||
|
break;
|
||||||
|
case FNC_PRESET: /* read-in preset */
|
||||||
|
rs_attn[ctlr] = 1;
|
||||||
|
uptr->CMD |= DS_DRY|DS_ATA;
|
||||||
|
uptr->CMD &= ~CR_GO;
|
||||||
|
df->status &= ~BUSY;
|
||||||
|
if (df->status & IADR_ATTN)
|
||||||
|
df10_setirq(df);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o seekdone\n", unit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FNC_SEARCH: /* search */
|
||||||
|
if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect ||
|
||||||
|
GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf)
|
||||||
|
uptr->CMD |= (ER1_IAE << 16)|DS_ERR;
|
||||||
|
rs_attn[ctlr] = 1;
|
||||||
|
uptr->CMD |= DS_DRY|DS_ATA;
|
||||||
|
uptr->CMD &= ~CR_GO;
|
||||||
|
df->status &= ~BUSY;
|
||||||
|
if ((df->status & (IADR_ATTN|BUSY)) == IADR_ATTN)
|
||||||
|
df10_setirq(df);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o searchdone\n", unit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FNC_READ: /* read */
|
||||||
|
case FNC_WCHK: /* write check */
|
||||||
|
if (uptr->DATAPTR == 0) {
|
||||||
|
int wc;
|
||||||
|
if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect ||
|
||||||
|
GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf) {
|
||||||
|
uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA;
|
||||||
|
df->status &= ~BUSY;
|
||||||
|
uptr->CMD &= ~CR_GO;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o readx done\n", unit);
|
||||||
|
df10_finish_op(df, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o read (%d,%d)\n", unit,
|
||||||
|
GET_SC(uptr->DA), GET_SF(uptr->DA));
|
||||||
|
da = GET_DA(uptr->DA, dtype) * RS_NUMWD;
|
||||||
|
(void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
wc = sim_fread (&rs_buf[ctlr][0], sizeof(uint64), RS_NUMWD,
|
||||||
|
uptr->fileref);
|
||||||
|
while (wc < RS_NUMWD)
|
||||||
|
rs_buf[ctlr][wc++] = 0;
|
||||||
|
uptr->hwmark = RS_NUMWD;
|
||||||
|
}
|
||||||
|
|
||||||
|
df->buf = rs_buf[ctlr][uptr->DATAPTR++];
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "RSA%o read word %d %012llo %09o %06o\n",
|
||||||
|
unit, uptr->DATAPTR, df->buf, df->cda, df->wcr);
|
||||||
|
if (df10_write(df)) {
|
||||||
|
if (uptr->DATAPTR == uptr->hwmark) {
|
||||||
|
/* Increment to next sector. Set Last Sector */
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
uptr->DA += 1 << DA_V_SC;
|
||||||
|
if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect) {
|
||||||
|
uptr->DA &= (DA_M_SF << DA_V_SF);
|
||||||
|
uptr->DA += 1 << DA_V_SF;
|
||||||
|
if (GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf)
|
||||||
|
uptr->CMD |= DS_LST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sim_activate(uptr, 20);
|
||||||
|
} else {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o read done\n", unit);
|
||||||
|
uptr->CMD |= DS_DRY;
|
||||||
|
uptr->CMD &= ~CR_GO;
|
||||||
|
df10_finish_op(df, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FNC_WRITE: /* write */
|
||||||
|
if (uptr->DATAPTR == 0) {
|
||||||
|
if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect ||
|
||||||
|
GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf) {
|
||||||
|
uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA;
|
||||||
|
uptr->CMD &= ~CR_GO;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o writex done\n", unit);
|
||||||
|
df10_finish_op(df, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r = df10_read(df);
|
||||||
|
rs_buf[ctlr][uptr->DATAPTR++] = df->buf;
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "RSA%o write word %d %012llo %09o %06o\n",
|
||||||
|
unit, uptr->DATAPTR, df->buf, df->cda, df->wcr);
|
||||||
|
if (r == 0 || uptr->DATAPTR == RS_NUMWD) {
|
||||||
|
while (uptr->DATAPTR < RS_NUMWD)
|
||||||
|
rs_buf[ctlr][uptr->DATAPTR++] = 0;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o write (%d,%d)\n", unit,
|
||||||
|
GET_SC(uptr->DA), GET_SF(uptr->DA));
|
||||||
|
da = GET_DA(uptr->DA, dtype) * RS_NUMWD;
|
||||||
|
(void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
(void)sim_fwrite (&rs_buf[ctlr][0], sizeof(uint64), RS_NUMWD,
|
||||||
|
uptr->fileref);
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
if (r) {
|
||||||
|
uptr->DA += 1 << DA_V_SC;
|
||||||
|
if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect) {
|
||||||
|
uptr->DA &= (DA_M_SF << DA_V_SF);
|
||||||
|
uptr->DA += 1 << DA_V_SF;
|
||||||
|
if (GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf)
|
||||||
|
uptr->CMD |= DS_LST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r) {
|
||||||
|
sim_activate(uptr, 20);
|
||||||
|
} else {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "RSA%o write done\n", unit);
|
||||||
|
uptr->CMD |= DS_DRY;
|
||||||
|
uptr->CMD &= ~CR_GO;
|
||||||
|
df10_finish_op(df, 0);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
rs_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (uptr == NULL) return SCPE_IERR;
|
||||||
|
uptr->flags &= ~(UNIT_DTYPE);
|
||||||
|
uptr->flags |= val;
|
||||||
|
i = GET_DTYPE(val);
|
||||||
|
uptr->capac = rs_drv_tab[i].size;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
rs_reset(DEVICE * rstr)
|
||||||
|
{
|
||||||
|
int ctlr;
|
||||||
|
for (ctlr = 0; ctlr < NUM_DEVS_RS; ctlr++) {
|
||||||
|
rs_df10[ctlr].devnum = rs_dib[ctlr].dev_num;
|
||||||
|
rs_df10[ctlr].nxmerr = 19;
|
||||||
|
rs_df10[ctlr].ccw_comp = 14;
|
||||||
|
rs_df10[ctlr].status = 0;
|
||||||
|
rs_attn[ctlr] = 0;
|
||||||
|
rs_rae[ctlr] = 0;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boot from given device */
|
||||||
|
t_stat
|
||||||
|
rs_boot(int32 unit_num, DEVICE * rptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &rptr->units[unit_num];
|
||||||
|
int ctlr = GET_CNTRL(uptr->flags);
|
||||||
|
DEVICE *dptr;
|
||||||
|
struct df10 *df;
|
||||||
|
uint32 addr;
|
||||||
|
uint32 ptr = 0;
|
||||||
|
uint64 word;
|
||||||
|
int wc;
|
||||||
|
|
||||||
|
df = &rs_df10[ctlr];
|
||||||
|
dptr = rs_devs[ctlr];
|
||||||
|
(void)sim_fseek(uptr->fileref, 0, SEEK_SET);
|
||||||
|
(void)sim_fread (&rs_buf[0][0], sizeof(uint64), RS_NUMWD, uptr->fileref);
|
||||||
|
uptr->CMD |= DS_VV;
|
||||||
|
addr = rs_buf[0][ptr] & RMASK;
|
||||||
|
wc = (rs_buf[0][ptr++] >> 18) & RMASK;
|
||||||
|
while (wc != 0) {
|
||||||
|
wc = (wc + 1) & RMASK;
|
||||||
|
addr = (addr + 1) & RMASK;
|
||||||
|
word = rs_buf[0][ptr++];
|
||||||
|
if (addr < 020)
|
||||||
|
FM[addr] = word;
|
||||||
|
else
|
||||||
|
M[addr] = word;
|
||||||
|
}
|
||||||
|
addr = rs_buf[0][ptr] & RMASK;
|
||||||
|
wc = (rs_buf[0][ptr++] >> 18) & RMASK;
|
||||||
|
word = rs_buf[0][ptr++];
|
||||||
|
rs_reg[ctlr] = 040;
|
||||||
|
rs_drive[ctlr] = uptr - dptr->units;
|
||||||
|
df->status |= CCW_COMP_1|PI_ENABLE;
|
||||||
|
PC = word & RMASK;
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Device attach */
|
||||||
|
|
||||||
|
t_stat rs_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
DEVICE *rstr;
|
||||||
|
DIB *dib;
|
||||||
|
int ctlr;
|
||||||
|
|
||||||
|
uptr->capac = rs_drv_tab[GET_DTYPE (uptr->flags)].size;
|
||||||
|
r = attach_unit (uptr, cptr);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
rstr = find_dev_from_unit(uptr);
|
||||||
|
if (rstr == 0)
|
||||||
|
return SCPE_OK;
|
||||||
|
dib = (DIB *) rstr->ctxt;
|
||||||
|
ctlr = dib->dev_num & 014;
|
||||||
|
uptr->DA = 0;
|
||||||
|
uptr->CMD &= ~DS_VV;
|
||||||
|
uptr->CMD |= DS_DPR|DS_MOL|DS_DRY;
|
||||||
|
if (uptr->flags & UNIT_WLK)
|
||||||
|
uptr->CMD |= DS_WRL;
|
||||||
|
rs_df10[ctlr].status |= PI_ENABLE;
|
||||||
|
set_interrupt(dib->dev_num, rs_df10[ctlr].status);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device detach */
|
||||||
|
|
||||||
|
t_stat rs_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
if (!(uptr->flags & UNIT_ATT)) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
|
if (sim_is_active (uptr)) /* unit active? */
|
||||||
|
sim_cancel (uptr); /* cancel operation */
|
||||||
|
uptr->CMD &= ~(DS_VV|DS_WRL|DS_DPR|DS_DRY);
|
||||||
|
return detach_unit (uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat rs_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "RS04 Disk Pack Drives (RS)\n\n");
|
||||||
|
fprintf (st, "The RS controller implements the Massbus family of fast disk drives. RS\n");
|
||||||
|
fprintf (st, "options include the ability to set units write enabled or write locked, to\n");
|
||||||
|
fprintf (st, "set the drive type to one of six disk types or autosize, and to write a DEC\n");
|
||||||
|
fprintf (st, "standard 044 compliant bad block table on the last track.\n\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n");
|
||||||
|
fprintf (st, "The RS device supports the BOOT command.\n");
|
||||||
|
fprint_reg_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *rs_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "RS04 Massbus disk controller";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
1187
PDP10/kx10_sys.c
Normal file
1187
PDP10/kx10_sys.c
Normal file
File diff suppressed because it is too large
Load diff
1161
PDP10/kx10_tu.c
Normal file
1161
PDP10/kx10_tu.c
Normal file
File diff suppressed because it is too large
Load diff
482
PDP10/pdp6_dcs.c
Normal file
482
PDP10/pdp6_dcs.c
Normal file
|
@ -0,0 +1,482 @@
|
||||||
|
/* pdp6_dcs.c: PDP-6 DC630 communication server simulator
|
||||||
|
|
||||||
|
Copyright (c) 2011-2017, 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"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_DCS
|
||||||
|
#define NUM_DEVS_DCS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DCS > 0)
|
||||||
|
|
||||||
|
#define DCS_DEVNUM 0300
|
||||||
|
|
||||||
|
#define DCS_LINES 16
|
||||||
|
|
||||||
|
|
||||||
|
#define STATUS u3
|
||||||
|
|
||||||
|
#define RPI_CHN 000007 /* IN STATUS. */
|
||||||
|
#define TPI_CHN 000700 /* In STATUS */
|
||||||
|
#define RLS_SCN 000010 /* CONO DCSA release scanner */
|
||||||
|
#define RST_SCN 000020 /* CONO DCSA reset to 0 */
|
||||||
|
#define RSCN_ACT 000040 /* Scanner line is active */
|
||||||
|
#define XMT_RLS 004000 /* Clear transmitter flag */
|
||||||
|
#define XSCN_ACT 004000 /* Transmit scanner active */
|
||||||
|
|
||||||
|
#define DATA 0000377
|
||||||
|
#define LINE 0000077 /* Line number in Left */
|
||||||
|
|
||||||
|
|
||||||
|
int dcs_rx_scan = 0; /* Scan counter */
|
||||||
|
int dcs_tx_scan = 0; /* Scan counter */
|
||||||
|
int dcs_send_line = 0; /* Send line number */
|
||||||
|
TMLN dcs_ldsc[DCS_LINES] = { 0 }; /* Line descriptors */
|
||||||
|
TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc };
|
||||||
|
uint32 dcs_tx_enable, dcs_rx_rdy; /* Flags */
|
||||||
|
uint32 dcs_enable; /* Enable line */
|
||||||
|
uint32 dcs_rx_conn; /* Connection flags */
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
|
||||||
|
t_stat dcs_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat dcs_svc (UNIT *uptr);
|
||||||
|
t_stat dcs_doscan (UNIT *uptr);
|
||||||
|
t_stat dcs_reset (DEVICE *dptr);
|
||||||
|
t_stat dcs_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dcs_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dcs_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
t_stat dcs_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||||
|
t_stat dcs_attach (UNIT *uptr, CONST char *cptr);
|
||||||
|
t_stat dcs_detach (UNIT *uptr);
|
||||||
|
t_stat dcs_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *dcs_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
/* Type 630 data structures
|
||||||
|
|
||||||
|
dcs_dev Type 630 device descriptor
|
||||||
|
dcs_unit Type 630 unit descriptor
|
||||||
|
dcs_reg Type 630 register list
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#if !PDP6
|
||||||
|
#define D DEV_DIS
|
||||||
|
#else
|
||||||
|
#define D 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DIB dcs_dib = { DCS_DEVNUM, 2, &dcs_devio, NULL };
|
||||||
|
|
||||||
|
UNIT dcs_unit = {
|
||||||
|
UDATA (&dcs_svc, TT_MODE_7B+UNIT_IDLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT
|
||||||
|
};
|
||||||
|
|
||||||
|
REG dcs_reg[] = {
|
||||||
|
{ DRDATA (TIME, dcs_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||||
|
{ DRDATA (STATUS, dcs_unit.STATUS, 18), PV_LEFT },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB dcs_mod[] = {
|
||||||
|
{ TT_MODE, TT_MODE_KSR, "KSR", "KSR", 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_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
|
||||||
|
&tmxr_dscln, NULL, &dcs_desc, "Disconnect a specific line" },
|
||||||
|
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
|
||||||
|
NULL, &tmxr_show_summ, (void *) &dcs_desc, "Display a summary of line states" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &dcs_desc, "Display current connections" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
|
||||||
|
NULL, &tmxr_show_cstat, (void *) &dcs_desc, "Display multiplexer statistics" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "LINES", "LINES=n",
|
||||||
|
&dcs_setnl, &tmxr_show_lines, (void *) &dcs_desc, "Set number of lines" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NC, 0, NULL, "LOG=n=file",
|
||||||
|
&dcs_set_log, NULL, (void *)&dcs_desc },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "NOLOG",
|
||||||
|
&dcs_set_nolog, NULL, (void *)&dcs_desc, "Disable logging on designated line" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "LOG", NULL,
|
||||||
|
NULL, &dcs_show_log, (void *)&dcs_desc, "Display logging for all lines" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dcs_dev = {
|
||||||
|
"DCS", &dcs_unit, dcs_reg, dcs_mod,
|
||||||
|
1, 10, 31, 1, 8, 8,
|
||||||
|
&tmxr_ex, &tmxr_dep, &dcs_reset,
|
||||||
|
NULL, &dcs_attach, &dcs_detach,
|
||||||
|
&dcs_dib, DEV_MUX | DEV_DISABLE | DEV_DEBUG | D, 0, dev_debug,
|
||||||
|
NULL, NULL, &dcs_help, NULL, NULL, &dcs_description
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* IOT routine */
|
||||||
|
t_stat dcs_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &dcs_unit;
|
||||||
|
TMLN *lp;
|
||||||
|
int ln;
|
||||||
|
|
||||||
|
switch(dev & 7) {
|
||||||
|
case CONI:
|
||||||
|
/* Check if we might have any interrupts pending */
|
||||||
|
if ((uptr->STATUS & (RSCN_ACT|XSCN_ACT)) != 0)
|
||||||
|
dcs_doscan(uptr);
|
||||||
|
*data = uptr->STATUS & (RPI_CHN|TPI_CHN);
|
||||||
|
if ((uptr->STATUS & (RSCN_ACT)) == 0)
|
||||||
|
*data |= 010LL;
|
||||||
|
if ((uptr->STATUS & (XSCN_ACT)) == 0)
|
||||||
|
*data |= 01000LL;
|
||||||
|
sim_debug(DEBUG_CONI, &dcs_dev, "DCS %03o CONI %06o PC=%o\n",
|
||||||
|
dev, (uint32)*data, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
/* Set PI */
|
||||||
|
uptr->STATUS &= ~(RPI_CHN|TPI_CHN);
|
||||||
|
uptr->STATUS |= (RPI_CHN|TPI_CHN) & *data;
|
||||||
|
if (*data & RST_SCN)
|
||||||
|
dcs_rx_scan = 0;
|
||||||
|
if ((*data & (RLS_SCN|RST_SCN)) != 0)
|
||||||
|
uptr->STATUS |= RSCN_ACT;
|
||||||
|
if ((*data & (XMT_RLS)) != 0) {
|
||||||
|
uptr->STATUS |= XSCN_ACT;
|
||||||
|
dcs_tx_enable &= ~(1 << dcs_tx_scan);
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_debug(DEBUG_CONO, &dcs_dev, "DCS %03o CONO %06o PC=%06o\n",
|
||||||
|
dev, (uint32)*data, PC);
|
||||||
|
dcs_doscan(uptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
case DATAO|4:
|
||||||
|
ln = (dev & 4) ? dcs_send_line : dcs_tx_scan;
|
||||||
|
if (ln < dcs_desc.lines) {
|
||||||
|
lp = &dcs_ldsc[ln];
|
||||||
|
if (lp->conn) {
|
||||||
|
int32 ch = *data & DATA;
|
||||||
|
ch = sim_tt_outcvt(ch, TT_GET_MODE (dcs_unit.flags) | TTUF_KSR);
|
||||||
|
tmxr_putc_ln (lp, ch);
|
||||||
|
dcs_tx_enable |= (1 << ln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dev & 4) {
|
||||||
|
uptr->STATUS |= XSCN_ACT;
|
||||||
|
dcs_doscan(uptr);
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DATAIO, &dcs_dev, "DC %03o DATO %012llo PC=%06o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
case DATAI|4:
|
||||||
|
ln = dcs_rx_scan;
|
||||||
|
if (ln < dcs_desc.lines) {
|
||||||
|
/* Nothing happens if no recieve data, which is transmit ready */
|
||||||
|
lp = &dcs_ldsc[ln];
|
||||||
|
if (tmxr_rqln (lp) > 0) {
|
||||||
|
int32 ch = tmxr_getc_ln (lp);
|
||||||
|
if (ch & SCPE_BREAK) /* break? */
|
||||||
|
ch = 0;
|
||||||
|
else
|
||||||
|
ch = sim_tt_inpcvt (ch, TT_GET_MODE(dcs_unit.flags) | TTUF_KSR);
|
||||||
|
*data = (uint64)(ch & DATA);
|
||||||
|
dcs_tx_enable &= ~(1 << ln);
|
||||||
|
}
|
||||||
|
dcs_rx_rdy &= ~(1 << ln);
|
||||||
|
}
|
||||||
|
if (dev & 4) {
|
||||||
|
uptr->STATUS |= RSCN_ACT;
|
||||||
|
dcs_doscan(uptr);
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DATAIO, &dcs_dev, "DCS %03o DATI %012llo PC=%06o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
break;
|
||||||
|
case CONI|4:
|
||||||
|
/* Read in scanner */
|
||||||
|
if ((uptr->STATUS & (RSCN_ACT)) != 0)
|
||||||
|
*data = (uint64)(dcs_tx_scan) + 2;
|
||||||
|
else
|
||||||
|
*data = (uint64)(dcs_rx_scan) + 2;
|
||||||
|
sim_debug(DEBUG_CONI, &dcs_dev, "DCS %03o CONI %06o PC=%o recieve line\n",
|
||||||
|
dev, (uint32)*data, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO|4:
|
||||||
|
/* Output buffer pointer */
|
||||||
|
dcs_send_line = (int)(*data & 077) - 2;
|
||||||
|
sim_debug(DEBUG_CONO, &dcs_dev, "DCS %03o CONO %06o PC=%06o send line\n",
|
||||||
|
dev, (uint32)*data, PC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Unit service */
|
||||||
|
|
||||||
|
t_stat dcs_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int32 ln;
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
|
ln = tmxr_poll_conn (&dcs_desc); /* look for connect */
|
||||||
|
if (ln >= 0) { /* got one? rcv enb*/
|
||||||
|
dcs_ldsc[ln].rcve = 1;
|
||||||
|
dcs_tx_enable |= 1 << ln;
|
||||||
|
sim_debug(DEBUG_DETAIL, &dcs_dev, "DC line connect %d\n", ln);
|
||||||
|
}
|
||||||
|
tmxr_poll_tx(&dcs_desc);
|
||||||
|
tmxr_poll_rx(&dcs_desc);
|
||||||
|
for (ln = 0; ln < dcs_desc.lines; ln++) {
|
||||||
|
/* Check to see if any pending data for this line */
|
||||||
|
if (tmxr_rqln(&dcs_ldsc[ln]) > 0) {
|
||||||
|
dcs_rx_rdy |= (1 << ln);
|
||||||
|
sim_debug(DEBUG_DETAIL, &dcs_dev, "DC recieve %d\n", ln);
|
||||||
|
}
|
||||||
|
/* Check if disconnect */
|
||||||
|
if ((dcs_rx_conn & (1 << ln)) != 0 && dcs_ldsc[ln].conn == 0) {
|
||||||
|
dcs_tx_enable &= ~(1 << ln);
|
||||||
|
dcs_rx_conn &= ~(1 << ln);
|
||||||
|
sim_debug(DEBUG_DETAIL, &dcs_dev, "DC line disconnect %d\n", ln);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If any pending status request, raise the PI signal */
|
||||||
|
dcs_doscan(uptr);
|
||||||
|
sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan to see if something to do */
|
||||||
|
t_stat dcs_doscan (UNIT *uptr) {
|
||||||
|
|
||||||
|
clr_interrupt(DCS_DEVNUM);
|
||||||
|
if ((uptr->STATUS & (RSCN_ACT)) != 0) {
|
||||||
|
for (;dcs_rx_rdy != 0; dcs_rx_scan++) {
|
||||||
|
dcs_rx_scan &= 037;
|
||||||
|
/* Check if we found it */
|
||||||
|
if (dcs_rx_rdy & (1 << dcs_rx_scan)) {
|
||||||
|
uptr->STATUS &= ~RSCN_ACT;
|
||||||
|
/* Stop scanner */
|
||||||
|
set_interrupt(DCS_DEVNUM, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((uptr->STATUS & (XSCN_ACT)) != 0) {
|
||||||
|
for (;dcs_tx_enable != 0; dcs_tx_scan++) {
|
||||||
|
dcs_tx_scan &= 037;
|
||||||
|
/* Check if we found it */
|
||||||
|
if (dcs_tx_enable & (1 << dcs_tx_scan)) {
|
||||||
|
uptr->STATUS &= ~XSCN_ACT;
|
||||||
|
/* Stop scanner */
|
||||||
|
set_interrupt(DCS_DEVNUM, (uptr->STATUS >> 6));
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset routine */
|
||||||
|
|
||||||
|
t_stat dcs_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
if (dcs_unit.flags & UNIT_ATT) /* if attached, */
|
||||||
|
sim_activate (&dcs_unit, tmxr_poll); /* activate */
|
||||||
|
else
|
||||||
|
sim_cancel (&dcs_unit); /* else stop */
|
||||||
|
dcs_tx_enable = 0;
|
||||||
|
dcs_rx_rdy = 0; /* Flags */
|
||||||
|
dcs_rx_conn = 0;
|
||||||
|
dcs_send_line = 0;
|
||||||
|
dcs_tx_scan = 0;
|
||||||
|
dcs_rx_scan = 0;
|
||||||
|
dcs_unit.STATUS = 0;
|
||||||
|
clr_interrupt(DCS_DEVNUM);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SET LINES processor */
|
||||||
|
|
||||||
|
t_stat dcs_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
int32 newln, i, t;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
newln = (int32) get_uint (cptr, 10, DCS_LINES, &r);
|
||||||
|
if ((r != SCPE_OK) || (newln == dcs_desc.lines))
|
||||||
|
return r;
|
||||||
|
if ((newln == 0) || (newln >= DCS_LINES) || (newln % 8) != 0)
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (newln < dcs_desc.lines) {
|
||||||
|
for (i = newln, t = 0; i < dcs_desc.lines; i++)
|
||||||
|
t = t | dcs_ldsc[i].conn;
|
||||||
|
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
|
||||||
|
return SCPE_OK;
|
||||||
|
for (i = newln; i < dcs_desc.lines; i++) {
|
||||||
|
if (dcs_ldsc[i].conn) {
|
||||||
|
tmxr_linemsg (&dcs_ldsc[i], "\r\nOperator disconnected line\r\n");
|
||||||
|
tmxr_send_buffered_data (&dcs_ldsc[i]);
|
||||||
|
}
|
||||||
|
tmxr_detach_ln (&dcs_ldsc[i]); /* completely reset line */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dcs_desc.lines < newln)
|
||||||
|
memset (dcs_ldsc + dcs_desc.lines, 0, sizeof(*dcs_ldsc)*(newln-dcs_desc.lines));
|
||||||
|
dcs_desc.lines = newln;
|
||||||
|
return dcs_reset (&dcs_dev); /* setup lines and auto config */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SET LOG processor */
|
||||||
|
|
||||||
|
t_stat dcs_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
char gbuf[CBUFSIZE];
|
||||||
|
int32 ln;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
cptr = get_glyph (cptr, gbuf, '=');
|
||||||
|
if ((cptr == NULL) || (*cptr == 0) || (gbuf[0] == 0))
|
||||||
|
return SCPE_ARG;
|
||||||
|
ln = (int32) get_uint (gbuf, 10, dcs_desc.lines, &r);
|
||||||
|
if ((r != SCPE_OK) || (ln >= dcs_desc.lines))
|
||||||
|
return SCPE_ARG;
|
||||||
|
return tmxr_set_log (NULL, ln, cptr, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SET NOLOG processor */
|
||||||
|
|
||||||
|
t_stat dcs_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
int32 ln;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
ln = (int32) get_uint (cptr, 10, dcs_desc.lines, &r);
|
||||||
|
if ((r != SCPE_OK) || (ln >= dcs_desc.lines))
|
||||||
|
return SCPE_ARG;
|
||||||
|
return tmxr_set_nolog (NULL, ln, NULL, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SHOW LOG processor */
|
||||||
|
|
||||||
|
t_stat dcs_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < dcs_desc.lines; i++) {
|
||||||
|
fprintf (st, "line %d: ", i);
|
||||||
|
tmxr_show_log (st, NULL, i, desc);
|
||||||
|
fprintf (st, "\n");
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Attach routine */
|
||||||
|
|
||||||
|
t_stat dcs_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat reason;
|
||||||
|
|
||||||
|
reason = tmxr_attach (&dcs_desc, uptr, cptr);
|
||||||
|
if (reason != SCPE_OK)
|
||||||
|
return reason;
|
||||||
|
sim_activate (uptr, tmxr_poll);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detach routine */
|
||||||
|
|
||||||
|
t_stat dcs_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
t_stat reason;
|
||||||
|
reason = tmxr_detach (&dcs_desc, uptr);
|
||||||
|
for (i = 0; i < dcs_desc.lines; i++)
|
||||||
|
dcs_ldsc[i].rcve = 0;
|
||||||
|
sim_cancel (uptr);
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat dcs_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Type 630 Terminal Interfaces\n\n");
|
||||||
|
fprintf (st, "The Type 630 supported up to 8 blocks of 8 lines. Modem control was on a seperate\n");
|
||||||
|
fprintf (st, "line. The number of lines is specified with a SET command:\n\n");
|
||||||
|
fprintf (st, " sim> SET DCS LINES=n set number of additional lines to n [8-32]\n\n");
|
||||||
|
fprintf (st, "Lines must be set in multiples of 8.\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.\n");
|
||||||
|
fprintf (st, "Finally, each line supports output logging. The SET DCn LOG command enables\n");
|
||||||
|
fprintf (st, "logging on a line:\n\n");
|
||||||
|
fprintf (st, " sim> SET DCSn LOG=filename log output of line n to filename\n\n");
|
||||||
|
fprintf (st, "The SET DCSn NOLOG command disables logging and closes the open log file,\n");
|
||||||
|
fprintf (st, "if any.\n\n");
|
||||||
|
fprintf (st, "Once DC 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 DC DISCONNECT command, or a DETACH DC command.\n\n");
|
||||||
|
fprintf (st, "Other special commands:\n\n");
|
||||||
|
fprintf (st, " sim> SHOW DCS CONNECTIONS show current connections\n");
|
||||||
|
fprintf (st, " sim> SHOW DCS STATISTICS show statistics for active connections\n");
|
||||||
|
fprintf (st, " sim> SET DCSn DISCONNECT disconnects the specified line.\n");
|
||||||
|
fprint_reg_help (st, &dcs_dev);
|
||||||
|
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 DC is detached.\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dcs_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Type 630 asynchronous line interface";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
284
PDP10/pdp6_dct.c
Normal file
284
PDP10/pdp6_dct.c
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
/* ka10_dct.c: Type 136 Data Control
|
||||||
|
|
||||||
|
Copyright (c) 2013-2019, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_DCT
|
||||||
|
#define NUM_DEVS_DCT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DCT > 0)
|
||||||
|
|
||||||
|
#define DCT_DEVNUM 0200 /* First device number */
|
||||||
|
|
||||||
|
#define STATUS u3
|
||||||
|
|
||||||
|
/* CONI/CONO Flags */
|
||||||
|
#define PIA 0000000000007LL
|
||||||
|
#define DEV 0000000000070LL
|
||||||
|
#define PACK 0000000000300LL
|
||||||
|
#define IN_OUT 0000000000400LL
|
||||||
|
#define DB_RQ 0000000001000LL /* DCT has data for 10 or needs data */
|
||||||
|
#define DB_AC 0000000002000LL /* DCT has completed a word. */
|
||||||
|
#define DB_MV 0000000004000LL /* Data needs to be moved between buffers */
|
||||||
|
#define MISS 0000000010000LL
|
||||||
|
#define NUM_CHARS 0000000160000LL
|
||||||
|
|
||||||
|
uint64 dct_buf[NUM_DEVS_DCT];
|
||||||
|
uint64 dct_acc[NUM_DEVS_DCT];
|
||||||
|
|
||||||
|
t_stat dct_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat dct_svc(UNIT *);
|
||||||
|
t_stat dct_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *dct_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
|
||||||
|
#if !PDP6
|
||||||
|
#define D DEV_DIS
|
||||||
|
#else
|
||||||
|
#define D 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UNIT dct_unit[] = {
|
||||||
|
/* Controller 1 */
|
||||||
|
{ UDATA (&dct_svc, UNIT_DISABLE, 0) },
|
||||||
|
{ UDATA (&dct_svc, UNIT_DISABLE, 0) },
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB dct_dib[] = {
|
||||||
|
{DCT_DEVNUM, NUM_DEVS_DCT, &dct_devio, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
REG dct_reg[] = {
|
||||||
|
{BRDATA(BUFF, &dct_buf[0], 16, 36, NUM_DEVS_DCT), REG_HRO},
|
||||||
|
{BRDATA(BUFF, &dct_acc[0], 16, 36, NUM_DEVS_DCT), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dct_dev = {
|
||||||
|
"DCT", dct_unit, dct_reg, NULL,
|
||||||
|
NUM_DEVS_DCT, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
&dct_dib[0], DEV_DISABLE | DEV_DEBUG | D, 0, dev_debug,
|
||||||
|
NULL, NULL, &dct_help, NULL, NULL, &dct_description
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dct_devio(uint32 dev, uint64 *data) {
|
||||||
|
int u;
|
||||||
|
UNIT *uptr = NULL;
|
||||||
|
|
||||||
|
u = (dev - dct_dib[0].dev_num) >> 2;
|
||||||
|
|
||||||
|
if (u >= NUM_DEVS_DCT)
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
uptr = &dct_unit[u];
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
*data = (uint64)(uptr->STATUS);
|
||||||
|
sim_debug(DEBUG_CONI, &dct_dev, "DCT %03o CONI %012llo %d PC=%o\n", dev,
|
||||||
|
*data, u, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
/* Clear flags */
|
||||||
|
uptr->STATUS = *data & 017777;
|
||||||
|
if (uptr->STATUS & DB_RQ)
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
sim_debug(DEBUG_CONO, &dct_dev, "DCT %03o CONO %06o %d PC=%o %06o\n", dev,
|
||||||
|
(uint32)*data, u, PC, uptr->STATUS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
if (uptr->STATUS & DB_RQ) {
|
||||||
|
*data = dct_buf[u];
|
||||||
|
uptr->STATUS &= ~(DB_RQ);
|
||||||
|
uptr->STATUS |= DB_MV;
|
||||||
|
sim_activate(uptr, 10);
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DATAIO, &dct_dev, "DCT %03o DATI %012llo %d PC=%o\n",
|
||||||
|
dev, *data, u, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
sim_debug(DEBUG_DATAIO, &dct_dev, "DCT %03o DATO %012llo, %d PC=%o\n",
|
||||||
|
dev, *data, u, PC);
|
||||||
|
if (uptr->STATUS & DB_RQ) {
|
||||||
|
dct_buf[u] = *data;
|
||||||
|
uptr->STATUS &= ~(DB_RQ);
|
||||||
|
uptr->STATUS |= DB_MV;
|
||||||
|
sim_activate(uptr, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OUT = 0, dev-> 10, OUT=1 10 -> dev */
|
||||||
|
|
||||||
|
/* OUT starts with RQ & AC with MV =0 */
|
||||||
|
/* IN starts with MV = 1 RQ & AC = 0 */
|
||||||
|
t_stat
|
||||||
|
dct_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int u = uptr - dct_unit;
|
||||||
|
int dev = dct_dib[0].dev_num + (u << 2);
|
||||||
|
|
||||||
|
/* Transfer from 10 to device */
|
||||||
|
if ((uptr->STATUS & (DB_MV|IN_OUT|DB_AC|DB_RQ)) == (DB_AC|DB_MV|IN_OUT)) {
|
||||||
|
dct_acc[u] = dct_buf[u];
|
||||||
|
uptr->STATUS &= ~(DB_MV|DB_AC);
|
||||||
|
uptr->STATUS |= DB_RQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tranfer from device to 10 */
|
||||||
|
if ((uptr->STATUS & (DB_MV|IN_OUT|DB_AC|DB_RQ)) == (DB_AC|DB_MV)) {
|
||||||
|
dct_buf[u] = dct_acc[u];
|
||||||
|
uptr->STATUS &= ~(DB_MV|DB_AC);
|
||||||
|
uptr->STATUS |= DB_RQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uptr->STATUS & DB_RQ)
|
||||||
|
set_interrupt(dev, uptr->STATUS);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Check if the dct is still connected to this device. */
|
||||||
|
int
|
||||||
|
dct_is_connect (int dev)
|
||||||
|
{
|
||||||
|
int d = dev & 07;
|
||||||
|
int u = (dev >> 3) & 07;
|
||||||
|
UNIT *uptr;
|
||||||
|
|
||||||
|
/* Valid device? */
|
||||||
|
if (u >= NUM_DEVS_DCT)
|
||||||
|
return 0;
|
||||||
|
uptr = &dct_unit[u];
|
||||||
|
/* Is DCT pointed at this device? */
|
||||||
|
if (((uptr->STATUS & DEV) >> 3) != d)
|
||||||
|
return 0;
|
||||||
|
/* If sending processor to device, and no data, terminate */
|
||||||
|
if ((uptr->STATUS & IN_OUT) != 0 && (uptr->STATUS & DB_AC) != 0)
|
||||||
|
return 0;
|
||||||
|
/* Everything ok, still connected */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read data from memory */
|
||||||
|
int
|
||||||
|
dct_read (int dev, uint64 *data, int cnt)
|
||||||
|
{
|
||||||
|
int d = dev & 07;
|
||||||
|
int u = (dev >> 3) & 07;
|
||||||
|
DEVICE *dptr = &dct_dev;
|
||||||
|
UNIT *uptr;
|
||||||
|
|
||||||
|
/* Valid device? */
|
||||||
|
if (u >= NUM_DEVS_DCT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uptr = &dct_unit[u];
|
||||||
|
/* Is DCT pointed at this device? */
|
||||||
|
if (((uptr->STATUS & DEV) >> 3) != d)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check if correct direction */
|
||||||
|
if ((uptr->STATUS & IN_OUT) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If we have data return it */
|
||||||
|
if ((uptr->STATUS & DB_AC) == 0) {
|
||||||
|
*data = dct_acc[u];
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "DCT Read %012llo, %d \n",
|
||||||
|
*data, u);
|
||||||
|
uptr->STATUS &= ~(NUM_CHARS);
|
||||||
|
uptr->STATUS |= DB_AC | DB_MV | ((cnt & 7) << 13);
|
||||||
|
sim_activate(uptr, 20);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write data to memory */
|
||||||
|
int
|
||||||
|
dct_write (int dev, uint64 *data, int cnt)
|
||||||
|
{
|
||||||
|
int d = dev & 07;
|
||||||
|
int u = (dev >> 3) & 07;
|
||||||
|
DEVICE *dptr = &dct_dev;
|
||||||
|
UNIT *uptr;
|
||||||
|
|
||||||
|
/* Valid device? */
|
||||||
|
if (u >= NUM_DEVS_DCT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uptr = &dct_unit[u];
|
||||||
|
/* Is DCT pointed at this device? */
|
||||||
|
if (((uptr->STATUS & DEV) >> 3) != d)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check if correct direction */
|
||||||
|
if ((uptr->STATUS & IN_OUT) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If buffer is empty put data in it. */
|
||||||
|
if ((uptr->STATUS & DB_AC) == 0) {
|
||||||
|
dct_acc[u] = *data;
|
||||||
|
sim_debug(DEBUG_DATA, dptr, "DCT Write %012llo, %d %06o\n", *data, u, uptr->STATUS);
|
||||||
|
uptr->STATUS &= ~(NUM_CHARS);
|
||||||
|
uptr->STATUS |= DB_AC | DB_MV | ((cnt & 7) << 13);
|
||||||
|
sim_activate(uptr, 20);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dct_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Data Controller Type 136 is a data buffer between fast ");
|
||||||
|
fprintf (st, "devices and the PDP6. Individual devices are hooked up to ports ");
|
||||||
|
fprintf (st, "on each DCT.\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
dct_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Data Controller Type 136";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
511
PDP10/pdp6_dsk.c
Normal file
511
PDP10/pdp6_dsk.c
Normal file
|
@ -0,0 +1,511 @@
|
||||||
|
/* ka10_dsk.c: 270 Disk Controller.
|
||||||
|
|
||||||
|
Copyright (c) 2013-2019, 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 MEDSKHANTABILITY,
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_DSK
|
||||||
|
#define NUM_DEVS_DSK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_DSK > 0)
|
||||||
|
|
||||||
|
#define DSK_DEVNUM 0270 /* 0174 */
|
||||||
|
#define NUM_UNITS_DSK 4
|
||||||
|
|
||||||
|
/* Flags in the unit flags word */
|
||||||
|
|
||||||
|
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||||
|
#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
|
||||||
|
#define UNIT_M_DTYPE 1
|
||||||
|
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||||
|
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
|
||||||
|
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
|
||||||
|
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||||
|
|
||||||
|
/* Parameters in the unit descriptor */
|
||||||
|
|
||||||
|
#define CUR_CYL u3 /* current cylinder */
|
||||||
|
#define DATAPTR u4 /* data pointer */
|
||||||
|
#define UFLAGS u5 /* Function */
|
||||||
|
|
||||||
|
/* CONO bits */
|
||||||
|
#define PIA 0000007
|
||||||
|
#define EIS 0000010 /* Enable Idle State */
|
||||||
|
#define EFR 0000020 /* Enable file ready */
|
||||||
|
#define EES 0000040 /* Enable end of sector */
|
||||||
|
#define EFE 0000100 /* Enable file error */
|
||||||
|
#define SCL 0000200 /* Clear error flags WO */
|
||||||
|
#define MRB 0000200 /* Meter read bad RO */
|
||||||
|
#define MRG 0000400 /* Meter read good RO */
|
||||||
|
#define CMD 0003000 /* Command */
|
||||||
|
#define WR_CMD 0002000 /* Command is write */
|
||||||
|
#define RD_CMD 0001000 /* Command is read */
|
||||||
|
#define END 0010000 /* End */
|
||||||
|
#define CLR 0020000 /* Clear */
|
||||||
|
#define MCL 0040000 /* Master clear RO */
|
||||||
|
|
||||||
|
/* CONI bits */
|
||||||
|
/* Upper 18 bits, same as CONO */
|
||||||
|
#define SECT_END (1 << 18) /* End of sector flag set */
|
||||||
|
#define DCE 0001000 /* Data clock error */
|
||||||
|
#define CME 0000400 /* Command error */
|
||||||
|
#define WLE 0000200 /* Write lock error */
|
||||||
|
#define ADE 0000100 /* Not operational */
|
||||||
|
#define ALM 0000040 /* ALARM */
|
||||||
|
#define DRL 0000020 /* Data request late */
|
||||||
|
#define RCE 0000010 /* Read Compare error */
|
||||||
|
#define PER 0000004 /* Parity error */
|
||||||
|
#define FER 0000002 /* File error */
|
||||||
|
#define OPR 0000001 /* Not operational */
|
||||||
|
|
||||||
|
/* Octoflop states */
|
||||||
|
#define IDS 0200 /* Selcted idle state */
|
||||||
|
#define SNA 0100 /* Selected new address */
|
||||||
|
#define ADT 0040 /* Address terminated */
|
||||||
|
#define DFR 0020 /* Disc file ready */
|
||||||
|
#define ALS 0010 /* Alert state */
|
||||||
|
#define CMS 0004 /* Command selected */
|
||||||
|
#define SCS 0002 /* Sector started */
|
||||||
|
#define SCE 0001 /* Sector end */
|
||||||
|
|
||||||
|
/* Start in IDS state.
|
||||||
|
*
|
||||||
|
* DATAO sets state to SNA.
|
||||||
|
* 43 us later state to ADT.
|
||||||
|
* State ADT:
|
||||||
|
* Seek cylinder/sector.
|
||||||
|
* DATAO resets to SNA.
|
||||||
|
* Find cylinder state to DFR.
|
||||||
|
* State DFR:
|
||||||
|
* Remain in DFR for 1ms then set to ADT.
|
||||||
|
* CONO set state to ALS.
|
||||||
|
* DATAO nop.
|
||||||
|
* State ALS:
|
||||||
|
* 15us later advance to CMS if Read/Write command
|
||||||
|
* State CMS:
|
||||||
|
* 200us later advance to SCS, before first bit of sector.
|
||||||
|
* State SCS:
|
||||||
|
* Transfer data.
|
||||||
|
* End of sector advance to SCE
|
||||||
|
* CONO +END or +CLR
|
||||||
|
* Read command, terminate read. Advance to SCE.
|
||||||
|
* Write/read cmp.
|
||||||
|
* State SCE:
|
||||||
|
* Increase sector by 1.
|
||||||
|
* If END set CMD = NOP.
|
||||||
|
* 2us, if CMD = NOP advance to IDS, else CMS.
|
||||||
|
* set SECT_END flag. (Possible IRQ).
|
||||||
|
*
|
||||||
|
* CONO +SCL clear error bits. ADE,CME,DCE,DRL,FER,PER,RCE,SECT_END,WLE.
|
||||||
|
* CONO +CLR clears CMD=0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DSK_WDS 128
|
||||||
|
#define DSK_SECS 44
|
||||||
|
#define DSK_CYL 64 * 16
|
||||||
|
#define DSK_SIZE (DSK_SECS * DSK_CYL * DSK_WDS)
|
||||||
|
|
||||||
|
uint64 dsk_buf[DSK_WDS];
|
||||||
|
uint8 dsk_octflp;
|
||||||
|
uint32 dsk_status;
|
||||||
|
uint32 dsk_cmd;
|
||||||
|
uint32 dsk_addr;
|
||||||
|
int dsk_dct = 0;
|
||||||
|
|
||||||
|
t_stat dsk_devio(uint32 dev, uint64 *data);
|
||||||
|
t_stat dsk_svc(UNIT *);
|
||||||
|
t_stat dsk_boot(int32, DEVICE *);
|
||||||
|
t_stat dsk_set_dct (UNIT *, int32, CONST char *, void *);
|
||||||
|
t_stat dsk_show_dct (FILE *, UNIT *, int32, CONST void *);
|
||||||
|
void dsk_ini(UNIT *, t_bool);
|
||||||
|
t_stat dsk_reset(DEVICE *);
|
||||||
|
t_stat dsk_attach(UNIT *, CONST char *);
|
||||||
|
t_stat dsk_detach(UNIT *);
|
||||||
|
t_stat dsk_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *dsk_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
#if !PDP6
|
||||||
|
#define D DEV_DIS
|
||||||
|
#else
|
||||||
|
#define D 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UNIT dsk_unit[] = {
|
||||||
|
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||||
|
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||||
|
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||||
|
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB dsk_dib[] = {
|
||||||
|
{DSK_DEVNUM, 1, &dsk_devio, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB dsk_mod[] = {
|
||||||
|
{UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||||||
|
{UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL},
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "DCT", "DCT",
|
||||||
|
&dsk_set_dct, &dsk_show_dct, NULL},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
REG dsk_reg[] = {
|
||||||
|
{BRDATA(BUFF, &dsk_buf[0], 16, 64, DSK_WDS), REG_HRO},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE dsk_dev = {
|
||||||
|
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
||||||
|
NUM_UNITS_DSK, 8, 18, 1, 8, 36,
|
||||||
|
NULL, NULL, &dsk_reset, &dsk_boot, &dsk_attach, &dsk_detach,
|
||||||
|
&dsk_dib[0], DEV_DISABLE | DEV_DEBUG | D, 0, dev_debug,
|
||||||
|
NULL, NULL, &dsk_help, NULL, NULL, &dsk_description
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dsk_devio(uint32 dev, uint64 *data) {
|
||||||
|
UNIT *uptr = &dsk_unit[(dsk_addr >> 16) & 03];
|
||||||
|
uint64 res;
|
||||||
|
|
||||||
|
switch(dev & 3) {
|
||||||
|
case CONI:
|
||||||
|
res = ((uint64)(dsk_cmd) << 18);
|
||||||
|
res |= ((uint64)(dsk_octflp)) << 10;
|
||||||
|
res |= ((uint64)(dsk_status & RMASK));
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
res |= OPR;
|
||||||
|
if (uptr->flags & UNIT_WLK)
|
||||||
|
res |= WLE;
|
||||||
|
*data = res;
|
||||||
|
sim_debug(DEBUG_CONI, &dsk_dev, "DSK %03o CONI %012llo PC=%o\n", dev,
|
||||||
|
*data, PC);
|
||||||
|
break;
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(dev);
|
||||||
|
if (*data & SCL)
|
||||||
|
dsk_status &= ADE|CME|DCE|DRL|FER|PER|RCE|SECT_END;
|
||||||
|
/* If disk controller is busy */
|
||||||
|
if (dsk_octflp & (ALS|CMS|SCS|SCE)) {
|
||||||
|
/* Only update IRQ flags and stop flags */
|
||||||
|
dsk_cmd &= END|CLR|CMD;
|
||||||
|
dsk_cmd |= *data & ~(CMD|SCL);
|
||||||
|
} else {
|
||||||
|
dsk_cmd &= END|CLR;
|
||||||
|
dsk_cmd |= *data & ~(SCL);
|
||||||
|
}
|
||||||
|
if ((dsk_cmd & EIS) != 0 && dsk_octflp == IDS)
|
||||||
|
set_interrupt(dev, dsk_cmd);
|
||||||
|
if ((dsk_cmd & EFE) != 0 && (dsk_status & (FER|PER|WLE|RCE|DRL)) != 0)
|
||||||
|
set_interrupt(dev, dsk_cmd);
|
||||||
|
if ((dsk_cmd & EFR) != 0 && dsk_octflp == DFR)
|
||||||
|
set_interrupt(dev, dsk_cmd);
|
||||||
|
if ((dsk_cmd & EFR) != 0 && dsk_status & SECT_END)
|
||||||
|
set_interrupt(dev, dsk_cmd);
|
||||||
|
sim_debug(DEBUG_CONO, &dsk_dev, "DSK %03o CONO %06o PC=%o %06o\n", dev,
|
||||||
|
(uint32)*data, PC, dsk_status);
|
||||||
|
break;
|
||||||
|
case DATAI:
|
||||||
|
sim_debug(DEBUG_DATAIO, &dsk_dev, "DSK %03o DATI %012llo PC=%o\n",
|
||||||
|
dev, *data, PC);
|
||||||
|
break;
|
||||||
|
case DATAO:
|
||||||
|
sim_debug(DEBUG_DATAIO, &dsk_dev, "DSK %03o DATO %012llo, PC=%o %03o\n",
|
||||||
|
dev, *data, PC, dsk_octflp);
|
||||||
|
/* If not in right state we can't change it */
|
||||||
|
if (dsk_octflp & (SCE|SCS|CMS|ALS))
|
||||||
|
break;
|
||||||
|
/* Zero lower 3 bits of sector if read next sector set */
|
||||||
|
if (*data & 01000000LL)
|
||||||
|
*data &= ~07LL;
|
||||||
|
|
||||||
|
dsk_addr = (*data & RMASK);
|
||||||
|
uptr = &dsk_unit[(dsk_addr >> 16) & 03];
|
||||||
|
/* If we are idle, start controller */
|
||||||
|
if (dsk_octflp == IDS) {
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
clr_interrupt(dev);
|
||||||
|
}
|
||||||
|
dsk_octflp = SNA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dsk_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
int ctlr = (dsk_addr >> 16) & 03;
|
||||||
|
int cyl;
|
||||||
|
int sec;
|
||||||
|
int wc;
|
||||||
|
uint64 data;
|
||||||
|
DEVICE *dptr;
|
||||||
|
t_stat err;
|
||||||
|
|
||||||
|
dptr = &dsk_dev;
|
||||||
|
|
||||||
|
/* Check if we need to seek */
|
||||||
|
if (dsk_octflp == SCE) {
|
||||||
|
if ((dsk_cmd & CMD) == WR_CMD && (uptr->flags & UNIT_WLK) == 0) {
|
||||||
|
/* Write the block */
|
||||||
|
int da;
|
||||||
|
for (; uptr->DATAPTR < DSK_WDS; uptr->DATAPTR++)
|
||||||
|
dsk_buf[uptr->DATAPTR] = 0;
|
||||||
|
cyl = (dsk_addr >> 6) & 01777;
|
||||||
|
sec = dsk_addr & 077;
|
||||||
|
if (sec > DSK_SECS)
|
||||||
|
sec -= DSK_SECS;
|
||||||
|
da = (sec + (cyl * DSK_SECS)) * DSK_WDS;
|
||||||
|
err = sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
(void)sim_fwrite (&dsk_buf[0], sizeof(uint64),
|
||||||
|
DSK_WDS, uptr->fileref);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Write %d %d\n", ctlr, da, cyl);
|
||||||
|
}
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
sec = (dsk_addr + 1) & 077;
|
||||||
|
if (sec >= DSK_SECS)
|
||||||
|
sec = 0;
|
||||||
|
dsk_addr = (dsk_addr & ~077) | sec;
|
||||||
|
if (dsk_cmd & CLR)
|
||||||
|
dsk_cmd &= ~(CMD|CLR);
|
||||||
|
dsk_octflp = CMS;
|
||||||
|
if (dsk_cmd & END || (dsk_cmd & CMD) == 0 || dct_is_connect(dsk_dct) == 0) {
|
||||||
|
dsk_cmd &= ~(CMD|CLR|END);
|
||||||
|
dsk_octflp = IDS;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
|
||||||
|
/* Do transfer */
|
||||||
|
if (dsk_octflp == SCS) {
|
||||||
|
if (dsk_cmd & END) {
|
||||||
|
dsk_octflp = SCE;
|
||||||
|
} else if ((dsk_status & DRL) == 0) {
|
||||||
|
if (dsk_cmd & WR_CMD) {
|
||||||
|
if (dct_read(dsk_dct, &data, 2) == 0) {
|
||||||
|
dsk_status |= DRL;
|
||||||
|
} else if (dsk_cmd & RD_CMD) {
|
||||||
|
if (dsk_buf[uptr->DATAPTR] != data)
|
||||||
|
dsk_status |= RCE;
|
||||||
|
} else {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Write %012llo %d\n",
|
||||||
|
ctlr, data, uptr->DATAPTR);
|
||||||
|
if ((uptr->flags & UNIT_WLK) != 0)
|
||||||
|
dsk_status |= DCE|PER|FER;
|
||||||
|
dsk_buf[uptr->DATAPTR] = data;
|
||||||
|
}
|
||||||
|
} else if (dsk_cmd & RD_CMD) {
|
||||||
|
data = dsk_buf[uptr->DATAPTR];
|
||||||
|
if (dct_write(dsk_dct, &data, 2) == 0)
|
||||||
|
dsk_status |= DRL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uptr->DATAPTR++;
|
||||||
|
if (uptr->DATAPTR == DSK_WDS)
|
||||||
|
dsk_octflp = SCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dsk_octflp == CMS) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DSK %d CMS\n", ctlr);
|
||||||
|
if (dsk_cmd & RD_CMD) {
|
||||||
|
/* Read the block */
|
||||||
|
int da;
|
||||||
|
cyl = (dsk_addr >> 6) & 01777;
|
||||||
|
sec = dsk_addr & 077;
|
||||||
|
if (sec > DSK_SECS)
|
||||||
|
sec -= DSK_SECS;
|
||||||
|
da = (sec + (cyl * DSK_SECS)) * DSK_WDS;
|
||||||
|
err = sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||||||
|
wc = sim_fread (&dsk_buf[0], sizeof(uint64),
|
||||||
|
DSK_WDS, uptr->fileref);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Read %d %d\n", ctlr, da, cyl);
|
||||||
|
for (; wc < DSK_WDS; wc++)
|
||||||
|
dsk_buf[wc] = 0;
|
||||||
|
} else if (dsk_cmd & WR_CMD) {
|
||||||
|
/* Check if we can write disk */
|
||||||
|
if (uptr->flags & UNIT_WLK) {
|
||||||
|
dsk_status |= CME|FER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uptr->DATAPTR = 0;
|
||||||
|
dsk_octflp = SCS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ready for data transfer */
|
||||||
|
if (dsk_octflp == DFR) {
|
||||||
|
if (dsk_cmd & CMD) {
|
||||||
|
dsk_octflp = ALS;
|
||||||
|
} else {
|
||||||
|
dsk_octflp = ADT;
|
||||||
|
}
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If at ADT then seek to correct cylinder */
|
||||||
|
if (dsk_octflp == ADT) {
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
|
dsk_status |= ADE|FER;
|
||||||
|
} else {
|
||||||
|
cyl = (dsk_addr >> 6) & 077;
|
||||||
|
if (cyl != uptr->CUR_CYL) {
|
||||||
|
cyl -= uptr->CUR_CYL;
|
||||||
|
if (cyl < 0)
|
||||||
|
cyl = -cyl;
|
||||||
|
uptr->CUR_CYL = (dsk_addr >> 6) & 077;
|
||||||
|
sim_activate(uptr, 10000 * cyl);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dsk_octflp = DFR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Address is correct and we have a command */
|
||||||
|
if (dsk_octflp == ALS) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Alarm\n", ctlr);
|
||||||
|
dsk_octflp = CMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If at SNA the switch to ADT */
|
||||||
|
if (dsk_octflp == SNA) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Sna\n", ctlr);
|
||||||
|
dsk_octflp = ADT;
|
||||||
|
if (uptr->flags & UNIT_WLK)
|
||||||
|
dsk_status |= WLE|FER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are in idle state, just return */
|
||||||
|
if (dsk_octflp == IDS) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Idle\n", ctlr);
|
||||||
|
if ((dsk_cmd & EIS) != 0)
|
||||||
|
set_interrupt(DSK_DEVNUM, dsk_cmd);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
if ((dsk_cmd & EIS) != 0 && dsk_octflp == IDS)
|
||||||
|
set_interrupt(DSK_DEVNUM, dsk_cmd);
|
||||||
|
if ((dsk_cmd & EFE) != 0 && (dsk_status & (FER|PER|WLE|RCE|DRL)) != 0)
|
||||||
|
set_interrupt(DSK_DEVNUM, dsk_cmd);
|
||||||
|
if ((dsk_cmd & EFR) != 0 && dsk_octflp == DFR)
|
||||||
|
set_interrupt(DSK_DEVNUM, dsk_cmd);
|
||||||
|
if ((dsk_cmd & EFR) != 0 && dsk_status & SECT_END)
|
||||||
|
set_interrupt(DSK_DEVNUM, dsk_cmd);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set DCT channel and unit. */
|
||||||
|
t_stat
|
||||||
|
dsk_set_dct (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
int32 dct;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
dct = (int32) get_uint (cptr, 8, 20, &r);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
dsk_dct = dct;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dsk_show_dct (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
|
{
|
||||||
|
if (uptr == NULL)
|
||||||
|
return SCPE_IERR;
|
||||||
|
|
||||||
|
fprintf (st, "DCT=%02o", dsk_dct);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dsk_reset(DEVICE * dptr)
|
||||||
|
{
|
||||||
|
int unit;
|
||||||
|
UNIT *uptr = dptr->units;
|
||||||
|
for(unit = 0; unit < NUM_UNITS_DSK; unit++) {
|
||||||
|
uptr->UFLAGS = 0;
|
||||||
|
uptr->CUR_CYL = 0;
|
||||||
|
uptr++;
|
||||||
|
}
|
||||||
|
dsk_octflp = IDS;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boot from given device */
|
||||||
|
t_stat
|
||||||
|
dsk_boot(int32 unit_num, DEVICE * dptr)
|
||||||
|
{
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device attach */
|
||||||
|
t_stat
|
||||||
|
dsk_attach (UNIT *uptr, CONST char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
r = attach_unit (uptr, cptr);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
uptr->CUR_CYL = 0;
|
||||||
|
uptr->UFLAGS = 0;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device detach */
|
||||||
|
t_stat
|
||||||
|
dsk_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
if (!(uptr->flags & UNIT_ATT)) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
|
if (sim_is_active (uptr)) /* unit active? */
|
||||||
|
sim_cancel (uptr); /* cancel operation */
|
||||||
|
return detach_unit (uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
dsk_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "The DSK controller implements the 270 disk controller for the PDP6\n");
|
||||||
|
fprintf (st, "Options include the ability to set units write enabled or write locked\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprintf (st, "The DSK device supports the BOOT command.\n");
|
||||||
|
fprint_reg_help (st, dptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dsk_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "270 disk controller";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1286
PDP10/pdp6_dtc.c
Normal file
1286
PDP10/pdp6_dtc.c
Normal file
File diff suppressed because it is too large
Load diff
942
PDP10/pdp6_mtc.c
Normal file
942
PDP10/pdp6_mtc.c
Normal file
|
@ -0,0 +1,942 @@
|
||||||
|
/* ka10_mtc.c: Type 516 Magnetic tape controller
|
||||||
|
|
||||||
|
Copyright (c) 2013-2019, 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.
|
||||||
|
|
||||||
|
Magnetic tapes are represented as a series of variable records
|
||||||
|
of the form:
|
||||||
|
|
||||||
|
32b byte count
|
||||||
|
byte 0
|
||||||
|
byte 1
|
||||||
|
:
|
||||||
|
byte n-2
|
||||||
|
byte n-1
|
||||||
|
32b byte count
|
||||||
|
|
||||||
|
If the byte count is odd, the record is padded with an extra byte
|
||||||
|
of junk. File marks are represented by a byte count of 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kx10_defs.h"
|
||||||
|
#include "sim_tape.h"
|
||||||
|
|
||||||
|
#ifndef NUM_DEVS_MTC
|
||||||
|
#define NUM_DEVS_MTC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (NUM_DEVS_MTC > 0)
|
||||||
|
|
||||||
|
#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF)
|
||||||
|
#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define MTUF_7TRK (1 << MTUF_V_UF)
|
||||||
|
|
||||||
|
#define BUFFSIZE (32 * 1024)
|
||||||
|
#define UNIT_MT UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE
|
||||||
|
#define LT 66 /* Time per char low density */
|
||||||
|
#define HT 16 /* Time per char high density */
|
||||||
|
|
||||||
|
/* MTC register */
|
||||||
|
#define FLAG_PIA 0000007 /* 0 */
|
||||||
|
#define DIS_EOR 0000010 /* 3 */
|
||||||
|
#define UNIT_NUM 0000160 /* 4 */
|
||||||
|
#define HOLD_SEL 0000200 /* 7 */
|
||||||
|
#define FUNCTION 0007400 /* 8 */
|
||||||
|
#define NOP 000 /* Nop */
|
||||||
|
#define NOP_1 010 /* Nop */
|
||||||
|
#define REWIND 001 /* Rewind */
|
||||||
|
#define UNLOAD 011 /* Unload */
|
||||||
|
#define WRITE 002 /* Write */
|
||||||
|
#define WRITE_1 012 /* Write */
|
||||||
|
#define WTM 003 /* Write End of File */
|
||||||
|
#define ERG 013 /* Write blank tape */
|
||||||
|
#define CMP 004 /* Compare */
|
||||||
|
#define CMP_1 014 /* Compare */
|
||||||
|
#define READ 005 /* Read */
|
||||||
|
#define READ_BK 015 /* Read Backward */
|
||||||
|
#define SPC_FWD 006 /* Space forward */
|
||||||
|
#define SPC_EOF 016 /* Space to end of file */
|
||||||
|
#define SPC_REV 007 /* Space reverse */
|
||||||
|
#define SPC_REV_EOF 017 /* Space reverse to EOF. */
|
||||||
|
#define DENS_200 0000000
|
||||||
|
#define DENS_556 0010000
|
||||||
|
#define DENS_800 0020000
|
||||||
|
#define DENS_MSK 0030000 /* 6 */
|
||||||
|
#define ODD_PARITY 0040000 /*14 */
|
||||||
|
#define SLICE 0100000
|
||||||
|
#define WRCLK 0200000
|
||||||
|
#define FALS_EOR 0400000
|
||||||
|
#define CMD_FULL 0x8000000
|
||||||
|
#define CMD_MASK 0777760
|
||||||
|
|
||||||
|
/* MTS register */
|
||||||
|
#define TAPE_FREE 0000001
|
||||||
|
#define TAPE_RDY 0000002
|
||||||
|
#define EOR_FLAG 0000004 /* End of record */
|
||||||
|
#define PARITY_ERR 0000010
|
||||||
|
#define PARITY_ERRL 0000020
|
||||||
|
#define READ_CMP 0000040
|
||||||
|
#define MIS_CHR 0000100 /* Charaters missed on tape */
|
||||||
|
#define WRITE_LOCK 0000200
|
||||||
|
#define EOF_FLAG 0000400
|
||||||
|
#define LD_PT 0001000 /* Tape near load point */
|
||||||
|
#define END_PT 0002000 /* Tape near end point */
|
||||||
|
#define BOT_FLAG 0004000
|
||||||
|
#define EOT_FLAG 0010000
|
||||||
|
#define REW 0020000
|
||||||
|
#define TRF_CMD 0040000
|
||||||
|
#define CONT_MOT 0100000
|
||||||
|
#define MOT_STOP 0200000
|
||||||
|
#define ILL_OPR 0400000
|
||||||
|
|
||||||
|
/* CONO to MTS */
|
||||||
|
#define ENB_ICE 0000001 /* Control Ready */
|
||||||
|
#define ENB_JNU 0000002 /* Set monitor unit */
|
||||||
|
#define ENB_ERF 0000004 /* End of Record */
|
||||||
|
#define ENB_XNE 0040000 /* New command rdy */
|
||||||
|
#define ENB_LIE 0100000 /* Load point */
|
||||||
|
|
||||||
|
/* IRQ Masks in status */
|
||||||
|
#define IRQ_ICE 001000000
|
||||||
|
#define IRQ_JNU 002000000
|
||||||
|
#define IRQ_ERF 004000000
|
||||||
|
#define IRQ_XNE 010000000
|
||||||
|
#define IRQ_LIE 020000000
|
||||||
|
#define IRQ_MASK 037000000
|
||||||
|
|
||||||
|
/* MTM register */
|
||||||
|
#define EOR_RD_DLY 0000001
|
||||||
|
#define EOR_WR_DLY 0000002
|
||||||
|
#define MIS_CHR_DLY 0000004
|
||||||
|
#define FR_CHR_INH 0000010
|
||||||
|
#define UNIT_BUF_FIN 0000160
|
||||||
|
#define MOT_DLY 0000200
|
||||||
|
#define FUNC_FIN 0007400
|
||||||
|
#define UNIT_SEL_NEW 0010000
|
||||||
|
#define CMD_HOLD 0020000
|
||||||
|
#define MOT_STOP_DLY 0040000
|
||||||
|
#define EOR_MOT_DLY 0100000
|
||||||
|
#define REC_IN_PROG 0200000
|
||||||
|
#define TRP_SPD_DLY 0400000
|
||||||
|
|
||||||
|
|
||||||
|
#define MTC_DEVCTL 0220
|
||||||
|
#define MTC_DEVSTA 0224
|
||||||
|
#define MTC_DEVSTM 0230
|
||||||
|
#define MTC_MOTION 000000001 /* Mag tape unit in motion */
|
||||||
|
#define MTC_BUSY 000000002 /* Mag tape unit is busy */
|
||||||
|
#define MTC_START 000000004 /* Start a command */
|
||||||
|
|
||||||
|
#define CNTRL u3
|
||||||
|
#define STATUS u4 /* Per drive status bits */
|
||||||
|
#define CPOS u5 /* Character position */
|
||||||
|
#define BPOS u6 /* Position in buffer */
|
||||||
|
|
||||||
|
t_stat mtc_devio(uint32 dev, uint64 *data);
|
||||||
|
void mtc_checkirq(UNIT * uptr);
|
||||||
|
t_stat mtc_srv(UNIT *);
|
||||||
|
t_stat mtc_boot(int32, DEVICE *);
|
||||||
|
t_stat mtc_reset(DEVICE *);
|
||||||
|
t_stat mtc_set_dct (UNIT *, int32, CONST char *, void *);
|
||||||
|
t_stat mtc_show_dct (FILE *, UNIT *, int32, CONST void *);
|
||||||
|
t_stat mtc_attach(UNIT *, CONST char *);
|
||||||
|
t_stat mtc_detach(UNIT *);
|
||||||
|
t_stat mtc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||||||
|
const char *cptr);
|
||||||
|
const char *mtc_description (DEVICE *dptr);
|
||||||
|
|
||||||
|
uint16 mtc_pia;
|
||||||
|
uint8 mtc_sel_unit;
|
||||||
|
uint32 mtc_hold_cmd;
|
||||||
|
uint32 mtc_status;
|
||||||
|
int mtc_dct; /* DCT Channel and unit */
|
||||||
|
|
||||||
|
static uint8 parity_table[64] = {
|
||||||
|
/* 0 1 2 3 4 5 6 7 */
|
||||||
|
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||||||
|
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||||||
|
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||||||
|
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||||||
|
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||||||
|
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||||||
|
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||||||
|
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* One buffer per channel */
|
||||||
|
uint8 mtc_buffer[BUFFSIZE];
|
||||||
|
|
||||||
|
#if !PDP6
|
||||||
|
#define D DEV_DIS
|
||||||
|
#else
|
||||||
|
#define D 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UNIT mtc_unit[] = {
|
||||||
|
/* Controller 1 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 0 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 1 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 2 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 3 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 4 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 5 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 6 */
|
||||||
|
{UDATA(&mtc_srv, UNIT_MT, 0)}, /* 7 */
|
||||||
|
};
|
||||||
|
|
||||||
|
DIB mtc_dib = {MTC_DEVCTL, 3, &mtc_devio, NULL};
|
||||||
|
|
||||||
|
MTAB mtc_mod[] = {
|
||||||
|
{MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||||||
|
{MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL},
|
||||||
|
{MTUF_7TRK, 0, "9T", "9T", NULL, NULL},
|
||||||
|
{MTUF_7TRK, MTUF_7TRK, "7T", "7T", NULL, NULL},
|
||||||
|
{MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||||
|
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL},
|
||||||
|
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LENGTH", "LENGTH",
|
||||||
|
&sim_tape_set_capac, &sim_tape_show_capac, NULL},
|
||||||
|
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DENSITY", "DENSITY",
|
||||||
|
&sim_tape_set_dens, &sim_tape_show_dens, NULL},
|
||||||
|
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "DCT", "DCT",
|
||||||
|
&mtc_set_dct, &mtc_show_dct, NULL},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DEVICE mtc_dev = {
|
||||||
|
"MTC", mtc_unit, NULL, mtc_mod,
|
||||||
|
8, 8, 15, 1, 8, 8,
|
||||||
|
NULL, NULL, &mtc_reset, &mtc_boot, &mtc_attach, &mtc_detach,
|
||||||
|
&mtc_dib, DEV_DISABLE | DEV_DEBUG | DEV_TAPE | D, 0, dev_debug,
|
||||||
|
NULL, NULL, &mtc_help, NULL, NULL, &mtc_description
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
mtc_devio(uint32 dev, uint64 *data) {
|
||||||
|
uint64 res;
|
||||||
|
DEVICE *dptr = &mtc_dev;
|
||||||
|
UNIT *uptr;
|
||||||
|
int u;
|
||||||
|
|
||||||
|
switch(dev & 0374) {
|
||||||
|
case MTC_DEVCTL:
|
||||||
|
switch(dev & 03) {
|
||||||
|
case CONI:
|
||||||
|
res = (uint64)((mtc_hold_cmd & CMD_MASK) | (mtc_pia & FLAG_PIA));
|
||||||
|
*data = res;
|
||||||
|
sim_debug(DEBUG_CONI, dptr, "MTC CONI %03o status %08o %o %o PC=%06o\n",
|
||||||
|
dev, mtc_status, mtc_sel_unit, mtc_pia, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
clr_interrupt(MTC_DEVCTL);
|
||||||
|
mtc_pia = (uint16)(*data) & (FLAG_PIA);
|
||||||
|
mtc_hold_cmd = (*data & CMD_MASK);
|
||||||
|
sim_debug(DEBUG_CONO, dptr, "MTC CONO %03o start %o %o%012llo PC=%06o\n",
|
||||||
|
dev, mtc_sel_unit, mtc_pia, *data, PC);
|
||||||
|
/* If nop done */
|
||||||
|
if ((mtc_hold_cmd & FUNCTION) == 0)
|
||||||
|
break;
|
||||||
|
u = (mtc_hold_cmd >> 4) & 07;
|
||||||
|
uptr = &mtc_unit[u];
|
||||||
|
if ((uptr->flags & UNIT_ATT) != 0) {
|
||||||
|
/* If unit is not busy, give it the command to run */
|
||||||
|
if ((uptr->CNTRL & (MTC_START|MTC_BUSY)) == 0) {
|
||||||
|
sim_debug(DEBUG_CONO, dptr, "MTC CONO %03o starting %o\n", dev, u);
|
||||||
|
mtc_sel_unit = u;
|
||||||
|
mtc_hold_cmd &= ~CMD_FULL;
|
||||||
|
uptr->CNTRL = (mtc_hold_cmd & ~UNIT_NUM) | MTC_START;
|
||||||
|
uptr->STATUS = 0;
|
||||||
|
mtc_status &= IRQ_MASK; /* Clear all flags but IRQ flags */
|
||||||
|
mtc_status |= TRF_CMD;
|
||||||
|
sim_activate(uptr, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MTC_DEVSTA:
|
||||||
|
switch(dev & 03) {
|
||||||
|
case CONI:
|
||||||
|
uptr = &mtc_unit[mtc_sel_unit];
|
||||||
|
res = mtc_status | (uint64)(uptr->STATUS);
|
||||||
|
if ((uptr->flags & MTUF_WLK) != 0)
|
||||||
|
res |= WRITE_LOCK;
|
||||||
|
if (sim_tape_bot(uptr))
|
||||||
|
res |= BOT_FLAG;
|
||||||
|
if (sim_tape_eot(uptr))
|
||||||
|
res |= EOT_FLAG;
|
||||||
|
if ((uptr->flags & UNIT_ATT) != 0 && (uptr->CNTRL & (MTC_START|MTC_BUSY)) == 0)
|
||||||
|
res |= TAPE_RDY;
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0 || (uptr->CNTRL & (MTC_START|MTC_MOTION|MTC_BUSY)) == 0)
|
||||||
|
res |= TAPE_FREE;
|
||||||
|
*data = res;
|
||||||
|
sim_debug(DEBUG_CONI, dptr, "MTC CONI %03o status %012llo %o %08o PC=%06o\n",
|
||||||
|
dev, res, mtc_sel_unit, mtc_status, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
mtc_status &= 00777777;
|
||||||
|
mtc_status |= (*data & 07) << 18;
|
||||||
|
mtc_status |= (*data & (ENB_XNE|ENB_LIE)) << 7;
|
||||||
|
if (*data & TAPE_RDY && (mtc_hold_cmd & FUNCTION) == 0) {
|
||||||
|
/* Switch to drive to check status */
|
||||||
|
mtc_sel_unit = (mtc_hold_cmd >> 4) & 07;
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_CONO, dptr, "MTC CONO %03o status %012llo %o %08o PC=%06o\n",
|
||||||
|
dev, *data, mtc_sel_unit, mtc_status, PC);
|
||||||
|
uptr = &mtc_unit[mtc_sel_unit];
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MTC_DEVSTM:
|
||||||
|
switch(dev & 03) {
|
||||||
|
case CONI:
|
||||||
|
uptr = &mtc_unit[mtc_sel_unit];
|
||||||
|
res = (mtc_sel_unit << 4) | (uptr->CNTRL & FUNC_FIN);
|
||||||
|
if (mtc_sel_unit != ((mtc_hold_cmd & UNIT_NUM) >> 4))
|
||||||
|
res |= UNIT_SEL_NEW;
|
||||||
|
if (mtc_hold_cmd & CMD_FULL)
|
||||||
|
res |= CMD_HOLD;
|
||||||
|
sim_debug(DEBUG_CONI, dptr, "MTC CONI %03o status2 %012llo %o %08o PC=%06o\n",
|
||||||
|
dev, res, mtc_sel_unit, mtc_status, PC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONO:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAI:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DATAO:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mtc_checkirq(UNIT * uptr)
|
||||||
|
{
|
||||||
|
clr_interrupt(MTC_DEVCTL);
|
||||||
|
if ((mtc_status & IRQ_XNE) != 0 && (mtc_status & TRF_CMD) != 0) {
|
||||||
|
set_interrupt(MTC_DEVCTL, mtc_pia);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((mtc_status & IRQ_LIE) != 0 && sim_tape_bot(uptr)) {
|
||||||
|
set_interrupt(MTC_DEVCTL, mtc_pia);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((mtc_status & (EOR_FLAG|IRQ_ERF)) == (EOR_FLAG|IRQ_ERF)) {
|
||||||
|
set_interrupt(MTC_DEVCTL, mtc_pia);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((mtc_status & IRQ_ICE) != 0 &&
|
||||||
|
(uptr->CNTRL & (MTC_START|MTC_MOTION|MTC_BUSY)) == 0) {
|
||||||
|
set_interrupt(MTC_DEVCTL, mtc_pia);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
/* Need to verify if this is real interrupt or not */
|
||||||
|
if ((mtc_status & IRQ_JNU) != 0 &&
|
||||||
|
(mtc_hold_cmd & CMD_FULL) == 0 &&
|
||||||
|
(uptr->CNTRL & (MTC_START|MTC_BUSY)) == 0) {
|
||||||
|
sim_debug(DEBUG_DETAIL, &mtc_dev, "MTC%o jnu %o %08o\n", mtc_sel_unit, mtc_pia, mtc_status);
|
||||||
|
set_interrupt(MTC_DEVCTL, mtc_pia);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle processing of tape requests. */
|
||||||
|
t_stat
|
||||||
|
mtc_srv(UNIT * uptr)
|
||||||
|
{
|
||||||
|
DEVICE *dptr = find_dev_from_unit(uptr);
|
||||||
|
int unit = (uptr - dptr->units) & 7;
|
||||||
|
int cmd = (uptr->CNTRL & FUNCTION) >> 8;
|
||||||
|
t_mtrlnt reclen;
|
||||||
|
t_stat r = SCPE_ARG; /* Force error if not set */
|
||||||
|
uint8 ch;
|
||||||
|
int cc;
|
||||||
|
uint64 hold_reg;
|
||||||
|
int cc_max;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((uptr->CNTRL & (MTC_START|MTC_BUSY)) == 0) {
|
||||||
|
if (uptr->STATUS & (PARITY_ERR|PARITY_ERRL|READ_CMP|MIS_CHR|EOF_FLAG)) {
|
||||||
|
mtc_hold_cmd &= ~CMD_FULL;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o stoping %o %08o\n", unit, mtc_pia, mtc_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If tape in motion, generate EOR and wait */
|
||||||
|
if (uptr->CNTRL & MTC_MOTION) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o EOR %08o\n", unit, uptr->STATUS);
|
||||||
|
uptr->CNTRL &= ~MTC_MOTION;
|
||||||
|
sim_activate(uptr, 500);
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o Done %08o %08o\n", unit, mtc_hold_cmd, mtc_status);
|
||||||
|
|
||||||
|
/* Check if command pending */
|
||||||
|
if ((mtc_hold_cmd & CMD_FULL) != 0) {
|
||||||
|
int u = (mtc_hold_cmd >> 4) & 07;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o New command %o\n", unit, u);
|
||||||
|
/* Is it for me? */
|
||||||
|
if (u == unit) {
|
||||||
|
mtc_hold_cmd &= ~CMD_FULL;
|
||||||
|
uptr->CNTRL = (mtc_hold_cmd & ~UNIT_NUM) | MTC_START;
|
||||||
|
uptr->STATUS = 0;
|
||||||
|
cmd = (uptr->CNTRL & FUNCTION) >> 8;
|
||||||
|
mtc_status |= TRF_CMD;
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
} else {
|
||||||
|
uptr = &mtc_unit[u];
|
||||||
|
/* See if other unit can be started */
|
||||||
|
mtc_sel_unit = u;
|
||||||
|
if ((uptr->CNTRL & (MTC_START|MTC_MOTION|MTC_BUSY)) == 0) {
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o stoping %o %08o\n", unit, mtc_pia, mtc_status);
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uptr->flags & MTUF_7TRK) {
|
||||||
|
cc_max = 6;
|
||||||
|
} else {
|
||||||
|
cc_max = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uptr->CNTRL & MTC_START)
|
||||||
|
uptr->BPOS = 0;
|
||||||
|
|
||||||
|
|
||||||
|
switch(cmd) {
|
||||||
|
case NOP:
|
||||||
|
case NOP_1:
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o Idle\n", unit);
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY|MTC_START);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REWIND:
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
UNIT *nuptr = &mtc_unit[(mtc_hold_cmd >> 4) & 07];
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
uptr->CNTRL |= MTC_BUSY|MTC_MOTION;
|
||||||
|
uptr->STATUS |= REW;
|
||||||
|
if ((mtc_hold_cmd & CMD_FULL) && ((mtc_hold_cmd >> 4) & 07) != unit &&
|
||||||
|
(nuptr->CNTRL & (MTC_START|MTC_MOTION|MTC_BUSY)) == 0) {
|
||||||
|
mtc_hold_cmd &= ~CMD_FULL;
|
||||||
|
nuptr->CNTRL = (mtc_hold_cmd & ~UNIT_NUM) | MTC_START;
|
||||||
|
if (mtc_status & IRQ_XNE)
|
||||||
|
set_interrupt(MTC_DEVCTL, mtc_pia);
|
||||||
|
sim_activate(nuptr, 100);
|
||||||
|
}
|
||||||
|
sim_activate(uptr, 100000);
|
||||||
|
} else {
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY|FUNCTION);
|
||||||
|
uptr->STATUS &= ~REW;
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o rewind\n", unit);
|
||||||
|
sim_tape_rewind(uptr);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
case UNLOAD:
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
uptr->CNTRL |= MTC_BUSY|MTC_MOTION;
|
||||||
|
uptr->STATUS |= REW;
|
||||||
|
sim_activate(uptr, 100000);
|
||||||
|
} else {
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
uptr->STATUS &= ~REW;
|
||||||
|
sim_activate(uptr, 100);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o unload\n", unit);
|
||||||
|
sim_tape_detach(uptr);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
case READ_BK:
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
if (sim_tape_bot(uptr)) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read back at bot\n", unit);
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_MOTION;
|
||||||
|
if ((r = sim_tape_rdrecr(uptr, &mtc_buffer[0], &reclen, BUFFSIZE)) != MTSE_OK) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read back error %d\n", unit, r);
|
||||||
|
if (r == MTSE_TMK)
|
||||||
|
uptr->STATUS |= EOF_FLAG;
|
||||||
|
else
|
||||||
|
uptr->STATUS |= PARITY_ERRL;
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_BUSY;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read back %d\n", unit, reclen);
|
||||||
|
uptr->hwmark = reclen;
|
||||||
|
uptr->BPOS = reclen-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hold_reg = 0;
|
||||||
|
for (i = cc_max - 1; i >= 0; i--) {
|
||||||
|
ch = mtc_buffer[uptr->BPOS];
|
||||||
|
if (uptr->flags & MTUF_7TRK) {
|
||||||
|
cc = 6 * (5 - i);
|
||||||
|
if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^
|
||||||
|
parity_table[ch & 0x3f]) != 0) {
|
||||||
|
mtc_status |= PARITY_ERR;
|
||||||
|
}
|
||||||
|
hold_reg |= (uint64)(ch & 0x3f) << cc;
|
||||||
|
} else {
|
||||||
|
cc = (8 * (3 - i)) + 4;
|
||||||
|
if (cc < 0)
|
||||||
|
hold_reg |= (uint64)(ch & 0x0f);
|
||||||
|
else
|
||||||
|
hold_reg |= (uint64)(ch & 0xff) << cc;
|
||||||
|
}
|
||||||
|
if ((uint32)uptr->BPOS == 0)
|
||||||
|
break;
|
||||||
|
uptr->BPOS--;
|
||||||
|
}
|
||||||
|
if (dct_write(mtc_dct, &hold_reg, cc_max - i) == 0) {
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case READ:
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
uptr->CNTRL |= MTC_MOTION;
|
||||||
|
if ((r = sim_tape_rdrecf(uptr, &mtc_buffer[0], &reclen, BUFFSIZE)) != MTSE_OK) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read error %d\n", unit, r);
|
||||||
|
if (r == MTSE_TMK)
|
||||||
|
uptr->STATUS |= EOF_FLAG;
|
||||||
|
else if (r == MTSE_EOM)
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
else
|
||||||
|
uptr->STATUS |= PARITY_ERRL;
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_BUSY;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read %d\n", unit, reclen);
|
||||||
|
uptr->hwmark = reclen;
|
||||||
|
uptr->BPOS = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hold_reg = 0;
|
||||||
|
for (i = 0; i < cc_max; i++) {
|
||||||
|
if ((uint32)uptr->BPOS >= uptr->hwmark)
|
||||||
|
break;
|
||||||
|
ch = mtc_buffer[uptr->BPOS];
|
||||||
|
if (uptr->flags & MTUF_7TRK) {
|
||||||
|
cc = 6 * (5 - i);
|
||||||
|
if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^
|
||||||
|
parity_table[ch & 0x3f]) != 0) {
|
||||||
|
mtc_status |= PARITY_ERR;
|
||||||
|
}
|
||||||
|
hold_reg |= (uint64)(ch & 0x3f) << cc;
|
||||||
|
} else {
|
||||||
|
cc = (8 * (3 - i)) + 4;
|
||||||
|
if (cc < 0)
|
||||||
|
hold_reg |= (uint64)(ch & 0x0f);
|
||||||
|
else
|
||||||
|
hold_reg |= (uint64)(ch & 0xff) << cc;
|
||||||
|
}
|
||||||
|
uptr->BPOS++;
|
||||||
|
}
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read data %012llo\n", unit, hold_reg);
|
||||||
|
if (dct_write(mtc_dct, &hold_reg, i) == 0 ||(uint32)uptr->BPOS >= uptr->hwmark) {
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read eor %d %08o\n", unit, uptr->BPOS, mtc_status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CMP:
|
||||||
|
case CMP_1:
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
uptr->CNTRL |= MTC_MOTION;
|
||||||
|
if ((r = sim_tape_rdrecf(uptr, &mtc_buffer[0], &reclen,
|
||||||
|
BUFFSIZE)) != MTSE_OK) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o read cmp error %d\n", unit, r);
|
||||||
|
if (r == MTSE_TMK)
|
||||||
|
uptr->STATUS |= EOF_FLAG;
|
||||||
|
else if (r == MTSE_EOM)
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
else
|
||||||
|
uptr->STATUS |= PARITY_ERRL;
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_BUSY;
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o compare %d\n", unit, reclen);
|
||||||
|
uptr->hwmark = reclen;
|
||||||
|
uptr->BPOS = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (uptr->BPOS >= (int32)uptr->hwmark) {
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
} else if (dct_read(mtc_dct, &hold_reg, cc_max)) {
|
||||||
|
for(i = 0; i < cc_max; i++) {
|
||||||
|
if (uptr->flags & MTUF_7TRK) {
|
||||||
|
ch = mtc_buffer[uptr->BPOS];
|
||||||
|
if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^
|
||||||
|
parity_table[ch & 0x3f]) != (ch & 0x40)) {
|
||||||
|
mtc_status |= PARITY_ERR;
|
||||||
|
}
|
||||||
|
mtc_buffer[uptr->BPOS] &= 0x3f;
|
||||||
|
cc = 6 * (6 - i);
|
||||||
|
ch = (hold_reg >> cc) & 0x3f;
|
||||||
|
} else {
|
||||||
|
if ((uptr->CNTRL & ODD_PARITY) == 0)
|
||||||
|
mtc_status |= PARITY_ERR;
|
||||||
|
/* Write next char out */
|
||||||
|
cc = (8 * (3 - i)) + 4;
|
||||||
|
if (cc < 0)
|
||||||
|
ch = hold_reg & 0x0f;
|
||||||
|
else
|
||||||
|
ch = (hold_reg >> cc) & 0xff;
|
||||||
|
}
|
||||||
|
if (mtc_buffer[uptr->BPOS] != ch) {
|
||||||
|
uptr->STATUS |= READ_CMP;
|
||||||
|
}
|
||||||
|
uptr->BPOS++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WRITE:
|
||||||
|
case WRITE_1:
|
||||||
|
/* Writing and Type A, request first data word */
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
if ((uptr->flags & MTUF_WLK) != 0) {
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_MOTION|MTC_BUSY;
|
||||||
|
sim_debug(DEBUG_EXP, dptr, "MTC%o Init write\n", unit);
|
||||||
|
uptr->hwmark = 0;
|
||||||
|
uptr->BPOS = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Force error if we exceed buffer size */
|
||||||
|
if (uptr->BPOS >= BUFFSIZE) {
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dct_read(mtc_dct, &hold_reg, 0)) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o Write data %012llo\n", unit, hold_reg);
|
||||||
|
for(i = 0; i < cc_max; i++) {
|
||||||
|
if (uptr->flags & MTUF_7TRK) {
|
||||||
|
cc = 6 * (6 - i);
|
||||||
|
ch = (hold_reg >> cc) & 0x3f;
|
||||||
|
ch |= ((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^
|
||||||
|
parity_table[ch & 0x3f];
|
||||||
|
} else {
|
||||||
|
/* Write next char out */
|
||||||
|
cc = (8 * (3 - i)) + 4;
|
||||||
|
if (cc < 0)
|
||||||
|
ch = hold_reg & 0x0f;
|
||||||
|
else
|
||||||
|
ch = (hold_reg >> cc) & 0xff;
|
||||||
|
}
|
||||||
|
mtc_buffer[uptr->BPOS] = ch;
|
||||||
|
uptr->BPOS++;
|
||||||
|
uptr->hwmark = uptr->BPOS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Write out the block */
|
||||||
|
reclen = uptr->hwmark;
|
||||||
|
r = sim_tape_wrrecf(uptr, &mtc_buffer[0], reclen);
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o Write %d %d\n", unit, reclen, r);
|
||||||
|
if (r == MTSE_EOM)
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
else if (r != MTSE_OK)
|
||||||
|
uptr->STATUS |= PARITY_ERRL;
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
uptr->BPOS = 0;
|
||||||
|
uptr->hwmark = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WTM:
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o WTM\n", unit);
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
if ((uptr->flags & MTUF_WLK) != 0) {
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
mtc_status |= (EOR_FLAG);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_MOTION;
|
||||||
|
r = sim_tape_wrtmk(uptr);
|
||||||
|
if (r != MTSE_OK)
|
||||||
|
uptr->STATUS |= PARITY_ERRL;
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERG:
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o ERG\n", unit);
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
if ((uptr->flags & MTUF_WLK) != 0) {
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
mtc_status |= (EOR_FLAG);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_MOTION;
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPC_REV_EOF:
|
||||||
|
case SPC_EOF:
|
||||||
|
case SPC_REV:
|
||||||
|
case SPC_FWD:
|
||||||
|
sim_debug(DEBUG_DETAIL, dptr, "MTC%o space %o\n", unit, cmd);
|
||||||
|
if (uptr->CNTRL & MTC_START) {
|
||||||
|
uptr->CNTRL &= ~MTC_START;
|
||||||
|
if ((cmd & 7) == SPC_REV && sim_tape_bot(uptr)) {
|
||||||
|
uptr->STATUS |= ILL_OPR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr->CNTRL |= MTC_MOTION|MTC_BUSY;
|
||||||
|
}
|
||||||
|
/* Always skip at least one record */
|
||||||
|
if ((cmd & 7) == SPC_FWD)
|
||||||
|
r = sim_tape_sprecf(uptr, &reclen);
|
||||||
|
else
|
||||||
|
r = sim_tape_sprecr(uptr, &reclen);
|
||||||
|
switch (r) {
|
||||||
|
case MTSE_OK: /* no error */
|
||||||
|
if ((cmd & 010) != 0)
|
||||||
|
break;
|
||||||
|
/* Fall through */
|
||||||
|
case MTSE_TMK: /* tape mark */
|
||||||
|
case MTSE_BOT: /* beginning of tape */
|
||||||
|
case MTSE_EOM: /* end of medium */
|
||||||
|
/* Stop motion if we recieve any of these */
|
||||||
|
uptr->CNTRL &= ~(MTC_BUSY);
|
||||||
|
mtc_status |= EOR_FLAG;
|
||||||
|
mtc_checkirq(uptr);
|
||||||
|
}
|
||||||
|
uptr->hwmark = 0;
|
||||||
|
sim_activate(uptr, 420 * (reclen/6));
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
sim_activate(uptr, 420);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64
|
||||||
|
mtc_read_word(UNIT *uptr) {
|
||||||
|
int i, cc, ch;
|
||||||
|
uint64 hold_reg = 0;
|
||||||
|
|
||||||
|
for(i = 0; i <= 4; i++) {
|
||||||
|
cc = (8 * (3 - i)) + 4;
|
||||||
|
ch = mtc_buffer[uptr->BPOS];
|
||||||
|
if (cc < 0)
|
||||||
|
hold_reg |= (uint64)(ch & 0x3f);
|
||||||
|
else
|
||||||
|
hold_reg |= (uint64)(ch & 0xff) << cc;
|
||||||
|
uptr->BPOS++;
|
||||||
|
}
|
||||||
|
return hold_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boot from given device */
|
||||||
|
t_stat
|
||||||
|
mtc_boot(int32 unit_num, DEVICE * dptr)
|
||||||
|
{
|
||||||
|
UNIT *uptr = &dptr->units[unit_num];
|
||||||
|
t_mtrlnt reclen;
|
||||||
|
t_stat r;
|
||||||
|
uint64 hold_reg;
|
||||||
|
int wc, addr;
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
return SCPE_UNATT; /* attached? */
|
||||||
|
|
||||||
|
r = sim_tape_rewind(uptr);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
uptr->CNTRL = 022200; /* Read 800 BPI, Core */
|
||||||
|
r = sim_tape_rdrecf(uptr, &mtc_buffer[0], &reclen, BUFFSIZE);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
uptr->BPOS = 0;
|
||||||
|
uptr->hwmark = reclen;
|
||||||
|
|
||||||
|
hold_reg = mtc_read_word(uptr);
|
||||||
|
wc = (hold_reg >> 18) & RMASK;
|
||||||
|
addr = hold_reg & RMASK;
|
||||||
|
while (wc != 0) {
|
||||||
|
wc = (wc + 1) & RMASK;
|
||||||
|
addr = (addr + 1) & RMASK;
|
||||||
|
if ((uint32)uptr->BPOS >= uptr->hwmark) {
|
||||||
|
r = sim_tape_rdrecf(uptr, &mtc_buffer[0], &reclen, BUFFSIZE);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
uptr->BPOS = 0;
|
||||||
|
uptr->hwmark = reclen;
|
||||||
|
}
|
||||||
|
hold_reg = mtc_read_word(uptr);
|
||||||
|
if (addr < 020)
|
||||||
|
FM[addr] = hold_reg;
|
||||||
|
else
|
||||||
|
M[addr] = hold_reg;
|
||||||
|
}
|
||||||
|
if (addr < 020)
|
||||||
|
FM[addr] = hold_reg;
|
||||||
|
else
|
||||||
|
M[addr] = hold_reg;
|
||||||
|
|
||||||
|
PC = hold_reg & RMASK;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
mtc_reset(DEVICE * dptr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0 ; i < 8; i++) {
|
||||||
|
UNIT *uptr = &mtc_unit[i];
|
||||||
|
|
||||||
|
if (MT_DENS(uptr->dynflags) == MT_DENS_NONE)
|
||||||
|
uptr->dynflags = MT_200_VALID | MT_556_VALID;
|
||||||
|
uptr->CNTRL = 0;
|
||||||
|
sim_cancel(uptr);
|
||||||
|
}
|
||||||
|
mtc_pia = 0;
|
||||||
|
mtc_status = 0;
|
||||||
|
mtc_sel_unit = TAPE_FREE|TAPE_RDY;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set DCT channel and unit. */
|
||||||
|
t_stat
|
||||||
|
mtc_set_dct (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
|
{
|
||||||
|
int32 dct;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if (cptr == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
dct = (int32) get_uint (cptr, 8, 20, &r);
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
mtc_dct = dct;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
mtc_show_dct (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
|
{
|
||||||
|
if (uptr == NULL)
|
||||||
|
return SCPE_IERR;
|
||||||
|
|
||||||
|
fprintf (st, "DCT=%02o", mtc_dct);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
mtc_attach(UNIT * uptr, CONST char *file)
|
||||||
|
{
|
||||||
|
uptr->CNTRL = 0;
|
||||||
|
uptr->STATUS = 0;
|
||||||
|
return sim_tape_attach_ex(uptr, file, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
mtc_detach(UNIT * uptr)
|
||||||
|
{
|
||||||
|
uptr->CPOS = 0;
|
||||||
|
return sim_tape_detach(uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat
|
||||||
|
mtc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf (st, "Type 516 Magnetic Tape\n\n");
|
||||||
|
fprint_set_help (st, dptr);
|
||||||
|
fprint_show_help (st, dptr);
|
||||||
|
fprintf (st, "\nThe type options can be used only when a unit is not attached to a file. The\n");
|
||||||
|
fprintf (st, "bad block option can be used only when a unit is attached to a file.\n");
|
||||||
|
fprintf (st, "The DTC does support the BOOT command, however this did not work on real PDP6.\n");
|
||||||
|
sim_tape_attach_help (st, dptr, uptr, flag, cptr);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
mtc_description (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "Type 516 magnetic tape controller" ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Reference in a new issue