640 lines
22 KiB
C
640 lines
22 KiB
C
/*************************************************************************
|
|
* *
|
|
* $Id: tx0_stddev.c 2063 2009-02-25 07:37:57Z hharte $ *
|
|
* *
|
|
* Copyright (c) 2009-2012 Howard M. Harte. *
|
|
* Based on pdp1_stddev.c, Copyright (c) 1993-2006, Robert M. Supnik *
|
|
* *
|
|
* 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 HOWARD M. HARTE 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. *
|
|
* *
|
|
* Except as contained in this notice, the name of Howard M. Harte shall *
|
|
* not be used in advertising or otherwise to promote the sale, use or *
|
|
* other dealings in this Software without prior written authorization *
|
|
* of Howard M. Harte. *
|
|
* *
|
|
* Module Description: *
|
|
* TX-0 Standard Devices *
|
|
* *
|
|
* Environment: *
|
|
* User mode only *
|
|
* *
|
|
*************************************************************************/
|
|
|
|
/*
|
|
petr paper tape reader
|
|
ptp paper tape punch
|
|
tti keyboard
|
|
tto teleprinter
|
|
|
|
Note: PTP timeout must be >10X faster than TTY output timeout for Macro
|
|
to work correctly!
|
|
*/
|
|
|
|
#include "tx0_defs.h"
|
|
#include "sim_tmxr.h"
|
|
|
|
#define FLEXO_STOP 061 /* stop code */
|
|
#define FLEXO_UC 071
|
|
#define FLEXO_LC 075
|
|
#define UC_V 6 /* upper case */
|
|
#define UC (1 << UC_V)
|
|
#define BOTH (1 << (UC_V + 1)) /* both cases */
|
|
#define CW (1 << (UC_V + 2)) /* char waiting */
|
|
#define TT_WIDTH 077
|
|
#define UNIT_V_ASCII (UNIT_V_UF + 0) /* ASCII/binary mode */
|
|
#define UNIT_ASCII (1 << UNIT_V_ASCII)
|
|
#define PETR_LEADER 20 /* ASCII leader chars */
|
|
|
|
#define TRACE_PRINT(dev, level, args) if(dev.dctrl & level) { \
|
|
printf args; \
|
|
}
|
|
|
|
int32 petr_state = 0;
|
|
int32 petr_wait = 0;
|
|
int32 petr_stopioe = 0;
|
|
int32 petr_uc = 0; /* upper/lower case */
|
|
int32 petr_hold = 0; /* holding buffer */
|
|
int32 petr_leader = PETR_LEADER; /* leader count */
|
|
int32 ptp_stopioe = 0;
|
|
int32 tti_hold = 0; /* tti hold buf */
|
|
int32 tty_buf = 0; /* tty buffer */
|
|
int32 tty_uc = 0; /* tty uc/lc */
|
|
int32 tto_sbs = 0;
|
|
|
|
extern int32 ios, iosta;
|
|
extern int32 PF, IR, PC, TA;
|
|
extern int32 M[];
|
|
|
|
t_stat petr_svc (UNIT *uptr);
|
|
t_stat ptp_svc (UNIT *uptr);
|
|
t_stat tti_svc (UNIT *uptr);
|
|
t_stat tto_svc (UNIT *uptr);
|
|
t_stat petr_reset (DEVICE *dptr);
|
|
t_stat ptp_reset (DEVICE *dptr);
|
|
t_stat tty_reset (DEVICE *dptr);
|
|
t_stat petr_boot (int32 unitno, DEVICE *dptr);
|
|
t_stat petr_attach (UNIT *uptr, char *cptr);
|
|
|
|
/* Character translation tables */
|
|
|
|
int32 flexo_to_ascii[128] = {
|
|
/*00*/ 0, 0, 'e', '8', 0, '|', 'a', '3', /* lower case */
|
|
/*10*/ ' ', '=', 's', '4', 'i', '+', 'u', '2',
|
|
/*20*/ 0, '.', 'd', '5', 'r', '1', 'j', '7',
|
|
/*30*/ 'n', ',', 'f', '6', 'c', '-', 'k', 0,
|
|
/*40*/ 't', 0, 'z', '\b','l', '\t','w', 0,
|
|
/*50*/ 'h', '\r','y', 0, 'p', 0, 'q', 0,
|
|
/*60*/ 'o', '*', 'b', 0, 'g', 0, '9', 0,
|
|
/*70*/ 'm', 0, 'x', 0, 'v', 0, '0', 0,
|
|
/*00*/ 0, 0, 'E', '8', 0, '_', 'A', '3', /* upper case */
|
|
/*10*/ ' ', ':', 'S', '4', 'I', '/', 'U', '2',
|
|
/*20*/ 0, ')', 'D', '5', 'R', '1', 'J', '7',
|
|
/*30*/ 'N', '(', 'F', '6', 'C', '-', 'K', 0,
|
|
/*40*/ 'T', 0, 'Z', '\b','L', '\t','W', 0,
|
|
/*50*/ 'H', '\r','Y', 0, 'P', 0, 'Q', 0,
|
|
/*60*/ 'O', '*', 'B', 0, 'G', 0, '9', 0,
|
|
/*70*/ 'M', 0, 'X', 0, 'V', 0, '0', 0,
|
|
};
|
|
|
|
int32 ascii_to_flexo[128] = {
|
|
/*00*/ 0, 0, 0, BOTH+061, 0, 0, 0, 0, /* STOP mapped to ^C */
|
|
/*10*/ BOTH+043, BOTH+045, 0, 0, 0, BOTH+051, 0, 0,
|
|
/*20*/ 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/*30*/ 0, 0, 0, BOTH+020, 0, 0, 0, 0, /* Color Shift mapped to ESC */
|
|
/*40*/ BOTH+010, 0, 0, 0, 0, 0, 0, 0, /* " ", */
|
|
/*50*/ UC+021, UC+031, 021, 015, 031, UC+035, UC+011, UC+015, /* ()*+,-./ */
|
|
/*60*/ 076, 025, 017, 007, 013, 023, 033, 027, /* 0-7 */
|
|
/*70*/ 003, 066, 0, 0, 0, 011, 0, 0, /* 89:;<=>? */
|
|
/*00*/ 040, UC+006, UC+062, UC+034, UC+022, UC+002, UC+032, UC+064, /* A-G */
|
|
/*10*/ UC+050, UC+014, UC+026, UC+036, UC+044, UC+070, UC+030, UC+060, /* H-O */
|
|
/*20*/ UC+054, UC+056, UC+024, UC+012, 040, 016, 074, 046, /* P-W */
|
|
/*30*/ UC+072, UC+052, UC+042, 0, 0, 0, 0, UC+005, /* X-Z, */
|
|
/*40*/ 00, 006, 062, 034, 022, 002, 032, 064, /* a-g */
|
|
/*50*/ 050, 014, 026, 036, 044, 070, 030, 060, /* h-o */
|
|
/*60*/ 054, 056, 024, 012, 040, 016, 074, 046, /* p-w */
|
|
/*70*/ 072, 052, 042, 0, 005, 0, UC+035, BOTH+077 /* x-z, */
|
|
};
|
|
|
|
/* PETR data structures
|
|
|
|
petr_dev PETR device descriptor
|
|
petr_unit PETR unit
|
|
petr_reg PETR register list
|
|
*/
|
|
|
|
UNIT petr_unit = {
|
|
UDATA (&petr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
|
|
SERIAL_IN_WAIT
|
|
};
|
|
|
|
REG petr_reg[] = {
|
|
{ ORDATA (BUF, petr_unit.buf, 18) },
|
|
{ FLDATA (UC, petr_uc, UC_V) },
|
|
{ FLDATA (DONE, iosta, IOS_V_PETR) },
|
|
{ ORDATA (HOLD, petr_hold, 9), REG_HRO },
|
|
{ ORDATA (STATE, petr_state, 5), REG_HRO },
|
|
{ FLDATA (WAIT, petr_wait, 0), REG_HRO },
|
|
{ DRDATA (POS, petr_unit.pos, T_ADDR_W), PV_LEFT },
|
|
{ DRDATA (TIME, petr_unit.wait, 24), PV_LEFT },
|
|
{ DRDATA (LEADER, petr_leader, 6), REG_HRO },
|
|
{ FLDATA (STOP_IOE, petr_stopioe, 0) },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB petr_mod[] = {
|
|
{ UNIT_ASCII, UNIT_ASCII, "ASCII", "ASCII", NULL },
|
|
{ UNIT_ASCII, 0, "FLEXO", "FLEXO", NULL },
|
|
{ 0 }
|
|
};
|
|
|
|
/* Debug flags */
|
|
#define ERROR_MSG (1 << 0)
|
|
#define TRACE_MSG (1 << 1)
|
|
#define VERBOSE_MSG (1 << 2)
|
|
|
|
/* Debug Flags */
|
|
static DEBTAB petr_dt[] = {
|
|
{ "ERROR", ERROR_MSG },
|
|
{ "TRACE", TRACE_MSG },
|
|
{ "VERBOSE",VERBOSE_MSG },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
DEVICE petr_dev = {
|
|
"PETR", &petr_unit, petr_reg, petr_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &petr_reset,
|
|
&petr_boot, &petr_attach, NULL,
|
|
NULL, DEV_DEBUG, (ERROR_MSG),
|
|
petr_dt, NULL
|
|
};
|
|
|
|
/* PTP data structures
|
|
|
|
ptp_dev PTP device descriptor
|
|
ptp_unit PTP unit
|
|
ptp_reg PTP register list
|
|
*/
|
|
|
|
UNIT ptp_unit = {
|
|
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
|
|
};
|
|
|
|
REG ptp_reg[] = {
|
|
{ ORDATA (BUF, ptp_unit.buf, 8) },
|
|
{ FLDATA (DONE, iosta, IOS_V_PTP) },
|
|
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
|
|
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
|
|
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB ptp_mod[] = {
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE ptp_dev = {
|
|
"PTP", &ptp_unit, ptp_reg, ptp_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &ptp_reset,
|
|
NULL, NULL, NULL,
|
|
NULL, DEV_DEBUG, (ERROR_MSG|TRACE_MSG),
|
|
petr_dt, NULL
|
|
};
|
|
|
|
/* TTI data structures
|
|
|
|
tti_dev TTI device descriptor
|
|
tti_unit TTI unit
|
|
tti_reg TTI register list
|
|
*/
|
|
|
|
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
|
|
|
|
REG tti_reg[] = {
|
|
{ ORDATA (BUF, tty_buf, 6) },
|
|
{ FLDATA (UC, tty_uc, UC_V) },
|
|
{ ORDATA (HOLD, tti_hold, 9), REG_HRO },
|
|
{ FLDATA (DONE, iosta, IOS_V_TTI) },
|
|
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
|
|
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB tti_mod[] = {
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE tti_dev = {
|
|
"TTI", &tti_unit, tti_reg, tti_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &tty_reset,
|
|
NULL, NULL, NULL,
|
|
NULL, DEV_DEBUG, (ERROR_MSG|TRACE_MSG),
|
|
petr_dt, NULL
|
|
};
|
|
|
|
/* TTO data structures
|
|
|
|
tto_dev TTO device descriptor
|
|
tto_unit TTO unit
|
|
tto_reg TTO register list
|
|
*/
|
|
|
|
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 };
|
|
|
|
REG tto_reg[] = {
|
|
{ ORDATA (BUF, tty_buf, 6) },
|
|
{ FLDATA (UC, tty_uc, UC_V) },
|
|
{ FLDATA (DONE, iosta, IOS_V_TTO) },
|
|
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
|
|
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB tto_mod[] = {
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE tto_dev = {
|
|
"TTO", &tto_unit, tto_reg, tto_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &tty_reset,
|
|
NULL, NULL, NULL,
|
|
NULL, DEV_DEBUG, (ERROR_MSG|TRACE_MSG),
|
|
petr_dt, NULL
|
|
};
|
|
|
|
/* Photoelectric Tape Reader:
|
|
|
|
The PETR is a 250 line per minute Ferranti photoelectric paper tape reader
|
|
using standard seven-hole Flexowriter tape that was modified to solid state
|
|
circuitry. Lines without seventh hole punched are ignored by the PETR.
|
|
As each line of the tape is read in, the data is stored into an 18-bit BUF
|
|
register with bits mapped as follows:
|
|
|
|
Tape BUF
|
|
0 0
|
|
1 3
|
|
2 6
|
|
3 9
|
|
4 12
|
|
5 15
|
|
|
|
Up to three lines of tape may be read into a single the single BUF register.
|
|
Before subsequent lines are read, the BUF register is cycled one bit right.
|
|
|
|
The PETR reads data from or a disk file. The POS register specifies the
|
|
number of the next data item to be read. Thus, by changing POS, the user can
|
|
backspace or advance the reader.
|
|
|
|
The PETR supports the BOOT command. BOOT PETR switches the CPU to Read-In
|
|
mode, and starts the processor running.
|
|
*/
|
|
|
|
int32 petr (int32 inst, int32 dev, int32 dat)
|
|
{
|
|
int32 tmpAC = 0;
|
|
int i = 0;
|
|
t_stat result;
|
|
ios = 1;
|
|
|
|
for (i=0;i<inst;i++) {
|
|
do {
|
|
result = petr_svc(&petr_unit);
|
|
if (result != SCPE_OK) {
|
|
sim_printf("PETR: Read error\n");
|
|
break;
|
|
}
|
|
} while ((petr_unit.buf & 0100) == 0); /* NOTE: Lines without seventh hole are ignored by PETR. */
|
|
petr_unit.buf &= 077; /* Mask to 6 bits. */
|
|
tmpAC |= ((petr_unit.buf & 001) >> 0) << 17; /* bit 0 */
|
|
tmpAC |= ((petr_unit.buf & 002) >> 1) << 14; /* bit 3 */
|
|
tmpAC |= ((petr_unit.buf & 004) >> 2) << 11; /* bit 6 */
|
|
tmpAC |= ((petr_unit.buf & 010) >> 3) << 8; /* bit 9 */
|
|
tmpAC |= ((petr_unit.buf & 020) >> 4) << 5; /* bit 12 */
|
|
tmpAC |= ((petr_unit.buf & 040) >> 5) << 2; /* bit 15 */
|
|
|
|
if (i < (inst-1)) {
|
|
uint32 bit0 = (tmpAC & 1) << 17;
|
|
TRACE_PRINT(petr_dev, TRACE_MSG, ("PETR read [%04x=0x%02x] %03o\n", petr_unit.pos-1, petr_unit.buf, petr_unit.buf));
|
|
tmpAC >>= 1;
|
|
tmpAC |= bit0;
|
|
} else {
|
|
TRACE_PRINT(petr_dev, TRACE_MSG, ("PETR read [%04x=0x%02x] %03o, tmpAC=%06o\n", petr_unit.pos-1, petr_unit.buf, petr_unit.buf, tmpAC));
|
|
}
|
|
}
|
|
return tmpAC;
|
|
|
|
/* sim_activate (&petr_unit, petr_unit.wait); */ /* start reader */
|
|
|
|
}
|
|
|
|
/* Unit service */
|
|
|
|
t_stat petr_svc (UNIT *uptr)
|
|
{
|
|
int32 temp;
|
|
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
|
|
ios = 0;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
if ((temp = getc (uptr->fileref)) != EOF) { /* no, get raw char */
|
|
uptr->pos = uptr->pos + 1; /* if not eof, count */
|
|
}
|
|
if (temp == EOF) { /* end of file? */
|
|
if (feof (uptr->fileref)) {
|
|
ios = 0;
|
|
return SCPE_IOERR;
|
|
}
|
|
else sim_perror ("PETR I/O error");
|
|
clearerr (uptr->fileref);
|
|
ios = 0;
|
|
return SCPE_IOERR;
|
|
}
|
|
|
|
uptr->buf = temp;
|
|
|
|
ios = 0;
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat petr_reset (DEVICE *dptr)
|
|
{
|
|
petr_state = 0; /* clear state */
|
|
petr_wait = 0;
|
|
petr_hold = 0;
|
|
petr_uc = 0;
|
|
petr_unit.buf = 0;
|
|
iosta = iosta & ~IOS_PETR; /* clear flag */
|
|
sim_cancel (&petr_unit); /* deactivate unit */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Attach routine */
|
|
|
|
t_stat petr_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
petr_leader = PETR_LEADER; /* set up leader */
|
|
return attach_unit (uptr, cptr);
|
|
}
|
|
|
|
/* Bootstrap routine */
|
|
extern t_stat cpu_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
|
|
extern UNIT cpu_unit;
|
|
|
|
//#define SANITY_CHECK_TAPE
|
|
|
|
/* Switches the CPU to READIN mode and starts execution. */
|
|
t_stat petr_boot (int32 unitno, DEVICE *dptr)
|
|
{
|
|
t_stat reason = SCPE_OK;
|
|
|
|
#ifdef SANITY_CHECK_TAPE
|
|
int32 AC, MBR, MAR, IR = 0;
|
|
int32 blkcnt, chksum = 0, fa, la;
|
|
int32 addr, tdata;
|
|
#endif /* SANITY_CHECK_TAPE */
|
|
|
|
/* Switch to READIN mode. */
|
|
cpu_set_mode(&cpu_unit, UNIT_MODE_READIN, NULL, NULL);
|
|
#ifdef SANITY_CHECK_TAPE
|
|
for(;(IR != 2) && (IR != 1);) {
|
|
AC = petr(3,0,0); /* Read three chars from tape into AC */
|
|
MAR = AC & AMASK; /* Set memory address */
|
|
IR = AC >> 16;
|
|
|
|
if (!MEM_ADDR_OK(MAR)) {
|
|
TRACE_PRINT(petr_dev, ERROR_MSG, ("READIN: Tape address out of range.\n"));
|
|
reason = SCPE_FMT;
|
|
}
|
|
|
|
switch (IR) {
|
|
case 00: /* Storage (sto x) */
|
|
case 03: /* Storage (opr x) */
|
|
MBR = petr(3,0,0); /* Read three characters from tape. */
|
|
TRACE_PRINT(petr_dev, ERROR_MSG, ("READIN: sto @%06o = %06o\n", MAR, MBR));
|
|
sim_printf("[%06o] = %06o\n", MAR, MBR);
|
|
break;
|
|
case 02: /* Transfer Control (trn x) Start Execution */
|
|
PC = MAR;
|
|
reason = SCPE_OK; /* let SIMH start execution. */
|
|
TRACE_PRINT(petr_dev, ERROR_MSG, ("READIN: trn %06o (Start Execution)\n", PC));
|
|
reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL);
|
|
break;
|
|
case 01: /* Transfer (add x) - Halt */
|
|
PC = MAR;
|
|
reason = SCPE_STOP; /* let SIMH halt. */
|
|
TRACE_PRINT(petr_dev, ERROR_MSG, ("READIN: add %06o (Halt)\n", PC));
|
|
reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL);
|
|
break;
|
|
default:
|
|
reason = SCPE_IERR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
blkcnt = 0;
|
|
while (1) {
|
|
chksum = 0;
|
|
|
|
fa = petr(3,0,0); /* Read three characters from tape. */
|
|
|
|
if ((fa & 0400000) || (fa & 0200000)) {
|
|
break;
|
|
}
|
|
|
|
chksum += fa;
|
|
if (chksum > 0777777) {
|
|
chksum +=1;
|
|
}
|
|
chksum &= 0777777;
|
|
|
|
la = petr(3,0,0); /* Read three characters from tape. */
|
|
|
|
chksum += la;
|
|
if (chksum > 0777777) {
|
|
chksum +=1;
|
|
}
|
|
chksum &= 0777777;
|
|
|
|
la = (~la) & 0177777;
|
|
|
|
sim_printf("First Address=%06o, Last Address=%06o\n", fa, la);
|
|
|
|
for(addr = fa; addr <= la; addr++) {
|
|
tdata = petr(3,0,0); /* Read three characters from tape. */
|
|
chksum += tdata;
|
|
if (chksum > 0777777) {
|
|
chksum +=1;
|
|
}
|
|
chksum &= 0777777;
|
|
}
|
|
|
|
chksum = (~chksum) & 0777777;
|
|
|
|
tdata = petr(3,0,0);
|
|
|
|
if (chksum != tdata) {
|
|
reason = SCPE_FMT;
|
|
}
|
|
|
|
sim_printf("Block %d: Calculated checksum=%06o, real checksum=%06o, %s\n", blkcnt, chksum, tdata, chksum == tdata ? "OK" : "BAD Checksum!");
|
|
blkcnt++;
|
|
}
|
|
|
|
fseek (petr_dev.units[0].fileref, 0, SEEK_SET);
|
|
#endif /* SANITY_CHECK_TAPE */
|
|
|
|
/* Start Execution */
|
|
return (reason);
|
|
|
|
}
|
|
|
|
/* Paper tape punch: punches standard seven-hole Flexowriter tape. */
|
|
|
|
int32 ptp (int32 inst, int32 dev, int32 dat)
|
|
{
|
|
iosta = iosta & ~IOS_PTP; /* clear flag */
|
|
ptp_unit.buf = dat & 0177;
|
|
ptp_svc (&ptp_unit);
|
|
/* sim_activate (&ptp_unit, ptp_unit.wait); */ /* start unit */
|
|
return dat;
|
|
}
|
|
|
|
/* Unit service */
|
|
|
|
t_stat ptp_svc (UNIT *uptr)
|
|
{
|
|
ios = 1; /* restart */
|
|
iosta = iosta | IOS_PTP; /* set flag */
|
|
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
|
|
return SCPE_UNATT;
|
|
if (putc (uptr->buf, uptr->fileref) == EOF) { /* I/O error? */
|
|
sim_perror ("PTP I/O error");
|
|
clearerr (uptr->fileref);
|
|
return SCPE_IOERR;
|
|
}
|
|
uptr->pos = uptr->pos + 1;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat ptp_reset (DEVICE *dptr)
|
|
{
|
|
ptp_unit.buf = 0; /* clear state */
|
|
iosta = iosta & ~IOS_PTP; /* clear flag */
|
|
sim_cancel (&ptp_unit); /* deactivate unit */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Typewriter IOT routines */
|
|
|
|
int32 tti (int32 inst, int32 dev, int32 dat)
|
|
{
|
|
iosta = iosta & ~IOS_TTI; /* clear flag */
|
|
return tty_buf & 077;
|
|
}
|
|
|
|
int32 tto (int32 inst, int32 dev, int32 dat)
|
|
{
|
|
tty_buf = dat & TT_WIDTH; /* load buffer */
|
|
ios = 0;
|
|
tto_svc(&tto_unit);
|
|
/* sim_activate (&tto_unit, tto_unit.wait); */ /* activate unit */
|
|
return dat;
|
|
}
|
|
|
|
/* Unit service routines */
|
|
|
|
t_stat tti_svc (UNIT *uptr)
|
|
{
|
|
int32 in = 0, temp = 0;
|
|
|
|
sim_activate (uptr, uptr->wait); /* continue poll */
|
|
if (tti_hold & CW) { /* char waiting? */
|
|
tty_buf = tti_hold & TT_WIDTH; /* return char */
|
|
tti_hold = 0; /* not waiting */
|
|
} else {
|
|
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp;
|
|
if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */
|
|
temp = temp & 0177;
|
|
if (temp == 0177) temp = '\b'; /* rubout? bs */
|
|
sim_putchar (temp); /* echo */
|
|
if (temp == '\r') sim_putchar ('\n'); /* cr? add nl */
|
|
in = ascii_to_flexo[temp]; /* translate char */
|
|
|
|
if (in == 0) return SCPE_OK; /* no xlation? */
|
|
if ((in & BOTH) || ((in & UC) == (tty_uc & UC))) {
|
|
tty_buf = in & TT_WIDTH;
|
|
} else { /* must shift */
|
|
tty_uc = in & UC; /* new case */
|
|
tty_buf = tty_uc? FLEXO_UC: FLEXO_LC;
|
|
tti_hold = in | CW; /* set 2nd waiting */
|
|
}
|
|
}
|
|
iosta = iosta | IOS_TTI; /* set flag */
|
|
TRACE_PRINT(tti_dev, TRACE_MSG, ("TTI read ASCII: %02x / FLEXO=%03o\n", temp, tty_buf));
|
|
uptr->pos = uptr->pos + 1;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat tto_svc (UNIT *uptr)
|
|
{
|
|
int32 c = 0;
|
|
t_stat r;
|
|
|
|
if (tty_buf == FLEXO_UC) tty_uc = UC; /* upper case? */
|
|
else if (tty_buf == FLEXO_LC) tty_uc = 0; /* lower case? */
|
|
else {
|
|
c = flexo_to_ascii[tty_buf | tty_uc]; /* translate */
|
|
if (c && ((r = sim_putchar_s (c)) != SCPE_OK)) { /* output; error? */
|
|
sim_activate (uptr, uptr->wait); /* retry */
|
|
return ((r == SCPE_STALL)? SCPE_OK: r);
|
|
}
|
|
}
|
|
iosta = iosta | IOS_TTO; /* set flag */
|
|
uptr->pos = uptr->pos + 1;
|
|
if (c == '\r') { /* cr? add lf */
|
|
sim_putchar ('\n');
|
|
uptr->pos = uptr->pos + 1;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat tty_reset (DEVICE *dptr)
|
|
{
|
|
tmxr_set_console_units (&tti_unit, &tto_unit);
|
|
tty_buf = 0; /* clear buffer */
|
|
tty_uc = 0; /* clear case */
|
|
tti_hold = 0; /* clear hold buf */
|
|
iosta = (iosta & ~IOS_TTI) | IOS_TTO; /* clear flag */
|
|
sim_activate (&tti_unit, tti_unit.wait); /* activate keyboard */
|
|
sim_cancel (&tto_unit); /* stop printer */
|
|
return SCPE_OK;
|
|
}
|