RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially debugged. Do NOT enable these features for normal operations. 1. New Features in 3.1-0 1.1 SCP and libraries - Added simulated Ethernet support for VMS, FreeBSD, Mac OS/X. - Added status return to tmxr_putc_ln. - Added sim_putchar_s to handle possible output stalls. 1.2 All DECtapes - Added "DECtape off reel" error stop. 1.3 All Asynchronous Consoles - Added support for output congestion stall if using a Telnet connection. 1.4 PDP-1 - Added Type 23 parallel drum support. 1.5 PDP-8 - Added instruction history. - Added TSC8-75 option support for ETOS. - Added TD8E DECtape support. 1.6 PDP-18b - Added instruction history. - Changed PDP-9, PDP-15 API default to enabled. 1.7 PDP-11 - Added support for 18b only Qbus devices. - Formalized bus and addressing definitions. - Added control to enable/disable autoconfiguration. - Added stub support for second Unibus Ethernet controller. 1.7 Interdata 32b - Added instruction history. 1.8 Eclipse - Added floating point support. - Added programmable interval timer support. 1.9 H316 - Added DMA/DMC support. - Added fixed head disk support. - Added moving head disk support. - Added magtape support. 1.10 IBM 1130 (Brian Knittel) - Added support for physical card reader, using the Cardread interface (www.ibm1130.org/sim/downloads). - Added support for physical printer (flushes output buffer after each line). 2. Bugs Fixed in 3.1-0 2.1 SCP and libraries - Fixed numerous bugs in Ethernet library. 2.2 All DECtapes - Fixed reverse checksum value in 'read all' mode. - Simplified (and sped up) timing. 2.3 PDP-8 - Fixed bug in RX28 read status (found by Charles Dickman). - Fixed RX28 double density write. 2.4 PDP-18b - Fixed autoincrement bug in PDP-4, PDP-7, PDP-9. 2.5 PDP-11/VAX - Revised RQ MB->LBN conversion for greater accuracy. - Fixed bug in IO configuration (found by David Hittner). - Fixed bug with multiple RQ RAUSER drives. - Fixed bug in second Qbus Ethernet controller interrupts. 2.6 Nova/Eclipse - Fixed bugs in DKP flag clear, map setup, map usage (Charles Owen). - Fixed bug in MT, reset completes despite I/O reset (Charles Owen). - Fixed bug in MT, space operations return word count (Charles Owen). 2.7 IBM 1130 (Brian Knittel) - Fixed bug in setting carry bit in subtract and subtract double. - Fixed timing problem in console printer simulation. 2.8 1620 - Fixed bug in branch digit (found by Dave Babcock). 3. New Features in 3.0 vs prior releases 3.1 SCP and Libraries - Added ASSIGN/DEASSIGN (logical name) commands. - Changed RESTORE to unconditionally detach files. - Added E11 and TPC format support to magtape library. - Fixed bug in SHOW CONNECTIONS. - Added USE_ADDR64 support. 3.2 All magtapes - Magtapes support SIMH format, E11 format, and TPC format (read only). - SET <tape_unit> FORMAT=format sets the specified tape unit's format. - SHOW <tape_unit> FORMAT displays the specified tape unit's format. - Tape format can also be set as part of the ATTACH command, using the -F switch. 3.3 VAX - VAX can be compiled without USE_INT64. - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support files > 2GB. - VAX ROM has speed control (SET ROM DELAY/NODELAY). 3.4 PDP-1 - Added block loader format support to LOAD. - Changed BOOT PTR to allow loading of all of the first bank of memory. - The LOAD command takes an optional argument specifying the memory field to be loaded. - The PTR BOOT command takes its starting memory field from the TA (address switch) register. 3.5 PDP-18b Family - Added PDP-4 EAE support. - Added PDP-15 FP15 support. - Added PDP-15 XVM support. - Added PDP-15 "re-entrancy ECO". - Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR. 4. Bugs Fixed in 3.0 vs prior releases 4.1 SCP and Libraries - Fixed end of file problem in dep, idep. - Fixed handling of trailing spaces in dep, idep. 4.2 VAX - Fixed CVTfi bug: integer overflow not set if exponent out of range - Fixed EMODx bugs: o First and second operands reversed o Separated fraction received wrong exponent o Overflow calculation on separated integer incorrect o Fraction not set to zero if exponent out of range - Fixed interval timer and ROM access to pass power-up self-test even on very fast host processors (fixes from Mark Pizzolato). - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.3 1401 - Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. - Fixed MCE bug, BS off by 1 if zero suppress. - Fixed chaining bug, D lost if return to SCP. - Fixed H branch, branch occurs after continue. - Added check for invalid 8 character MCW, LCA. - Fixed magtape load-mode end of record response. - Revised fetch to model hardware more closely. - Fixed tape read end-of-record handling based on real 1401. - Added diagnostic read (space forward). 4.4 Nova - Fixed DSK variable size interaction with restore. - Fixed bug in DSK set size routine. 4.5 PDP-1 - Fixed DT variable size interaction with restore. - Updated CPU, line printer, standard devices to detect indefinite I/O wait. - Fixed incorrect logical, missing activate, break in drum simulator. - Fixed bugs in instruction decoding, overprinting for line printer. - Fixed system hang if continue after PTR error. - Fixed PTR to start/stop on successive rpa instructions. 4.6 PDP-11 - Fixed DT variable size interaction with restore. - Fixed bug in MMR1 update (found by Tim Stark). - Added XQ features and fixed bugs: o Corrected XQ interrupts on IE state transition (code by Tom Evans). o Added XQ interrupt clear on soft reset. o Removed XQ interrupt when setting XL or RL (multiple people). o Added SET/SHOW XQ STATS. o Added SHOW XQ FILTERS. o Added ability to split received packet into multiple buffers. o Added explicit runt and giant packet processing. - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.7 PDP-18B - Fixed DT, RF variable size interaction with restore. - Fixed MT bug in MTTR. - Fixed bug in PDP-4 line printer overprinting. - Fixed bug in PDP-15 memory protect/skip interaction. - Fixed bug in RF set size routine. - Increased PTP TIME for PDP-15 operating systems. - Fixed priorities in PDP-15 API (differs from PDP-9). - Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9). - Fixed bug in CAF, clears API subsystem. 4.8 PDP-8 - Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed MT bug in SKTR. - Fixed bug in DF, RF set size routine. 4.9 HP2100 - Fixed bug in DP (13210A controller only), DQ read status. - Fixed bug in DP, DQ seek complete. - Fixed DR drum sizes. - Fixed DR variable capacity interaction with SAVE/RESTORE. 4.10 GRI - Fixed bug in SC queue pointer management. 4.11 PDP-10 - Fixed bug in RP read header. 4.12 Ibm1130 - Fixed bugs found by APL 1130. 4.13 Altairz80 - Fixed bug in real-time clock on Windows host. 4.14 1620 - Fixed bug in immediate index add (found by Michael Short).
799 lines
25 KiB
C
799 lines
25 KiB
C
/* ibm1130_prt.c: IBM 1130 line printer emulation
|
|
|
|
Based on the SIMH simulator package written by Robert M Supnik
|
|
|
|
Brian Knittel
|
|
Revision History
|
|
|
|
2003.12.02 - Added -p option for physical line printer output (flushes
|
|
output buffer after each line). When using a physical printer on
|
|
Windows, be sure to set printer to "send output directly to printer"
|
|
to disable spooling, otherwise nothing appears until printer is
|
|
detatched.
|
|
|
|
2003.11.25 - Changed magic filename for standard output to "(stdout)".
|
|
|
|
2002.09.13 - Added 1403 support. New file, taken from part of ibm1130_stddev.c
|
|
|
|
Note: The 1403 is much faster, even in emulation, because it takes much
|
|
less CPU power to run it. DMS doesn't use the WAIT command when waiting for
|
|
printer operations to complete, so it ends up burning LOTS of cpu cycles.
|
|
The 1403 printer doesn't require as many. HOWEVER: DMS must be loaded for the 1403,
|
|
and Fortran IOCS control cards must specify it.
|
|
|
|
The 1132 is still the default printer.
|
|
|
|
As written, we can't have two printers.
|
|
|
|
* (C) Copyright 2002, Brian Knittel.
|
|
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
|
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
|
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
|
* or modifications.
|
|
*
|
|
* This is not a supported product, but I welcome bug reports and fixes.
|
|
* Mail to simh@ibm1130.org
|
|
*/
|
|
|
|
#include "ibm1130_defs.h"
|
|
|
|
/***************************************************************************************
|
|
* 1132 PRINTER
|
|
***************************************************************************************/
|
|
|
|
#define PRT1132_DSW_READ_EMITTER_RESPONSE 0x8000
|
|
#define PRT1132_DSW_SKIP_RESPONSE 0x4000
|
|
#define PRT1132_DSW_SPACE_RESPONSE 0x2000
|
|
#define PRT1132_DSW_CARRIAGE_BUSY 0x1000
|
|
#define PRT1132_DSW_PRINT_SCAN_CHECK 0x0800
|
|
#define PRT1132_DSW_NOT_READY 0x0400
|
|
#define PRT1132_DSW_PRINTER_BUSY 0x0200
|
|
|
|
#define PRT1132_DSW_CHANNEL_MASK 0x00FF /* 1132 printer DSW bits */
|
|
#define PRT1132_DSW_CHANNEL_1 0x0080
|
|
#define PRT1132_DSW_CHANNEL_2 0x0040
|
|
#define PRT1132_DSW_CHANNEL_3 0x0020
|
|
#define PRT1132_DSW_CHANNEL_4 0x0010
|
|
#define PRT1132_DSW_CHANNEL_5 0x0008
|
|
#define PRT1132_DSW_CHANNEL_6 0x0004
|
|
#define PRT1132_DSW_CHANNEL_9 0x0002
|
|
#define PRT1132_DSW_CHANNEL_12 0x0001
|
|
|
|
#define PRT1403_DSW_PARITY_CHECK 0x8000 /* 1403 printer DSW bits */
|
|
#define PRT1403_DSW_TRANSFER_COMPLETE 0x4000
|
|
#define PRT1403_DSW_PRINT_COMPLETE 0x2000
|
|
#define PRT1403_DSW_CARRIAGE_COMPLETE 0x1000
|
|
#define PRT1403_DSW_RING_CHECK 0x0400
|
|
#define PRT1403_DSW_SYNC_CHECK 0x0200
|
|
#define PRT1403_DSW_CH9 0x0010
|
|
#define PRT1403_DSW_CH12 0x0008
|
|
#define PRT1403_DSW_CARRIAGE_BUSY 0x0004
|
|
#define PRT1403_DSW_PRINTER_BUSY 0x0002
|
|
#define PRT1403_DSW_NOT_READY 0x0001
|
|
|
|
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
|
|
|
|
static t_stat prt1132_svc(UNIT *uptr);
|
|
static t_stat prt1403_svc(UNIT *uptr);
|
|
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 = 1250; /* character rotation wait */
|
|
static int32 prt_fwait = 100; /* fast wait, for 1403 operations */
|
|
static int32 prt_twait = 50; /* transfer wait, for 1403 operations */
|
|
#define SKIPTARGET (uptr->u4) /* target for skip operation */
|
|
|
|
#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_V_TRANSFERRING (UNIT_V_UF + 5) /* unit is transferring print buffer (1403 only) */
|
|
#define UNIT_V_1403 (UNIT_V_UF + 6) /* printer model is 1403 rather than 1132 */
|
|
#define UNIT_V_PARITYCHECK (UNIT_V_UF + 7) /* error flags for 1403 */
|
|
#define UNIT_V_RINGCHECK (UNIT_V_UF + 8)
|
|
#define UNIT_V_SYNCCHECK (UNIT_V_UF + 9)
|
|
#define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* this appears in ibm1130_gui as well */
|
|
|
|
#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)
|
|
#define UNIT_TRANSFERRING (1u << UNIT_V_TRANSFERRING)
|
|
#define UNIT_1403 (1u << UNIT_V_1403)
|
|
#define UNIT_PARITYCHECK (1u << UNIT_V_PARITYCHECK)
|
|
#define UNIT_RINGCHECK (1u << UNIT_V_RINGCHECK)
|
|
#define UNIT_SYNCCHECK (1u << UNIT_V_SYNCCHECK)
|
|
#define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
|
|
|
|
UNIT prt_unit[] = {
|
|
{ UDATA (&prt_svc, UNIT_ATTABLE, 0) },
|
|
};
|
|
|
|
#define IS_1403(uptr) (uptr->flags & UNIT_1403) /* model test */
|
|
#define IS_1132(uptr) ((uptr->flags & UNIT_1403) == 0) /* model test */
|
|
#define IS_PHYSICAL(uptr) (uptr->flags & UNIT_PHYSICAL_PTR)
|
|
|
|
/* Parameter in the unit descriptor (1132 printer) */
|
|
|
|
#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 */
|
|
{ DRDATA (FTIME, prt_fwait, 24), PV_LEFT }, /* 1403 fast wait */
|
|
{ DRDATA (TTIME, prt_twait, 24), PV_LEFT }, /* 1403 transfer wait */
|
|
{ NULL } };
|
|
|
|
MTAB prt_mod[] = {
|
|
{ UNIT_1403, 0, "1132", "1132", NULL }, /* model option */
|
|
{ UNIT_1403, UNIT_1403, "1403", "1403", NULL },
|
|
{ 0 } };
|
|
|
|
DEVICE prt_dev = {
|
|
"PRT", prt_unit, prt_reg, prt_mod,
|
|
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 0x0800 /* carriage control tape punch values */
|
|
#define CC_CHANNEL_2 0x0400
|
|
#define CC_CHANNEL_3 0x0200
|
|
#define CC_CHANNEL_4 0x0100
|
|
#define CC_CHANNEL_5 0x0080
|
|
#define CC_CHANNEL_6 0x0040 /* 7, 8, 10 and 11 are not used on 1132 printer */
|
|
#define CC_CHANNEL_7 0x0020
|
|
#define CC_CHANNEL_8 0x0010
|
|
#define CC_CHANNEL_9 0x0008
|
|
#define CC_CHANNEL_10 0x0004
|
|
#define CC_CHANNEL_11 0x0002
|
|
#define CC_CHANNEL_12 0x0001
|
|
|
|
#define CC_1403_BITS 0x0FFF /* all bits for 1403, most for 1132 */
|
|
#define CC_1132_BITS (CC_1403_BITS & ~(CC_CHANNEL_7|CC_CHANNEL_8|CC_CHANNEL_10|CC_CHANNEL_11))
|
|
|
|
#define PRT_PAGELENGTH 66
|
|
|
|
static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */
|
|
|
|
static struct tag_ccpunches { /* list of rows and punches on tape */
|
|
int row, channels;
|
|
}
|
|
ccpunches[] = {
|
|
2, CC_CHANNEL_1, // channel 1 = top of form
|
|
62, CC_CHANNEL_12 // channel 12 = bottom of form
|
|
},
|
|
cccgi[] = {
|
|
2, CC_CHANNEL_1 // channel 1 = top of form; no bottom of form
|
|
};
|
|
|
|
#include "ibm1130_prtwheel.h"
|
|
|
|
extern int32 sim_switches;
|
|
|
|
// cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read
|
|
|
|
static int cc_format_1132 (int bits)
|
|
{
|
|
return ((bits & (CC_CHANNEL_1|CC_CHANNEL_2|CC_CHANNEL_3|CC_CHANNEL_4|CC_CHANNEL_5|CC_CHANNEL_6)) >> 4) |
|
|
((bits & CC_CHANNEL_9) >> 3) |
|
|
(bits & CC_CHANNEL_12);
|
|
}
|
|
|
|
#define cc_format_1403(bits) (bits)
|
|
|
|
// 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_1132_prt_line - fire hammers for character 'ch'
|
|
|
|
static t_bool save_1132_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 newpage (FILE *fd)
|
|
{
|
|
if (cgi)
|
|
fputs("<HR>\n", fd);
|
|
else
|
|
putc('\f', fd); // formfeed
|
|
}
|
|
|
|
static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush)
|
|
{
|
|
int r;
|
|
|
|
if (! (spacemode || maxnp)) // nothing to do
|
|
return;
|
|
|
|
prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line
|
|
|
|
if (spacemode && ! maxnp) { // spacing only
|
|
if (prt_row == 0 && prt_nnl) {
|
|
#ifdef WIN32
|
|
if (! cgi)
|
|
putc('\r', fd); // DOS/Windows: end with cr/lf
|
|
#endif
|
|
putc('\n', fd); // otherwise end with lf
|
|
if (spacemode & UNIT_SKIPPING) // add formfeed if we crossed page boundary while skipping
|
|
newpage(fd);
|
|
prt_nnl = 0;
|
|
}
|
|
else
|
|
prt_nnl++;
|
|
|
|
prt_unit->pos++; // note something written
|
|
return;
|
|
}
|
|
|
|
if (prt_nnl) { // there are queued newlines
|
|
// if we spaced to top of form, don't emit formfeed. We'd only ever emit the formfeed if we skipped via control tape channels
|
|
// if (prt_row == 0 && prt_nnl) { // we spaced to top of form
|
|
//#ifdef WIN32
|
|
// if (! cgi)
|
|
// putc('\r', fd); // DOS/Windows: end with cr/lf
|
|
//#endif
|
|
// putc('\n', fd); // otherwise end with lf
|
|
// newpage(fd);
|
|
// prt_nnl = 0;
|
|
// }
|
|
// else {
|
|
while (prt_nnl > 0) { // spit out queued newlines
|
|
#ifdef WIN32
|
|
if (! cgi)
|
|
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
|
|
fxwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd);
|
|
}
|
|
|
|
reset_prt_line();
|
|
|
|
prt_unit->pos++; // note something written
|
|
prt_nnl++; // queue a newline
|
|
|
|
if (phys_flush) // if physical printer, send buffered output to device
|
|
fflush(fd);
|
|
}
|
|
|
|
// 1132 printer commands
|
|
|
|
#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
|
|
|
|
extern char * saywhere (int addr);
|
|
|
|
static void mytrace (int start, char *what)
|
|
{
|
|
char *where;
|
|
|
|
if ((where = saywhere(prev_IAR)) == NULL) where = "?";
|
|
trace_io("%s %s at %04x: %s\n", start ? "start" : "stop", what, prev_IAR, where);
|
|
}
|
|
|
|
/* 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_1132;
|
|
break;
|
|
|
|
case XIO_SENSE_DEV:
|
|
ACC = PRT_DSW;
|
|
if (modify & 0x01) { /* reset interrupts */
|
|
CLRBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE | PRT1132_DSW_SKIP_RESPONSE | PRT1132_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);
|
|
// mytrace(1, "printing");
|
|
}
|
|
|
|
if (modify & PRT_CMD_STOP_PRINTER) {
|
|
CLRBIT(uptr->flags, UNIT_PRINTING);
|
|
// mytrace(0, "printing");
|
|
}
|
|
|
|
if (modify & PRT_CMD_START_CARRIAGE) {
|
|
SETBIT(uptr->flags, UNIT_SKIPPING);
|
|
// mytrace(1, "skipping");
|
|
}
|
|
|
|
if (modify & PRT_CMD_STOP_CARRIAGE) {
|
|
CLRBIT(uptr->flags, UNIT_SKIPPING);
|
|
// mytrace(0, "skipping");
|
|
}
|
|
|
|
if (modify & PRT_CMD_SPACE) {
|
|
SETBIT(uptr->flags, UNIT_SPACING);
|
|
// mytrace(1, "space");
|
|
}
|
|
|
|
sim_cancel(uptr);
|
|
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { // busy bits = doing something
|
|
SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
|
|
sim_activate(uptr, prt_cwait);
|
|
}
|
|
else
|
|
CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
|
|
|
|
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING))
|
|
SETBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY);
|
|
else
|
|
CLRBIT(PRT_DSW, PRT1132_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|UNIT_TRANSFERRING); (u)->flags |= a;}
|
|
|
|
static t_stat prt_svc (UNIT *uptr)
|
|
{
|
|
return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr);
|
|
}
|
|
|
|
// prt1132_svc - emulated timeout for 1132 operation
|
|
|
|
static t_stat prt1132_svc (UNIT *uptr)
|
|
{
|
|
if (PRT_DSW & PRT1132_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, UNIT_SPACING, IS_PHYSICAL(uptr));
|
|
|
|
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY);
|
|
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE);
|
|
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
|
|
calc_ints();
|
|
}
|
|
|
|
if (uptr->flags & UNIT_SKIPPING) {
|
|
do {
|
|
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
|
|
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK);
|
|
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]));
|
|
} while ((cctape[prt_row] & CC_1132_BITS) == 0); // slew directly to a cc tape punch
|
|
|
|
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE);
|
|
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
calc_ints();
|
|
}
|
|
|
|
if (uptr->flags & UNIT_PRINTING) {
|
|
if (! save_1132_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_1132; // advance print drum
|
|
|
|
SETBIT(PRT_DSW, PRT1132_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, PRT1132_DSW_PRINTER_BUSY);
|
|
sim_activate(uptr, prt_cwait);
|
|
}
|
|
else
|
|
CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
void save_1403_prt_line (int32 addr)
|
|
{
|
|
int i, j, r, ch, even = TRUE;
|
|
unsigned char ebcdic;
|
|
int32 wd;
|
|
|
|
for (i = 0; i < PRT_COLUMNS; i++) {
|
|
if (even) { // fetch next word from memory
|
|
wd = M[addr++];
|
|
ebcdic = (unsigned char) ((wd >> 8) & 0x7F);
|
|
even = FALSE;
|
|
}
|
|
else {
|
|
ebcdic = (unsigned char) (wd & 0x7F); // use low byte of previously fetched word
|
|
even = TRUE;
|
|
}
|
|
|
|
ch = ' '; // translate ebcdic to ascii. Don't bother checking for parity errors
|
|
for (j = 0; j < WHEELCHARS_1403; j++) {
|
|
if (codewheel1403[j].ebcdic == ebcdic) {
|
|
ch = codewheel1403[j].ascii;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ch > ' ') {
|
|
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]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify)
|
|
{
|
|
UNIT *uptr = &prt_unit[0];
|
|
|
|
switch (func) {
|
|
case XIO_INITW: /* print a line */
|
|
save_1403_prt_line(iocc_addr); /* put formatted line into our print buffer */
|
|
|
|
SETBIT(uptr->flags, UNIT_TRANSFERRING); /* schedule transfer complete interrupt */
|
|
SETBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);
|
|
sim_activate(uptr, prt_twait);
|
|
break;
|
|
|
|
case XIO_CONTROL: /* initiate single space */
|
|
if (uptr->flags & UNIT_SKIPPING) {
|
|
xio_error("1403 printer skip and space at same time?");
|
|
}
|
|
else {
|
|
SETBIT(uptr->flags, UNIT_SPACING);
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
|
sim_activate(uptr, prt_fwait);
|
|
}
|
|
break;
|
|
|
|
case XIO_WRITE: /* initiate skip */
|
|
if (uptr->flags & UNIT_SPACING) {
|
|
xio_error("1403 printer skip and space at same time?");
|
|
}
|
|
else {
|
|
SETBIT(uptr->flags, UNIT_SKIPPING);
|
|
SKIPTARGET = ReadW(iocc_addr) & CC_1403_BITS; /* get CC bits that we're to match */
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
|
sim_activate(uptr, prt_fwait);
|
|
}
|
|
break;
|
|
|
|
case XIO_SENSE_DEV: /* get device status word */
|
|
ACC = PRT_DSW;
|
|
if (modify & 0x01) { /* reset interrupts */
|
|
CLRBIT(PRT_DSW, PRT1403_DSW_PARITY_CHECK | PRT1403_DSW_TRANSFER_COMPLETE |
|
|
PRT1403_DSW_PRINT_COMPLETE | PRT1403_DSW_CARRIAGE_COMPLETE |
|
|
PRT1403_DSW_RING_CHECK | PRT1403_DSW_SYNC_CHECK);
|
|
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static t_stat prt1403_svc(UNIT *uptr)
|
|
{
|
|
if (PRT_DSW & PRT1403_DSW_NOT_READY) { // cancel operation if printer went offline
|
|
SET_ACTION(uptr, 0);
|
|
forms_check(TRUE); // and turn on forms check lamp
|
|
}
|
|
else if (uptr->flags & UNIT_TRANSFERRING) { // end of transfer
|
|
CLRBIT(uptr->flags, UNIT_TRANSFERRING);
|
|
SETBIT(uptr->flags, UNIT_PRINTING); // schedule "print complete"
|
|
|
|
SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); // issue transfer complete interrupt
|
|
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
|
}
|
|
else if (uptr->flags & UNIT_PRINTING) {
|
|
CLRBIT(uptr->flags, UNIT_PRINTING);
|
|
CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);
|
|
|
|
SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE);
|
|
SETBIT(ILSW[4], ILSW_4_1403_PRINTER); // issue print complete interrupt
|
|
}
|
|
else if (uptr->flags & UNIT_SKIPPING) {
|
|
do { // find line with exact match of tape punches
|
|
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
|
|
} while (cctape[prt_row] != SKIPTARGET); // slew directly to requested cc tape punch
|
|
|
|
CLRBIT(uptr->flags, UNIT_SKIPPING); // done with this
|
|
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
|
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
|
|
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
|
}
|
|
else if (uptr->flags & UNIT_SPACING) {
|
|
flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));
|
|
|
|
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
|
|
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
|
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
|
|
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
|
}
|
|
|
|
if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING))
|
|
sim_activate(uptr, prt_fwait);
|
|
|
|
CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); // set the two CC bits in the DSW
|
|
if (cctape[prt_row] & CC_CHANNEL_9)
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
|
|
if (cctape[prt_row] & CC_CHANNEL_12)
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
|
|
|
|
calc_ints();
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* delete_cmd - SCP command to delete a file */
|
|
|
|
static t_stat delete_cmd (int flag, char *cptr)
|
|
{
|
|
char gbuf[CBUFSIZE];
|
|
int status;
|
|
|
|
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
|
|
if (*gbuf == 0) return SCPE_2FARG;
|
|
if (*cptr != 0) return SCPE_2MARG; /* now eol? */
|
|
|
|
status = unlink(gbuf); /* delete the file */
|
|
|
|
if (status != 0 && errno != ENOENT) /* print message if failed and file exists */
|
|
perror(gbuf);
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* prt_reset - reset emulated printer */
|
|
|
|
static t_stat prt_reset (DEVICE *dptr)
|
|
{
|
|
UNIT *uptr = &prt_unit[0];
|
|
int i;
|
|
|
|
// add a DELETE filename command so we can be sure to have clean listings
|
|
register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n");
|
|
|
|
sim_cancel(uptr);
|
|
|
|
memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image
|
|
|
|
if (cgi)
|
|
for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++)
|
|
cctape[cccgi[i].row-1] |= cccgi[i].channels;
|
|
else
|
|
for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++)
|
|
cctape[ccpunches[i].row-1] |= ccpunches[i].channels;
|
|
|
|
prt_nchar = 0;
|
|
prt_row = 0;
|
|
prt_nnl = 0;
|
|
|
|
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK|UNIT_PRINTING|UNIT_SPACING|UNIT_SKIPPING|
|
|
UNIT_TRANSFERRING|UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);
|
|
|
|
if (IS_1132(uptr)) {
|
|
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
PRT_DSW = cc_format_1132(cctape[prt_row]);
|
|
if (! IS_ONLINE(uptr))
|
|
SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
|
}
|
|
else {
|
|
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
|
PRT_DSW = 0;
|
|
if (cctape[prt_row] & CC_CHANNEL_9)
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
|
|
if (cctape[prt_row] & CC_CHANNEL_12)
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
|
|
if (! IS_ONLINE(uptr))
|
|
SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);
|
|
}
|
|
|
|
SET_ACTION(uptr, 0);
|
|
calc_ints();
|
|
reset_prt_line();
|
|
|
|
forms_check(FALSE);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat prt_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
t_stat rval;
|
|
/* assume failure */
|
|
SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY);
|
|
|
|
if (uptr->flags & UNIT_ATT) {
|
|
if ((rval = prt_detach(uptr)) != SCPE_OK) {
|
|
return rval;
|
|
}
|
|
}
|
|
|
|
if (sim_switches & SWMASK('P')) /* set physical (unbuffered) printer flag */
|
|
SETBIT(uptr->flags, UNIT_PHYSICAL_PTR);
|
|
else
|
|
CLRBIT(uptr->flags, UNIT_PHYSICAL_PTR);
|
|
|
|
sim_cancel(uptr);
|
|
|
|
if (strcmp(cptr, "(stdout)") == 0) { /* connect printer to stdout */
|
|
if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */
|
|
uptr->filename = calloc(CBUFSIZE, sizeof(char));
|
|
strcpy(uptr->filename, "(stdout)");
|
|
uptr->fileref = stdout;
|
|
SETBIT(uptr->flags, UNIT_ATT);
|
|
uptr->pos = 0;
|
|
}
|
|
else {
|
|
if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK)
|
|
return rval;
|
|
}
|
|
|
|
fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */
|
|
uptr->pos = ftell(uptr->fileref);
|
|
|
|
if (IS_1132(uptr)) {
|
|
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);
|
|
}
|
|
else {
|
|
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
|
CLRBIT(uptr->flags, UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);
|
|
}
|
|
|
|
SET_ACTION(uptr, 0);
|
|
calc_ints();
|
|
|
|
prt_nchar = 0;
|
|
prt_nnl = 0;
|
|
prt_row = 0;
|
|
reset_prt_line();
|
|
|
|
if (IS_1132(uptr)) {
|
|
PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]);
|
|
|
|
if (IS_ONLINE(uptr))
|
|
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
|
}
|
|
else {
|
|
CLRBIT(PRT_DSW, PRT1403_DSW_CH9 | PRT1403_DSW_CH12);
|
|
if (cctape[prt_row] & CC_CHANNEL_9)
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
|
|
if (cctape[prt_row] & CC_CHANNEL_12)
|
|
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
|
|
|
|
if (IS_ONLINE(uptr))
|
|
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
|
}
|
|
|
|
forms_check(FALSE);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat prt_detach (UNIT *uptr)
|
|
{
|
|
t_stat rval;
|
|
|
|
flush_prt_line(uptr->fileref, TRUE, TRUE);
|
|
|
|
if (uptr->fileref == stdout) {
|
|
CLRBIT(uptr->flags, UNIT_ATT);
|
|
free(uptr->filename);
|
|
uptr->filename = NULL;
|
|
}
|
|
else if ((rval = detach_unit(uptr)) != SCPE_OK)
|
|
return rval;
|
|
|
|
sim_cancel(uptr);
|
|
|
|
if (IS_1132(uptr)) {
|
|
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
|
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);
|
|
SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
|
}
|
|
else {
|
|
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
|
SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);
|
|
}
|
|
SET_ACTION(uptr, 0);
|
|
|
|
calc_ints();
|
|
|
|
forms_check(FALSE);
|
|
return SCPE_OK;
|
|
}
|