1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-13 07:19:26 +00:00
rcornwell.sims/SEL32/sel32_con.c
AZBevier d198882980 SEL32: Correct real time clock interrupt processing.
SEL32: start code cleanup.
SEL32: add mfp and mfp scsi disk intitial support code.
SEL32: add new files sel32_mfp.c and sel32_scsi.c to makefile.
SEL32: modify sel32_mt.c code to define tape as BTP for UTX.
2020-03-06 21:41:59 -07:00

674 lines
31 KiB
C

/* sel32_con.c: SEL 32 Class F IOP processor console.
Copyright (c) 2018-2020, 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.
Change History:
12/10/2018 - force input chars to upper case if lower case
07/18/2019 - generate interrupt for INCH/NOP commands for UTX
*/
#include "sel32_defs.h"
#include "sim_tmxr.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);
extern int test_write_byte_end(uint16 chsa);
extern DEVICE *get_dev(UNIT *uptr);
extern t_stat set_inch(UNIT *uptr, uint32 inch_addr); /* set channel inch address */
extern CHANP *find_chanp_ptr(uint16 chsa); /* find chanp pointer */
#define CMD u3
/* Held in u3 is the device command and status */
#define CON_INCH 0x00 /* Initialize channel command */
#define CON_INCH2 0xf0 /* Initialize channel command for processing */
#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 */
#define SNS u5
/* 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 incnt; /* char count */
uint8 ibuff[145]; /* Input line buffer */
}
con_data[NUM_UNITS_CON];
uint32 atbuf=0; /* attention buffer */
/* forward definitions */
uint8 con_preio(UNIT *uptr, uint16 chan);
uint8 con_startcmd(UNIT*, uint16, uint8);
void con_ini(UNIT*, t_bool);
t_stat con_srvi(UNIT*);
t_stat con_srvo(UNIT*);
uint8 con_haltio(UNIT *);
t_stat con_poll(UNIT *);
t_stat con_reset(DEVICE *);
/* 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_IDLE, 0), 0, UNIT_ADDR(0x7EFC)}, /* Input */
{UDATA(&con_srvo, UNIT_IDLE, 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 = {
con_preio, /* uint8 (*pre_io)(UNIT *uptr, uint16 chan)*/ /* Start I/O */
con_startcmd, /* uint8 (*start_cmd)(UNIT *uptr, uint16 chan, uint8 cmd)*/ /* Start a command */
con_haltio, /* 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, &con_reset, 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 = get_dev(uptr);
uptr->u4 = 0; /* no input count */
con_data[unit].incnt = 0; /* no input data */
// con_data[0].incnt = 0; /* no input data */
// con_data[1].incnt = 0; /* no output data */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 1000); /* time increment */
}
/* start a console operation */
uint8 con_preio(UNIT *uptr, uint16 chan)
{
DEVICE *dptr = get_dev(uptr);
int unit = (uptr - dptr->units);
if ((uptr->CMD & 0xff00) != 0) { /* just return if busy */
sim_debug(DEBUG_CMD, &con_dev, "con_preio unit=%02x BUSY\n", unit);
return SNS_BSY;
}
sim_debug(DEBUG_CMD, &con_dev, "con_preio unit=%02x OK\n", unit);
return 0; /* good to go */
}
/* 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->CMD & CON_MSK) != 0) { /* is unit busy */
sim_debug(DEBUG_CMD, &con_dev,
"con_startcmd unit %01x chan %02x cmd %02x BUSY cmd %02x\n",
unit, chan, cmd, uptr->CMD);
return SNS_BSY; /* yes, return busy */
}
sim_debug(DEBUG_CMD, &con_dev,
"con_startcmd unit %01x chan %02x cmd %02x enter\n", unit, chan, cmd);
/* process the commands */
switch (cmd & 0xFF) {
case CON_INCH: /* 0x00 */ /* INCH command */
sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %04x: Cmd INCH\n", chan);
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= CON_INCH2; /* save INCH command as 0xf0 */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 20); /* start us off */
return 0; /* no status change */
break;
case CON_RWD: /* 0x37 */ /* TOF and write line */
case CON_WR: /* 0x01 */ /* Write command */
/* if input requested for output device, give error */
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 20); /* start us off */
return 0; /* no status change */
break;
case CON_RD: /* 0x02 */ /* Read command */
case CON_ECHO: /* 0x0a */ /* Read command w/ECHO */
/* if output requested for input device, give error */
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
if (cmd == CON_ECHO) /* echo command? */
uptr->CMD |= CON_EKO; /* save echo status */
uptr->CMD |= CON_READ; /* show read mode */
atbuf = 0; /* reset attention buffer */
uptr->u4 = 0; /* no I/O yet */
con_data[unit].incnt = 0; /* clear any input data */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
sim_activate(uptr, 20); /* start us off */
return 0;
break;
case CON_NOP: /* 0x03 */ /* NOP has do nothing */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
// uptr->u4 = 0; /* no I/O yet */
// con_data[unit].incnt = 0; /* clear any input data */
sim_activate(uptr, 20); /* start us off */
return 0; /* no status change */
break;
#ifndef JUNK
case 0x0C: /* 0x0C */ /* Unknown command */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
uptr->CMD &= LMASK; /* leave only chsa */
uptr->CMD |= (cmd & CON_MSK); /* save command */
sim_activate(uptr, 20); /* start us off */
return 0; /* no status change */
break;
#endif
case CON_CON: /* 0x1f */ /* Connect, return Data Set ready */
sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %04x: Cmd %02x CON\n", chan, cmd);
uptr->SNS |= (SNS_DSR|SNS_DCD); /* Data set ready, Data Carrier detected */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case CON_DIS: /* 0x23 */ /* Disconnect has do nothing */
sim_debug(DEBUG_CMD, &con_dev, "con_startcmd %04x: Cmd %02x DIS\n", chan, cmd);
uptr->SNS &= ~(SNS_DSR|SNS_DCD); /* Data set not ready */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
case CON_SNS: /* 0x04 */ /* Sense */
sim_debug(DEBUG_CMD, &con_dev,
"con_startcmd %04x: Cmd Sense %02x\n", chan, uptr->SNS);
/* value 4 is Data Set Ready */
/* value 5 is Data carrier detected n/u */
ch = uptr->SNS; /* status */
chan_write_byte(GET_UADDR(uptr->CMD), &ch); /* write status */
return SNS_CHNEND|SNS_DEVEND; /* good return */
break;
default: /* invalid command */
break;
}
/* invalid command */
uptr->SNS |= SNS_CMDREJ; /* command rejected */
// uptr->u4 = 0; /* no I/O yet */
// con_data[unit].incnt = 0; /* clear any input data */
sim_debug(DEBUG_CMD, &con_dev,
"con_startcmd %04x: Invalid command %02x Sense %02x\n",
chan, cmd, uptr->SNS);
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* unit check */
}
/* Handle output transfers for console */
t_stat con_srvo(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->CMD);
int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */
int cmd = uptr->CMD & CON_MSK;
CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
uint8 ch, cp;
sim_debug(DEBUG_DETAIL, &con_dev, "con_srvo enter chsa %04x cmd = %02x\n", chsa, cmd);
/* if input tried from output device, error */
if ((cmd == CON_RD) || (cmd == CON_ECHO) || (cmd == 0xC0)) { /* check for output */
/* CON_RD: 0x02 */ /* Read command */
/* CON_ECHO: 0x0a */ /* Read command w/ECHO */
/* if input requested for output device, give error */
if (unit == 1) {
uptr->SNS |= SNS_CMDREJ; /* command rejected */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo Read to output device chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* unit check */
return SCPE_OK;
}
}
if ((cmd == CON_NOP) || (cmd == CON_INCH2)) { /* NOP has to do nothing */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo INCH/NOP unit %02x: cmd %02x incnt %02x u4 %02x\n",
unit, cmd, con_data[unit].incnt, uptr->u4);
if (cmd == CON_INCH2) { /* Channel end only for INCH */
int len = chp->ccw_count; /* INCH command count */
uint32 mema = chp->ccw_addr; /* get inch or buffer addr */
// int i = set_inch(uptr, mema); /* new address */
set_inch(uptr, mema); /* new address */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo INCH chsa %04x len %02x inch %06x\n", chsa, len, mema);
chan_end(chsa, SNS_CHNEND); /* INCH done */
} else {
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo NOP chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
}
return SCPE_OK;
}
if ((cmd == CON_WR) || (cmd == CON_RWD)) {
/* Write to device */
if (chan_read_byte(chsa, &ch)) { /* get byte from memory */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo write %02x chsa %04x cmd %02x complete\n",
ch, chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
} else {
/* HACK HACK HACK */
ch &= 0x7f; /* make 7 bit w/o parity */
/* simh stops outputting chars to debug file if it is passed a null????? */
if (ch == 0) /* do not pass a null char */
//WAS ch = '@'; /* stop simh abort .... */
ch = ' '; /* stop simh abort .... */
#ifndef ALLOW_ESC
if (((ch >= 0x20) && (ch <= 0x7e)) || (ch == '\r') || (ch == '\n'))
cp = ch;
else
cp = '^';
sim_debug(DEBUG_CMD, &con_dev,
"con_srvo write %01x: putch 0x%02x %c\n", unit, ch, cp);
sim_putchar(ch); /* output next char to device */
//OLD sim_putchar(cp); /* output next char to device */
#else
sim_putchar(ch); /* output next char to device */
//WAS sim_putchar(cp); /* output next char to device */
#endif
sim_activate(uptr, 20); /* keep going */
}
}
return SCPE_OK;
}
/* Handle input transfers for console */
t_stat con_srvi(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->CMD);
int unit = (uptr - con_unit); /* unit 0 is read, unit 1 is write */
int cmd = uptr->CMD & CON_MSK;
CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
uint8 ch;
t_stat r;
sim_debug(DEBUG_DETAIL, &con_dev,
"con_srvi enter chsa %04x cmd %02x ccw_count %02x\n", chsa, cmd, chp->ccw_count);
/* if output tried to input device, error */
if ((cmd == CON_RWD) || (cmd == CON_WR) || (cmd == 0x0C)) { /* check for output */
/* CON_RWD: 0x37 */ /* TOF and write line */
/* CON_WR: 0x01 */ /* Write command */
/* if input requested for output device, give error */
if (unit == 0) {
uptr->SNS |= SNS_CMDREJ; /* command rejected */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi Write to input device chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* unit check */
// fall thru return SCPE_OK;
}
}
#ifdef JUNK
if (cmd == 0x0C) { /* unknown has to do nothing */
sim_debug(DEBUG_CMD, &con_dev, "con_srvi Unknown (0x0C) chsa %04x cmd = %02x\n", chsa, cmd);
uptr->CMD &= LMASK; /* command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
return SCPE_OK;
}
#endif
if ((cmd == CON_NOP) || (cmd == CON_INCH2)) { /* NOP is do nothing */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi INCH/NOP unit %02x: cmd %02x incnt %02x u4 %02x\n",
unit, cmd, con_data[unit].incnt, uptr->u4);
if (cmd == CON_INCH2) { /* Channel end only for INCH */
int len = chp->ccw_count; /* INCH command count */
uint32 mema = chp->ccw_addr; /* get inch or buffer addr */
// int i = set_inch(uptr, mema); /* new address */
set_inch(uptr, mema); /* new address */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi INCH chsa %04x len %02x inch %06x\n", chsa, len, mema);
//TRY228 chan_end(chsa, SNS_CHNEND); /* INCH done */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
} else {
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi NOP chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* NOP done */
}
/* drop through to poll input */
}
#define MOVE_CODE
#ifdef MOVE_CODE
switch (cmd) {
case CON_RD: /* 0x02 */ /* read from device */
case CON_ECHO: /* 0x0a */ /* read from device w/ECHO */
if (uptr->CMD & CON_INPUT) { /* input waiting? */
int len = chp->ccw_count; /* get command count */
ch = con_data[unit].ibuff[uptr->u4++]; /* get char from read buffer */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi readbuf unit %02x: read %02x incnt %02x u4 %02x len %02x\n",
unit, ch, con_data[unit].incnt, uptr->u4, len);
if (chan_write_byte(chsa, &ch)) { /* write byte to memory */
con_data[unit].incnt = 0; /* buffer empty */
cmd = 0; /* no cmd either */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi write to mem unit %02x: read %02x u4 %02x ccw_count %02x\n",
unit, ch, uptr->u4, chp->ccw_count);
uptr->u4 = 0; /* no I/O yet */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
} else {
if (test_write_byte_end(chsa)) { /* see if read request complete */
// len = chp->ccw_count; /* INCH command count */
// if ((len==0) && uptr->u4 == con_data[unit].incnt) { /* read completed */
// if (uptr->u4 == con_data[unit].incnt) { /* read completed */
con_data[unit].incnt = 0; /* buffer is empty */
cmd = 0; /* no cmd either */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi write nothing to mem unit %02x: u4 %02x ccw_count %02x\n",
unit, uptr->u4, chp->ccw_count);
uptr->u4 = 0; /* no I/O yet */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
}
}
}
// default:
break;
}
#endif
/* check for next input if reading or @@A sequence */
r = sim_poll_kbd(); /* poll for a char */
if (r & SCPE_KFLAG) { /* got a char */
ch = r & 0xff; /* drop any extra bits */
#ifdef LEAVE_LOWER
if ((ch >= 'a') && (ch <= 'z'))
ch &= 0xdf; /* make upper case */
#endif
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 */
#define DO_NO_CASE
#ifdef DO_NO_CASE
/* Handle end of buffer */
switch (ch) {
#ifdef ONE_AT_A_TIME
case 0x7f: /* Delete */
case '\b': /* backspace 0x08 */
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;
#endif
case '\r': /* return */
case '\n': /* newline */
uptr->CMD |= CON_CR; /* C/R received */
/* fall through */
default:
#endif /* DO_NO_CASE */
#ifdef MOVE_CODE
if (con_data[unit].incnt < sizeof(con_data[unit].ibuff)) {
if (uptr->CMD & CON_EKO) /* ECHO requested */
sim_putchar(ch); /* ECHO the char */
con_data[unit].ibuff[con_data[unit].incnt++] = ch;
uptr->CMD |= CON_INPUT; /* we have a char available */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi readch unit %02x: read %02x u4 %02x ccw_count %02x\n",
unit, ch, uptr->u4, chp->ccw_count);
#else
//MOVE if (con_data[unit].incnt < sizeof(con_data[unit].ibuff)) {
if (uptr->CMD & CON_EKO) /* ECHO requested */
sim_putchar(ch); /* ECHO the char */
//MOVE con_data[unit].ibuff[con_data[unit].incnt++] = ch;
//MOVE uptr->CMD |= CON_INPUT; /* we have a char available */
#endif
#ifndef MOVE_CODE
// CON_RD: /* 0x02 */ /* read from device */
// CON_ECHO: /* 0x0a */ /* read from device w/ECHO */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi unit %02x: read %02x u4 %02x ccw_count %02x\n",
unit, ch, uptr->u4, chp->ccw_count);
if (chan_write_byte(chsa, &ch)) { /* write byte to memory */
cmd = 0; /* no cmd left */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
} else
//WAS if (chp->ccw_count == 0) {
if (test_write_byte_end(chsa)) { /* see if read request complete */
cmd = 0; /* no cmd left */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
}
/* We are still looking for input */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi still looking unit %02x: read %02x u4 %02x ccw_count %02x\n",
unit, ch, uptr->u4, chp->ccw_count);
#else
}
#endif
#ifdef DO_NO_CASE
break;
}
#endif /* DO_NO_CASE */
} 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 */
sim_debug(DEBUG_CMD, &con_dev,
"con_srvi unit %02x: read @@A Console Trap\n", unit);
}
} 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 ((r & SCPE_KFLAG) && /* got something and */
((cmd == CON_RD) || (cmd == CON_ECHO))) /* looking for input */
//WAS return sim_activate (uptr, 20);
//WAS2 return sim_activate (uptr, 100);
//WAS3 return sim_activate (uptr, 50);
//LAST return sim_activate (uptr, 200);
return sim_activate (uptr, 40);
//TRY return sim_activate (uptr, 500);
return tmxr_clock_coschedule_tmr (uptr, TMR_RTC, 1); /* come back soon */
}
t_stat con_reset(DEVICE *dptr) {
tmxr_set_console_units (&con_unit[0], &con_unit[1]);
return SCPE_OK;
}
/* Handle haltio transfers for console */
uint8 con_haltio(UNIT *uptr) {
uint16 chsa = GET_UADDR(uptr->CMD);
int cmd = uptr->CMD & CON_MSK;
int unit = (uptr - con_unit); /* unit # 0 is read, 1 is write */
uint8 ch = 0x20; /* dummy space char for outstanding input */
CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
// int len = chp->ccw_count; /* command byte count */
sim_debug(DEBUG_EXP, &con_dev, "con_haltio enter chsa %04x cmd = %02x\n", chsa, cmd);
#ifdef DO_DYNAMIC_DEBUG
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
con_dev.dctrl |= (DEBUG_CMD | DEBUG_EXP | DEBUG_DETAIL);
#endif
/* terminate any input command */
if ((uptr->CMD & CON_MSK) != 0) { /* is unit busy */
sim_debug(DEBUG_CMD, &con_dev,
"con_haltio HIO chsa %04x cmd = %02x ccw_count %02x\n", chsa, cmd, chp->ccw_count);
if (unit == 0) {
// new code 2/28/2020
if (test_write_byte_end(chsa)) { /* see if read request complete */
chan_write_byte(chsa, &ch); /* write fake byte to memory */
con_data[unit].incnt = 0; /* buffer empty */
uptr->CMD &= LMASK; /* nothing left, command complete */
// chp->ccw_count = 0; /* zero command count */
sim_debug(DEBUG_CMD, &con_dev,
"con_haltio HIO I/O stop chsa %04x cmd %02x ccw_count %02x\n",
chsa, cmd, chp->ccw_count);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
// return SCPE_OK; /* not busy anymore */
return SCPE_IOERR;
}
#ifdef NOT_NOW
else
if (chan_write_byte(chsa, &ch)) { /* write fake byte to memory */
con_data[unit].incnt = 0; /* buffer is empty */
sim_debug(DEBUG_CMD, &con_dev,
"con_haltio write nothing to mem unit %02x: u4 %02x ccw_count %02x\n",
unit, uptr->u4, chp->ccw_count);
uptr->u4 = 0; /* no I/O yet */
uptr->CMD &= LMASK; /* nothing left, command complete */
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
//WAS return SCPE_IOERR;
}
#endif
} else {
if (chp->ccw_count > 0) {
if (chan_read_byte(chsa, &ch)) { /* get byte from memory */
uptr->CMD &= LMASK; /* nothing left, command complete */
sim_debug(DEBUG_CMD, &con_dev,
"con_haltio HIO I/O stop chsa %04x cmd = %02x\n", chsa, cmd);
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* done */
// return SCPE_OK; /* not busy anymore */
return SCPE_IOERR;
}
}
}
uptr->CMD &= LMASK; /* make non-busy */
uptr->SNS = SNS_RDY|SNS_ONLN; /* status is online & ready */
return SCPE_OK; /* not busy */
//no work chan_end(chsa, SNS_CHNEND|SNS_UNITCHK); /* write terminated */
// chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); /* write terminated */
// chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); /* done bit 15 */ /* bad status */
// return SCPE_IOERR;
}
return SCPE_OK; /* not busy */
}
#endif