1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-04-08 06:15:20 +00:00

SEL32: Initial commit of working simulator.

This commit is contained in:
James C. Bevier
2019-07-17 21:39:18 -04:00
committed by Richard Cornwell
parent c27809c194
commit d3d4e808cc
12 changed files with 11793 additions and 5965 deletions

File diff suppressed because it is too large Load Diff

367
SEL32/sel32_clk.c Normal file
View File

@@ -0,0 +1,367 @@
/* sel32_clk.c: SEL 32 Class F IOP processor RTOM functions.
Copyright (c) 2018, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This module support the real-time clock and the interval timer.
These are CD/TD class 3 devices. The RTC can be programmed to
50/100 HZ or 60/120 HZ rates and creates an interrupt at the
requested rate. The interval timer is a 32 bit register that is
loaded with a value to be down counted. An interrupt is generated
when the count reaches zero, The clock continues down counting
until read/reset by the programmer. The rate can be external or
38.4 microseconds per count.
*/
#include "sel32_defs.h"
#include "sim_defs.h"
#ifdef NUM_DEVS_RTOM
extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc);
extern void chan_end(uint16 chan, uint8 flags);
extern int chan_read_byte(uint16 chan, uint8 *data);
extern int chan_write_byte(uint16 chan, uint8 *data);
extern void set_devattn(uint16 addr, uint8 flags);
extern void post_extirq(void);
void rtc_setup (uint32 ss, uint32 level);
t_stat rtc_srv (UNIT *uptr);
t_stat rtc_reset (DEVICE *dptr);
t_stat rtc_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
extern int irq_pend; /* go scan for pending int or I/O */
extern uint32 INTS[]; /* interrupt control flags */
extern uint32 SPAD[]; /* computer SPAD */
extern uint32 M[]; /* system memory */
int32 rtc_pie = 0; /* rtc pulse ie */
int32 rtc_tps = 60; /* rtc ticks/sec */
int32 rtc_lvl = 0x18; /* rtc interrupt level */
/* Clock data structures
rtc_dev RTC device descriptor
rtc_unit RTC unit
rtc_reg RTC register list
*/
/* clock is attached all the time */
/* defailt to 60 HZ RTC */
UNIT rtc_unit = { UDATA (&rtc_srv, UNIT_ATT, 0), 16666, UNIT_ADDR(0x7F06)};
REG rtc_reg[] = {
{ FLDATA (PIE, rtc_pie, 0) },
{ DRDATA (TIME, rtc_unit.wait, 32), REG_NZ + PV_LEFT },
{ DRDATA (TPS, rtc_tps, 8), PV_LEFT + REG_HRO },
{ NULL }
};
MTAB rtc_mod[] = {
{ MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
&rtc_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
&rtc_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 100, NULL, "100HZ",
&rtc_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 120, NULL, "120HZ",
&rtc_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
NULL, &rtc_show_freq, NULL },
{ 0 }
};
DEVICE rtc_dev = {
"RTC", &rtc_unit, rtc_reg, rtc_mod,
1, 8, 8, 1, 8, 8,
NULL, NULL, &rtc_reset,
NULL, NULL, NULL
};
/* The real time clock runs continuously; therefore, it only has
a unit service routine and a reset routine. The service routine
sets an interrupt that invokes the clock counter.
*/
/* service clock signal from simulator */
t_stat rtc_srv (UNIT *uptr)
{
if (rtc_pie) { /* set pulse intr */
INTS[rtc_lvl] |= INTS_REQ; /* request the interrupt */
irq_pend = 1; /* make sure we scan for int */
}
// rtc_unit.wait = sim_rtcn_calb (rtc_tps, TMR_RTC); /* calibrate */
// sim_activate (&rtc_unit, rtc_unit.wait); /* reactivate */
sim_activate (&rtc_unit, 16667); /* reactivate */
return SCPE_OK;
}
/* Clock interrupt start/stop */
/* ss = 1 - starting clock */
/* ss = 0 - stopping clock */
/* level = interrupt level */
void rtc_setup(uint ss, uint32 level)
{
uint32 val = SPAD[level+0x80]; /* get SPAD value for interrupt vector */
rtc_lvl = level; /* save the interrupt level */
uint32 addr = SPAD[0xf1] + (level<<2); /* vector address in SPAD */
addr = M[addr>>2]; /* get the interrupt context block addr */
//fprintf(stderr, "rtc_setup called ss %x level %x SPAD %x icba %x\r\n", ss, level, val, addr);
if (ss == 1) { /* starting? */
INTS[level] |= INTS_ENAB; /* make sure enabled */
SPAD[level+0x80] |= SINT_ENAB; /* in spad too */
INTS[level] |= INTS_REQ; /* request the interrupt */
sim_activate(&rtc_unit, 20); /* start us off */
} else {
INTS[level] &= ~INTS_ENAB; /* make sure disabled */
SPAD[level+0x80] &= ~SINT_ENAB; /* in spad too */
}
rtc_pie = ss; /* set new state */
}
/* Clock reset */
t_stat rtc_reset(DEVICE *dptr)
{
rtc_pie = 0; /* disable pulse */
rtc_unit.wait = sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* initialize clock calibration */
sim_activate (&rtc_unit, rtc_unit.wait); /* activate unit */
return SCPE_OK;
}
/* Set frequency */
t_stat rtc_set_freq(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (cptr) /* if chars, bad */
return SCPE_ARG; /* ARG error */
if ((val != 50) && (val != 60) && (val != 100) && (val != 120))
return SCPE_IERR; /* scope error */
rtc_tps = val; /* set the new frequency */
return SCPE_OK; /* we done */
}
/* Show frequency */
t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
/* print the cirrent frequency setting */
if (rtc_tps < 100)
fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz");
else
fprintf (st, (rtc_tps == 100)? "100Hz": "120Hz");
return SCPE_OK;
}
/************************************************************************/
/* Interval Timer support */
int32 itm_pie = 0; /* itm pulse enable */
//int32 itm_tps = 38; /* itm 26041 ticks/sec = 38.4 us per tic */
///int32 itm_tps = 48; /* itm 26041 ticks/sec = 38.4 us per tic */
int32 itm_tps = 64; /* itm 26041 ticks/sec = 38.4 us per tic */
int32 itm_lvl = 0x5f; /* itm interrupt level */
int32 itm_cnt = 26041; /* value that we are downcounting */
int32 itm_run = 0; /* set when timer running */
t_stat itm_srv (UNIT *uptr);
t_stat itm_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat itm_reset (DEVICE *dptr);
t_stat itm_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
#define TMR_ITM 2
/* Clock data structures
itm_dev Interval Timer ITM device descriptor
itm_unit Interval Timer ITM unit
itm_reg Interval Timer ITM register list
*/
/* clock is attached all the time */
/* defailt to 60 HZ RTC */
//UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 38, UNIT_ADDR(0x7F04)};
//UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 48, UNIT_ADDR(0x7F04)};
//UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 26042, UNIT_ADDR(0x7F04)};
UNIT itm_unit = { UDATA (&itm_srv, UNIT_ATT, 0), 26042, UNIT_ADDR(0x7F04)};
REG itm_reg[] = {
{ FLDATA (PIE, itm_pie, 0) },
{ DRDATA (TIME, itm_unit.wait, 32), REG_NZ + PV_LEFT },
{ DRDATA (TPS, itm_tps, 32), PV_LEFT + REG_HRO },
{ NULL }
};
MTAB itm_mod[] = {
{ MTAB_XTD|MTAB_VDV, 384, NULL, "38.4us",
&itm_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 768, NULL, "76.86us",
&itm_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
NULL, &itm_show_freq, NULL },
{ 0 }
};
DEVICE itm_dev = {
"ITM", &itm_unit, itm_reg, itm_mod,
1, 8, 8, 1, 8, 8,
NULL, NULL, &itm_reset,
NULL, NULL, NULL
};
/* The interval timer downcounts the value it is loaded with and
runs continuously; therefore, it has a read/write routine,
a unit service routine and a reset routine. The service routine
sets an interrupt that invokes the clock counter.
*/
/* service clock signal from simulator */
/* for 38.4 us/tic we get 26041 ticks per second */
/* downcount the loaded value until zero and then cause interrupt */
t_stat itm_srv (UNIT *uptr)
{
// uint32 val = SPAD[itm_lvl+0x80]; /* get SPAD value for interrupt vector */
// uint32 addr = SPAD[0xf1] + (itm_lvl<<2); /* vector address in SPAD */
// addr = M[addr>>2]; /* get the interrupt context block addr */
//fprintf(stderr, "itm_srv level %x itm_pie %x wait %x spad %x icba %x\r\n",
// itm_lvl, itm_pie, itm_unit.wait, val, addr);
/* count down about 48 instructions per tick ~38.4 us */
/* we will be called once for each instructon */
itm_unit.wait -= 1; /* subtract 1 from wait count */
if (itm_unit.wait > 0)
return SCPE_OK; /* not time yet */
itm_unit.wait = itm_tps; /* reset wait count */
if (itm_run) { /* see if timer running */
itm_cnt--; /* down count by one */
if ((itm_cnt == 0) && itm_pie) { /* see if reached 0 yet */
// if (itm_cnt == 0) { /* see if reached 0 yet */
//fprintf(stderr, "itm_srv REQ itm_pie %x wait %x itm_cnt %x\r\n", itm_pie, itm_unit.wait, itm_cnt);
INTS[itm_lvl] |= INTS_REQ; /* request the interrupt on zero value */
irq_pend = 1; /* make sure we scan for int */
}
}
#if 0
itm_unit.wait = sim_rtcn_calb (itm_tps, TMR_ITM); /* calibrate */
sim_activate (&itm_unit, itm_unit.wait); /* reactivate */
#endif
return SCPE_OK;
}
/* ITM read/load function called from CD command processing */
/* level = interrupt level */
/* cmd = 0x39 load and enable interval timer, no return value */
/* = 0x40 read timer value */
/* = 0x60 read timer value and stop timer */
/* = 0x79 read/reload and start timer */
/* cnt = value to write to timer */
/* ret = return value read from timer */
int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level)
{
uint32 temp;
// uint32 val = SPAD[level+0x80]; /* get SPAD value for interrupt vector */
// itm_lvl = level; /* save the interrupt level */
// uint32 addr = SPAD[0xf1] + (level<<2); /* vector address in SPAD */
// addr = M[addr>>2]; /* get the interrupt context block addr */
//fprintf(stderr, "itm_rdwr called ss %x level %x SPAD %x icba %x\r\n", ss, level, val, addr);
//fprintf(stderr, "itm_rdwr called cmd %x count %x (%d) level %x return cnt %x (%d)\r\n",
// cmd, cnt, cnt, level, itm_cnt, itm_cnt);
switch (cmd) {
case 0x39: /* load timer with new value and start*/
if (cnt < 0)
cnt = 26042; /* TRY ??*/
itm_cnt = cnt; /* load timer with value from user to down count */
itm_run = 1; /* start timer */
return 0; /* does not matter, no value returned */
case 0x60: /* read and stop timer */
temp = itm_cnt; /* get timer value and stop timer */
itm_run = 0; /* stop timer */
// itm_cnt = 0; /* reset with timer value from user to down count */
return temp; /* return current count value */
case 0x79: /* read the current timer value */
temp = itm_cnt; /* get timer value, load new value and start timer */
itm_cnt = cnt; /* load timer with value from user to down count */
itm_run = 1; /* start timer */
return temp; /* return current count value */
case 0x40: /* read the current timer value */
return itm_cnt; /* return current count value */
break;
}
return 0; /* does not matter, no value returned */
}
/* Clock interrupt start/stop */
/* ss = 1 - clock interrupt enabled */
/* ss = 0 - clock interrupt disabled */
/* level = interrupt level */
void itm_setup(uint ss, uint32 level)
{
itm_lvl = level; /* save the interrupt level */
// fprintf(stderr, "itm_setup called ss %x level %x\r\n", ss, level);
if (ss == 1) { /* starting? */
INTS[level] |= INTS_ENAB; /* make sure enabled */
SPAD[level+0x80] |= SINT_ENAB; /* in spad too */
INTS[level] |= INTS_REQ; /* request the interrupt */
itm_cnt = 26042; /* start with 1 sec */
itm_run = 0; /* not running yet */
/// sim_activate(&itm_unit, 48); /* start us off */
} else {
INTS[level] &= ~INTS_ENAB; /* make sure disabled */
SPAD[level+0x80] &= ~SINT_ENAB; /* in spad too */
}
itm_pie = ss; /* set new state */
}
/* Clock reset */
t_stat itm_reset (DEVICE *dptr)
{
// int intlev = 0x5f; /* interrupt level for itm */
//fprintf(stderr, "itm_reset called\r\n");
itm_pie = 0; /* disable pulse */
itm_cnt = 26042; /* start with 1 sec */
itm_run = 0; /* not running yet */
#if 0
rtc_unit.wait = sim_rtcn_init (itm_unit.wait, TMR_ITM); /* initialize clock calibration */
sim_activate (&itm_unit, itm_unit.wait); /* activate unit */
#endif
return SCPE_OK;
}
/* Set frequency */
t_stat itm_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (cptr) /* if chars, bad */
return SCPE_ARG; /* ARG error */
if ((val != 384) && (val != 768))
return SCPE_IERR; /* scope error */
itm_tps = val/10; /* set the new frequency */
return SCPE_OK; /* we done */
}
/* Show frequency */
t_stat itm_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
/* print the cirrent frequency setting */
fprintf (st, (itm_tps == 38)? "38.4us": "76.8us");
return SCPE_OK;
}
#endif

899
SEL32/sel32_com.c Normal file
View File

@@ -0,0 +1,899 @@
/* sel32_com.c: SEL 32 8-Line IOP communications controller
Copyright (c) 2018, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sel32_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>
#ifdef NUM_DEVS_COM
extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc);
extern void chan_end(uint16 chan, uint8 flags);
extern int chan_read_byte(uint16 chan, uint8 *data);
extern int chan_write_byte(uint16 chan, uint8 *data);
extern void set_devwake(uint16 addr, uint8 flags);
extern int traceme, trstart;
/* Constants */
#define COM_LINES 8 /* max lines */
//#define COM_LINES 16 /* max lines */
#define COM_LINES_DFLT 8 /* default lines */
#define COM_INIT_POLL 8000
#define COML_WAIT 500
#define COM_WAIT 500
#define COM_NUMLIN com_desc.lines /* curr # lines */
#define COMC 0 /* channel thread */
#define COMI 1 /* input thread */
/* Line status */
#define COML_XIA 0x01 /* xmt intr armed */
#define COML_XIR 0x02 /* xmt intr req */
#define COML_REP 0x04 /* rcv enable pend */
#define COML_RBP 0x10 /* rcv break pend */
/* Channel state */
#define COMC_IDLE 0 /* idle */
#define COMC_INIT 1 /* init */
#define COMC_RCV 2 /* receive */
#define COMC_END 3 /* end */
uint8 com_rbuf[COM_LINES]; /* rcv buf */
uint8 com_xbuf[COM_LINES]; /* xmt buf */
uint8 com_sta[COM_LINES]; /* status */
uint32 com_lstat[COM_LINES][2] = { 0 }; /* 8 bytes of line settings status */
uint32 com_tps = 2; /* polls/second */
uint32 com_scan = 0; /* scanner */
uint32 com_slck = 0; /* scanner locked */
uint32 comc_cmd = COMC_IDLE; /* channel state */
TMLN com_ldsc[COM_LINES] = { 0 }; /* line descrs */
TMXR com_desc = { COM_LINES_DFLT, 0, 0, com_ldsc }; /* com descr */
/* Held in u3 is the device command and status */
#define COM_INCH 0x00 /* Initialize channel command */
#define COM_WR 0x01 /* Write terminal */
#define COM_RD 0x02 /* Read terminal */
#define COM_NOP 0x03 /* No op command */
#define COM_SNS 0x04 /* Sense command */
#define COM_WRSCM 0x05 /* Write w/Sub chan monitor */
#define COM_RDECHO 0x06 /* Read with Echo */
#define COM_RDFC 0x0A /* Read w/flow control */
#define COM_DEFSC 0x0B /* Define special char */
#define COM_WRHFC 0x0D /* Write hardware flow control */
#define COM_RDTR 0x13 /* Reset DTR (ADVR) */
#define COM_SDTR 0x17 /* Set DTR (ADVF) */
#define COM_RRTS 0x1B /* Reset RTS */
#define COM_SRTS 0x1F /* Set RTS */
#define COM_RBRK 0x33 /* Reset BREAK */
#define COM_SBRK 0x37 /* Set BREAK */
#define COM_RDHFC 0x8E /* Read w/hardware flow control only */
#define COM_SACE 0xFF /* Set ACE parameters */
#define COM_MSK 0xFF /* Command mask */
/* Status held in u3 */
/* controller/unit address in upper 16 bits */
#define COM_INPUT 0x100 /* Input ready for unit */
#define COM_CR 0x200 /* Output at beginning of line */
#define COM_REQ 0x400 /* Request key pressed */
#define COM_EKO 0x800 /* Echo input character */
#define COM_OUTPUT 0x1000 /* Output ready for unit */
#define COM_READ 0x2000 /* Read mode selected */
/* ACE data kept in u4 */
/* in u5 packs sense byte 0, 1, 2 and 3 */
/* Sense byte 0 */
#define SNS_CMDREJ 0x80000000 /* Command reject */
#define SNS_INTVENT 0x40000000 /* Unit intervention required (N/U) */
#define SNS_BOCHK 0x20000000 /* Bus out check (IOP parity error */
#define SNS_EQUIPCK 0x10000000 /* Equipment check (device error) */
#define SNS_DATACK 0x08000000 /* Data check */
#define SNS_OVERRN 0x04000000 /* Overrun (N/U) */
#define SNS_NUB01 0x02000000 /* Zero (N/U) */
#define SNS_NUB02 0x01000000 /* Zero (N/U) */
/* Sense byte 1 */
#define SNS_ASCIICD 0x00800000 /* ASCII control char detected interrupt */
#define SNS_SPCLCD 0x00400000 /* Special char detected interrupt */
#define SNS_ETX 0x00200000 /* ETX interrupt */
#define SNS_BREAK 0x00100000 /* BREAK interrupt */
#define SNS_ACEFE 0x00080000 /* ACE framing error interrupt */
#define SNS_ACEPEI 0x00040000 /* ACE parity error interrupt */
#define SNS_ACEOVR 0x00020000 /* ACE overrun error interrupt */
#define SNS_RING 0x00010000 /* Ring character interrupt */
/* Sense byte 2 Modem status */
#define SNS_RLSDS 0x00008000 /* Received line signal detect status */
#define SNS_RINGST 0x00004000 /* Ring indicator line status */
#define SNS_DSRS 0x00002000 /* DSR Data set ready line status */
#define SNS_CTSS 0x00001000 /* CTS Clear to send line status */
#define SNS_DELTA 0x00000800 /* Delta receive line signal detect failure interrupt */
#define SNS_MRING 0x00000400 /* RI Modem ring interrupt */
#define SNS_DELDSR 0x00000200 /* Delta data set ready interrupt */
#define SNS_DELCLR 0x00000100 /* Ring character interrupt */
/* Sense byte 3 Modem Control/Operation status */
#define SNS_HALFD 0x00000080 /* Half-duplix operation set */
#define SNS_MRINGE 0x00000040 /* Modem ring enabled (1) */
#define SNS_ACEDEF 0x00000020 /* ACE parameters defined */
#define SNS_DIAGM 0x00000010 /* Diagnostic mode set */
#define SNS_AUXOL2 0x00000008 /* Auxiliary output level 2 */
#define SNS_AUXOL1 0x00000004 /* Auxiliary output level 1 */
#define SNS_RTS 0x00000002 /* RTS Request to send set */
#define SNS_DTR 0x00000001 /* DTR Data terminal ready set */
/* Sense byte 4 ACE Parameters status */
#define SNS_ACEDLE 0x80000000 /* Divisor latch enable 0=dis, 1=enb */
#define SNS_ACEBS 0x40000000 /* Break set 0=reset, 1=set */
#define SNS_ACEFP 0x20000000 /* Forced parity 0=odd, 1=even */
#define SNS_ACEP 0x10000000 /* Parity 0=odd, 1=even */
#define SNS_ACEPE 0x08000000 /* Parity enable 0=dis, 1=enb */
#define SNS_ACESTOP 0x04000000 /* Stop bit 0=1, 1=1.5 or 2 */
#define SNS_ACECLEN 0x02000000 /* Character length 00=5, 01=6, 11=7, 11=8 */
#define SNS_ACECL2 0x01000000 /* 2nd bit for above */
/* Sense byte 5 Baud rate */
#define SNS_NUB50 0x00800000 /* Zero N/U */
#define SNS_NUB51 0x00400000 /* Zero N/U */
#define SNS_RINGCR 0x00200000 /* Ring or wakeup character recognition 0=enb, 1=dis */
#define SNS_DIAGL 0x00100000 /* Set diagnostic loopback */
#define SNS_BAUD 0x000F0000 /* Baud rate bits 4-7 */
#define BAUD50 0x00000000 /* 50 baud */
#define BAUD75 0x00010000 /* 75 baud */
#define BAUD110 0x00020000 /* 110 baud */
#define BAUD114 0x00030000 /* 134 baud */
#define BAUD150 0x00040000 /* 150 baud */
#define BAUD300 0x00050000 /* 300 baud */
#define BAUD600 0x00060000 /* 600 baud */
#define BAUD1200 0x00070000 /* 1200 baud */
#define BAUD1800 0x00080000 /* 1800 baud */
#define BAUD2000 0x00090000 /* 2000 baud */
#define BAUD2400 0x000A0000 /* 2400 baud */
#define BAUD3600 0x000B0000 /* 3600 baud */
#define BAUD4800 0x000C0000 /* 4800 baud */
#define BAUD7200 0x000D0000 /* 7200 baud */
#define BAUD9600 0x000E0000 /* 9600 baud */
#define BAUD19200 0x000F0000 /* 19200 baud */
/* Sense byte 6 Firmware ID, Revision Level */
#define SNS_FID 0x00006200 /* ID part 1 */
/* Sense byte 7 Firmware ID, Revision Level */
#define SNS_REV 0x0000004f /* ID part 2 plus 4 bit rev # */
/* ACE information in u4 */
#define ACE_WAKE 0x0000FF00 /* 8 bit wake-up character */
/* in u5 packs sense byte 0,1 and 3 */
/* Sense byte 0 */
#define SNS_CMDREJ 0x80000000 /* Command reject */
#define SNS_INTVENT 0x40000000 /* Unit intervention required */
/* sense byte 3 */
#define SNS_RDY 0x80 /* device ready */
#define SNS_ONLN 0x40 /* device online */
#define SNS_DSR 0x04 /* data set ready */
/* u6 */
uint8 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd);
uint8 com_haltio(uint16 addr);
void com_ini(UNIT *, t_bool);
void coml_ini(UNIT *, t_bool);
t_stat com_reset(DEVICE *);
t_stat com_attach(UNIT *, CONST char *);
t_stat com_detach(UNIT *);
t_stat comc_srv(UNIT *uptr);
t_stat como_srv(UNIT *uptr);
t_stat comi_srv(UNIT *uptr);
t_stat com_reset(DEVICE *dptr);
t_stat com_attach(UNIT *uptr, CONST char *cptr);
t_stat com_detach(UNIT *uptr);
void com_reset_ln(int32 ln);
const char *com_description(DEVICE *dptr); /* device description */
/* COM data structures
com_chp COM channel program information
com_dev COM device descriptor
com_unit COM unit descriptor
com_reg COM register list
com_mod COM modifieers list
*/
//#define COM_UNITS 2
#define COM_UNITS 1
/* channel program information */
CHANP com_chp[COM_UNITS] = {0};
/* dummy mux for 16 lines */
MTAB com_mod[] = {
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL},
{MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &com_desc},
{UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tmxr_show_summ, (void *) &com_desc},
{MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat,(void *)&com_desc},
{MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, (void *)&com_desc},
// {MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", &io_set_dvc, &io_show_dvc, NULL},
// {MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", &io_set_dva, &io_show_dva, NULL},
// {MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", &com_vlines, &tmxr_show_lines, (void *)&com_desc},
// {MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, NULL, &io_show_cst, NULL},
// {MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "POLL", "POLL", &rtc_set_tps, &rtc_show_tps,(void *)&com_tps},
/// { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
/// { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
/// { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
/// { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
/// { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &com_desc },
/// { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &com_desc },
/// { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &com_desc },
{ 0 }
};
UNIT com_unit[] = {
{UDATA(&comi_srv, UNIT_ATTABLE, 0), COM_WAIT, UNIT_ADDR(0x0000)}, /* 0 */
};
//DIB com_dib = {NULL, com_startcmd, NULL, NULL, com_ini, com_unit, com_chp, COM_UNITS, 0x0f, 0x7e00, 0, 0, 0};
DIB com_dib = {
NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */
com_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */
NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */
NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */
NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */
com_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
com_unit, /* UNIT* units */ /* Pointer to units structure */
com_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
COM_UNITS, /* uint8 numunits */ /* number of units defined */
0x0f, /* uint8 mask */ /* 16 devices - device mask */
0x7E00, /* uint16 chan_addr */ /* parent channel address */
0, /* uint32 chan_fifo_in */ /* fifo input index */
0, /* uint32 chan_fifo_out */ /* fifo output index */
0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */
};
REG com_reg[] = {
{ BRDATAD (STA, com_sta, 16, 8, COM_LINES, "status buffers, lines 0 to 8") },
{ BRDATAD (RBUF, com_rbuf, 16, 8, COM_LINES, "input buffer, lines 0 to 8") },
{ BRDATAD (XBUF, com_xbuf, 16, 8, COM_LINES, "output buffer, lines 0 to 8") },
{ ORDATAD (SCAN, com_scan, 6, "scanner line number") },
{ FLDATAD (SLCK, com_slck, 0, "scanner lock") },
{ DRDATA (TPS, com_tps, 8), REG_HRO},
{ NULL }
};
/* devices for channel 0x7ecx */
DEVICE com_dev = {
"COMC", com_unit, com_reg, com_mod,
COM_UNITS, 8, 15, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &com_reset, NULL, &com_attach, &com_detach,
&com_dib, DEV_NET | DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, NULL, NULL, NULL, &com_description
};
/* COML data structures
coml_dev COM device descriptor
coml_unit COM unit descriptor
coml_reg COM register list
coml_mod COM modifieers list
*/
#define UNIT_COML UNIT_ATTABLE|UNIT_DISABLE|UNIT_ATT
//#define UNIT_COML UNIT_ATTABLE|UNIT_DISABLE
/* channel program information */
CHANP coml_chp[COM_LINES*2] = {0};
UNIT coml_unit[] = {
/* 0-7 is input, 8-f is output */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC0)}, /* 0 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC1)}, /* 1 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC2)}, /* 2 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC3)}, /* 3 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC4)}, /* 4 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC5)}, /* 5 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC6)}, /* 6 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC7)}, /* 7 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC8)}, /* 8 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7EC9)}, /* 9 */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECA)}, /* A */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECB)}, /* B */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECC)}, /* C */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECD)}, /* D */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECE)}, /* E */
{UDATA(&como_srv, TT_MODE_UC|UNIT_COML, 0), COML_WAIT, UNIT_ADDR(0x7ECF)}, /* F */
};
//DIB coml_dib = { NULL, com_startcmd, NULL, NULL, NULL, coml_ini, coml_unit, coml_chp, COM_LINES*2, 0x0f, 0x7E00};
DIB coml_dib = {
NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Pre Start I/O */
com_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */
NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */
NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */
NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */
coml_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
coml_unit, /* UNIT* units */ /* Pointer to units structure */
coml_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
COM_LINES*2, /* uint8 numunits */ /* number of units defined */
0x0f, /* uint8 mask */ /* 16 devices - device mask */
0x7E00, /* uint16 chan_addr */ /* parent channel address */
};
REG coml_reg[] = {
{ URDATA (TIME, coml_unit[0].wait, 10, 24, 0, COM_LINES, REG_NZ + PV_LEFT) },
{ NULL }
};
MTAB coml_mod[] = {
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &com_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &com_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &com_desc },
{ 0 }
};
DEVICE coml_dev = {
"COML", coml_unit, coml_reg, coml_mod,
COM_LINES*2, 10, 31, 1, 8, 8,
NULL, NULL, &com_reset,
NULL, NULL, NULL,
&coml_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, NULL, NULL, NULL, &com_description
};
/* 8-line serial routines */
void coml_ini(UNIT *uptr, t_bool f)
{
int unit;
uint16 chsa;
unit = uptr - coml_unit; /* unit # */
chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */
/* maybe do someting here on master channel init */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
}
/* 8-line serial routines */
void com_ini(UNIT *uptr, t_bool f)
{
DEVICE *dptr = find_dev_from_unit(uptr);
sim_debug(DEBUG_CMD, &com_dev, "COM init device %s controller 0x7e00\n", dptr->name);
sim_activate(uptr, 1000); /* time increment */
}
/* called from sel32_chan to start an I/O operation */
uint8 com_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
{
DEVICE *dptr = find_dev_from_unit(uptr);
int unit = (uptr - dptr->units);
uint8 ch;
if ((uptr->u3 & COM_MSK) != 0) { /* is unit busy */
return SNS_BSY; /* yes, return busy */
}
sim_debug(DEBUG_CMD, dptr, "CMD unit %x chan %x cmd %x", unit, chan, cmd);
/* process the commands */
switch (cmd & 0xFF) {
case COM_INCH: /* 00 */ /* INCH command */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: CMD INCH\n", chan);
return SNS_CHNEND|SNS_DEVEND; /* all is well */
break;
/* write commands must use address 8-f */
case COM_WR: /* 0x01 */ /* Write command */
case COM_WRSCM: /* 0x05 */ /* Write w/sub channel monitor */
case COM_WRHFC: /* 0x0D */ /* Write w/hardware flow control */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd WRITE %x\n", chan, cmd);
uptr->u3 &= LMASK; /* leave only chsa */
uptr->u3 |= (cmd & COM_MSK); /* save command */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 150); /* TRY 08-13-18 */
return 0; /* no status change */
break;
/* read commands must use address 0-7 */
/* DSR must be set when a read command is issued, else it is unit check */
/* bit 1-3 (ASP) of command has more definition */
/* bit 1 A=1 ASCII control character detect (7-char mode only) */
/* bit 2 S=1 Special character detect (7-char mode only) */
/* bit 3 P=1 Purge input buffer */
case COM_RD: /* 0x02 */ /* Read command */
case COM_RDECHO: /* 0x06 */ /* Read command w/ECHO */
case 0x46: /* 0x46 */ /* Read command w/ECHO & ASCII */
case 0x56: /* 0x56 */ /* Read command w/ECHO & ASCII & Purge input */
/* if bit 0 set for COM_RDFC, use DTR for flow, else use RTS for flow control */
case COM_RDFC: /* 0x0A */ /* Read command w/flow control */
case COM_RDHFC: /* 0x8E */ /* Read command w/hardware flow control only */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd read\n", chan);
uptr->u3 &= LMASK; /* leave only chsa */
uptr->u3 |= (cmd & COM_MSK); /* save command */
if ((cmd & 0x06) == COM_RDECHO) /* echo command? */
uptr->u3 |= COM_EKO; /* save echo status */
uptr->u3 |= COM_READ; /* show read mode */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
return 0;
break;
case COM_NOP: /* 0x03 */ /* NOP has do nothing */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x NOP\n", chan, cmd);
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_SNS: /* 0x04 */ /* Sense (8 bytes) */
com_lstat[unit][0] = 0; /* Clear status wd 0 */
com_lstat[unit][1] = 0; /* Clear status wd 1 */
/* value 4 is Data Set Ready */
/* value 5 is Data carrier detected n/u */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: unit %x Cmd Sense %02x\n", chan, unit, uptr->u5);
/* Sense byte 0 */
//#define SNS_CMDREJ 0x80000000 /* Command reject */
//#define SNS_INTVENT 0x40000000 /* Unit intervention required (N/U) */
//#define SNS_BOCHK 0x20000000 /* Bus out check (IOP parity error */
//#define SNS_EQUIPCK 0x10000000 /* Equipment check (device error) */
//#define SNS_DATACK 0x08000000 /* Data check */
//#define SNS_OVERRN 0x04000000 /* Overrun (N/U) */
//#define SNS_NUB01 0x02000000 /* Zero (N/U) */
//#define SNS_NUB02 0x01000000 /* Zero (N/U) */
// com_lstat[unit][0] |= (SNS_ASCIICD | SNS_SPCLCD|SNS_RING); /* set char detect status */
// com_lstat[unit][0] |= (SNS_ASCIICD | SNS_SPCLCD); /* set char detect status */
// com_lstat[unit][0] |= (SNS_RING); /* set char detect status */
ch = (com_lstat[unit][0] >> 24) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
/* Sense byte 1 */
//#define SNS_ASCIICD 0x00800000 /* ASCII control char detected interrupt */
//#define SNS_SPCLCD 0x00400000 /* Special char detected interrupt */
//#define SNS_ETX 0x00200000 /* ETX interrupt */
//#define SNS_BREAK 0x00100000 /* X BREAK interrupt */
//#define SNS_ACEFE 0x00080000 /* ACE framing error interrupt */
//#define SNS_ACEPEI 0x00040000 /* ACE parity error interrupt */
//#define SNS_ACEOVR 0x00020000 /* ACE overrun error interrupt */
//#define SNS_RING 0x00010000 /* X Ring character interrupt */
com_lstat[unit][0] |= (SNS_RING); /* set char detect status */
com_lstat[unit][0] |= (SNS_ASCIICD); /* set char detect status */
ch = (com_lstat[unit][0] >> 16) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
/* Sense byte 2 Modem status */
//#define SNS_RLSDS 0x00008000 /* S Received line signal detect status */
//#define SNS_RINGST 0x00004000 /* Ring indicator line status */
//#define SNS_DSRS 0x00002000 /* C DSR Data set ready line status */
//#define SNS_CTSS 0x00001000 /* C CTS Clear to send line status */
//#define SNS_DELTA 0x00000800 /* BS Delta receive line signal detect failure interrupt */
//#define SNS_MRING 0x00000400 /* X RI Modem ring interrupt */
//#define SNS_DELDSR 0x00000200 /* BS Delta data set ready interrupt */
//#define SNS_DELCLR 0x00000100 /* B Delta data set CTS failure interrupt */
com_lstat[unit][0] |= (SNS_CTSS|SNS_DSRS); /* set CTS & DSR status */
com_lstat[unit][0] |= (SNS_MRING); /* set char detect status */
ch = (com_lstat[unit][0] >> 8) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
/* Sense byte 3 Modem Control/Operation status */
//#define SNS_HALFD 0x00000080 /* Half-duplix operation set */
//#define SNS_MRINGE 0x00000040 /* Modem ring enabled (1) */
//#define SNS_ACEDEF 0x00000020 /* ACE parameters defined */
//#define SNS_DIAGM 0x00000010 /* Diagnostic mode set */
//#define SNS_AUXOL2 0x00000008 /* Auxiliary output level 2 */
//#define SNS_AUXOL1 0x00000004 /* Auxiliary output level 1 */
//#define SNS_RTS 0x00000002 /* RTS Request to send set */
//#define SNS_DTR 0x00000001 /* DTR Data terminal ready set */
// com_lstat[unit][0] |= (SNS_RTS|SNS_DTR); /* set RTS & DTR status */
com_lstat[unit][0] |= (SNS_DTR); /* set DTR status */
ch = (com_lstat[unit][0] >> 0) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
ch = (com_lstat[unit][1] >> 24) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
ch = (com_lstat[unit][1] >> 16) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
ch = (com_lstat[unit][1] >> 8) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
ch = (com_lstat[unit][1] >> 0) & 0xff;
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
sim_debug(DEBUG_CMD, &com_dev,
"com_startcmd Cmd SENSE return chan %x u5-status %x ls0 %x ls1 %x\n",
chan, uptr->u5, com_lstat[unit][0], com_lstat[unit][1]);
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_DEFSC: /* 0x0B */ /* Define special char */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x DEFSC\n", chan, cmd);
chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char */
uptr->u5 = ~SNS_RTS; /* Request to send not ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_RRTS: /* 0x1B */ /* Reset RTS */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x RRTS\n", chan, cmd);
uptr->u5 &= ~SNS_RTS; /* Request to send not ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_SRTS: /* 0x1F */ /* Set RTS */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SRTS\n", chan, cmd);
uptr->u5 |= SNS_RTS; /* Requestd to send ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_RBRK: /* 0x33 */ /* Reset BREAK */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x RBRK\n", chan, cmd);
uptr->u5 &= ~SNS_BREAK; /* Request to send not ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_SBRK: /* 0x37 */ /* Set BREAK */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SBRK\n", chan, cmd);
uptr->u5 |= SNS_BREAK; /* Requestd to send ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_RDTR: /* 0x13 */ /* Reset DTR (ADVR) */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x DTR\n", chan, cmd);
uptr->u5 &= ~SNS_DTR; /* Data terminal not ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case COM_SDTR: /* 0x17 */ /* Set DTR (ADVF) */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x NOP\n", chan, cmd);
uptr->u5 |= SNS_DTR; /* Data terminal ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
#if 0
/* ACE byte 0 Modem Control/Operation status */
/* stored in u4 bytes 0-3 */
#define SNS_HALFD 0x80000000 /* Half-duplix operation set */
#define SNS_MRINGE 0x40000000 /* Modem ring enabled */
#define SNS_ACEFP 0x20000000 /* Forced parity 0=odd, 1=even */
#define SNS_ACEP 0x10000000 /* Parity 0=odd, 1=even */
#define SNS_ACEPE 0x08000000 /* Parity enable 0=dis, 1=enb */
#define SNS_ACESTOP 0x04000000 /* Stop bit 0=1, 1=1.5 or 2 */
#define SNS_ACECLEN 0x02000000 /* Character length 00=5, 01=6, 11=7, 11=8 */
#define SNS_ACECL2 0x01000000 /* 2nd bit for above */
/* ACE byte 1 Baud rate */
#define SNS_NUB50 0x00800000 /* Zero N/U */
#define SNS_NUB51 0x00400000 /* Zero N/U */
#define SNS_RINGCR 0x00200000 /* Ring or wakeup character recognition 0=enb, 1=dis */
#define SNS_DIAGL 0x00100000 /* Set diagnostic loopback */
#define SNS_BAUD 0x000F0000 /* Baud rate bits 4-7 */
#define BAUD50 0x00000000 /* 50 baud */
#define BAUD75 0x00010000 /* 75 baud */
#define BAUD110 0x00020000 /* 110 baud */
#define BAUD114 0x00030000 /* 134 baud */
#define BAUD150 0x00040000 /* 150 baud */
#define BAUD300 0x00050000 /* 300 baud */
#define BAUD600 0x00060000 /* 600 baud */
#define BAUD1200 0x00070000 /* 1200 baud */
#define BAUD1800 0x00080000 /* 1800 baud */
#define BAUD2000 0x00090000 /* 2000 baud */
#define BAUD2400 0x000A0000 /* 2400 baud */
#define BAUD3600 0x000B0000 /* 3600 baud */
#define BAUD4800 0x000C0000 /* 4800 baud */
#define BAUD7200 0x000D0000 /* 7200 baud */
#define BAUD9600 0x000E0000 /* 9600 baud */
#define BAUD19200 0x000F0000 /* 19200 baud */
/* ACE byte 2 Wake-up character */
#define ACE_WAKE 0x0000FF00 /* 8 bit wake-up character */
#endif
case COM_SACE: /* 0xff */ /* Set ACE parameters (3 chars) */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SACE\n", chan, cmd);
chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char 0 */
uptr->u4 = ((uint32)ch)<<24; /* byte 0 of ACE data */
chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char 1 */
uptr->u4 |= ((uint32)ch)<<16; /* byte 1 of ACE data */
chan_read_byte(GET_UADDR(uptr->u3), &ch); /* read char 2 */
uptr->u4 |= ((uint32)ch)<<8; /* byte 2 of ACE data */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd %x SACE bytes %x\n", chan, cmd, uptr->u4);
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
default: /* invalid command */
uptr->u5 |= SNS_CMDREJ; /* command rejected */
sim_debug(DEBUG_CMD, &com_dev, "com_startcmd %x: Cmd Invald %x status %02x\n", chan, cmd, uptr->u5);
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
break;
}
if (uptr->u5 & 0xff)
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
return SNS_CHNEND|SNS_DEVEND;
}
/* Unit service - polled input
Poll for new connections
Poll all connected lines for input
*/
t_stat comi_srv(UNIT *uptr)
{
uint8 ch;
int32 newln, ln, c;
uint16 chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */
int cmd = uptr->u3 & 0xff;
uint32 cln = (uptr - coml_unit) & 0x7; /* use line # 0-7 for 8-15 */
UNIT *comlp;
ln = uptr - com_unit; /* line # */
if ((com_unit[COMC].flags & UNIT_ATT) == 0){ /* attached? */
return SCPE_OK;
}
newln = tmxr_poll_conn(&com_desc); /* look for connect */
if (newln >= 0) { /* rcv enb pending? */
uint16 chsa = GET_UADDR(coml_unit[newln].u3); /* get channel/sub-addr */
int chan = ((chsa >> 8) & 0x7f); /* get the channel number */
UNIT *comlp = coml_unit+ln; /* get uptr for coml line */
int cmd = comlp->u3 & 0xff; /* get the active cmd */
//fprintf(stderr, "comi_srv poll chsa %x new line %x\r\n", chsa, newln);
com_ldsc[newln].rcve = 1; /* enable rcv */
com_ldsc[newln+8].xmte = 1; /* enable xmt for output line */
com_sta[newln] &= ~COML_REP; /* clr pending */
/* send attention to OS here for this channel */
/* need to get chsa here for the channel */
//fprintf(stderr, "comi_srv chsa %x chan %x\r\n", chsa, chan);
set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND); /* tell user */
}
/* poll all devices for input */
tmxr_poll_rx(&com_desc); /* poll for input */
for (ln = 0; ln < COM_NUMLIN; ln++) { /* loop thru lines */
UNIT *comlp = coml_unit+ln; /* get uptr for coml line */
int cmd = comlp->u3 & 0xff; /* get the active cmd */
uint16 chsa = GET_UADDR(comlp->u3); /* get channel/sub-addr */
if (com_ldsc[ln].conn) { /* connected? */
if ((c = tmxr_getc_ln(&com_ldsc[ln]))) { /* get char */
//fprintf(stderr, "comi_srv chsa %x input %x cmd %x\r\n", chsa, c, cmd);
ch = c; /* just the char */
/* echo the char out */
tmxr_putc_ln(&com_ldsc[ln], ch); /* output char */
tmxr_poll_tx(&com_desc); /* poll xmt */
if (c & SCPE_BREAK) /* break? */
com_sta[ln] |= COML_RBP; /* set rcv brk */
else { /* normal char */
com_sta[ln] &= ~COML_RBP; /* clr rcv brk */
c = sim_tt_inpcvt(c, TT_GET_MODE(coml_unit[ln].flags));
com_rbuf[ln] = c; /* save char */
if ((cmd & COM_RD) == COM_RD) { /* read active? */
ch = c; /* clean the char */
if (ch == '\n') /* convert newline */
ch = '\r'; /* to C/R */
/* write byte to memory */
if (chan_write_byte(chsa, &ch)) {
/* done, reading chars */
//fprintf(stderr, "comi_srv chsa %x input %x complete cmd %x\r\n", chsa, c, cmd);
comlp->u3 &= LMASK; /* nothing left, clear cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
} else {
/* more to go, continue */
//fprintf(stderr, "comi_srv chsa %x input %x cnt %x cmd %x\r\n", chsa, c, cmd);
if (ch == '\r') { /* see if done */
comlp->u3 &= LMASK; /* nothing left, clear cmd */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
}
}
}
else {
/* see if user hit the wakeup key */
if (((comlp->u4 & ACE_WAKE) >> 8) == ch) {
/* send attention to OS here for this channel */
/* need to get chsa here for the channel */
// fprintf(stderr, "comi_srv WAKEUP chsa %x ch %x wake %x\r\n", chsa, ch, (comlp->u4 & ACE_WAKE)>>8);
set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND); /* tell user */
}
}
} /* end else char */
} /* end if char */
} /* end if conn */
else
com_sta[ln] &= ~COML_RBP; /* disconnected */
} /* end for */
return sim_clock_coschedule(uptr, 200); /* continue poll */
}
/* Unit service - output transfers */
t_stat como_srv(UNIT *uptr)
{
uint16 chsa = GET_UADDR(uptr->u3); /* get channel/sub-addr */
uint32 ln = (uptr - coml_unit) & 0x7; /* use line # 0-7 for 8-15 */
uint32 done;
int cmd = uptr->u3 & 0xff; /* get active cmd */
uint8 ch;
//fprintf(stderr, "como_srv entry 1 chsa %x line %x cmd %x\r\n", chsa, ln, cmd);
if (cmd) {
/* get a user byte from memory */
done = chan_read_byte(chsa, &ch); /* get byte from memory */
#if 0
if (!done)
fprintf(stderr, "como_srv mem_read chsa %x line %x char %c %x\r\n", chsa, ln, ch, ch);
else
uptr->u3 &= LMASK; /* leave only chsa */
#else
if (done)
uptr->u3 &= LMASK; /* leave only chsa */
#endif
} else
return SCPE_OK;
if (com_dev.flags & DEV_DIS) { /* disabled */
//fprintf(stderr, "como_srv chsa %x line %x DEV_DIS set\r\n", chsa, ln);
if (done) {
//fprintf(stderr, "como_srv Write DONE %d status %x\r\n", ln, SNS_CHNEND|SNS_DEVEND);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
}
return SCPE_OK; /* return */
}
//fprintf(stderr, "como_srv poll chsa %x line %x\r\n", chsa, ln);
if (com_ldsc[ln].conn) { /* connected? */
if (com_ldsc[ln].xmte) { /* xmt enabled? */
if (done) { /* are we done writing */
endit:
uptr->u3 &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &com_dev, "com_srvo write %d: chnend|devend\n", ln);
//fprintf(stderr, "como_srv Write DONE %d status %x\r\n", ln, SNS_CHNEND|SNS_DEVEND);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
return SCPE_OK;
}
/* send the next char out */
tmxr_putc_ln(&com_ldsc[ln], ch); /* output char */
//fprintf(stderr, "como_srv writing char %c to ln %d\r\n", ch, ln);
tmxr_poll_tx(&com_desc); /* poll xmt */
sim_activate(uptr, uptr->wait); /* wait */
return SCPE_OK;
} else { /* buf full */
if (done) /* are we done writing */
goto endit; /* done */
/* just dump the char */
// /* xmt disabled, just wait around */
//fprintf(stderr, "como_srv Write dumping %x on line %d\r\n", ch, ln);
tmxr_poll_tx(&com_desc); /* poll xmt */
//?? sim_activate(uptr, coml_unit[ln].wait); /* wait */
sim_activate(uptr, uptr->wait); /* wait */
return SCPE_OK;
}
} else {
/* not connected, so dump char on ground */
if (done) {
//fprintf(stderr, "como_srv Write dump DONE %d status %x\r\n", ln, SNS_CHNEND|SNS_DEVEND);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
uptr->u3 &= LMASK; /* nothing left, command complete */
}
sim_activate(uptr, uptr->wait); /* wait */
return SCPE_OK;
}
}
/* Reset routine */
t_stat com_reset (DEVICE *dptr)
{
int32 i;
if (com_dev.flags & DEV_DIS) /* master disabled? */
com_dev.flags |= DEV_DIS; /* disable lines */
else
com_dev.flags &= ~DEV_DIS;
if (com_unit[COMC].flags & UNIT_ATT) /* master att? */
sim_clock_coschedule(&com_unit[0], 200); /* activate */
for (i = 0; i < COM_LINES; i++) /* reset lines */
com_reset_ln(i);
return SCPE_OK;
}
/* attach master unit */
t_stat com_attach(UNIT *uptr, CONST char *cptr)
{
uint16 chsa = GET_UADDR(com_unit[COMC].u3); /* get channel/subaddress */
t_stat r;
chsa = GET_UADDR(com_unit[COMC].u3); /* get channel/subaddress */
//fprintf(stderr, "com_attach chsa %x\r\n", chsa);
r = tmxr_attach(&com_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) /* error? */
return r; /* return error */
sim_activate(uptr, 0); /* start poll at once */
//fprintf(stderr, "com_attach chsa %x\r\n", chsa);
return SCPE_OK;
}
/* detach master unit */
t_stat com_detach(UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach(&com_desc, uptr); /* detach */
for (i = 0; i < COM_LINES; i++) /* disable rcv */
com_reset_ln(i); /* reset the line */
sim_cancel(uptr); /* stop poll, cancel timer */
return r;
}
/* Reset an individual line */
void com_reset_ln (int32 ln)
{
sim_cancel(&coml_unit[ln]);
com_sta[ln] = 0;
com_rbuf[ln] = 0; /* clear read buffer */
com_xbuf[ln] = 0; /* clear write buffer */
com_ldsc[ln].rcve = 0;
return;
}
t_stat com_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "SEL32 8-Line Async Controller Terminal Interfaces\n\n");
fprintf (st, "For very early system programs, the PDP-11 simulator supports up to sixteen\n");
fprintf (st, "additional DC11 terminal interfaces. The additional terminals consist of two\n");
fprintf (st, "independent devices, DCI and COML. The entire set is modeled as a terminal\n");
fprintf (st, "multiplexer, with DCI as the master controller. The additional terminals\n");
fprintf (st, "perform input and output through Telnet sessions connected to a user-specified\n");
fprintf (st, "port.\n\n");
fprintf (st, "The ATTACH command specifies the port to be used:\n\n");
tmxr_attach_help (st, dptr, uptr, flag, cptr);
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
fprintf (st, " mode input characters output characters\n\n");
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
fprintf (st, " to upper case, high-order bit cleared,\n");
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
fprintf (st, " non-printing characters suppressed\n");
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
fprintf (st, " 8B no changes no changes\n\n");
fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n");
fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n");
fprintf (st, " sim> SET COMLn DATASET simulate attachment to a dataset (modem)\n");
fprintf (st, " sim> SET COMLn NODATASET simulate direct attachment to a terminal\n\n");
fprintf (st, "Finally, each line supports output logging. The SET COMLn LOG command enables\n");
fprintf (st, "logging on a line:\n\n");
fprintf (st, " sim> SET COMLn LOG=filename log output of line n to filename\n\n");
fprintf (st, "The SET COMLn NOLOG command disables logging and closes the open log file,\n");
fprintf (st, "if any.\n\n");
fprintf (st, "Once DCI is attached and the simulator is running, the terminals listen for\n");
fprintf (st, "connections on the specified port. They assume that the incoming connections\n");
fprintf (st, "are Telnet connections. The connections remain open until disconnected either\n");
fprintf (st, "by the Telnet client, a SET DCI DISCONNECT command, or a DETACH DCI command.\n\n");
fprintf (st, "Other special commands:\n\n");
fprintf (st, " sim> SHOW COMC CONNECTIONS show current connections\n");
fprintf (st, " sim> SHOW COMC STATISTICS show statistics for active connections\n");
fprintf (st, " sim> SET COMLn DISCONNECT disconnects the specified line.\n");
fprintf (st, "\nThe additional terminals do not support save and restore. All open connections\n");
fprintf (st, "are lost when the simulator shuts down or DCI is detached.\n");
fprint_set_help (st, dptr);
fprint_show_help (st, dptr);
return SCPE_OK;
}
/* description of controller */
const char *com_description (DEVICE *dptr)
{
return "SEL 32 8-Line async communications controller";
}
#endif

370
SEL32/sel32_con.c Normal file
View File

@@ -0,0 +1,370 @@
/* sel32_con.c: SEL 32 Class F IOP processor console.
Copyright (c) 2018, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This is the standard console interface. It is subchannel of the IOP 7e00.
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 ASCII characters.
*/
#include "sel32_defs.h"
#include "sim_defs.h"
#ifdef NUM_DEVS_CON
extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc);
extern void chan_end(uint16 chan, uint8 flags);
extern int chan_read_byte(uint16 chan, uint8 *data);
extern int chan_write_byte(uint16 chan, uint8 *data);
extern void set_devattn(uint16 addr, uint8 flags);
extern void post_extirq(void);
extern uint32 attention_trap; /* set when trap is requested */
extern void set_devwake(uint16 addr, uint8 flags);
/* Held in u3 is the device command and status */
#define CON_INCH 0x00 /* Initialize channel command */
#define CON_WR 0x01 /* Write console */
#define CON_RD 0x02 /* Read console */
#define CON_NOP 0x03 /* No op command */
#define CON_SNS 0x04 /* Sense command */
#define CON_ECHO 0x0a /* Read with Echo */
#define CON_CON 0x1f /* connect line */
#define CON_DIS 0x23 /* disconnect line */
#define CON_RWD 0x37 /* TOF and write line */
#define CON_MSK 0xff /* Command mask */
/* Status held in u3 */
/* controller/unit address in upper 16 bits */
#define CON_INPUT 0x100 /* Input ready for unit */
#define CON_CR 0x200 /* Output at beginning of line */
#define CON_REQ 0x400 /* Request key pressed */
#define CON_EKO 0x800 /* Echo input character */
#define CON_OUTPUT 0x1000 /* Output ready for unit */
#define CON_READ 0x2000 /* Read mode selected */
/* Input buffer pointer held in u4 */
/* in u5 packs sense byte 0,1 and 3 */
/* Sense byte 0 */
#define SNS_CMDREJ 0x80000000 /* Command reject */
#define SNS_INTVENT 0x40000000 /* Unit intervention required */
/* sense byte 3 */
#define SNS_RDY 0x80 /* device ready */
#define SNS_ONLN 0x40 /* device online */
//#define SNS_DSR 0x04 /* data set ready */
#define SNS_DSR 0x08 /* data set ready */
#define SNS_DCD 0x04 /* data carrier detect */
/* std devices. data structures
con_dev Console device descriptor
con_unit Console unit descriptor
con_reg Console register list
con_mod Console modifiers list
*/
struct _con_data
{
uint8 ibuff[145]; /* Input line buffer */
uint8 incnt; /* char count */
}
con_data[NUM_UNITS_CON];
uint32 atbuf=0; /* attention buffer */
/* forward definitions */
uint8 con_startcmd(UNIT *, uint16, uint8);
void con_ini(UNIT *, t_bool);
t_stat con_srvi(UNIT *);
t_stat con_srvo(UNIT *);
t_stat con_reset(DEVICE *);
t_stat con_attach(UNIT *, char *);
t_stat con_detach(UNIT *);
/* channel program information */
CHANP con_chp[NUM_UNITS_CON] = {0};
MTAB con_mod[] = {
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL},
{0}
};
UNIT con_unit[] = {
{UDATA(con_srvi, UNIT_ATT, 0), 0, UNIT_ADDR(0x7EFC)}, /* Input */
{UDATA(con_srvo, UNIT_ATT, 0), 0, UNIT_ADDR(0x7EFD)}, /* Output */
};
//DIB con_dib = {NULL, con_startcmd, NULL, NULL, NULL, con_ini, con_unit, con_chp, NUM_UNITS_CON, 0xf, 0x7e00, 0, 0, 0};
DIB con_dib = {
NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */
con_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */
NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */
NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */
NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */
con_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
con_unit, /* UNIT* units */ /* Pointer to units structure */
con_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
NUM_UNITS_CON, /* uint8 numunits */ /* number of units defined */
0x0f, /* uint8 mask */ /* 2 devices - device mask */
0x7e00, /* uint16 chan_addr */ /* parent channel address */
0, /* uint32 chan_fifo_in */ /* fifo input index */
0, /* uint32 chan_fifo_out */ /* fifo output index */
0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */
};
DEVICE con_dev = {
"CON", con_unit, NULL, con_mod,
NUM_UNITS_CON, 8, 15, 1, 8, 8,
NULL, NULL, NULL, NULL, NULL, NULL,
&con_dib, DEV_UADDR|DEV_DISABLE|DEV_DEBUG, 0, dev_debug
};
/*
* Console print routines.
*/
/* initialize the console chan/unit */
void con_ini(UNIT *uptr, t_bool f) {
int unit = (uptr - con_unit); /* unit 0 */
DEVICE *dptr = find_dev_from_unit(uptr);
con_data[unit].incnt = 0; /* no input data */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 1000); /* time increment */
}
/* start an I/O operation */
uint8 con_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
int unit = (uptr - con_unit); /* unit 0,1 */
uint8 ch;
if ((uptr->u3 & CON_MSK) != 0) /* is unit busy */
return SNS_BSY; /* yes, return busy */
/* process the commands */
switch (cmd & 0xFF) {
case CON_INCH: /* 0x00 */ /* INCH command */
sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd INCH\n", chan);
return SNS_CHNEND|SNS_DEVEND; /* all is well */
break;
case CON_RWD: /* 0x37 */ /* TOF and write line */
case CON_WR: /* 0x01 */ /* Write command */
/* if input requested for output device, give error */
if (unit == 0) {
uptr->u5 |= SNS_CMDREJ; /* command rejected */
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
}
uptr->u3 &= LMASK; /* leave only chsa */
uptr->u3 |= (cmd & CON_MSK); /* save command */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 20); /* TRY 06-09-18 */
return 0; /* no status change */
break;
case CON_RD: /* Read command */
case CON_ECHO: /* Read command w/ECHO */
/* if output requested for input device, give error */
if (unit == 1) {
uptr->u5 |= SNS_CMDREJ; /* command rejected */
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
}
uptr->u3 &= LMASK; /* leave only chsa */
uptr->u3 |= (cmd & CON_MSK); /* save command */
if (cmd == CON_ECHO) /* echo command? */
uptr->u3 |= CON_EKO; /* save echo status */
uptr->u3 |= CON_READ; /* show read mode */
atbuf = 0; /* reset attention buffer */
uptr->u4 = 0; /* no I/O yet */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
return 0;
break;
case CON_NOP: /* NOP has do nothing */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case CON_CON: /* Connect, return Data Set ready */
sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd %x NOP\n", chan, cmd);
uptr->u5 |= (SNS_DSR|SNS_DCD); /* Data set ready, Data Carrier detected */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case CON_DIS: /* NOP has do nothing */
sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd %x NOP\n", chan, cmd);
uptr->u5 &= ~(SNS_DSR|SNS_DCD); /* Data set not ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case CON_SNS: /* Sense */
sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %x: Cmd Sense %02x\n", chan, uptr->u5);
/* value 4 is Data Set Ready */
/* value 5 is Data carrier detected n/u */
ch = uptr->u5; /* status */
chan_write_byte(GET_UADDR(uptr->u3), &ch); /* write status */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
default: /* invalid command */
uptr->u5 |= SNS_CMDREJ; /* command rejected */
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
break;
}
if (uptr->u5 & (~(SNS_RDY|SNS_ONLN|SNS_DSR)))
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
return SNS_CHNEND|SNS_DEVEND;
}
/* Handle output transfers for console */
t_stat con_srvo(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->u3);
int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */
int cmd = uptr->u3 & CON_MSK;
uint8 ch;
if ((cmd == CON_WR) || (cmd == CON_RWD)) {
/* Write to device */
if (chan_read_byte(chsa, &ch)) { /* get byte from memory */
uptr->u3 &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
} else {
sim_debug(DEBUG_CMD, &con_dev, "con_srvo write %d: putch %0.2x %c\n", unit, ch, ch);
sim_putchar(ch); /* output next char to device */
sim_activate(uptr, 20); /* TRY 07-18-18 */
}
}
return SCPE_OK;
}
/* Handle input transfers for console */
t_stat con_srvi(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->u3);
int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */
int cmd = uptr->u3 & CON_MSK;
t_stat r = SCPE_ARG; /* Force error if not set */
uint8 ch;
int i;
switch (cmd) {
case CON_RD: /* read from device */
case CON_ECHO: /* read from device w/ECHO */
if (uptr->u3 & CON_INPUT) { /* input waiting? */
ch = con_data[unit].ibuff[uptr->u4++]; /* get char from read buffer */
sim_debug(DEBUG_CMD, &con_dev, "con_srvi %d: read %02x\n", unit, ch);
if (chan_write_byte(chsa, &ch)) { /* write byte to memory */
con_data[unit].incnt = 0; /* buffer empty */
cmd = 0; /* no cmd either */
uptr->u3 &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
} else {
if (uptr->u4 == con_data[unit].incnt) { /* read completed */
con_data[unit].incnt = 0; /* buffer is empty */
cmd = 0; /* no cmd either */
uptr->u3 &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
}
}
}
break;
}
/* poll for next input if reading or @@A sequence */
r = sim_poll_kbd(); /* poll for ready */
if (r & SCPE_KFLAG) { /* got a char */
ch = r & 0377; /* drop any extra bits */
if ((cmd == CON_RD) || (cmd == CON_ECHO)) { /* looking for input */
atbuf = 0; /* reset attention buffer */
if (ch == '\n') /* convert newline */
ch = '\r'; /* make newline into carriage return */
/* Handle end of buffer */
switch (ch) {
case 0x7f: /* Delete */
case '\b': /* backspace */
if (con_data[unit].incnt != 0) {
con_data[unit].incnt--;
sim_putchar('\b');
sim_putchar(' ');
sim_putchar('\b');
}
break;
case 03: /* ^C */
case 025: /* ^U clear line */
for (i = con_data[unit].incnt; i> 0; i--) {
sim_putchar('\b');
sim_putchar(' ');
sim_putchar('\b');
}
con_data[unit].incnt = 0;
break;
case '\r': /* return */
case '\n': /* newline */
uptr->u3 |= CON_CR; /* C/R received */
/* fall through */
default:
if (con_data[unit].incnt < sizeof(con_data[unit].ibuff)) {
if (uptr->u3 & CON_EKO) /* ECHO requested */
sim_putchar(ch); /* ECHO the char */
con_data[unit].ibuff[con_data[unit].incnt++] = ch;
uptr->u3 |= CON_INPUT; /* we have a char available */
}
break;
}
} else {
/* look for attention sequence '@@A' */
if (ch == '@' || ch == 'A' || ch == 'a') {
if (ch == 'a')
ch = 'A';
atbuf = (atbuf|ch)<<8;
sim_putchar(ch); /* ECHO the char */
if (atbuf == 0x40404100) {
attention_trap = CONSOLEATN_TRAP; /* console attn (0xb4) */
atbuf = 0; /* reset attention buffer */
sim_putchar('\r'); /* return char */
sim_putchar('\n'); /* line feed char */
}
} else {
if (ch == '?') {
int chan = ((chsa >> 8) & 0x7f); /* get the channel number */
/* set ring bit? */
set_devwake(chsa, SNS_ATTN|SNS_DEVEND|SNS_CHNEND); /* tell user */
}
}
}
}
if ((cmd == CON_RD) || (cmd == CON_ECHO)) /* looking for input */
sim_activate(uptr, 200); /* keep going */
else
sim_activate(uptr, 400); /* keep going */
return SCPE_OK;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* sel32_defs.h: Gould Concept/32 (orignal SEL32) simulator definitions
/* sel32_defs.h: SEL 32 Concept/32 simulator definitions
Copyright (c) 2017, Richard Cornwell
Copyright (c) 2018, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -16,37 +16,37 @@
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
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sim_defs.h" /* simulator defns */
#include "sim_defs.h" /* simh simulator defns */
/* Simulator stop codes */
#define STOP_IONRDY 1 /* I/O dev not ready */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_UUO 4 /* invalid opcode */
#define STOP_INVINS 5 /* invalid instr */
#define STOP_INVIOP 6 /* invalid I/O op */
#define STOP_INDLIM 7 /* indirect limit */
#define STOP_XECLIM 8 /* XEC limit */
#define STOP_IOCHECK 9 /* IOCHECK */
#define STOP_MMTRP 10 /* mm in trap */
#define STOP_TRPINS 11 /* trap inst not BRM */
#define STOP_RTCINS 12 /* rtc inst not MIN/SKR */
#define STOP_ILLVEC 13 /* zero vector */
#define STOP_CCT 14 /* runaway CCT */
#define STOP_IONRDY 1 /* I/O dev not ready */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_UUO 4 /* invalid opcode */
#define STOP_INVINS 5 /* invalid instr */
#define STOP_INVIOP 6 /* invalid I/O op */
#define STOP_INDLIM 7 /* indirect limit */
#define STOP_XECLIM 8 /* XEC limit */
#define STOP_IOCHECK 9 /* IOCHECK */
#define STOP_MMTRP 10 /* mm in trap */
#define STOP_TRPINS 11 /* trap inst not BRM */
#define STOP_RTCINS 12 /* rtc inst not MIN/SKR */
#define STOP_ILLVEC 13 /* zero vector */
#define STOP_CCT 14 /* runaway CCT */
/* I/O equates */
/* Channel sense bytes */
#define SNS_ATTN 0x80 /* Unit attention */
#define SNS_SMS 0x40 /* Status modifier */
/* Channel sense bytes set by device */
#define SNS_BSY 0x80 /* Unit Busy */
#define SNS_SMS 0x40 /* Status modified */
#define SNS_CTLEND 0x20 /* Control unit end */
#define SNS_BSY 0x10 /* Unit Busy */
#define SNS_ATTN 0x10 /* Unit attention */
#define SNS_CHNEND 0x08 /* Channel end */
#define SNS_DEVEND 0x04 /* Device end */
#define SNS_UNITCHK 0x02 /* Unit check */
@@ -64,22 +64,23 @@
#define CMD_READ 0x02 /* Read command */
#define CMD_CTL 0x03 /* Control command */
#define STATUS_ATTN 0x8000 /* Device raised attention */
#define STATUS_MOD 0x4000 /* Status modifier */
#define STATUS_CTLEND 0x2000 /* Control end */
#define STATUS_BUSY 0x1000 /* Device busy */
#define STATUS_CEND 0x0800 /* Channel end */
#define STATUS_DEND 0x0400 /* Device end */
#define STATUS_CHECK 0x0200 /* Unit check */
#define STATUS_EXPT 0x0100 /* Unit excpetion */
#define STATUS_PCI 0x0080 /* Program interupt */
#define STATUS_LENGTH 0x0040 /* Incorrect lenght */
#define STATUS_PCHK 0x0020 /* Program check */
#define STATUS_PROT 0x0010 /* Protection check */
#define STATUS_CDATA 0x0008 /* Channel data check */
#define STATUS_CCNTL 0x0004 /* Channel control check */
#define STATUS_INTER 0x0002 /* Channel interface check */
#define STATUS_CHAIN 0x0001 /* Channel chain check */
/* IOCD word 2 status bits */
#define STATUS_ECHO 0x8000 /* Halt I/O and Stop I/O function */
#define STATUS_PCI 0x4000 /* Program controlled interrupt */
#define STATUS_LENGTH 0x2000 /* Incorrect length */
#define STATUS_PCHK 0x1000 /* Channel program check */
#define STATUS_CDATA 0x0800 /* Channel data check */
#define STATUS_CCNTL 0x0400 /* Channel control check */
#define STATUS_INTER 0x0200 /* Channel interface check */
#define STATUS_CHAIN 0x0100 /* Channel chain check */
#define STATUS_BUSY 0x0080 /* Device busy */
#define STATUS_MOD 0x0040 /* Status modified */
#define STATUS_CTLEND 0x0020 /* Controller end */
#define STATUS_ATTN 0x0010 /* Device raised attention */
#define STATUS_CEND 0x0008 /* Channel end */
#define STATUS_DEND 0x0004 /* Device end */
#define STATUS_CHECK 0x0002 /* Unit check */
#define STATUS_EXPT 0x0001 /* Unit exception */
/* Class F channel bits */
/* bit 32 - 37 of IOCD word 2 (0-5) */
@@ -90,34 +91,45 @@
#define FLAG_PCI 0x0800 /* Program controlled interrupt */
#define FLAG_RTO 0x0400 /* Real-Time Option */
#if 0
#define CCMDMSK 0xff000000 /* Mask for command */
#define CDADRMSK 0x00ffffff /* Mask for data address */
#define CCNTMSK 0x0000ffff /* Mask for data count */
#define CHD 0x80000000 /* Chain data */
#define CHC 0x40000000 /* Chain command */
#define SLI 0x20000000 /* Suppress length indication */
#define SKIP 0x10000000 /* Skip flag */
#define PCI 0x08000000 /* Program controlled interuption */
#endif
#define BUFF_EMPTY 0x4 /* Buffer is empty */
#define BUFF_DIRTY 0x8 /* Buffer is dirty flag */
#define BUFF_NEWCMD 0x10 /* Channel ready for new command */
#define BUFF_CHNEND 0x20 /* Channel end */
#define MAX_CHAN 128 /* max channels that can be defined */
#define SUB_CHANS 256 /* max sub channels that can be defined */
#define MAX_DEV (MAX_CHAN * SUB_CHANS) /* max possible */
#define MAX_CHAN 128 /* max channels that can be defined */
#define SUB_CHANS 256 /* max sub channels that can be defined */
#define MAX_DEV (MAX_CHAN * SUB_CHANS) /* max possible */
/* simulator devices configuration */
#define NUM_DEVS_MT 1 /* mag tape units */
#define NUM_UNITS_MT 8 /* 8 devices */
#define NUM_DEVS_DISK 2 /* disk drive devices */
#define NUM_UNITS_DISK 2 /* 2 devices */
#define NUM_DEVS_IOP 1 /* 1 device IOP channel controller */
#define NUM_UNITS_IOP 1 /* 1 master IOP channel device */
#define NUM_DEVS_COM 2 /* 8-Line async controller */
#define NUM_UNITS_COM 16 /* 8-Line async units */
#define NUM_DEVS_CON 1 /* 1 I/O console controller */
#define NUM_UNITS_CON 2 /* 2 console input & output */
#define NUM_DEVS_MT 1 /* 1 mag tape controllers */
#define NUM_UNITS_MT 4 /* 4 of 8 devices */
#define NUM_DEVS_DISK 1 /* 1 DP02 disk drive controller */
#define NUM_UNITS_DISK 4 /* 4 disk drive devices */
#define NUM_DEVS_SCFI 2 /* 2 scfi (SCSI) disk drive units */
#define NUM_UNITS_SCFI 2 /* 2 of 4 disk drive devices */
#define NUM_DEVS_RTOM 1 /* 1 IOP RTOM channel */
#define NUM_UNITS_RTOM 1 /* 1 IOP RTOM device (clock & interval timer) */
#define NUM_DEVS_LPR 1 /* 1 IOP Line printer */
#define NUM_UNITS_LPR 1 /* 1 IOP Line printer device */
extern DEVICE cpu_dev; /* cpu device */
extern UNIT cpu_unit; /* the cpu unit */
extern DEVICE cpu_dev; /* cpu device */
extern UNIT cpu_unit; /* the cpu unit */
#ifdef NUM_DEVS_IOP
extern DEVICE iop_dev; /* IOP channel controller */
#endif
#ifdef NUM_DEVS_RTOM
extern DEVICE rtc_dev; /* RTOM rtc */
extern DEVICE itm_dev; /* RTOM itm */
#endif
#ifdef NUM_DEVS_CON
extern DEVICE con_dev;
#endif
#ifdef NUM_DEVS_MT
extern DEVICE mta_dev;
#endif
@@ -130,29 +142,65 @@ extern DEVICE dda_dev;
#if NUM_DEVS_DISK > 1
extern DEVICE ddb_dev;
#endif
#ifdef NUM_DEVS_SCFI
extern DEVICE sda_dev;
#endif
#if NUM_DEVS_SCFI > 1
extern DEVICE sdb_dev;
#endif
#ifdef NUM_DEVS_COM
extern DEVICE coml_dev;
extern DEVICE com_dev;
#endif
#ifdef NUM_DEVS_LPR
extern DEVICE lpr_dev;
#endif
/* Memory */
#define MAXMEMSIZE ((16*1024*1024)/4) /* max memory size */
#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((x)) < MEMSIZE)
#define MAXMEMSIZE ((16*1024*1024)/4) /* max memory size */
#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((x)) < MEMSIZE)
/* channel program data for a chan/sub-address */
typedef struct chp {
/* channel program values */
uint32 chan_inch_addr; /* Channel status dw in memory */
uint32 chan_caw; /* Channel command address word */
uint32 ccw_addr; /* Channel address */
uint16 ccw_count; /* Channel count */
uint8 ccw_cmd; /* Channel command and flags */
uint16 ccw_flags; /* Channel flags */
uint16 chan_status; /* Channel status */
uint16 chan_dev; /* Device on channel */
uint32 chan_buf; /* Channel data buffer */
uint8 chan_byte; /* Current byte, dirty/full */
} CHANP;
/* Device information block */
#define FIFO_SIZE 256 /* fifo to hold 128 double words of status */
typedef struct dib {
uint8 mask; /* device mask */
uint8 numunits; /* number of units */
/* Start I/O */
uint8 (*start_io)(UNIT *uptr, uint16 chan);
/* Start a command */
uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd);
/* Stop I/O */
uint8 (*halt_io)(UNIT *uptr);
UNIT *units; /* Pointer to units structure */
void (*dev_ini)(UNIT *, t_bool); /* init function */
uint8 dev_addr; /* Device address */
uint8 dev_class; /* Device class */
/* Pre start I/O operation */
uint8 (*pre_io)(UNIT *uptr, uint16 chan);
/* Start a channel command SIO */
uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd);
/* Halt I/O HIO */
uint8 (*halt_io)(UNIT *uptr);
/* Test I/O TESTIO */
uint8 (*test_io)(UNIT *uptr);
/* Post I/O processing */
uint8 (*post_io)(UNIT *uptr);
/* Controller init */
void (*dev_ini)(UNIT *, t_bool); /* init function */
UNIT *units; /* Pointer to units structure */
CHANP *chan_prg; /* Pointer to channel program */
uint8 numunits; /* number of units */
uint8 mask; /* device mask */
uint16 chan_addr; /* parent channel address */
uint32 chan_fifo_in; /* fifo input index */
uint32 chan_fifo_out; /* fifo output index */
uint32 chan_fifo[FIFO_SIZE]; /* interrupt status fifo for each channel */
} DIB;
/* DEV 0x7F000000 UNIT 0x00ff0000 */
@@ -186,22 +234,22 @@ typedef struct dib {
extern DEBTAB dev_debug[];
/* defines for all programs */
#define RMASK 0x0000FFFF /* right hw 16 bit mask */
#define LMASK 0xFFFF0000 /* left hw 16 bit mask */
#define FMASK 0xFFFFFFFF /* 32 bit mask */
#define DMASK 0xFFFFFFFFFFFFFFFFLL /* 64 bit all bits mask */
#define D48LMASK 0xFFFFFFFFFFFF0000LL /* 64 bit left 48 bits mask */
#define D32LMASK 0xFFFFFFFF00000000LL /* 64 bit left 32 bits mask */
#define D32RMASK 0x00000000FFFFFFFFLL /* 64 bit right 32 bits mask */
#define MSIGN 0x80000000 /* 32 bit minus sign */
#define DMSIGN 0x8000000000000000LL /* 64 bit minus sign */
#define FSIGN 0x80000000 /* 32 bit minus sign */
#define RMASK 0x0000FFFF /* right hw 16 bit mask */
#define LMASK 0xFFFF0000 /* left hw 16 bit mask */
#define FMASK 0xFFFFFFFF /* 32 bit mask */
#define DMASK 0xFFFFFFFFFFFFFFFFLL /* 64 bit all bits mask */
#define D48LMASK 0xFFFFFFFFFFFF0000LL /* 64 bit left 48 bits mask */
#define D32LMASK 0xFFFFFFFF00000000LL /* 64 bit left 32 bits mask */
#define D32RMASK 0x00000000FFFFFFFFLL /* 64 bit right 32 bits mask */
#define MSIGN 0x80000000 /* 32 bit minus sign */
#define DMSIGN 0x8000000000000000LL /* 64 bit minus sign */
#define FSIGN 0x80000000 /* 32 bit minus sign */
/* sign extend 16 bit value to uint32 */
#define SEXT16(x) (x&MSIGN?(uint32)(((uint32)x&RMASK)|LMASK):(uint32)x)
#define SEXT16(x) (x&0x8000?(uint32)(((uint32)x&RMASK)|LMASK):(uint32)x)
/* sign extend 16 bit value to uint64 */
#define DSEXT16(x) (x&MSIGN?(l_uint64)(((l_uint64)x&RMASK)|D48LMASK):(t_uint64)x)
#define DSEXT16(x) (x&0x8000?(l_uint64)(((l_uint64)x&RMASK)|D48LMASK):(t_uint64)x)
/* sign extend 32 bit value to uint64 */
#define DSEXT32(x) (x&MSIGN?(l_uint64)(((l_uint64)x&D32RMASK)|D32LMASK):(t_uint64)x)
#define DSEXT32(x) (x&0x8000?(l_uint64)(((l_uint64)x&D32RMASK)|D32LMASK):(t_uint64)x)
#define UNIT_V_MODEL (UNIT_V_UF + 0)
#define UNIT_MODEL (7 << UNIT_V_MODEL)
@@ -209,7 +257,7 @@ extern DEBTAB dev_debug[];
#define UNIT_V_MSIZE (UNIT_V_MODEL + 3)
#define UNIT_MSIZE (0x1F << UNIT_V_MSIZE)
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_MODEL) & 0x7) /* cpu model 0-7 */
#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_MODEL) & 0x7) /* cpu model 0-7 */
#define MODEL_55 0 /* 512K Mode Only */
#define MODEL_75 1 /* Extended */
@@ -227,70 +275,75 @@ extern DEBTAB dev_debug[];
#define HIST_PC 0x80000000
/* CC defs Held in CC */
#define CC1 0x40 /* CC1 in CC */
#define CC2 0x20 /* CC2 in CC */
#define CC3 0x10 /* CC3 in CC */
#define CC4 0x08 /* CC4 in CC */
#define CC1BIT 0x40000000 /* CC1 in PSD1 */
#define CC2BIT 0x20000000 /* CC2 in PSD1 */
#define CC3BIT 0x10000000 /* CC3 in PSD1 */
#define CC4BIT 0x08000000 /* CC4 in PSD1 */
#define CC1BIT 0x40000000 /* CC1 in PSD1 */
#define CC2BIT 0x20000000 /* CC2 in PSD1 */
#define CC3BIT 0x10000000 /* CC3 in PSD1 */
#define CC4BIT 0x08000000 /* CC4 in PSD1 */
/* PSD mode bits in 'modes' variable */
#define PRIV 0x80 /* Privileged mode PSD 1 bit 0 */
#define EXTD 0x04 /* Extended Addressing PSD 1 bit 5 */
#define BASE 0x02 /* Base Mode PSD 1 bit 6 */
#define AEXP 0x01 /* Arithmetic exception PSD 1 bit 7 */
#define MAP 0x40 /* Map mode, PSD 2 bit 0 */
#define RET 0x20 /* Retain current maps, PSD 2 bit 15 */
#define BLKED 0x10 /* Set blocked mode, PSD 2 bit 17 */
#define BLKRET 0x08 /* Set retain blocked mode, PSD 2 bit 16 */
#define MAPMODE 0x40 /* Map mode, PSD 2 bit 0 */
#define RETMODE 0x20 /* Retain current maps, PSD 2 bit 15 */
#define BLKMODE 0x10 /* Set blocked mode, PSD 2 bit 17 */
#define RETBLKM 0x08 /* Set retain blocked mode, PSD 2 bit 16 */
/* PSD mode bits in PSD words 1&2 variable */
#define PRIVBIT 0x80000000 /* Privileged mode PSD 1 bit 0 */
#define EXTDBIT 0x04000000 /* Extended Addressing PSD 1 bit 5 */
#define BASEBIT 0x02000000 /* Base Mode PSD 1 bit 6 */
#define AEXPBIT 0x01000000 /* Arithmetic exception PSD 1 bit 7 */
#define PRIVBIT 0x80000000 /* Privileged mode PSD 1 bit 0 */
#define EXTDBIT 0x04000000 /* Extended Addressing PSD 1 bit 5 */
#define BASEBIT 0x02000000 /* Base Mode PSD 1 bit 6 */
#define AEXPBIT 0x01000000 /* Arithmetic exception PSD 1 bit 7 */
#define BLKEDBIT 0x00004000 /* Set blocked mode, PSD 2 bit 17 */
#define RETBIT 0x00010000 /* Retain current maps, PSD 2 bit 15 */
#define MAPBIT 0x80000000 /* Map mode, PSD 2 bit 0 */
#define BLKEDBIT 0x00004000 /* Set blocked mode, PSD 2 bit 17 */
#define RETBBIT 0x00008000 /* Retain current blocking state, PSD 2 bit 16 */
#define RETMBIT 0x00010000 /* Retain current maps, PSD 2 bit 15 */
#define MAPBIT 0x80000000 /* Map mode, PSD 2 bit 0 */
/* Trap Table Address in memory is pointed to by SPAD 0xF0 */
#define POWERFAIL_TRAP 0x80 /* Power fail trap */
#define POWERON_TRAP 0x84 /* Power-On trap */
#define MEMPARITY_TRAP 0x88 /* Memory Parity Error trap */
#define NONPRESMEM_TRAP 0x8C /* Non Present Memory trap */
#define UNDEFINSTR_TRAP 0x90 /* Undefined Instruction Trap */
#define PRIVVIOL_TRAP 0x94 /* Privlege Violation Trap */
#define SVCCALL_TRAP 0x98 /* Supervisor Call Trap */
#define MACHINECHK_TRAP 0x9C /* Machine Check Trap */
#define SYSTEMCHK_TRAP 0xA0 /* System Check Trap */
#define MAPFAULT_TRAP 0xA4 /* Map Fault Trap */
#define IPUUNDEFI_TRAP 0xA8 /* IPU Undefined Instruction Trap */
#define SIGNALIPU_TRAP 0xAC /* Signal IPU/CPU Trap */
#define ADDRSPEC_TRAP 0xB0 /* Address Specification Trap */
#define CONSOLEATN_TRAP 0xB4 /* Console Attention Trap */
#define PRIVHALT_TRAP 0xB8 /* Privlege Mode Halt Trap */
#define AEXPCEPT_TRAP 0xBC /* Arithmetic Exception Trap */
#define POWERFAIL_TRAP 0x80 /* Power fail trap */
#define POWERON_TRAP 0x84 /* Power-On trap */
#define MEMPARITY_TRAP 0x88 /* Memory Parity Error trap */
#define NONPRESMEM_TRAP 0x8C /* Non Present Memory trap */
#define UNDEFINSTR_TRAP 0x90 /* Undefined Instruction Trap */
#define PRIVVIOL_TRAP 0x94 /* Privlege Violation Trap */
#define SVCCALL_TRAP 0x98 /* Supervisor Call Trap */
#define MACHINECHK_TRAP 0x9C /* Machine Check Trap */
#define SYSTEMCHK_TRAP 0xA0 /* System Check Trap */
#define MAPFAULT_TRAP 0xA4 /* Map Fault Trap */
#define IPUUNDEFI_TRAP 0xA8 /* IPU Undefined Instruction Trap */
#define SIGNALIPU_TRAP 0xAC /* Signal IPU/CPU Trap */
#define ADDRSPEC_TRAP 0xB0 /* Address Specification Trap */
#define CONSOLEATN_TRAP 0xB4 /* Console Attention Trap */
#define PRIVHALT_TRAP 0xB8 /* Privlege Mode Halt Trap */
#define AEXPCEPT_TRAP 0xBC /* Arithmetic Exception Trap */
/* Errors returned from various functions */
#define ALLOK 0x0000 /* no error, all is OK */
#define MAPFLT MAPFAULT_TRAP /* map fault error */
#define NPMEM NONPRESMEM_TRAP /* non present memory */
#define MPVIOL PRIVVIOL_TRAP /* memory protection violation */
#define ALLOK 0x0000 /* no error, all is OK */
#define MAPFLT MAPFAULT_TRAP /* map fault error */
#define NPMEM NONPRESMEM_TRAP /* non present memory */
#define MPVIOL PRIVVIOL_TRAP /* memory protection violation */
/* general instruction decode equates */
#define IND 0x00100000 /* indirect bit in instruction, bit 11 */
#define F_BIT 0x00080000 /* byte flag addressing bit 11 in instruction */
#define C_BITS 0x00000003 /* byte number or hw, dw, dw flags bits 20 & 31 */
#define BIT0 0x80000000 /* general use for bit 0 testing */
#define BIT1 0x40000000 /* general use for bit 1 testing */
#define MASK16 0x0000FFFF /* 16 bit address mask */
#define MASK19 0x0007FFFF /* 19 bit address mask */
#define MASK20 0x000FFFFF /* 20 bit address mask */
#define MASK24 0x00FFFFFF /* 24 bit address mask */
#define MASK32 0xFFFFFFFF /* 32 bit address mask */
#define IND 0x00100000 /* indirect bit in instruction, bit 11 */
#define F_BIT 0x00080000 /* byte flag addressing bit 11 in instruction */
#define C_BITS 0x00000003 /* byte number or hw, dw, dw flags bits 20 & 31 */
#define BIT0 0x80000000 /* general use for bit 0 testing */
#define BIT1 0x40000000 /* general use for bit 1 testing */
#define MASK16 0x0000FFFF /* 16 bit address mask */
#define MASK19 0x0007FFFF /* 19 bit address mask */
#define MASK20 0x000FFFFF /* 20 bit address mask */
#define MASK24 0x00FFFFFF /* 24 bit address mask */
#define MASK32 0xFFFFFFFF /* 32 bit address mask */
/* SPAD int entry equates, entries accessed by interrupt level number */
#define SINT_RAML 0x80000000 /* ram loaded (n/u) */
#define SINT_EWCS 0x40000000 /* Enabled channel WCS executed (XIO) */
#define SINT_ACT 0x20000000 /* Interrupt active when set (copy is in INTS */
#define SINT_ENAB 0x10000000 /* Interrupt enabled when set (copy is in INTS */
#define SINT_EXTL 0x08000000 /* IOP/RTOM ext interrupt if set, I/O if not set (copy in INTS) */
/* INTS int entry equates, entries accessed by interrupt level number */
#define INTS_NU1 0x80000000 /* Not used */
#define INTS_NU2 0x40000000 /* Not used */
#define INTS_ACT 0x20000000 /* Interrupt active when set (copy is of SPAD */
#define INTS_ENAB 0x10000000 /* Interrupt enabled when set (copy is of SPAD */
#define INTS_EXTL 0x08000000 /* IOP/RTOM ext interrupt if set, I/O if not set (copy of SPAD) */
#define INTS_REQ 0x04000000 /* Interrupt is requesting */

1165
SEL32/sel32_disk.c Normal file

File diff suppressed because it is too large Load Diff

199
SEL32/sel32_iop.c Normal file
View File

@@ -0,0 +1,199 @@
/* sel32_iop.c: SEL 32 Class F IOP processor channel.
Copyright (c) 2018, James C. Bevier
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This channel is the interrupt fielder for all of the IOP sub channels. It's
channel address is 7E00. This code handles the INCH command for the IOP
devices and controls the status FIFO for the iop devices on interrupts and
TIO instructions..
Possible devices:
The f8iop communication controller (TY7EA0), (TY7EB0), (TY7EC0)
The ctiop console communications controller (CT7EFC & CT7EFD)
The lpiop line printer controller (LP7EF8), (LP7EF9)
*/
#include "sel32_defs.h"
#include "sim_defs.h"
#ifdef NUM_DEVS_IOP
extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc);
extern void chan_end(uint16 chan, uint8 flags);
extern int chan_read_byte(uint16 chan, uint8 *data);
extern int chan_write_byte(uint16 chan, uint8 *data);
extern void set_devattn(uint16 addr, uint8 flags);
extern void post_extirq(void);
extern uint32 attention_trap; /* set when trap is requested */
extern void set_devwake(uint16 addr, uint8 flags);
/* Held in u3 is the device command and status */
#define IOP_INCH 0x00 /* Initialize channel command */
#define IOP_MSK 0xff /* Command mask */
/* Status held in u3 */
/* controller/unit address in upper 16 bits */
#define CON_INPUT 0x100 /* Input ready for unit */
#define CON_CR 0x200 /* Output at beginning of line */
#define CON_REQ 0x400 /* Request key pressed */
#define CON_EKO 0x800 /* Echo input character */
#define CON_OUTPUT 0x1000 /* Output ready for unit */
#define CON_READ 0x2000 /* Read mode selected */
/* Input buffer pointer held in u4 */
/* in u5 packs sense byte 0,1 and 3 */
/* Sense byte 0 */
#define SNS_CMDREJ 0x80000000 /* Command reject */
#define SNS_INTVENT 0x40000000 /* Unit intervention required */
/* sense byte 3 */
#define SNS_RDY 0x80 /* device ready */
#define SNS_ONLN 0x40 /* device online */
/* std devices. data structures
iop_dev Console device descriptor
iop_unit Console unit descriptor
iop_reg Console register list
iop_mod Console modifiers list
*/
struct _iop_data
{
uint8 ibuff[145]; /* Input line buffer */
uint8 incnt; /* char count */
}
iop_data[NUM_UNITS_CON];
/* forward definitions */
uint8 iop_startcmd(UNIT *, uint16, uint8);
void iop_ini(UNIT *, t_bool);
t_stat iop_srv(UNIT *);
/* channel program information */
CHANP iop_chp[NUM_UNITS_MT] = {0};
MTAB iop_mod[] = {
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, &show_dev_addr, NULL},
{0}
};
UNIT iop_unit[] = {
{UDATA(iop_srv, UNIT_ATT, 0), 0, UNIT_ADDR(0x7E00)}, /* Channel controlller */
};
//DIB iop_dib = {NULL, iop_startcmd, NULL, NULL, NULL, iop_ini, iop_unit, iop_chp, NUM_UNITS_IOP, 0xff, 0x7e00,0,0,0};
DIB iop_dib = {
NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */
iop_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command SIO */
NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O HIO */
NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O TIO */
NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */
iop_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
iop_unit, /* UNIT* units */ /* Pointer to units structure */
iop_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
NUM_UNITS_IOP, /* uint8 numunits */ /* number of units defined */
0xff, /* uint8 mask */ /* 16 devices - device mask */
0x7e00, /* uint16 chan_addr */ /* parent channel address */
0, /* uint32 chan_fifo_in */ /* fifo input index */
0, /* uint32 chan_fifo_out */ /* fifo output index */
0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */
};
DEVICE iop_dev = {
"IOP", iop_unit, NULL, iop_mod,
NUM_UNITS_IOP, 8, 15, 1, 8, 8,
NULL, NULL, NULL, NULL, NULL, NULL,
&iop_dib, DEV_UADDR|DEV_DISABLE|DEV_DEBUG, 0, dev_debug
};
/* IOP controller routines */
/* initialize the console chan/unit */
void iop_ini(UNIT *uptr, t_bool f)
{
int unit = (uptr - iop_unit); /* unit 0 */
DEVICE *dptr = &iop_dev; /* one and only dummy device */
sim_debug(DEBUG_CMD, &iop_dev, "IOP init device %s controller/device %x\n", dptr->name, GET_UADDR(uptr->u3));
iop_data[unit].incnt = 0; /* no input data */
uptr->u5 = SNS_RDY|SNS_ONLN; /* status is online & ready */
}
/* start an I/O operation */
uint8 iop_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
{
if ((uptr->u3 & IOP_MSK) != 0) /* is unit busy */
return SNS_BSY; /* yes, return busy */
/* process the commands */
switch (cmd & 0xFF) {
case IOP_INCH: /* INCH command */
sim_debug(DEBUG_CMD, &iop_dev, "iop_startcmd %x: Cmd INCH\n", chan);
return SNS_CHNEND|SNS_DEVEND; /* all is well */
break;
default: /* invalid command */
uptr->u5 |= SNS_CMDREJ; /* command rejected */
sim_debug(DEBUG_CMD, &iop_dev, "iop_startcmd %x: Cmd Invald %x status %02x\n", chan, cmd, uptr->u5);
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
break;
}
if (uptr->u5 & (~(SNS_RDY|SNS_ONLN)))
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
return SNS_CHNEND|SNS_DEVEND;
}
/* Handle transfers for other sub-channels on IOP */
t_stat iop_srv(UNIT *uptr)
{
uint16 chsa = GET_UADDR(uptr->u3);
int unit = (uptr - iop_unit); /* unit 0 is channel */
uptr->u3 &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &iop_dev, "iop_srv chan %d: devend|devend\n", unit);
// chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* TRY 6/12/18 done */
return SCPE_OK;
}
/* Handle output transfers for console */
t_stat iop_srvo(UNIT *uptr)
{
uint16 chsa = GET_UADDR(uptr->u3);
int cmd = uptr->u3 & IOP_MSK;
sim_debug(DEBUG_CMD, &iop_dev, "iop_srvo start %x: cmd %x \n", chsa, cmd);
return SCPE_OK;
}
/* Handle input transfers for console */
t_stat iop_srvi(UNIT *uptr)
{
uint16 chsa = GET_UADDR(uptr->u3);
int cmd = uptr->u3 & IOP_MSK;
sim_debug(DEBUG_CMD, &iop_dev, "iop_srv start %x: cmd %x \n", chsa, cmd);
return SCPE_OK;
}
#endif

465
SEL32/sel32_lpr.c Normal file
View File

@@ -0,0 +1,465 @@
/* sel32_lpr.c: SEL 32 Line Printer
Copyright (c) 2018, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This is the standard line printer.
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 "sel32_defs.h"
#include "sim_defs.h"
#include <ctype.h>
/**** COMMANDS TO PRINT BUFFER THEN DO FORMS CONTROL */
/*
LP.CMD1 DATAW X'01000000' PRINT ONLY - NO FORMS CONTROL
LP.CMD2 DATAW X'05000000' PRINT BUFFER, <CR>
LP.CMD3 DATAW X'15000000' PRINT BUFFER, <LF>
LP.CMD4 DATAW X'25000000' PRINT BUFFER, <LF> <LF>
LP.CMD5 DATAW X'35000000' PRINT BUFFER, <LF> <LF> <LF>
LP.CMD6 DATAW X'45000000' PRINT BUFFER, <FF>
LP.CMD7 DATAW X'85000000' PRINT BUFFER, <CR>, THEN CLEAR BUFFER
*
**** COMMANDS TO DO FORMS CONTROL AND THEN PRINT BUFFER.
**** NOTE: THESE COMMANDS ARE ARRANGED SO THAT BY USING THE INDEX
**** OF THE FORMS CONTROL TABLE AND A OFFSET INTO THIS TABLE
**** YOU CAN GET THE APPROPRIATE COMMAND FOR THE FC CHAR.
*
LP.CMD8 DATAW X'0D000000' <CR>, PRINT BUFFER, <CR>
LP.CMD9 DATAW X'4D000000' <FF>, PRINT BUFFER, <CR>
DATAW X'4D000000' <FF>, PRINT BUFFER, <CR>
LP.CMD10 DATAW X'2D000000' <LF> <LF>, PRINT BUFFER <CR>
LP.CMD11 DATAW X'1D000000' <LF>, PRINT BUFFER, <CR>
LP.CMD12 DATAW X'3D000000' <LF> <LF> <LF>, PRINT, <CR> (SPARE)
*
**** COMMANDS THAT DO ONLY FORMS CONTROL (NO PRINTING)
*
LP.CMD13 DATAW X'03000000' <CR>
LP.CMD14 DATAW X'47000000' <FF>
DATAW X'47000000' <FF>
LP.CMD15 DATAW X'27000000' <LF> <LF>
LP.CMD16 DATAW X'17000000' <LF>
LP.CMD17 DATAW X'37000000' <LF> <LF> <LF> (SPARE)
*
** LINE PRINTER FORMS CONTROL TABLE
*
LPFCTBL EQU $
P0006C 2B DATAB C'+' 0x2b FORMS CONTROL FOR CR THEN PRINT
P0006D 31 DATAB C'1' 0x31 FORMS CONTROL FOR FF THEN PRINT
P0006E 2D DATAB C'-' 0x2d FORMS CONTROL FOR FF THEN PRINT
P0006F 30 DATAB C'0' 0x30 FORMS CONTROL FOR 2 LF'S THEN PRINT
P00070 20 DATAB C' ' 0x20 FORMS CONTROL FOR LF THEN PRINT
*/
#ifdef NUM_DEVS_LPR
#define UNIT_LPR UNIT_ATTABLE | UNIT_DISABLE
extern t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat show_dev_addr(FILE *st, UNIT * uptr, int32 v, CONST void *desc);
extern void chan_end(uint16 chan, uint8 flags);
extern int chan_read_byte(uint16 chan, uint8 *data);
extern int chan_write_byte(uint16 chan, uint8 *data);
extern void set_devattn(uint16 addr, uint8 flags);
/* u3 hold command and status information */
#define LPR_INCH 0x00 /* INCH command */
/* print buffer then CC commands */
#define LPR_PBNCC 0x01 /* print only, no forms control */
#define LPR_PBC 0x05 /* print buffer, then <CR> */
#define LPR_PBL 0x15 /* print buffer, then <LF> */
#define LPR_PBLL 0x25 /* print buffer, then <LF> <LF> */
#define LPR_PBLLL 0x35 /* print buffer, then <LF> <LF> <LF> */
#define LPR_PBF 0x45 /* print buffer, then <FF> */
#define LPR_PBCCB 0x85 /* print buffer, then <CR> <CLEAR BUFFER> */
/* Do CC then print commands then CC */
#define LPR_CPBC 0x0d /* <CR> print buffer <CR> */
#define LPR_LPBC 0x1d /* <LF> print buffer <CR> */
#define LPR_LLPBC 0x2d /* <LF> <LF> print buffer <CR> */
#define LPR_LLLPBC 0x3d /* <LF> <LF> <LF> print buffer <CR> */
#define LPR_FPBC 0x4d /* <FF> print buffer <CR> */
/* Do CC only, no print */
#define LPR_NPC 0x03 /* <CR> */
#define LPR_NPL 0x17 /* <LF> */
#define LPR_NPLL 0x27 /* <LF> <LF> */
#define LPR_NPLLL 0x37 /* <LF> <LF> <LF> */
#define LPR_NPF 0x47 /* <FF> */
#define LPR_SNS 0x04 /* Sense command */
#define LPR_CMDMSK 0xff /* Mask command part. */
#define LPR_FULL 0x100 /* Buffer full (BOF) */
#define LPR_PRE 0x200 /* Apply pre CC */
#define LPR_POST 0x400 /* Apply post CC */
/* u4 holds current line */
/* in u5 packs sense byte 0,1 and 3 */
/* Sense byte 0 */
#define SNS_CMDREJ 0x80 /* Command reject */
#define SNS_INTVENT 0x40 /* Unit intervention required */
#define SNS_BUSCHK 0x20 /* Parity error on bus */
#define SNS_EQUCHK 0x10 /* Equipment check */
#define SNS_DATCHK 0x08 /* Data Check */
#define SNS_OVRRUN 0x04 /* Data overrun */
#define SNS_SEQUENCE 0x02 /* Unusual sequence */
#define SNS_BOF 0x01 /* BOF on printer */
/* u6 hold buffer position */
/* std devices. data structures
lpr_dev Line Printer device descriptor
lpr_unit Line Printer unit descriptor
lpr_reg Line Printer register list
lpr_mod Line Printer modifiers list
*/
struct _lpr_data
{
uint8 lbuff[160]; /* Output line buffer */
}
lpr_data[NUM_DEVS_LPR];
uint8 lpr_startcmd(UNIT *, uint16, uint8);
void lpr_ini(UNIT *, t_bool);
t_stat lpr_srv(UNIT *);
t_stat lpr_reset(DEVICE *);
t_stat lpr_attach(UNIT *, CONST char *);
t_stat lpr_detach(UNIT *);
t_stat lpr_setlpp(UNIT *, int32, CONST char *, void *);
t_stat lpr_getlpp(FILE *, UNIT *, int32, CONST void *);
/* channel program information */
CHANP lpr_chp[NUM_DEVS_LPR] = {0};
MTAB lpr_mod[] = {
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LINESPERPAGE", "LINESPERPAGE",
&lpr_setlpp, &lpr_getlpp, NULL, "Number of lines per page"},
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
&show_dev_addr, NULL},
{0}
};
UNIT lpr_unit[] = {
{UDATA(lpr_srv, UNIT_LPR, 55), 300, UNIT_ADDR(0x7EF8)}, /* A */
#if NUM_DEVS_LPR > 1
{UDATA(lpr_srv, UNIT_LPR, 55), 300, UNIT_ADDR(0x7EF9)}, /* B */
#endif
};
/* Device Information Block */
//DIB lpr_dib = {NULL, lpr_startcmd, NULL, NULL, lpr_ini, lpr_unit, lpr_chp, NUM_DEVS_LPR, 0xff, 0x7e00, 0, 0, 0};
DIB lpr_dib = {
NULL, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */
lpr_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */
NULL, /* uint8 (*halt_io)(UNIT *uptr) */ /* Stop I/O */
NULL, /* uint8 (*test_io)(UNIT *uptr) */ /* Test I/O */
NULL, /* uint8 (*post_io)(UNIT *uptr) */ /* Post I/O */
lpr_ini, /* void (*dev_ini)(UNIT *, t_bool) */ /* init function */
lpr_unit, /* UNIT* units */ /* Pointer to units structure */
lpr_chp, /* CHANP* chan_prg */ /* Pointer to chan_prg structure */
NUM_DEVS_LPR, /* uint8 numunits */ /* number of units defined */
0xff, /* uint8 mask */ /* 2 devices - device mask */
0x7e00, /* uint16 chan_addr */ /* parent channel address */
0, /* uint32 chan_fifo_in */ /* fifo input index */
0, /* uint32 chan_fifo_out */ /* fifo output index */
0, /* uint32 chan_fifo[FIFO_SIZE] */ /* interrupt status fifo for channel */
};
DEVICE lpr_dev = {
"LPR", lpr_unit, NULL, lpr_mod,
NUM_DEVS_LPR, 8, 15, 1, 8, 8,
NULL, NULL, NULL, NULL, &lpr_attach, &lpr_detach,
&lpr_dib, DEV_UADDR | DEV_DISABLE | DEV_DEBUG, 0, dev_debug
};
/* initialize the line printer */
void lpr_ini(UNIT *uptr, t_bool f) {
/* do nothing for now */
}
/* start an I/O operation */
uint8 lpr_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
{
uint8 ch;
if ((uptr->u3 & LPR_CMDMSK) != 0) { /* unit busy */
return SNS_BSY; /* yes, busy (already tested) */
}
uptr->u3 &= ~(LPR_POST|LPR_PRE); /* set no CC */
if (((cmd & 0x03) == 0x03) || (cmd & 0x0d) == 0x0d) {
uptr->u3 |= LPR_PRE; /* apply pre CC */
}
if (((cmd & 0x05) == 0x05) || (cmd & 0x0d) == 0x0d) {
uptr->u3 |= LPR_POST; /* apply post CC */
}
sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd Cmd %02x\n", cmd);
/* process the command */
switch (cmd & LPR_CMDMSK) {
case 0x00: /* INCH command */
sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd INCH\n", chan);
return SNS_CHNEND|SNS_DEVEND; /* all is well */
break;
/* No CC */
case 0x01: /* print only, no forms control */
/* print buffer then CC commands */
case 0x05: /* print buffer, then <CR> */
case 0x15: /* print buffer, then <LF> */
case 0x25: /* print buffer, then <LF> <LF> */
case 0x35: /* print buffer, then <LF> <LF> <LF> */
case 0x45: /* print buffer, then <FF> */
case 0x85: /* print buffer, then <CR> <CLEAR BUFFER> */
/* Do CC then print commands then CC */
case 0x0d: /* <CR> print buffer <CR> */
case 0x1d: /* <LF> print buffer <CR> */
case 0x2d: /* <LF> <LF> print buffer <CR> */
case 0x3d: /* <LF> <LF> <LF> print buffer <CR> */
case 0x4d: /* <FF> print buffer <CR> */
/* Do CC only, no print */
case 0x03: /* <CR> */
case 0x17: /* <LF> */
case 0x27: /* <LF> <LF> */
case 0x37: /* <LF> <LF> <LF> */
case 0x47: /* <FF> */
/* process the command */
sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd %x print\n", chan, cmd&LPR_CMDMSK);
uptr->u3 &= ~(LPR_CMDMSK); /* zero cmd */
uptr->u3 |= (cmd & LPR_CMDMSK); /* save new command in u3 */
sim_activate(uptr, 10); /* Start unit off */
uptr->u5 = 0; /* no status */
uptr->u6 = 0; /* start of buffer */
return 0; /* we are good to go */
case 0x4: /* Sense Status */
sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd %x sense\n", chan, cmd&LPR_CMDMSK);
uptr->u3 &= ~(LPR_CMDMSK); /* zero cmd */
uptr->u3 |= (cmd & LPR_CMDMSK); /* save new command in u3 */
sim_activate(uptr, 10); /* Start unit off */
uptr->u5 = 0; /* no status */
uptr->u6 = 0; /* start of buffer */
return 0; /* we are good to go */
default: /* invalid command */
sim_debug(DEBUG_CMD, &lpr_dev, "lpr_startcmd %x: Cmd %x INVALID \r\n", chan, cmd&LPR_CMDMSK);
uptr->u5 |= SNS_CMDREJ;
break;
}
if (uptr->u5 & 0xff)
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
return SNS_CHNEND|SNS_DEVEND;
}
/* Handle transfer of data for printer */
t_stat lpr_srv(UNIT *uptr) {
int chsa = GET_UADDR(uptr->u3);
int u = (uptr - lpr_unit);
int cmd = (uptr->u3 & 0xff);
sim_debug(DEBUG_CMD, &lpr_dev, "lpr_srv called chsa %x cmd %x u3 %x cnt %x\r\n", chsa, cmd, uptr->u3, uptr->u6);
/* FIXME, need IOP lp status bit assignments */
if (cmd == 0x04) { /* sense? */
uint8 ch = uptr->u5; /* get current status */
uptr->u3 &= ~(LPR_CMDMSK); /* clear command */
chan_write_byte(chsa, &ch); /* write the status to memory */
uptr->u6 = 0; /* reset to beginning of buffer */
chan_end(chsa, SNS_DEVEND|SNS_CHNEND); /* we are done */
return SCPE_OK;
}
/* process any CC before printing buffer */
if ((uptr->u3 & LPR_PRE) && (((cmd & 0x03) == 0x03) || (cmd & 0x0d) == 0x0d)) {
uptr->u3 &= ~LPR_PRE; /* remove pre flag */
/* we have CC to do */
switch ((cmd & 0xf0) >> 4) {
case 0: /* <CR> (0x0d) */
lpr_data[u].lbuff[uptr->u6++] = 0x0d;
break;
case 3: /* <LF> <LF> <LF> */
lpr_data[u].lbuff[uptr->u6++] = 0x0a;
uptr->u4++; /* increment the line count */
/* drop thru */
case 2: /* <LF> <LF> */
lpr_data[u].lbuff[uptr->u6++] = 0x0a;
uptr->u4++; /* increment the line count */
/* drop thru */
case 1: /* <LF> (0x0a) */
lpr_data[u].lbuff[uptr->u6++] = 0x0a;
uptr->u4++; /* increment the line count */
break;
case 4: /* <FF> (0x0c) */
lpr_data[u].lbuff[uptr->u6++] = 0x0c;
uptr->u4 = 0; /* restart line count */
break;
}
}
/* Copy next byte from users buffer */
if ((uptr->u3 & LPR_FULL) == 0) { /* copy in a char if not full */
if(chan_read_byte(chsa, &lpr_data[u].lbuff[uptr->u6])) {
uptr->u3 |= LPR_FULL; /* end of buffer or error */
} else {
sim_activate(uptr, 20); /* got a char, wait for a while */
uptr->u6++; /* next buffer loc */
return SCPE_OK; /* done til next char */
}
}
/* process any CC after printing buffer */
if ((uptr->u3 & LPR_FULL) && (uptr->u3 & LPR_POST) && ((cmd & 0x0d) == 0x0d)) {
/* we have CC to do */
uptr->u3 &= ~LPR_POST; /* remove post flag */
lpr_data[u].lbuff[uptr->u6++] = 0x0d; /* just a <CR> */
}
/* process any CC after printing buffer */
if ((uptr->u3 & LPR_FULL) && (uptr->u3 & LPR_POST) && ((cmd & 0x05) == 0x05)) {
/* we have CC to do */
uptr->u3 &= ~LPR_POST; /* remove post flag */
switch ((cmd & 0xf0) >> 4) {
case 0: /* <CR> (0x0d) */
lpr_data[u].lbuff[uptr->u6++] = 0x0d;
break;
case 3: /* <LF> <LF> <LF> */
lpr_data[u].lbuff[uptr->u6++] = 0x0a;
/* drop thru */
case 2: /* <LF> <LF> */
lpr_data[u].lbuff[uptr->u6++] = 0x0a;
/* drop thru */
case 1: /* <LF> (0x0a) */
lpr_data[u].lbuff[uptr->u6++] = 0x0a;
break;
case 4: /* <FF> (0x0c) */
lpr_data[u].lbuff[uptr->u6++] = 0x0c;
uptr->u4 = 0; /* restart line count */
break;
}
}
/* print the line if buffer is full */
if (uptr->u3 & LPR_FULL || uptr->u6 >= 156) {
lpr_data[u].lbuff[uptr->u6] = 0x00; /* NULL terminate */
sim_fwrite(&lpr_data[u].lbuff, 1, uptr->u6, uptr->fileref); /* Print our buffer */
sim_debug(DEBUG_DETAIL, &lpr_dev, "LPR %s", &lpr_data[u].lbuff);
uptr->u3 &= ~(LPR_FULL|LPR_CMDMSK); /* clear old status */
uptr->u6 = 0; /* start at beginning of buffer */
uptr->u4++; /* increment the line count */
if (uptr->u4 > uptr->capac) { /* see if at max lines/page */
uptr->u4 = 0; /* yes, restart count */
chan_end(chsa, SNS_DEVEND|SNS_CHNEND|SNS_UNITEXP); /* we are done */
} else
chan_end(chsa, SNS_DEVEND|SNS_CHNEND); /* we are done */
sim_activate(uptr, 3000); /* wait a long time for next look */
return SCPE_OK;
}
sim_activate(uptr, 20); /* got a char, wait for a while */
return SCPE_OK;
}
/* print a line to the "printer" */
void print_line(UNIT *uptr)
{
char out[150]; /* Temp conversion buffer */
int i;
int u = (uptr - lpr_unit);
/* Try to convert to text */
memset(out, ' ', sizeof(out));
/* Scan each column */
for (i = 0; i < uptr->u6; i++) {
int ch = lpr_data[u].lbuff[i];
if (!isprint(ch)) /* make sure char is printable */
ch = '.'; /* not printable, make it a '.' */
out[i] = ch; /* save to buffer */
}
for (--i; i > 0 && out[i] == ' '; i--) /* Trim trailing spaces */
;
out[++i] = '\r'; /* output CR, LF. NULL */
out[++i] = '\n';
out[++i] = '\0';
sim_fwrite(&out, 1, i, uptr->fileref); /* Print our buffer */
sim_debug(DEBUG_DETAIL, &lpr_dev, "%s", out);
memset(&lpr_data[u].lbuff[0], 0, 144); /* clear the output buffer */
}
/* Set the number of lines per page on printer */
t_stat lpr_setlpp(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int i;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
i = 0;
while(*cptr != '\0') {
if (*cptr < '0' || *cptr > '9')
return SCPE_ARG;
i = (i * 10) + (*cptr++) - '0';
}
if (i < 20 || i > 100)
return SCPE_ARG;
uptr->capac = i;
uptr->u4 = 0;
return SCPE_OK;
}
/* display the number of lines per page */
t_stat lpr_getlpp(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
{
if (uptr == NULL)
return SCPE_IERR;
fprintf(st, "linesperpage=%d", uptr->capac);
return SCPE_OK;
}
/* attach a file to the line printer device */
t_stat lpr_attach(UNIT * uptr, CONST char *file)
{
t_stat r;
if ((r = attach_unit(uptr, file)) != SCPE_OK)
return r;
uptr->u3 &= ~(LPR_FULL|LPR_CMDMSK);
uptr->u4 = 0;
uptr->u5 = 0;
return SCPE_OK;
}
/* detach a file from the line printer */
t_stat lpr_detach(UNIT * uptr)
{
if (uptr->u3 & LPR_FULL)
print_line(uptr);
return detach_unit(uptr);
}
#endif

File diff suppressed because it is too large Load Diff

1137
SEL32/sel32_scfi.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff