/* altair_sio: MITS Altair serial I/O card These functions support a simulated MITS 2SIO interface card. The card had two physical I/O ports which could be connected to any serial I/O device that would connect to a current loop, RS232, or TTY interface. Available baud rates were jumper selectable for each port from 110 to 9600. All I/O is via programmed I/O. Each each has a status port and a data port. A write to the status port can select some options for the device (0x03 will reset the port). A read of the status port gets the port status: +---+---+---+---+---+---+---+---+ | X X X X X X O I | +---+---+---+---+---+---+---+---+ I - A 1 in this bit position means a character has been received on the data port and is ready to be read. O - A 1 in this bit means the port is ready to receive a character on the data port and transmit it out over the serial line. A read to the data port gets the buffered character, a write to the data port writes the character to the device. */ #include #include "altair_defs.h" #define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */ #define UNIT_ANSI (1 << UNIT_V_ANSI) t_stat sio_svc (UNIT *uptr); t_stat sio_reset (DEVICE *dptr); t_stat ptr_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); t_stat ptp_svc (UNIT *uptr); t_stat ptp_reset (DEVICE *dptr); int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ extern t_stat sim_activate (UNIT *uptr, int32 interval); extern t_stat sim_cancel (UNIT *uptr); extern t_stat sim_poll_kbd (void); extern t_stat sim_putchar (int32 out); /* 2SIO Standard I/O Data Structures */ UNIT sio_unit = { UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT }; REG sio_reg[] = { { ORDATA (DATA, sio_unit.buf, 8) }, { ORDATA (STAT, sio_unit.u3, 8) }, { NULL } }; MTAB sio_mod[] = { { UNIT_ANSI, 0, "TTY", "TTY", NULL }, { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, { 0 } }; DEVICE sio_dev = { "2SIO", &sio_unit, sio_reg, sio_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &sio_reset, NULL, NULL, NULL }; UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG ptr_reg[] = { { ORDATA (DATA, ptr_unit.buf, 8) }, { ORDATA (STAT, ptr_unit.u3, 8) }, { ORDATA (POS, ptr_unit.pos, 31) }, { NULL } }; DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, NULL, NULL, NULL }; UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG ptp_reg[] = { { ORDATA (DATA, ptp_unit.buf, 8) }, { ORDATA (STAT, ptp_unit.u3, 8) }, { ORDATA (POS, ptp_unit.pos, 31) }, { NULL } }; DEVICE ptp_dev = { "PTP", &ptp_unit, ptp_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, NULL, NULL, NULL }; /* Service routines to handle simulator functions */ /* service routine - actually gets char & places in buffer */ int32 sio_svc (UNIT *uptr) { int32 temp; sim_activate (&sio_unit, sio_unit.wait); /* continue poll */ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ sio_unit.buf = temp & 0377; /* Save char */ sio_unit.u3 |= 0x01; /* Set status */ /* Do any special character handling here */ sio_unit.pos++; return SCPE_OK; } int32 ptr_svc (UNIT *uptr) { return SCPE_OK; } int32 ptp_svc (UNIT *uptr) { return SCPE_OK; } /* Reset routine */ int32 sio_reset (DEVICE *dptr) { sio_unit.buf = 0; /* Data */ sio_unit.u3 = 0x02; /* Status */ sim_activate (&sio_unit, sio_unit.wait); /* activate unit */ return SCPE_OK; } int32 ptr_reset (DEVICE *dptr) { ptr_unit.buf = 0; ptr_unit.u3 = 0x02; sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; } int32 ptp_reset (DEVICE *dptr) { ptp_unit.buf = 0; ptp_unit.u3 = 0x02; sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; } /* I/O instruction handlers, called from the CPU module when an IN or OUT instruction is issued. Each function is passed an 'io' flag, where 0 means a read from the port, and 1 means a write to the port. On input, the actual input is passed as the return value, on output, 'data' is written to the device. */ int32 sio0s(int32 io, int32 data) { if (io == 0) { return (sio_unit.u3); } else { if (data == 0x03) { /* reset port! */ sio_unit.u3 = 0x02; sio_unit.buf = 0; sio_unit.pos = 0; } return (0); } } int32 sio0d(int32 io, int32 data) { if (io == 0) { sio_unit.u3 = sio_unit.u3 & 0xFE; return (sio_unit.buf); } else { sim_putchar(data); } } /* Port 2 controls the PTR/PTP devices */ int32 sio1s(int32 io, int32 data) { if (io == 0) { if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ return 0x02; if (ptr_unit.u3 != 0) /* No more data? */ return 0x02; return (0x03); /* ready to read/write */ } else { if (data == 0x03) { ptr_unit.u3 = 0; ptr_unit.buf = 0; ptr_unit.pos = 0; ptp_unit.u3 = 0; ptp_unit.buf = 0; ptp_unit.pos = 0; } return (0); } } int32 sio1d(int32 io, int32 data) { int32 temp; UNIT *uptr; if (io == 0) { if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ return 0; if (ptr_unit.u3 != 0) return 0; uptr = ptr_dev.units; if ((temp = getc(uptr -> fileref)) == EOF) { /* end of file? */ ptr_unit.u3 = 0x01; return 0; } ptr_unit.pos++; return (temp & 0xFF); } else { uptr = ptp_dev.units; putc(data, uptr -> fileref); ptp_unit.pos++; } }