These include simulators for the IBM 701, IBM 702, IBM 704, IBM 705, IBM 705/3, IBM 709, IBM 1410/IBM 7010, IBM 7070, IBM 7080, IBM 7090 and IBM7094. These basically were a collection of machines that shared a common set it peripherals, Each group had its own instruction set, hence different simulators. IBM 701 -> i701 IBM 702/705/705/3/7080 -> i7080 IBM 7070/7074 -> i7070 IBM 1410/7010 -> i7010 IBM 704 -> i704 IBM 704/709/7090/7094 -> i7090 The i7090 can be set to simulate a IBM 704 however you end up disabling almost everything, since the 704 did not have any channels. A build option exists that allows this one to be built without all the extra features. The i7090 simulator’s implementation of the IBM 7094 is a more complete implementation of the IBM 7094 which can run CTSS while the existing simh I7094 can’t.
279 lines
8.8 KiB
C
279 lines
8.8 KiB
C
/* i7000_con.c: IBM 7000 Inquiry Console.
|
||
|
||
Copyright (c) 2005-2016, Richard Cornwell
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a
|
||
copy of this software and associated documentation files (the "Software"),
|
||
to deal in the Software without restriction, including without limitation
|
||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
and/or sell copies of the Software, and to permit persons to whom the
|
||
Software is furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
This is the standard inquiry or console interface.
|
||
|
||
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 "i7000_defs.h"
|
||
#include "sim_card.h"
|
||
#include "sim_defs.h"
|
||
|
||
#ifdef NUM_DEVS_CON
|
||
|
||
|
||
/* std devices. data structures
|
||
|
||
cdr_dev Card Reader device descriptor
|
||
cdr_unit Card Reader unit descriptor
|
||
cdr_reg Card Reader register list
|
||
cdr_mod Card Reader modifiers list
|
||
*/
|
||
|
||
/* Device status information stored in u5 */
|
||
|
||
struct _con_data
|
||
{
|
||
uint8 ibuff[145]; /* Input line buffer */
|
||
uint8 inptr;
|
||
}
|
||
con_data[NUM_DEVS_CON];
|
||
|
||
uint32 con_cmd(UNIT *, uint16, uint16);
|
||
void con_ini(UNIT *, t_bool);
|
||
t_stat con_srv(UNIT *);
|
||
t_stat con_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
const char *con_description(DEVICE *dptr);
|
||
|
||
extern char ascii_to_six[128];
|
||
|
||
UNIT con_unit[] = {
|
||
{UDATA(con_srv, UNIT_S_CHAN(CHAN_CHUREC), 0), 0}, /* A */
|
||
};
|
||
|
||
DEVICE con_dev = {
|
||
"INQ", con_unit, NULL, NULL,
|
||
NUM_DEVS_CON, 8, 15, 1, 8, 8,
|
||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||
&con_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||
NULL, NULL, &con_help, NULL, NULL, &con_description
|
||
};
|
||
|
||
|
||
|
||
/*
|
||
*Console printer routines.
|
||
*/
|
||
void
|
||
con_ini(UNIT *uptr, t_bool f) {
|
||
int u = (uptr - con_unit);
|
||
con_data[u].inptr = 0;
|
||
uptr->u5 = 0;
|
||
sim_activate(uptr, 1000);
|
||
}
|
||
|
||
uint32
|
||
con_cmd(UNIT * uptr, uint16 cmd, uint16 dev)
|
||
{
|
||
int chan = UNIT_G_CHAN(uptr->flags);
|
||
int u = (uptr - con_unit);
|
||
|
||
/* Are we currently tranfering? */
|
||
if (uptr->u5 & (URCSTA_READ|URCSTA_WRITE|URCSTA_BUSY))
|
||
return SCPE_BUSY;
|
||
|
||
switch (cmd) {
|
||
/* Test ready */
|
||
case IO_TRS:
|
||
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd TRS\n", u);
|
||
return SCPE_OK;
|
||
|
||
/* Get record from CPU */
|
||
case IO_WRS:
|
||
sim_putchar('R');
|
||
sim_putchar(' ');
|
||
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd WRS\n", u);
|
||
chan_set_sel(chan, 1);
|
||
uptr->u5 |= URCSTA_WRITE;
|
||
uptr->u3 = 0;
|
||
return SCPE_OK;
|
||
|
||
/* Send record to CPU */
|
||
case IO_RDS:
|
||
if (uptr->u5 & URCSTA_INPUT)
|
||
return SCPE_BUSY;
|
||
if (con_data[u].inptr == 0) {
|
||
/* Activate input so we can get response */
|
||
uptr->u5 |= URCSTA_INPUT;
|
||
sim_putchar('I');
|
||
sim_putchar(' ');
|
||
}
|
||
sim_debug(DEBUG_CMD, &con_dev, "%d: Cmd RDS\n", u);
|
||
chan_set_sel(chan, 0);
|
||
uptr->u5 |= URCSTA_READ;
|
||
uptr->u3 = 0;
|
||
return SCPE_OK;
|
||
}
|
||
chan_set_attn(chan);
|
||
return SCPE_IOERR;
|
||
}
|
||
|
||
/* Handle transfer of data for printer */
|
||
t_stat
|
||
con_srv(UNIT *uptr) {
|
||
int chan = UNIT_G_CHAN(uptr->flags);
|
||
uint8 ch;
|
||
int u = (uptr - con_unit);
|
||
t_stat r;
|
||
|
||
/* Waiting for disconnect */
|
||
if (uptr->u5 & URCSTA_WDISCO) {
|
||
if (chan_stat(chan, DEV_DISCO)) {
|
||
sim_debug(DEBUG_DETAIL, &con_dev, " Disco\n");
|
||
chan_clear(chan, DEV_SEL|DEV_WEOR);
|
||
uptr->u5 &= ~ URCSTA_WDISCO;
|
||
sim_activate(uptr, 25);
|
||
return SCPE_OK;
|
||
} else {
|
||
/* No disco yet, try again in a bit */
|
||
sim_activate(uptr, 50);
|
||
return SCPE_OK;
|
||
}
|
||
}
|
||
|
||
uptr->u5 &= ~URCSTA_BUSY; /* Clear busy */
|
||
|
||
/* Copy next column over */
|
||
if (uptr->u5 & URCSTA_WRITE) {
|
||
switch(chan_read_char(chan, &ch, 0)) {
|
||
case TIME_ERROR:
|
||
case END_RECORD:
|
||
sim_putchar('\r');
|
||
sim_putchar('\n');
|
||
sim_debug(DEBUG_EXP, &con_dev, "\n\r");
|
||
uptr->u5 |= URCSTA_WDISCO|URCSTA_BUSY;
|
||
uptr->u5 &= ~URCSTA_WRITE;
|
||
break;
|
||
case DATA_OK:
|
||
ch &= 077;
|
||
sim_debug(DEBUG_EXP, &con_dev, "%c", sim_six_to_ascii[ch]);
|
||
sim_putchar(sim_six_to_ascii[ch]);
|
||
break;
|
||
}
|
||
sim_activate(uptr, 100);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Copy next column over */
|
||
if ((uptr->u5 & URCSTA_INPUT) == 0 && uptr->u5 & URCSTA_READ) {
|
||
sim_debug(DEBUG_DATA, &con_dev, "%d: Char > %02o %x\n", u,
|
||
con_data[u].ibuff[uptr->u3], chan_flags[chan]);
|
||
switch(chan_write_char(chan, &con_data[u].ibuff[uptr->u3],
|
||
((uptr->u3+1) == con_data[u].inptr)? DEV_REOR: 0)) {
|
||
case TIME_ERROR:
|
||
case END_RECORD:
|
||
uptr->u5 |= URCSTA_WDISCO|URCSTA_BUSY;
|
||
uptr->u5 &= ~URCSTA_READ;
|
||
sim_debug(DEBUG_EXP, &con_dev, "EOR");
|
||
chan_clear_attn_inq(chan);
|
||
con_data[u].inptr = 0;
|
||
break;
|
||
case DATA_OK:
|
||
uptr->u3++;
|
||
break;
|
||
}
|
||
sim_activate(uptr, 10);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
r = sim_poll_kbd();
|
||
if (r & SCPE_KFLAG) {
|
||
ch = r & 0377;
|
||
if (uptr->u5 & URCSTA_INPUT) {
|
||
/* Handle end of buffer */
|
||
switch (ch) {
|
||
case '\r':
|
||
case '\n':
|
||
uptr->u5 &= ~URCSTA_INPUT;
|
||
sim_putchar('\r');
|
||
sim_putchar('\n');
|
||
chan_set_attn_inq(chan);
|
||
break;
|
||
case 033:
|
||
uptr->u5 &= ~URCSTA_INPUT;
|
||
con_data[u].inptr = 0;
|
||
break;
|
||
case '\b':
|
||
if (con_data[u].inptr != 0) {
|
||
con_data[u].inptr--;
|
||
sim_putchar(ch);
|
||
}
|
||
break;
|
||
default:
|
||
if (con_data[u].inptr < sizeof(con_data[u].ibuff)) {
|
||
ch = sim_ascii_to_six[0177&ch];
|
||
if (ch == 0xff) {
|
||
sim_putchar('\007');
|
||
break;
|
||
}
|
||
sim_putchar(sim_six_to_ascii[ch]);
|
||
con_data[u].ibuff[con_data[u].inptr++] = ch;
|
||
}
|
||
break;
|
||
}
|
||
} else {
|
||
if (ch == 033) {
|
||
if (con_data[u].inptr != 0) {
|
||
chan_clear_attn_inq(chan);
|
||
} else {
|
||
#ifdef I7070
|
||
chan_set_attn_inq(chan);
|
||
#endif
|
||
sim_putchar('I');
|
||
sim_putchar(' ');
|
||
uptr->u5 |= URCSTA_INPUT;
|
||
}
|
||
con_data[u].inptr = 0;
|
||
}
|
||
}
|
||
}
|
||
sim_activate(uptr, 500);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
con_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "Supervisory Printer\n\n");
|
||
fprintf (st, "This is the interface from the operator to the system. The printer\n");
|
||
fprintf (st, "operated in a half duplex mode. To request the system to accept input\n");
|
||
fprintf (st, "press the <esc> key and wait until the system responds with a line with\n");
|
||
fprintf (st, "I as the first character. When you have finished typing your line, press\n");
|
||
fprintf (st, "return or enter key. Backspace will delete the last character.\n");
|
||
fprintf (st, "All responses from the system are prefixed with a R and blank as the\n");
|
||
fprintf (st, "first character\n");
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
con_description(DEVICE *dptr)
|
||
{
|
||
return "Supervisory Printer";
|
||
}
|
||
|
||
#endif
|
||
|