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:
committed by
Richard Cornwell
parent
c27809c194
commit
d3d4e808cc
2077
SEL32/sel32_chan.c
2077
SEL32/sel32_chan.c
File diff suppressed because it is too large
Load Diff
367
SEL32/sel32_clk.c
Normal file
367
SEL32/sel32_clk.c
Normal 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
899
SEL32/sel32_com.c
Normal 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
370
SEL32/sel32_con.c
Normal 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
|
||||
|
||||
7634
SEL32/sel32_cpu.c
7634
SEL32/sel32_cpu.c
File diff suppressed because it is too large
Load Diff
@@ -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
1165
SEL32/sel32_disk.c
Normal file
File diff suppressed because it is too large
Load Diff
199
SEL32/sel32_iop.c
Normal file
199
SEL32/sel32_iop.c
Normal 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
465
SEL32/sel32_lpr.c
Normal 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
|
||||
1118
SEL32/sel32_mt.c
1118
SEL32/sel32_mt.c
File diff suppressed because it is too large
Load Diff
1137
SEL32/sel32_scfi.c
Normal file
1137
SEL32/sel32_scfi.c
Normal file
File diff suppressed because it is too large
Load Diff
1984
SEL32/sel32_sys.c
1984
SEL32/sel32_sys.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user