/************************************************************************* | |
* * | |
* $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[] = { | |
{ ORDATAD (BUF, petr_unit.buf, 18, "18-bit buffer to store up to three lines of paper tape input") }, | |
{ FLDATAD (UC, petr_uc, UC_V, "upper case/lower case state") }, | |
{ FLDATAD (DONE, iosta, IOS_V_PETR, "input ready flag") }, | |
{ ORDATA (HOLD, petr_hold, 9), REG_HRO }, | |
{ ORDATA (STATE, petr_state, 5), REG_HRO }, | |
{ FLDATA (WAIT, petr_wait, 0), REG_HRO }, | |
{ DRDATAD (POS, petr_unit.pos, T_ADDR_W, "position in input file"), PV_LEFT }, | |
{ DRDATAD (TIME, petr_unit.wait, 24, "time from I/O initiation to interrupt"), PV_LEFT }, | |
{ DRDATA (LEADER, petr_leader, 6), REG_HRO }, | |
{ FLDATAD (STOP_IOE, petr_stopioe, 0, "stop on I/O error") }, | |
{ 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[] = { | |
{ ORDATAD (BUF, ptp_unit.buf, 8, "last data item processed") }, | |
{ FLDATAD (DONE, iosta, IOS_V_PTP, "device done flag") }, | |
{ DRDATAD (POS, ptp_unit.pos, T_ADDR_W, "position in the output file"), PV_LEFT }, | |
{ DRDATAD (TIME, ptp_unit.wait, 24, "time from I/O initiation to interrupt"), PV_LEFT }, | |
{ FLDATAD (STOP_IOE, ptp_stopioe, 0, "stop on I/O error") }, | |
{ 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[] = { | |
{ ORDATAD (BUF, tty_buf, 6, "typewrite buffer (shared)") }, | |
{ FLDATAD (UC, tty_uc, UC_V, "upper case/lower case state (shared)") }, | |
{ ORDATA (HOLD, tti_hold, 9), REG_HRO }, | |
{ FLDATAD (DONE, iosta, IOS_V_TTI, "input ready flag") }, | |
{ DRDATAD (POS, tti_unit.pos, T_ADDR_W, "number of characters input"), PV_LEFT }, | |
{ DRDATAD (TIME, tti_unit.wait, 24, "keyboard polling interval"), 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[] = { | |
{ ORDATAD (BUF, tty_buf, 6, "typewrite buffer (shared)") }, | |
{ FLDATAD (UC, tty_uc, UC_V, "upper case/lower case state (shared)") }, | |
{ FLDATAD (DONE, iosta, IOS_V_TTO, "output done flag") }, | |
{ DRDATAD (POS, tto_unit.pos, T_ADDR_W, "number of characters output"), PV_LEFT }, | |
{ DRDATAD (TIME, tto_unit.wait, 24, "time from I/O initiation to interrupt"), 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; | |
} |