1. New Features 1.1 GRI-909 - This is a new simulator for the GRI-909. - It has been hand-tested; so far, no software has been discovered. 1.2 VAX - SET CPU CONHALT will cause a HALT instruction to return to the boot ROM console rather than to SIMH. SET CPU SIMHALT restores the default behavior. - BRB/W self at IPL 1F stops the simulator. This is the default behavior of VMS at exit. 1.3 PDP-18b - ATTACH -A PTR/PTP attaches the reader and punch in ASCII mode. In ASCII mode, the reader automatically sets the high order bit of incoming alphabetic data, and the punch clears the high order bit of outgoing data. 1.4 SCP - DO -V echoes commands from the file as they are executed. - Under Windows, execution priority is set BELOW_NORMAL when the simulator is running. 2. Release Notes 2.1 Bugs Fixed - PDP-11 CPU: fixed updating of MMR0 on a memory management error. - VAX FPA: changed function names to avoid conflict with C math library. - 1401 MT: read end of record generates group mark without word mark. - 1401 DP: fixed address generation and checking. - SCP: an EXIT within a DO command will cause the simulator to exit. 3. In Progress - Interdata 16b/32b: coded, not tested. - SDS 940: coded, not tested. - IBM 1620: coded, not tested. If you would like to help with the debugging of the untested simulators, they can be made available by special request.
748 lines
21 KiB
C
748 lines
21 KiB
C
/* ibm1130_stddev.c: IBM 1130 standard I/O devices simulator
|
|
|
|
Copyright (c) 2001, Brian Knittel
|
|
Based on PDP-11 simulator written by Robert M Supnik
|
|
|
|
Brian Knittel
|
|
Revision History
|
|
|
|
31July2001 - Derived from pdp11_stddev.c, which carries this disclaimer:
|
|
|
|
Copyright (c) 1993-2001, 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
|
|
ROBERT M SUPNIK 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 Robert M Supnik shall not
|
|
be used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Robert M Supnik.
|
|
*/
|
|
|
|
#include "ibm1130_defs.h"
|
|
|
|
/* ---------------------------------------------------------------------------- */
|
|
|
|
static void badio (char *dev)
|
|
{
|
|
// the real 1130 just ignores attempts to use uninstalled devices. They get tested
|
|
// at times, so it's best to be quiet about this
|
|
// printf("%s I/O is not yet supported", dev);
|
|
// wait_state = WAIT_INVALID_OP;
|
|
}
|
|
|
|
void xio_1134_papertape (int32 addr, int32 func, int32 modify) {badio("papertape");}
|
|
void xio_1627_plotter (int32 addr, int32 func, int32 modify) {badio("plotter");}
|
|
void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical mark");}
|
|
void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");}
|
|
void xio_1131_synch (int32 addr, int32 func, int32 modify) {badio("SCA");}
|
|
void xio_system7 (int32 addr, int32 func, int32 modify) {badio("System 7");}
|
|
void xio_1403_printer (int32 addr, int32 func, int32 modify) {badio("1403 printer");}
|
|
|
|
void xio_2250_display (int32 addr, int32 func, int32 modify)
|
|
{
|
|
if (func != XIO_CONTROL)
|
|
badio("2250 display"); // resmon issues stop control, so ignore XIO_CONTROL
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------- */
|
|
|
|
static int32 tti_dsw = 0; /* device status words */
|
|
static int32 tto_dsw = 0;
|
|
static int32 con_dsw = 0;
|
|
|
|
static t_stat tti_svc (UNIT *uptr);
|
|
static t_stat tto_svc (UNIT *uptr);
|
|
static t_stat tti_reset (DEVICE *dptr);
|
|
static t_stat tto_reset (DEVICE *dptr);
|
|
|
|
extern t_stat sim_poll_kbd (void);
|
|
extern t_stat sim_wait_kbd (void);
|
|
extern t_stat sim_putchar (int32 out);
|
|
|
|
extern UNIT *sim_clock_queue;
|
|
|
|
#define CSET_MASK 1 /* character set */
|
|
#define CSET_NORMAL 0
|
|
#define CSET_ASCII 1
|
|
|
|
#define IRQ_KEY 0x11 /* ctrl-Q */
|
|
#define PROGRAM_STOP_KEY 0x03 /* ctrl-C */
|
|
|
|
#include "ibm1130_conout.h" /* conout_to_ascii table */
|
|
#include "ibm1130_conin.h" /* ascii_to_conin table */
|
|
|
|
/* TTI data structures
|
|
|
|
tti_dev TTI device descriptor
|
|
tti_unit TTI unit descriptor
|
|
tti_reg TTI register list
|
|
*/
|
|
|
|
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
|
|
|
|
REG tti_reg[] = {
|
|
{ ORDATA (BUF, tti_unit.buf, 8) },
|
|
{ ORDATA (DSW, tti_dsw, 16) },
|
|
{ DRDATA (POS, tti_unit.pos, 32), PV_LEFT },
|
|
{ DRDATA (STIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
|
|
{ NULL } };
|
|
|
|
MTAB tti_mod[] = {
|
|
{ CSET_MASK, CSET_NORMAL, NULL, "1130", NULL},
|
|
{ CSET_MASK, CSET_ASCII, NULL, "ASCII", NULL},
|
|
{ 0 } };
|
|
|
|
DEVICE tti_dev = {
|
|
"KEYBOARD", &tti_unit, tti_reg, tti_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &tti_reset,
|
|
NULL, NULL, NULL };
|
|
|
|
/* TTO data structures
|
|
|
|
tto_dev TTO device descriptor
|
|
tto_unit TTO unit descriptor
|
|
tto_reg TTO register list
|
|
*/
|
|
|
|
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
|
|
|
|
REG tto_reg[] = {
|
|
{ ORDATA (BUF, tto_unit.buf, 8) },
|
|
{ ORDATA (DSW, tto_dsw, 16) },
|
|
{ DRDATA (POS, tto_unit.pos, 32), PV_LEFT },
|
|
{ DRDATA (STIME, tto_unit.wait, 24), PV_LEFT },
|
|
{ NULL } };
|
|
|
|
MTAB tto_mod[] = {
|
|
{ CSET_MASK, CSET_NORMAL, NULL, "1130", NULL},
|
|
{ CSET_MASK, CSET_ASCII, NULL, "ASCII", NULL},
|
|
{ 0 } };
|
|
|
|
DEVICE tto_dev = {
|
|
"TTO", &tto_unit, tto_reg, tto_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &tto_reset,
|
|
NULL, NULL, NULL };
|
|
|
|
/* Terminal input routines
|
|
|
|
tti_svc process event (character ready)
|
|
tti_reset process reset
|
|
tto_svc process event (print character)
|
|
tto_reset process reset
|
|
*/
|
|
|
|
#define TT_DSW_PRINTER_RESPONSE 0x8000
|
|
#define TT_DSW_KEYBOARD_RESPONSE 0x4000
|
|
#define TT_DSW_INTERRUPT_REQUEST 0x2000
|
|
#define TT_DSW_KEYBOARD_CONSOLE 0x1000
|
|
#define TT_DSW_PRINTER_BUSY 0x0800
|
|
#define TT_DSW_PRINTER_NOT_READY 0x0400
|
|
#define TT_DSW_KEYBOARD_BUSY 0x0200
|
|
|
|
void xio_1131_console (int32 iocc_addr, int32 func, int32 modify)
|
|
{
|
|
int ch;
|
|
char msg[80];
|
|
|
|
switch (func) {
|
|
case XIO_CONTROL:
|
|
SETBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY);
|
|
keyboard_selected(TRUE);
|
|
// sim_activate(&tti_unit, tti_unit.wait); /* poll keyboard never stops */
|
|
break;
|
|
|
|
case XIO_READ:
|
|
WriteW(iocc_addr, tti_unit.buf);
|
|
CLRBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY);
|
|
keyboard_selected(FALSE);
|
|
break;
|
|
|
|
case XIO_WRITE:
|
|
ch = (ReadW(iocc_addr) >> 8) & 0xFF; /* get character to write */
|
|
|
|
if ((tto_unit.flags & CSET_MASK) == CSET_NORMAL)
|
|
ch = conout_to_ascii[ch]; /* convert to ASCII */
|
|
|
|
if (ch == 0)
|
|
ch = '?'; /* hmmm, unknown character */
|
|
|
|
tto_unit.buf = ch; /* save character to write */
|
|
SETBIT(tto_dsw, TT_DSW_PRINTER_BUSY);
|
|
sim_activate(&tto_unit, tto_unit.wait); /* schedule interrupt */
|
|
break;
|
|
|
|
case XIO_SENSE_DEV:
|
|
ACC = tto_dsw | tti_dsw;
|
|
if (modify & 0x01) { /* reset interrupts */
|
|
CLRBIT(tto_dsw, TT_DSW_PRINTER_RESPONSE);
|
|
CLRBIT(tti_dsw, TT_DSW_KEYBOARD_RESPONSE);
|
|
CLRBIT(ILSW[4], ILSW_4_CONSOLE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
sprintf(msg, "Invalid console XIO function %x", func);
|
|
xio_error(msg);
|
|
}
|
|
}
|
|
|
|
static void Beep (void) // notify user keyboard was locked or key was bad
|
|
{
|
|
sim_putchar(7);
|
|
}
|
|
|
|
// tti_svc - keyboard polling (never stops)
|
|
|
|
t_stat tti_svc (UNIT *uptr)
|
|
{
|
|
int32 temp;
|
|
|
|
sim_activate(&tti_unit, tti_unit.wait); /* continue polling */
|
|
|
|
temp = sim_poll_kbd();
|
|
|
|
if (temp < SCPE_KFLAG)
|
|
return temp; /* no char or error? */
|
|
|
|
temp &= 0xFF; /* remove SCPE_KFLAG */
|
|
|
|
if (temp == IRQ_KEY) { /* interrupt request key */
|
|
SETBIT(tti_dsw, TT_DSW_INTERRUPT_REQUEST); /* queue interrupt */
|
|
SETBIT(ILSW[4], ILSW_4_CONSOLE);
|
|
calc_ints();
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
if (temp == PROGRAM_STOP_KEY) { /* simulate the program stop button */
|
|
SETBIT(con_dsw, CON_DSW_PROGRAM_STOP);
|
|
SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP);
|
|
calc_ints();
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
if (tti_dsw & TT_DSW_KEYBOARD_BUSY) { /* only store character if it was requested (keyboard unlocked) */
|
|
if ((uptr->flags & CSET_MASK) == CSET_NORMAL)
|
|
temp = ascii_to_conin[temp];
|
|
|
|
if (temp == 0) { /* ignore invalid characters */
|
|
Beep();
|
|
calc_ints();
|
|
return SCPE_OK;
|
|
}
|
|
|
|
tti_unit.buf = temp & 0xFFFE; /* save keystroke except last bit (not defined, */
|
|
tti_unit.pos = tti_unit.pos + 1; /* but it lets us distinguish 0 from no punch ' ' */
|
|
|
|
CLRBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY); /* clear busy flag (relock keyboard) */
|
|
keyboard_selected(FALSE);
|
|
|
|
SETBIT(tti_dsw, TT_DSW_KEYBOARD_RESPONSE); /* queue interrupt */
|
|
SETBIT(ILSW[4], ILSW_4_CONSOLE);
|
|
calc_ints();
|
|
}
|
|
else
|
|
Beep();
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat tti_reset (DEVICE *dptr)
|
|
{
|
|
tti_unit.buf = 0;
|
|
tti_dsw = 0;
|
|
|
|
CLRBIT(ILSW[4], ILSW_4_CONSOLE);
|
|
calc_ints();
|
|
keyboard_selected(FALSE);
|
|
|
|
sim_activate(&tti_unit, tti_unit.wait); /* always poll keyboard */
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_bool keyboard_is_locked (void) /* return TRUE if keyboard is not expecting a character */
|
|
{
|
|
return (tti_dsw & TT_DSW_KEYBOARD_BUSY) == 0;
|
|
}
|
|
|
|
t_stat tto_svc (UNIT *uptr)
|
|
{
|
|
int32 temp;
|
|
int ch;
|
|
|
|
CLRBIT(tto_dsw, TT_DSW_PRINTER_BUSY);
|
|
SETBIT(tto_dsw, TT_DSW_PRINTER_RESPONSE);
|
|
|
|
SETBIT(ILSW[4], ILSW_4_CONSOLE);
|
|
calc_ints();
|
|
|
|
ch = tto_unit.buf & 0xFF;
|
|
|
|
switch (ch) {
|
|
case IGNR:
|
|
break;
|
|
|
|
case CRLF:
|
|
if ((temp = sim_putchar('\r')) != SCPE_OK)
|
|
return temp;
|
|
if ((temp = sim_putchar('\n')) != SCPE_OK)
|
|
return temp;
|
|
|
|
break;
|
|
|
|
default:
|
|
if ((temp = sim_putchar(ch)) != SCPE_OK)
|
|
return temp;
|
|
|
|
break;
|
|
}
|
|
|
|
tto_unit.pos = tto_unit.pos + 1; /* hmm, why do we count these? */
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat tto_reset (DEVICE *dptr)
|
|
{
|
|
tto_unit.buf = 0;
|
|
tto_dsw = 0;
|
|
|
|
CLRBIT(ILSW[4], ILSW_4_CONSOLE);
|
|
calc_ints();
|
|
|
|
sim_cancel(&tto_unit); /* deactivate unit */
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/***************************************************************************************
|
|
* 1132 PRINTER
|
|
***************************************************************************************/
|
|
|
|
#define PRT_DSW_READ_EMITTER_RESPONSE 0x8000
|
|
#define PRT_DSW_SKIP_RESPONSE 0x4000
|
|
#define PRT_DSW_SPACE_RESPONSE 0x2000
|
|
#define PRT_DSW_CARRIAGE_BUSY 0x1000
|
|
#define PRT_DSW_PRINT_SCAN_CHECK 0x0800
|
|
#define PRT_DSW_NOT_READY 0x0400
|
|
#define PRT_DSW_PRINTER_BUSY 0x0200
|
|
|
|
#define PRT_DSW_CHANNEL_MASK 0x00FF
|
|
#define PRT_DSW_CHANNEL_1 0x0080
|
|
#define PRT_DSW_CHANNEL_2 0x0040
|
|
#define PRT_DSW_CHANNEL_3 0x0020
|
|
#define PRT_DSW_CHANNEL_4 0x0010
|
|
#define PRT_DSW_CHANNEL_5 0x0008
|
|
#define PRT_DSW_CHANNEL_6 0x0004
|
|
#define PRT_DSW_CHANNEL_9 0x0002
|
|
#define PRT_DSW_CHANNEL_12 0x0001
|
|
|
|
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
|
|
|
|
static t_stat prt_svc (UNIT *uptr);
|
|
static t_stat prt_reset (DEVICE *dptr);
|
|
static t_stat prt_attach (UNIT *uptr, char *cptr);
|
|
static t_stat prt_detach (UNIT *uptr);
|
|
|
|
static int16 prt_dsw = 0; /* device status word */
|
|
static int32 prt_swait = 500; /* line skip wait */
|
|
static int32 prt_cwait = 1000; /* character rotation wait */
|
|
|
|
#define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */
|
|
#define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */
|
|
#define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */
|
|
#define UNIT_V_SPACING (UNIT_V_UF + 3) /* printer is spacing */
|
|
#define UNIT_V_PRINTING (UNIT_V_UF + 4) /* printer printing */
|
|
|
|
#define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK)
|
|
#define UNIT_DATACHECK (1u << UNIT_V_DATACHECK)
|
|
#define UNIT_SKIPPING (1u << UNIT_V_SKIPPING)
|
|
#define UNIT_SPACING (1u << UNIT_V_SPACING)
|
|
#define UNIT_PRINTING (1u << UNIT_V_PRINTING)
|
|
|
|
UNIT prt_unit[] = {
|
|
{ UDATA (&prt_svc, UNIT_ATTABLE, 0) },
|
|
};
|
|
|
|
/* Parameter in the unit descriptor */
|
|
|
|
#define CMD_NONE 0
|
|
#define CMD_SPACE 1
|
|
#define CMD_SKIP 2
|
|
#define CMD_PRINT 3
|
|
|
|
REG prt_reg[] = {
|
|
{ HRDATA (PRTDSW, prt_dsw, 16) }, /* device status word */
|
|
{ DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */
|
|
{ DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */
|
|
{ NULL } };
|
|
|
|
DEVICE prt_dev = {
|
|
"PRT", prt_unit, prt_reg, NULL,
|
|
1, 16, 16, 1, 16, 16,
|
|
NULL, NULL, &prt_reset,
|
|
NULL, prt_attach, prt_detach};
|
|
|
|
#define PRT_COLUMNS 120
|
|
#define PRT_ROWLEN 120
|
|
#define MAX_OVPRINT 20
|
|
|
|
static char prtbuf[PRT_ROWLEN*MAX_OVPRINT];
|
|
static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp;
|
|
static int prt_nchar, prt_row; /* current printwheel position, current page row */
|
|
static int prt_nnl; /* number of queued newlines */
|
|
|
|
#define CC_CHANNEL_1 0x0080 /* carriage control tape punch values */
|
|
#define CC_CHANNEL_2 0x0040
|
|
#define CC_CHANNEL_3 0x0020
|
|
#define CC_CHANNEL_4 0x0010
|
|
#define CC_CHANNEL_5 0x0008
|
|
#define CC_CHANNEL_6 0x0004
|
|
#define CC_CHANNEL_9 0x0002
|
|
#define CC_CHANNEL_12 0x0001
|
|
|
|
#define PRT_PAGELENGTH 66
|
|
|
|
// glunk need to fill these two arrays in -- cctape and codewheel1132
|
|
|
|
static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */
|
|
|
|
static struct tag_ccpunches { /* list of rows and punches on tape */
|
|
int row, channels;
|
|
} ccpunches[] = {
|
|
7, CC_CHANNEL_12, /* these came from the tape in our printer */
|
|
13, CC_CHANNEL_1 /* modulo 66 */
|
|
};
|
|
|
|
#include "ibm1130_prtwheel.h"
|
|
|
|
// reset_prt_line - clear the print line following paper advancement
|
|
|
|
static void reset_prt_line (void)
|
|
{
|
|
memset(nprint, 0, sizeof(nprint));
|
|
memset(ncol, 0, sizeof(ncol));
|
|
maxnp = 0;
|
|
}
|
|
|
|
// save_prt_line - fire hammers for character 'ch'
|
|
|
|
static t_bool save_prt_line (int ch)
|
|
{
|
|
int i, r, addr = 32;
|
|
int32 mask = 0, wd = 0;
|
|
|
|
for (i = 0; i < PRT_COLUMNS; i++) {
|
|
if (mask == 0) { // fetch next word from memory
|
|
mask = 0x8000;
|
|
wd = M[addr++];
|
|
}
|
|
|
|
if (wd & mask) { // hammer is to fire in this column
|
|
if ((r = nprint[i]) < MAX_OVPRINT) {
|
|
if (ncol[r] <= i) { // we haven't moved this far yet
|
|
if (ncol[r] == 0) // first char in this row?
|
|
memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row
|
|
ncol[r] = i+1; // remember new row length
|
|
}
|
|
prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character
|
|
|
|
nprint[i]++; // remember max overprintings for this column
|
|
maxnp = MAX(maxnp, nprint[i]);
|
|
}
|
|
}
|
|
|
|
mask >>= 1; // prepare to examine next bit
|
|
}
|
|
|
|
return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set
|
|
}
|
|
|
|
// write_line - write collected line to output file. No need to trim spaces as the hammers
|
|
// are never fired for them, so ncol[r] is the last printed position on each line.
|
|
|
|
static void flush_prt_line (FILE *fd, t_bool space)
|
|
{
|
|
int r;
|
|
|
|
if (! (space || maxnp)) // nothing to do
|
|
return;
|
|
|
|
prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line
|
|
|
|
if (space && ! maxnp) { // spacing only
|
|
if (prt_row == 0 && prt_nnl) {
|
|
putc('\f', fd);
|
|
prt_nnl = 0;
|
|
}
|
|
else
|
|
prt_nnl++;
|
|
|
|
return;
|
|
}
|
|
|
|
if (prt_nnl) { // there are queued newlines
|
|
if (prt_row == 0 && prt_nnl) { // we spaced to top of form: use formfeed
|
|
putc('\f', fd);
|
|
prt_nnl = 0;
|
|
}
|
|
else {
|
|
while (prt_nnl > 0) { // spit out queued newlines
|
|
#ifdef WIN32
|
|
putc('\r', fd); // DOS/Windows: end with cr/lf
|
|
#endif
|
|
putc('\n', fd); // otherwise end with lf
|
|
prt_nnl--;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (r = 0; r < maxnp; r++) {
|
|
if (r > 0)
|
|
putc('\r', fd); // carriage return between overprinted lines
|
|
fwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd);
|
|
}
|
|
|
|
reset_prt_line();
|
|
|
|
prt_nnl++; // queue a newline
|
|
}
|
|
|
|
#define PRT_CMD_START_PRINTER 0x0080
|
|
#define PRT_CMD_STOP_PRINTER 0x0040
|
|
#define PRT_CMD_START_CARRIAGE 0x0004
|
|
#define PRT_CMD_STOP_CARRIAGE 0x0002
|
|
#define PRT_CMD_SPACE 0x0001
|
|
|
|
#define PRT_CMD_MASK 0x00C7
|
|
|
|
/* xio_1132_printer - XIO command interpreter for the 1132 printer */
|
|
|
|
void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)
|
|
{
|
|
char msg[80];
|
|
UNIT *uptr = &prt_unit[0];
|
|
|
|
switch (func) {
|
|
case XIO_READ:
|
|
M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8;
|
|
|
|
if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */
|
|
prt_nchar = (prt_nchar + 1) % WHEELCHARS;
|
|
break;
|
|
|
|
case XIO_SENSE_DEV:
|
|
ACC = prt_dsw;
|
|
if (modify & 0x01) { /* reset interrupts */
|
|
CLRBIT(prt_dsw, PRT_DSW_READ_EMITTER_RESPONSE | PRT_DSW_SKIP_RESPONSE | PRT_DSW_SPACE_RESPONSE);
|
|
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
}
|
|
break;
|
|
|
|
case XIO_CONTROL:
|
|
if (modify & PRT_CMD_START_PRINTER)
|
|
SETBIT(uptr->flags, UNIT_PRINTING);
|
|
|
|
if (modify & PRT_CMD_STOP_PRINTER)
|
|
CLRBIT(uptr->flags, UNIT_PRINTING);
|
|
|
|
if (modify & PRT_CMD_START_CARRIAGE)
|
|
SETBIT(uptr->flags, UNIT_SKIPPING);
|
|
|
|
if (modify & PRT_CMD_STOP_CARRIAGE)
|
|
CLRBIT(uptr->flags, UNIT_SKIPPING);
|
|
|
|
if (modify & PRT_CMD_SPACE)
|
|
SETBIT(uptr->flags, UNIT_SPACING);
|
|
|
|
sim_cancel(uptr);
|
|
if (uptr->flags & PRT_CMD_MASK) { // busy bit = doing something
|
|
SETBIT(prt_dsw, PRT_DSW_PRINTER_BUSY);
|
|
sim_activate(uptr, prt_cwait);
|
|
}
|
|
else
|
|
CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY);
|
|
|
|
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING))
|
|
SETBIT(prt_dsw, PRT_DSW_CARRIAGE_BUSY);
|
|
else
|
|
CLRBIT(prt_dsw, PRT_DSW_CARRIAGE_BUSY);
|
|
|
|
if ((uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) == (UNIT_SKIPPING|UNIT_SPACING)) {
|
|
sprintf(msg, "1132 printer skip and space at same time?");
|
|
xio_error(msg);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
sprintf(msg, "Invalid 1132 printer XIO function %x", func);
|
|
xio_error(msg);
|
|
}
|
|
}
|
|
|
|
#define SET_ACTION(u,a) {(u)->flags &= ~(UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING); (u)->flags |= a;}
|
|
|
|
static t_stat prt_svc (UNIT *uptr)
|
|
{
|
|
if (prt_dsw & PRT_DSW_NOT_READY) { // cancel operation if printer went offline
|
|
SETBIT(uptr->flags, UNIT_FORMCHECK);
|
|
SET_ACTION(uptr, 0);
|
|
forms_check(TRUE); // and turn on forms check lamp
|
|
return SCPE_OK;
|
|
}
|
|
|
|
if (uptr->flags & UNIT_SPACING) {
|
|
flush_prt_line(uptr->fileref, TRUE);
|
|
|
|
prt_dsw = prt_dsw & ~PRT_DSW_CHANNEL_MASK;
|
|
prt_dsw |= cctape[prt_row];
|
|
|
|
SETBIT(prt_dsw, PRT_DSW_SPACE_RESPONSE);
|
|
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
calc_ints();
|
|
|
|
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
|
|
CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY|PRT_DSW_CARRIAGE_BUSY);
|
|
}
|
|
|
|
if (uptr->flags & UNIT_SKIPPING) {
|
|
do {
|
|
flush_prt_line(uptr->fileref, TRUE);
|
|
prt_dsw = (prt_dsw & ~PRT_DSW_CHANNEL_MASK) | cctape[prt_row];
|
|
} while (cctape[prt_row] == 0); // slew directly to a cc tape punch
|
|
|
|
SETBIT(prt_dsw, PRT_DSW_SKIP_RESPONSE);
|
|
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
calc_ints();
|
|
}
|
|
|
|
if (uptr->flags & UNIT_PRINTING) {
|
|
if (! save_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line
|
|
SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time
|
|
SET_ACTION(uptr, 0);
|
|
print_check(TRUE); // and turn on forms check lamp
|
|
return SCPE_OK;
|
|
}
|
|
|
|
prt_nchar = (prt_nchar + 1) % WHEELCHARS; // advance print drum
|
|
|
|
SETBIT(prt_dsw, PRT_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer
|
|
SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130)
|
|
calc_ints();
|
|
}
|
|
|
|
if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something
|
|
SETBIT(prt_dsw, PRT_DSW_PRINTER_BUSY);
|
|
sim_activate(uptr, prt_cwait);
|
|
}
|
|
else
|
|
CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY);
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat prt_reset (DEVICE *dptr)
|
|
{
|
|
UNIT *uptr = &prt_unit[0];
|
|
int i;
|
|
|
|
sim_cancel(uptr);
|
|
|
|
memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image
|
|
for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++)
|
|
cctape[ccpunches[i].row-1] |= ccpunches[i].channels;
|
|
|
|
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);
|
|
SET_ACTION(uptr, 0);
|
|
calc_ints();
|
|
|
|
prt_nchar = 0;
|
|
prt_row = 0;
|
|
prt_nnl = 0;
|
|
prt_dsw = cctape[prt_row];
|
|
reset_prt_line();
|
|
|
|
if (! IS_ONLINE(uptr))
|
|
SETBIT(prt_dsw, PRT_DSW_NOT_READY);
|
|
|
|
forms_check(FALSE);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat prt_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
t_stat rval;
|
|
|
|
if (uptr->flags & UNIT_ATT) {
|
|
if ((rval = prt_detach(uptr)) != SCPE_OK) {
|
|
prt_dsw |= PRT_DSW_NOT_READY;
|
|
return rval;
|
|
}
|
|
}
|
|
|
|
sim_cancel(uptr);
|
|
|
|
if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) {
|
|
prt_dsw |= PRT_DSW_NOT_READY;
|
|
return rval;
|
|
}
|
|
|
|
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);
|
|
SET_ACTION(uptr, 0);
|
|
calc_ints();
|
|
|
|
prt_nchar = 0;
|
|
prt_nnl = 0;
|
|
prt_row = 0;
|
|
prt_dsw = (prt_dsw & ~PRT_DSW_CHANNEL_MASK) | cctape[prt_row];
|
|
if (IS_ONLINE(uptr))
|
|
CLRBIT(prt_dsw, PRT_DSW_NOT_READY);
|
|
else
|
|
SETBIT(prt_dsw, PRT_DSW_NOT_READY);
|
|
|
|
reset_prt_line();
|
|
forms_check(FALSE);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat prt_detach (UNIT *uptr)
|
|
{
|
|
t_stat rval;
|
|
|
|
flush_prt_line(uptr->fileref, FALSE);
|
|
|
|
if ((rval = detach_unit(uptr)) != SCPE_OK)
|
|
return rval;
|
|
|
|
sim_cancel(uptr);
|
|
|
|
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);
|
|
SET_ACTION(uptr, 0);
|
|
calc_ints();
|
|
|
|
SETBIT(prt_dsw, PRT_DSW_NOT_READY);
|
|
|
|
forms_check(FALSE);
|
|
return SCPE_OK;
|
|
}
|