diff --git a/IBM360/ibm360_defs.h b/IBM360/ibm360_defs.h index f9e1bbd..28ca54a 100644 --- a/IBM360/ibm360_defs.h +++ b/IBM360/ibm360_defs.h @@ -70,6 +70,8 @@ #define NUM_UNITS_DASD 8 #define NUM_DEVS_COM 1 #define NUM_UNITS_COM 16 +#define NUM_DEVS_SCOM 1 +#define NUM_UNITS_SCOM 8 /* Device information block */ typedef struct dib { @@ -381,6 +383,8 @@ extern DEVICE ddc_dev; extern DEVICE ddd_dev; extern DEVICE coml_dev; extern DEVICE com_dev; +extern DEVICE scoml_dev; +extern DEVICE scom_dev; extern UNIT cpu_unit[]; extern void fprint_inst(FILE *, uint16 *); diff --git a/IBM360/ibm360_scom.c b/IBM360/ibm360_scom.c new file mode 100644 index 0000000..039c75a --- /dev/null +++ b/IBM360/ibm360_scom.c @@ -0,0 +1,647 @@ +/* ibm360_scom.c: IBM 360 3271 scommunications controller + + Copyright (c) 2017-2020, Richard Cornwell + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +*/ + +#include "ibm360_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +#ifdef NUM_DEVS_COM +#define UNIT_COM 0 + + + +/* u3 */ +#define CMD_WR 0x01 /* Write data to com line */ +#define CMD_RD 0x02 /* Read buffer */ +#define CMD_NOP 0x03 /* Nop scommand */ +#define CMD_WRER 0x05 /* Erase and write data */ +#define CMD_RDMD 0x06 /* Read modified */ +#define CMD_SEL 0x0B /* Select */ +#define CMD_EAU 0x0F /* Erase all un protected */ + +/* u3 second byte */ +#define RECV 0x00100 /* Recieving data */ +#define SEND 0x00200 /* Sending data */ +#define ENAB 0x00400 /* Line enabled */ +#define DATA 0x00800 /* Data available */ +#define INIT1 0x01000 /* Send DO EOR, waiting WILL EOR */ +#define INPUT 0x02000 /* Input ready */ +#define ATTN 0x04000 /* Send attention signal */ +#define HALT 0x08000 /* Halt operation */ + +/* Upper 11 bits of u3 hold the device address */ + +/* u4 */ +/* Where we are reading from */ + +/* u5 */ +/* 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_UNITSPC 0x04 /* Specific to unit */ +#define SNS_CTLCHK 0x02 /* Timeout on device */ +#define SNS_OPRCHK 0x01 /* Invalid operation to device */ + +/* u6 */ +/* Pointer into buffer */ + +#define CMD u3 +#define IPTR u4 +#define SNS u5 +#define BPTR u6 + +#define TC_WILL 0x1 /* Option in will state */ +#define TC_WONT 0x2 /* Wont do option */ +#define TC_DO 0x4 /* Will do option. */ +#define TC_DONT 0x8 /* Dont do option */ + +#define IAC 255 /* Interpret as command */ +#define DONT 254 /* Dont use option */ +#define DO 253 /* Use this option */ +#define WONT 252 /* I wont use this option */ +#define WILL 251 /* I will use this option */ +#define IP 244 /* Interrupt pending */ +#define BREAK 243 /* Break */ +#define EOR 239 /* End of record */ + +/* Telnet options we care about */ +#define OPTION_BINARY 0 /* Send 8 bit data */ +#define OPTION_ECHO 1 /* Echo */ +#define OPTION_SGA 3 /* Set go ahead */ +#define OPTION_TERMINAL 24 /* Request terminal type */ +#define OPTION_EOR 25 /* Handle end of record */ + +#define TS_DATA 0 /* Regular state */ +#define TS_IAC 1 /* Have seen IAC */ +#define TS_WILL 2 /* Have seen IAC WILL */ +#define TS_WONT 3 /* Have seen IAC WONT */ +#define TS_DO 4 /* Have seen IAC DO */ +#define TS_DONT 5 /* Have seen IAC DONT */ + +/* Remove orders */ +#define REMOTE_EAU 0x6F /* Erase all unprotected */ +#define REMOTE_EW 0xF5 /* Erase/Write */ +#define REMOTE_RB 0xF2 /* Read Buffer */ +#define REMOTE_RM 0x6e /* Read Modified */ +#define REMOTE_WRT 0xF1 /* Write */ + +struct _line { + uint16 option_state[256]; /* Current telnet state */ + uint8 state; /* Current line status */ +} line_data[NUM_UNITS_SCOM]; + +extern int32 tmxr_poll; + +uint8 scoml_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) ; +uint8 scoml_haltio(UNIT *uptr); +t_stat scoml_srv(UNIT *uptr); +t_stat scom_reset(DEVICE *dptr); +t_stat scom_scan(UNIT *uptr); +t_stat scom_readinput(UNIT *uptr); +void scom_sendoption(UNIT *uptr, int unit, uint8 state, uint8 opt); +t_stat scom_attach(UNIT *uptr, CONST char *); +t_stat scom_detach(UNIT *uptr); +t_stat scom_help (FILE *, DEVICE *, UNIT *, int32, const char *); +const char *scom_description (DEVICE *); + +uint8 scom_buf[NUM_UNITS_SCOM][256]; +TMLN scom_ldsc[NUM_UNITS_SCOM]; +TMXR scom_desc = { NUM_UNITS_SCOM, 0, 0, scom_ldsc}; + + +MTAB scom_mod[] = { + {0} +}; + +MTAB scoml_mod[] = { + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr, + &show_dev_addr, NULL}, + {0} +}; + +UNIT scom_unit[] = { + {UDATA(&scom_scan, UNIT_ATTABLE | UNIT_IDLE, 0)}, /* Line scanner */ +}; + +UNIT scoml_unit[] = { + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x050)}, /* 0 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x051)}, /* 1 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x052)}, /* 2 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x053)}, /* 3 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x054)}, /* 4 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x055)}, /* 5 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x056)}, /* 6 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x057)}, /* 7 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x058)}, /* 8 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x059)}, /* 9 */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x05A)}, /* A */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x05B)}, /* B */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x05C)}, /* C */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x05D)}, /* D */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x05E)}, /* E */ + {UDATA(&scoml_srv, UNIT_COM, 0), 0, UNIT_ADDR(0x05F)}, /* F */ +}; + +struct dib scom_dib = { 0xF0, NUM_UNITS_SCOM, NULL, scoml_startcmd, + scoml_haltio, scoml_unit, NULL}; + +DEVICE scom_dev = { + "SCOM", scom_unit, NULL, scom_mod, + NUM_DEVS_SCOM, 8, 15, 1, 8, 8, + NULL, NULL, scom_reset, NULL, &scom_attach, &scom_detach, + NULL, DEV_MUX | DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, &scom_help, NULL, NULL, &scom_description +}; + +DEVICE scoml_dev = { + "SCOML", scoml_unit, NULL, scoml_mod, + NUM_UNITS_SCOM, 8, 15, 1, 8, 8, + NULL, NULL, NULL, NULL, NULL, NULL, + &scom_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug +}; + + +/* + * Issue a scommand to the 2701 controller. + */ +uint8 scoml_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) { + uint16 addr = GET_UADDR(uptr->CMD); + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + + sim_debug(DEBUG_CMD, dptr, "CMD unit=%d %x\n", unit, cmd); + if ((uptr->CMD & 0xff) != 0) { + return SNS_BSY; + } + + + switch (cmd & 0x3) { + case 0x2: /* Read scommand */ + case 0x1: /* Write scommand */ + case 0x3: /* Control */ + if (cmd != CMD_NOP) + uptr->SNS = 0; + uptr->CMD |= cmd; + sim_activate(uptr, 200); + return 0; + + case 0x0: /* Status */ + if (cmd == 0x4) { /* Sense */ + uptr->CMD |= cmd; + sim_activate(uptr, 200); + return 0; + } + break; + } + if (uptr->SNS & 0xff) + return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; + return SNS_CHNEND|SNS_DEVEND; +} + +/* + * Handle halt I/O instruction by stoping running scommand. + */ +uint8 scoml_haltio(UNIT *uptr) { + uint16 addr = GET_UADDR(uptr->CMD); + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + int cmd = uptr->CMD & 0xff; + + sim_debug(DEBUG_CMD, dptr, "HLTIO unit=%d %x\n", unit, cmd); + if ((scom_unit[0].flags & UNIT_ATT) == 0) /* attached? */ + return 3; + + switch (cmd) { + case 0: + case 0x4: + case CMD_SEL: /* Select */ + case CMD_NOP: /* Nop scommand */ + /* Short scommands nothing to do */ + break; + + case CMD_WR: /* Write data to com line */ + case CMD_RD: /* Read buffer */ + case CMD_WRER: /* Erase and write data */ + case CMD_RDMD: /* Read modified */ + case CMD_EAU: /* Erase all un protected */ + uptr->CMD |= HALT; + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + sim_activate(uptr, 20); + break; + } + return 1; +} + +/* Handle per unit scommands */ +t_stat scoml_srv(UNIT * uptr) +{ + uint16 addr = GET_UADDR(uptr->CMD); + DEVICE *dptr = find_dev_from_unit(uptr); + int unit = (uptr - dptr->units); + int cmd = uptr->CMD & 0xff; + uint8 ch; + + if ((uptr->CMD & (RECV|DATA)) != 0) { + sim_activate(uptr, 200); + return scom_readinput(uptr); + } + + switch (cmd) { + case 0: + break; + + case 0x4: + ch = uptr->SNS & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "sense unit=%d 1 %x\n", unit, ch); + chan_write_byte(addr, &ch) ; + uptr->CMD &= ~0xff; + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + break; + + case CMD_RDMD: /* Read modified */ + case CMD_RD: /* Read in data from scom line */ + uptr->SNS = 0; + if (uptr->CMD & HALT) { + uptr->CMD &= ~(0xFF|RECV); + return SCPE_OK; + } + if (uptr->CMD & ENAB) { + if (scom_ldsc[unit].conn == 0) { + sim_debug(DEBUG_DETAIL, dptr, "unit=%d disco\n", unit); + uptr->CMD &= ~(0xff|INPUT|ENAB|RECV|INIT1|SEND|DATA); + uptr->SNS = SNS_CTLCHK; + uptr->BPTR = 0; + uptr->IPTR = 0; + chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); + return SCPE_OK; + } + if ((uptr->CMD & RECV) == 0) { + /* Send cmd IAC EOR */ + if (tmxr_rqln(&scom_ldsc[unit]) == 0) { + sim_debug(DEBUG_DETAIL, dptr, "unit=%d Send read cmd %x\n", unit, cmd); + if (cmd == CMD_RD) + tmxr_putc_ln( &scom_ldsc[unit], REMOTE_RB); + else + tmxr_putc_ln( &scom_ldsc[unit], REMOTE_RM); + tmxr_putc_ln( &scom_ldsc[unit], IAC); + tmxr_putc_ln( &scom_ldsc[unit], EOR); + } + uptr->CMD |= RECV; + } + sim_activate(uptr, 200); + } + break; + + + case CMD_WRER: /* Erase and write data */ + ch = REMOTE_EW; + goto write; + + case CMD_EAU: /* Erase all un protected */ + ch = REMOTE_EAU; + goto write; + + case CMD_WR: /* Write data to com line */ + ch = REMOTE_WRT; +write: + uptr->SNS = 0; + if (uptr->CMD & HALT) { + uptr->CMD &= ~(0xFF|SEND); + return SCPE_OK; + } + if (uptr->CMD & ENAB) { + if ((uptr->CMD & SEND) == 0) { + sim_debug(DEBUG_DETAIL, dptr, "unit=%d send write %x\n", unit, ch); + tmxr_putc_ln( &scom_ldsc[unit], ch); + uptr->CMD |= SEND; + } + if (scom_ldsc[unit].conn == 0) { + sim_debug(DEBUG_DETAIL, dptr, "unit=%d disco\n", unit); + uptr->CMD &= ~(0xff|INPUT|ENAB|RECV|INIT1|SEND|DATA); + uptr->SNS = SNS_CTLCHK; + uptr->BPTR = 0; + uptr->IPTR = 0; + chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP); + return SCPE_OK; + } + if (chan_read_byte (addr, &ch)) { + tmxr_putc_ln( &scom_ldsc[unit], IAC); + tmxr_putc_ln( &scom_ldsc[unit], EOR); + uptr->CMD &= ~(0xff| SEND); + sim_debug(DEBUG_CMD, dptr, "COM: unit=%d eor\n", unit); + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + } else { + int32 data; + data = ebcdic_to_ascii[ch]; + sim_debug(DEBUG_CMD, dptr, "COM: unit=%d send %02x '%c'\n", + unit, ch, isprint(data)? data: '^'); + tmxr_putc_ln( &scom_ldsc[unit], ch); + if (ch == IAC) + tmxr_putc_ln( &scom_ldsc[unit], ch); + sim_activate(uptr, 200); + } + } + break; + + case CMD_NOP: /* Nop scommand */ + uptr->CMD &= ~0xff; + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + break; + + case CMD_SEL: /* Select */ + uptr->CMD &= ~0xff; + uptr->SNS = 0; + sim_debug(DEBUG_CMD, dptr, "COM: unit=%d select done\n", unit); + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + break; + } + + return SCPE_OK; +} + +/* Scan for new connections, flush and poll for data */ +t_stat scom_scan(UNIT * uptr) +{ + UNIT *line; + int32 ln; + struct _line *data; + int i; + + sim_activate(uptr, tmxr_poll); /* continue poll */ + if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_OK; + ln = tmxr_poll_conn (&scom_desc); /* look for connect */ + sim_debug(DEBUG_EXP, &scom_dev, "SCOM Poll %d\n", ln); + if (ln >= 0) { /* got one? rcv enb*/ + line = &scoml_unit[ln]; + data = (struct _line *)(line->up7); + sim_debug(DEBUG_DETAIL, &scom_dev, "SCOM line connect %d\n", ln); + scom_ldsc[ln].rcve = 1; /* Mark as ok */ + for (i = 0; i < 256; i++) + data->option_state[i] = 0; + scom_sendoption(line, ln, DO, OPTION_TERMINAL); + scom_sendoption(line, ln, DO, OPTION_EOR); + line->CMD |= ENAB|DATA|INIT1; + line->CMD &= ~(RECV|SEND); + sim_activate(line, 20000); + } + + /* See if a line is disconnected with no scommand on it. */ + for (ln = 0; ln < scom_desc.lines; ln++) { + line = &scoml_unit[ln]; + if ((line->CMD & (SEND|RECV|ENAB)) == ENAB && tmxr_rqln(&scom_ldsc[ln]) > 0) { + if ((line->CMD & (DATA|INIT1)) != 0 || (line->CMD & 0xff) != 0) + sim_activate(line, 200); + else + set_devattn(GET_UADDR(line->CMD), SNS_ATTN); + } + } + tmxr_poll_tx(&scom_desc); + tmxr_poll_rx(&scom_desc); + return SCPE_OK; +} + +/* Process characters from remote */ +t_stat +scom_readinput(UNIT *uptr) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + uint16 addr = GET_UADDR(uptr->CMD); + int unit = (uptr - dptr->units); + int cmd = uptr->CMD & 0xff; + int32 r; + struct _line *data = (struct _line *)(uptr->up7); + uint8 ch; + + while (((r = tmxr_getc_ln (&scom_ldsc[unit])) & TMXR_VALID) != 0) { + ch = r & 0xff; + sim_debug(DEBUG_DETAIL, dptr, "unit=%d got %x\n", unit, ch); + switch (data->state) { + case TS_DATA: + if (ch == IAC) { + data->state = TS_IAC; + break; + } + if (uptr->CMD & RECV) { + if (chan_write_byte( addr, &ch)) { + uptr->CMD &= ~(0xff|RECV); + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + return SCPE_OK; + } + } + break; + case TS_IAC: + switch (ch) { + case WILL: + data->state = TS_WILL; + break; + case WONT: + data->state = TS_WONT; + break; + case DO: + data->state = TS_DO; + break; + case DONT: + data->state = TS_DONT; + break; + case IAC: + data->state = TS_DATA; + if (uptr->CMD & RECV) { + if (chan_write_byte( addr, &ch)) { + uptr->CMD &= ~(0xff|RECV); + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + return SCPE_OK; + } + } + break; + case IP: + case BREAK: + case EOR: + data->state = TS_DATA; + if (uptr->CMD & RECV) { + uptr->CMD &= ~(0xff|RECV); + chan_end(addr, SNS_CHNEND|SNS_DEVEND); + } + break; + } + break; + + case TS_WILL: + switch (ch) { + case OPTION_TERMINAL: /* Ignore terminal option */ + data->option_state[ch] |= TC_WILL|TC_DONT; + break; + + case OPTION_BINARY: + case OPTION_ECHO: + case OPTION_SGA: + case OPTION_EOR: + if ((data->option_state[ch] & TC_WILL) == 0) { + scom_sendoption(uptr, unit, WILL, ch); + if (ch == OPTION_EOR && (uptr->CMD & INIT1) != 0) { + scom_sendoption(uptr, unit, DO, OPTION_BINARY); + } + } + + break; + default: + if ((data->option_state[ch] & TC_DONT) == 0) + scom_sendoption(uptr, unit, DONT, ch); + break; + } + data->state = TS_DATA; + break; + + case TS_WONT: + if ((data->option_state[ch] & TC_WONT) == 0) + scom_sendoption(uptr, unit, WONT, ch); + break; + + case TS_DO: + switch (ch) { + case OPTION_BINARY: + case OPTION_ECHO: + case OPTION_SGA: + case OPTION_EOR: + if ((data->option_state[ch] & TC_WILL) != 0) { + if (ch == OPTION_BINARY) { + uptr->CMD &= ~(DATA|INIT1); + uptr->CMD |= ENAB; + tmxr_putc_ln( &scom_ldsc[unit], REMOTE_EW); + tmxr_putc_ln( &scom_ldsc[unit], 0xc1); + tmxr_putc_ln( &scom_ldsc[unit], IAC); + tmxr_putc_ln( &scom_ldsc[unit], EOR); + if ((uptr->CMD & 0xff) == 0) + set_devattn(addr, SNS_ATTN); + else + sim_activate(uptr, 200); + } + } + if ((data->option_state[ch] & TC_DO) == 0) + scom_sendoption(uptr, unit, DO, ch); + break; + default: + if ((data->option_state[ch] & TC_WONT) == 0) + scom_sendoption(uptr, unit, WONT, ch); + break; + } + data->state = TS_DATA; + break; + case TS_DONT: + if ((data->option_state[ch] & TC_WILL) != 0) { + /* send IAC WONT option */ + data->option_state[ch] &= ~TC_WILL; + scom_sendoption(uptr, unit, WILL, ch); + } + data->state = TS_DATA; + break; + } + } + return SCPE_OK; +} + +void +scom_sendoption(UNIT *uptr, int unit, uint8 state, uint8 opt) +{ + struct _line *data = (struct _line *)(uptr->up7); + + tmxr_putc_ln( &scom_ldsc[unit], IAC); + tmxr_putc_ln( &scom_ldsc[unit], state); + tmxr_putc_ln( &scom_ldsc[unit], opt); + tmxr_send_buffered_data(&scom_ldsc[unit]); + switch(state) { + case WILL: + data->option_state[opt] |= TC_WILL; + break; + case WONT: + data->option_state[opt] |= TC_WONT; + break; + case DO: + data->option_state[opt] |= TC_DO; + break; + case DONT: + data->option_state[opt] |= TC_DONT; + } +} + +t_stat +scom_reset(DEVICE * dptr) +{ + int i; + sim_activate(&scom_unit[0], tmxr_poll); + (void)tmxr_set_notelnet (&scom_desc); + for (i = 0; i < NUM_UNITS_SCOM; i++) + scoml_unit[i].up7 = &line_data[i]; + return SCPE_OK; +} + + +t_stat +scom_attach(UNIT * uptr, CONST char *cptr) +{ + t_stat r; + int i; + + if ((r = tmxr_attach(&scom_desc, uptr, cptr)) != SCPE_OK) + return r; + for (i = 0; i< scom_desc.lines; i++) { + scoml_unit[i].CMD &= ~0xffff; + } + sim_activate(uptr, tmxr_poll); + return SCPE_OK; +} + +t_stat +scom_detach(UNIT * uptr) +{ + t_stat r; + int i; + + for (i = 0; i< scom_desc.lines; i++) { + (void)tmxr_set_get_modem_bits(&scom_ldsc[i], 0, TMXR_MDM_DTR, NULL); + (void)tmxr_reset_ln(&scom_ldsc[i]); + scoml_unit[i].CMD &= ~0xffff; + } + sim_cancel(uptr); + r = tmxr_detach(&scom_desc, uptr); + return r; +} + +t_stat scom_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr) +{ +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +return SCPE_OK; +} + +const char *scom_description (DEVICE *dptr) +{ +return "IBM 3271 communications controller"; +} + +#endif diff --git a/IBM360/ibm360_sys.c b/IBM360/ibm360_sys.c index 533efd2..730b108 100644 --- a/IBM360/ibm360_sys.c +++ b/IBM360/ibm360_sys.c @@ -80,6 +80,10 @@ DEVICE *sim_devices[] = { #ifdef NUM_DEVS_COM &coml_dev, &com_dev, +#endif +#ifdef NUM_DEVS_SCOM + &scoml_dev, + &scom_dev, #endif NULL }; @@ -103,6 +107,7 @@ DEBTAB crd_debug[] = { {"DETAIL", DEBUG_DETAIL, "Show details about device"}, {"EXP", DEBUG_EXP, "Show exception information"}, {"CARD", DEBUG_CARD, "Show Card read/punches"}, + {"CDATA", DEBUG_CDATA, "Show channel data"}, {0, 0} }; diff --git a/Visual Studio Projects/IBM360.vcproj b/Visual Studio Projects/IBM360.vcproj index 4448192..ba16729 100644 --- a/Visual Studio Projects/IBM360.vcproj +++ b/Visual Studio Projects/IBM360.vcproj @@ -230,6 +230,10 @@ RelativePath="..\IBM360\ibm360_mt.c" > + + diff --git a/Visual Studio Projects/IBM360_32.vcproj b/Visual Studio Projects/IBM360_32.vcproj index 2a5b6d5..22fa726 100644 --- a/Visual Studio Projects/IBM360_32.vcproj +++ b/Visual Studio Projects/IBM360_32.vcproj @@ -229,6 +229,10 @@ RelativePath="..\IBM360\ibm360_mt.c" > + + diff --git a/doc/ibm360.doc b/doc/ibm360.doc index 9b7d771..5b3d271 100644 Binary files a/doc/ibm360.doc and b/doc/ibm360.doc differ diff --git a/makefile b/makefile index f61b2be..fee9353 100644 --- a/makefile +++ b/makefile @@ -1987,11 +1987,10 @@ ICL1900 = ${ICL1900D}/icl1900_cpu.c ${ICL1900D}/icl1900_sys.c \ ICL1900_OPT = -I $(ICL1900D) -DICL1900 -DUSE_SIM_CARD IBM360D = ${SIMHD}/IBM360 -IBM360 = ${IBM360D}/ibm360_cpu.c ${IBM360D}/ibm360_sys.c \ - ${IBM360D}/ibm360_con.c ${IBM360D}/ibm360_chan.c \ - ${IBM360D}/ibm360_cdr.c ${IBM360D}/ibm360_cdp.c \ - ${IBM360D}/ibm360_mt.c ${IBM360D}/ibm360_lpr.c \ - ${IBM360D}/ibm360_dasd.c ${IBM360D}/ibm360_com.c +IBM360 = ${IBM360D}/ibm360_cpu.c ${IBM360D}/ibm360_sys.c ${IBM360D}/ibm360_con.c \ + ${IBM360D}/ibm360_chan.c ${IBM360D}/ibm360_cdr.c ${IBM360D}/ibm360_cdp.c \ + ${IBM360D}/ibm360_mt.c ${IBM360D}/ibm360_lpr.c ${IBM360D}/ibm360_dasd.c \ + ${IBM360D}/ibm360_com.c ${IBM360D}/ibm360_scom.c IBM360_OPT = -I $(IBM360D) -DIBM360 -DUSE_64BIT -DUSE_SIM_CARD IBM360_OPT32 = -I $(IBM360D) -DIBM360 -DUSE_SIM_CARD