The B5500 simulator supports the following peripherals. Two CPUs with between 4K and 32K of memory. The second CPU can be enabled with "set cpu1 enable". "set cpu1 disable" disables the second CPU. Up to 4 floating IO channels. Individual channels can be enabled with "set io# enable", or "set io# disable". There are two card readers. The second reader is disabled by default. There is one Card Punch. The Card reader and Card Punch support the following options: set cr format= auto - will automatically determine the format based on the text it recieves. text Text based cards. Tabs are converted to the correct number of spaces. A record of ~raw octal will enter a binary card. ~eor will enter a 7/8/9 punch in column 1. ~eof will enter a 6/7/9 punch in column 1. ~eoi will enter a 6/7/8/9 punch in column 1. ~~ will enter a ~ as the first character. bin Binary Card format: Each record 160 characters. First characters 6789---- Second character 21012345 111 Top 4 bits of second character are 0. It is unlikely that any other format could look like this. bcd BCD Format: Each record variable length (80 chars or less). Record mark has bit 7 set. Bit 6 is even parity. Bits 5-0 are character. cbn CBN Format: Each record 160 charaters. First char has bit 7 set. Rest set to 0. Bit 6 is odd parity. Bit 5-0 of first character are top 6 bits of card. Bit 5-0 of second character are lower 6 bits of card. For punch format of auto if the card can't be converted to text it is output as a raw record. There are two line printers, the second one is disabled by default. The LP supports the option "set lp# linesperpage=#" which determines when the printer will force out a page break. There are up to 16 mag tape drives, the format is controlled by the standard simh format control for tapes. These are 6 bit tapes, 1 character per record with parity. Units 8-16 are disabled by default. There are up to two drum units DR0 and DR1. These can either be attached to a file or set to AUXMEM. Setting to AUXMEM causes them to exist only during the given simh run. Setting back to DRUM will clear whatever was stored on the drum. To enable use of DRUM on XV the following options should be turned on "DRA,DRB,CODEOLAY,DATAOLAY". MCP will then use the drum as a overlay device instead of the disk system. Disks can be attached to the various ESU's, ESU0-9 are on DKA by default, ESU10-19 are on DKB. If "set dk1 dfx" is set, then ESU10-19 are not used and the disks are shared by both DKA and DKB. To use more then 10 ESU's in a non shared mode, a new version of MCP must be created. MCP must be compiled with DFX option set to false. For MCP XV DKBNODFX must also be set to true. ESU units can be set to MODI or MODIB. MODIB will double the size of the drive. The DTC can be attached to a telnet port with "attach dtc #" to enable dialup access to the sim. The loader card for the card reader is: ~raw0104441100204231524012004000004444550211002041317700000000000024045303040243 00050000006501004131011041310055005500000062005042310000006600304231000000720010 42310000007675610165001002310010413100040107202500440106202533554061256520252265 20251765202514655355536117650000004401062025155522610165225572610465044101160500 4131 This card should be all in one line.
1007 lines
30 KiB
C
1007 lines
30 KiB
C
/* b5500_urec.c: Burrioughs 5500 Unit record devices.
|
||
|
||
Copyright (c) 2016, Richard Cornwell
|
||
|
||
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
|
||
RICHARD CORNWELL 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.
|
||
|
||
This is the standard card reader. 10,14
|
||
This is the standard card punch. 10
|
||
This is the standard line printer. 22,26
|
||
This is the standard operators console. 30
|
||
|
||
*/
|
||
|
||
#include "b5500_defs.h"
|
||
#include "sim_card.h"
|
||
#include "sim_defs.h"
|
||
#include "sim_console.h"
|
||
|
||
#define UNIT_CDR UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | UNIT_ROABLE | \
|
||
MODE_029
|
||
#define UNIT_CDP UNIT_ATTABLE | UNIT_DISABLE | MODE_029
|
||
#define UNIT_LPR UNIT_ATTABLE | UNIT_DISABLE
|
||
|
||
/* For Card reader, when set returns end of file at end of deck. */
|
||
/* Reset after sent to system */
|
||
#define MODE_EOF (0x40 << UNIT_V_MODE)
|
||
|
||
|
||
|
||
/* std devices. data structures
|
||
|
||
cdr_dev Card Reader device descriptor
|
||
cdr_unit Card Reader unit descriptor
|
||
cdr_reg Card Reader register list
|
||
cdr_mod Card Reader modifiers list
|
||
*/
|
||
|
||
/* Device status information stored in u5 */
|
||
#define URCSTA_CHMASK 0003 /* Mask of I/O channel to send data on */
|
||
#define URCSTA_CARD 0004 /* Unit has card in buffer */
|
||
#define URCSTA_FULL 0004 /* Unit has full buffer */
|
||
#define URCSTA_BUSY 0010 /* Device is busy */
|
||
#define URCSTA_BIN 0020 /* Card reader in binary mode */
|
||
#define URCSTA_ACTIVE 0040 /* Unit is active */
|
||
#define URCSTA_EOF 0100 /* Flag the end of file */
|
||
#define URCSTA_INPUT 0200 /* Console fill buffer from keyboard */
|
||
#define URCSTA_FILL 010000 /* Fill unit buffer */
|
||
#define URCSTA_CMD_V 16
|
||
|
||
#define URCSTA_SKIP 000017 /* Skip mask */
|
||
#define URCSTA_DOUBLE 000020 /* Double space skip */
|
||
#define URCSTA_SINGLE 000040 /* Single space skip. */
|
||
#define URCSTA_READ 000400 /* Read flag */
|
||
#define URCSTA_WC 001000 /* Use word count */
|
||
#define URCSTA_DIRECT 002000 /* Direction, Long line */
|
||
#define URCSTA_BINARY 004000 /* Binary transfer */
|
||
#define URCSTA_INHIBIT 040000 /* Inhibit transfer to memory */
|
||
|
||
/* Simulator debug controls */
|
||
DEBTAB cdr_debug[] = {
|
||
{"CMD", DEBUG_CMD, "Show command execution to devices"},
|
||
{"DATA", DEBUG_DATA, "Show data transfers"},
|
||
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
|
||
{"EXP", DEBUG_EXP, "Show console data"},
|
||
{"CARD", DEBUG_CARD, "Show Card read/punches"},
|
||
{0, 0}
|
||
};
|
||
|
||
|
||
#if NUM_DEVS_CDR > 0
|
||
t_stat cdr_boot(int32, DEVICE *);
|
||
t_stat cdr_srv(UNIT *);
|
||
t_stat cdr_attach(UNIT *, char *);
|
||
t_stat cdr_detach(UNIT *);
|
||
t_stat cdr_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
const char *cdr_description(DEVICE *dptr);
|
||
#endif
|
||
|
||
#if NUM_DEVS_CDP > 0
|
||
t_stat cdp_srv(UNIT *);
|
||
t_stat cdp_attach(UNIT *, char *);
|
||
t_stat cdp_detach(UNIT *);
|
||
t_stat cdp_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
const char *cdp_description(DEVICE *dptr);
|
||
#endif
|
||
|
||
#if NUM_DEVS_LPR > 0
|
||
struct _lpr_data
|
||
{
|
||
uint8 lbuff[145]; /* Output line buffer */
|
||
}
|
||
lpr_data[NUM_DEVS_LPR];
|
||
|
||
t_stat lpr_srv(UNIT *);
|
||
t_stat lpr_attach(UNIT *, char *);
|
||
t_stat lpr_detach(UNIT *);
|
||
t_stat lpr_setlpp(UNIT *, int32, char *, void *);
|
||
t_stat lpr_getlpp(FILE *, UNIT *, int32, void *);
|
||
t_stat lpr_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
const char *lpr_description(DEVICE *dptr);
|
||
#endif
|
||
|
||
#if NUM_DEVS_CON > 0
|
||
struct _con_data
|
||
{
|
||
uint8 ibuff[145]; /* Input line buffer */
|
||
uint8 inptr;
|
||
uint8 outptr;
|
||
}
|
||
con_data[NUM_DEVS_CON];
|
||
|
||
t_stat con_ini(DEVICE *);
|
||
t_stat con_srv(UNIT *);
|
||
t_stat con_attach(UNIT *, char *);
|
||
t_stat con_detach(UNIT *);
|
||
t_stat con_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
const char *con_description(DEVICE *dptr);
|
||
#endif
|
||
|
||
|
||
|
||
#if NUM_DEVS_CDR > 0
|
||
UNIT cdr_unit[] = {
|
||
{UDATA(cdr_srv, UNIT_CDR, 0)}, /* A */
|
||
#if NUM_DEVS_CDR > 1
|
||
{UDATA(cdr_srv, UNIT_CDR|UNIT_DIS, 0)}, /* B */
|
||
#endif
|
||
};
|
||
|
||
MTAB cdr_mod[] = {
|
||
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||
&sim_card_set_fmt, &sim_card_show_fmt, NULL,
|
||
"Sets card format"},
|
||
{MODE_EOF, MODE_EOF, "EOF", "EOF", NULL, NULL,
|
||
"Causes EOF to be set when reader empty"},
|
||
{0}
|
||
};
|
||
|
||
DEVICE cdr_dev = {
|
||
"CR", cdr_unit, NULL, cdr_mod,
|
||
NUM_DEVS_CDR, 8, 15, 1, 8, 8,
|
||
NULL, NULL, NULL, &cdr_boot, &cdr_attach, &cdr_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, cdr_debug,
|
||
NULL, NULL, &cdr_help, NULL, NULL,
|
||
&cdr_description
|
||
};
|
||
#endif
|
||
|
||
#if NUM_DEVS_CDP > 0
|
||
UNIT cdp_unit[] = {
|
||
{UDATA(cdp_srv, UNIT_CDP, 0)}, /* A */
|
||
};
|
||
|
||
MTAB cdp_mod[] = {
|
||
{MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||
&sim_card_set_fmt, &sim_card_show_fmt, NULL,
|
||
"Sets card format"},
|
||
{0}
|
||
};
|
||
|
||
DEVICE cdp_dev = {
|
||
"CP", cdp_unit, NULL, cdp_mod,
|
||
NUM_DEVS_CDP, 8, 15, 1, 8, 8,
|
||
NULL, NULL, NULL, NULL, &cdp_attach, &cdp_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, cdr_debug,
|
||
NULL, NULL, &cdp_help, NULL, NULL,
|
||
&cdp_description
|
||
};
|
||
|
||
#endif
|
||
|
||
#if NUM_DEVS_LPR > 0
|
||
UNIT lpr_unit[] = {
|
||
{UDATA(lpr_srv, UNIT_LPR, 59)}, /* A */
|
||
#if NUM_DEVS_LPR > 1
|
||
{UDATA(lpr_srv, UNIT_LPR|UNIT_DIS, 59)}, /* B */
|
||
#endif
|
||
};
|
||
|
||
MTAB lpr_mod[] = {
|
||
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LINESPERPAGE", "LINESPERPAGE",
|
||
&lpr_setlpp, &lpr_getlpp, NULL,
|
||
"Sets number of lines on a printed page"},
|
||
{0}
|
||
};
|
||
|
||
DEVICE lpr_dev = {
|
||
"LP", lpr_unit, NULL, lpr_mod,
|
||
NUM_DEVS_LPR, 8, 15, 1, 8, 8,
|
||
NULL, NULL, NULL, NULL, &lpr_attach, &lpr_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||
NULL, NULL, &lpr_help, NULL, NULL,
|
||
&lpr_description
|
||
};
|
||
#endif
|
||
|
||
#if NUM_DEVS_CON > 0
|
||
UNIT con_unit[] = {
|
||
{UDATA(con_srv, 0, 0), 0}, /* A */
|
||
};
|
||
|
||
DEVICE con_dev = {
|
||
"CON", con_unit, NULL, NULL,
|
||
NUM_DEVS_CON, 8, 15, 1, 8, 8,
|
||
NULL, NULL, con_ini, NULL, NULL, NULL,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||
NULL, NULL, &con_help, NULL, NULL,
|
||
&con_description
|
||
};
|
||
#endif
|
||
|
||
|
||
|
||
#if ((NUM_DEVS_CDR > 0) | (NUM_DEVS_CDP > 0))
|
||
/*
|
||
* Device entry points for card reader.
|
||
* And Card punch.
|
||
*/
|
||
t_stat card_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc)
|
||
{
|
||
UNIT *uptr;
|
||
int u;
|
||
|
||
if (dev == CARD1_DEV)
|
||
u = 0;
|
||
else if (dev == CARD2_DEV)
|
||
u = 1;
|
||
else
|
||
return SCPE_NXDEV;
|
||
/* Check if card reader or card punch */
|
||
if (cmd & URCSTA_READ) {
|
||
uptr = &cdr_unit[u];
|
||
if ((uptr->flags & UNIT_ATT) == 0)
|
||
return SCPE_UNATT;
|
||
|
||
/* Are we currently tranfering? */
|
||
if (uptr->u5 & URCSTA_ACTIVE)
|
||
return SCPE_BUSY;
|
||
|
||
/* Check if we ran out of cards */
|
||
if (uptr->u5 & URCSTA_EOF) {
|
||
/* If end of file, return to system */
|
||
if (uptr->flags & MODE_EOF) {
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "cdr %d %d report eof\n", u,
|
||
chan);
|
||
chan_set_eof(chan);
|
||
uptr->flags &= ~MODE_EOF;
|
||
}
|
||
/* Clear unit ready */
|
||
iostatus &= ~(CARD1_FLAG << u);
|
||
return SCPE_UNATT;
|
||
}
|
||
|
||
if (cmd & URCSTA_BINARY) {
|
||
uptr->u5 |= URCSTA_BIN;
|
||
*wc = 20;
|
||
} else {
|
||
uptr->u5 &= ~URCSTA_BIN;
|
||
*wc = 10;
|
||
}
|
||
|
||
uptr->u5 &= ~URCSTA_CHMASK;
|
||
uptr->u5 |= URCSTA_ACTIVE|chan;
|
||
uptr->u4 = 0;
|
||
|
||
sim_activate(uptr, 500000);
|
||
return SCPE_OK;
|
||
} else {
|
||
/* Talking to punch */
|
||
if (u != 0)
|
||
return SCPE_NXDEV;
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "cdp %d %d start\n", u, chan);
|
||
uptr = &cdp_unit[0];
|
||
if ((uptr->flags & UNIT_ATT) == 0)
|
||
return SCPE_UNATT;
|
||
if (uptr->u5 & URCSTA_ACTIVE)
|
||
return SCPE_BUSY;
|
||
uptr->u5 &= ~URCSTA_CHMASK;
|
||
uptr->u5 |= URCSTA_ACTIVE|chan;
|
||
uptr->u4 = 0;
|
||
*wc = 10;
|
||
|
||
sim_activate(uptr, 500000);
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "cdp %d %d go\n", u, chan);
|
||
return SCPE_OK;
|
||
}
|
||
return SCPE_IOERR;
|
||
}
|
||
|
||
/* Handle transfer of data for card reader */
|
||
t_stat
|
||
cdr_srv(UNIT *uptr) {
|
||
int chan = URCSTA_CHMASK & uptr->u5;
|
||
int u = (uptr - cdr_unit);
|
||
|
||
if (uptr->u5 & URCSTA_EOF) {
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "cdr %d %d unready\n", u, chan);
|
||
iostatus &= ~(CARD1_FLAG << u);
|
||
uptr->u5 &= ~ URCSTA_EOF;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
/* Check if new card requested. */
|
||
if (uptr->u4 == 0 && uptr->u5 & URCSTA_ACTIVE &&
|
||
(uptr->u5 & URCSTA_CARD) == 0) {
|
||
switch(sim_read_card(uptr)) {
|
||
case SCPE_UNATT:
|
||
iostatus &= ~(CARD1_FLAG << u);
|
||
uptr->u5 &= ~(URCSTA_ACTIVE);
|
||
iostatus &= ~(CARD1_FLAG << u);
|
||
chan_set_notrdy(chan);
|
||
break;
|
||
case SCPE_EOF:
|
||
/* If end of file, return to system */
|
||
if (uptr->flags & MODE_EOF) {
|
||
sim_debug(DEBUG_DETAIL, &cdr_dev, "cdr %d %d set eof\n", u, chan);
|
||
chan_set_eof(chan);
|
||
uptr->flags &= ~MODE_EOF;
|
||
}
|
||
uptr->u5 &= ~(URCSTA_ACTIVE);
|
||
uptr->u5 |= URCSTA_EOF;
|
||
chan_set_notrdy(chan);
|
||
sim_activate(uptr, 500);
|
||
break;
|
||
case SCPE_IOERR:
|
||
chan_set_error(chan);
|
||
uptr->u5 &= ~(URCSTA_ACTIVE);
|
||
uptr->u5 |= URCSTA_EOF;
|
||
chan_set_end(chan);
|
||
break;
|
||
case SCPE_OK:
|
||
uptr->u5 |= URCSTA_CARD;
|
||
sim_activate(uptr, 500);
|
||
break;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
/* Copy next column over */
|
||
if (uptr->u5 & URCSTA_CARD &&
|
||
uptr->u4 <= ((uptr->u5 & URCSTA_BIN) ? 160 : 80)) {
|
||
struct _card_data *data;
|
||
uint8 ch = 0;
|
||
int u = (uptr - cdr_unit);
|
||
|
||
data = (struct _card_data *)uptr->up7;
|
||
|
||
if (uptr->u5 & URCSTA_BIN) {
|
||
ch = (data->image[uptr->u4 >> 1] >>
|
||
((uptr->u4 & 1)? 0 : 6)) & 077;
|
||
} else {
|
||
ch = sim_hol_to_bcd(data->image[uptr->u4]);
|
||
/* Remap some characters from 029 to BCL */
|
||
switch(ch) {
|
||
case 0: ch = 020; break; /* Translate blanks */
|
||
case 10: /* Check if 0 punch of 82 punch */
|
||
if (data->image[uptr->u4] != 0x200) {
|
||
ch = 0;
|
||
if (uptr->u4 == 0)
|
||
chan_set_parity(chan);
|
||
}
|
||
break;
|
||
case 0111:
|
||
ch = 0;
|
||
/* Handle invalid punch */
|
||
chan_set_parity(chan);
|
||
break; /* Translate ? to error*/
|
||
}
|
||
}
|
||
if(chan_write_char(chan, &ch, 0)) {
|
||
uptr->u5 &= ~(URCSTA_ACTIVE|URCSTA_CARD);
|
||
chan_set_end(chan);
|
||
/* Drop ready a bit after the last card is read */
|
||
if (sim_card_eof(uptr)) {
|
||
uptr->u5 |= URCSTA_EOF;
|
||
sim_activate(uptr, 100);
|
||
}
|
||
} else {
|
||
uptr->u4++;
|
||
sim_activate(uptr, 100);
|
||
}
|
||
sim_debug(DEBUG_DATA, &cdr_dev, "cdr %d: Char > %03o '%c' %d\n", u, ch,
|
||
sim_six_to_ascii[ch & 077], uptr->u4);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
cdr_boot(int32 unit_num, DEVICE * dptr)
|
||
{
|
||
UNIT *uptr = &dptr->units[unit_num];
|
||
uint8 dev;
|
||
t_uint64 desc;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0)
|
||
return SCPE_UNATT; /* attached? */
|
||
dev = (uptr == &cdr_unit[0]) ? CARD1_DEV : CARD2_DEV;
|
||
uptr->u5 &= ~URCSTA_ACTIVE;
|
||
desc = ((t_uint64)dev) << DEV_V | DEV_IORD| DEV_BIN | 020LL;
|
||
/* Read in one record */
|
||
return chan_boot(desc);
|
||
}
|
||
|
||
t_stat
|
||
cdr_attach(UNIT * uptr, char *file)
|
||
{
|
||
t_stat r;
|
||
int u = uptr-cdr_unit;
|
||
|
||
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
|
||
return r;
|
||
uptr->u5 &= URCSTA_BUSY;
|
||
uptr->u4 = 0;
|
||
uptr->u6 = 0;
|
||
iostatus |= (CARD1_FLAG << u);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cdr_detach(UNIT * uptr)
|
||
{
|
||
int u = uptr-cdr_unit;
|
||
|
||
iostatus &= ~(CARD1_FLAG << u);
|
||
return sim_card_detach(uptr);
|
||
}
|
||
|
||
t_stat
|
||
cdr_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "B124 Card Reader\n\n");
|
||
fprintf (st, "The system supports up to two card readers, the second one is disabled\n");
|
||
fprintf (st, "by default. To have the card reader return the EOF flag when the deck\n");
|
||
fprintf (st, "has finished reading do:\n");
|
||
fprintf (st, " sim> SET CRn EOF\n");
|
||
fprintf (st, "This flag is cleared each time a deck has been read, so it must be set\n");
|
||
fprintf (st, "again after each deck. MCP does not require this to be set as long as\n");
|
||
fprintf (st, "the deck includes a ?END card\n");
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
cdr_description(DEVICE *dptr)
|
||
{
|
||
return "B124 Card Reader";
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
|
||
#if NUM_DEVS_CDR > 0 | NUM_DEVS_CDP > 0
|
||
|
||
/* Handle transfer of data for card punch */
|
||
t_stat
|
||
cdp_srv(UNIT *uptr) {
|
||
int chan = URCSTA_CHMASK & uptr->u5;
|
||
int u = (uptr - cdp_unit);
|
||
|
||
if (uptr->u5 & URCSTA_BUSY) {
|
||
/* Done waiting, punch card */
|
||
if (uptr->u5 & URCSTA_FULL) {
|
||
sim_debug(DEBUG_DETAIL, &cdp_dev, "cdp %d %d punch\n", u, chan);
|
||
switch(sim_punch_card(uptr, NULL)) {
|
||
case SCPE_EOF:
|
||
case SCPE_UNATT:
|
||
sim_debug(DEBUG_DETAIL, &cdp_dev, "cdp %d %d set eof\n", u,
|
||
chan);
|
||
chan_set_eof(chan);
|
||
break;
|
||
/* If we get here, something is wrong */
|
||
case SCPE_IOERR:
|
||
chan_set_error(chan);
|
||
break;
|
||
case SCPE_OK:
|
||
break;
|
||
}
|
||
uptr->u5 &= ~URCSTA_FULL;
|
||
chan_set_end(chan);
|
||
}
|
||
uptr->u5 &= ~URCSTA_BUSY;
|
||
}
|
||
|
||
/* Copy next column over */
|
||
if (uptr->u5 & URCSTA_ACTIVE && uptr->u4 <= 80) {
|
||
struct _card_data *data;
|
||
uint8 ch = 0;
|
||
|
||
data = (struct _card_data *)uptr->up7;
|
||
|
||
if(chan_read_char(chan, &ch, 0)) {
|
||
uptr->u5 |= URCSTA_BUSY|URCSTA_FULL;
|
||
uptr->u5 &= ~URCSTA_ACTIVE;
|
||
} else {
|
||
sim_debug(DEBUG_DATA, &cdp_dev, "cdp %d: Char %d < %02o\n", u,
|
||
uptr->u4, ch);
|
||
data->image[uptr->u4++] = sim_bcd_to_hol(ch & 077);
|
||
}
|
||
sim_activate(uptr, 10);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
t_stat
|
||
cdp_attach(UNIT * uptr, char *file)
|
||
{
|
||
t_stat r;
|
||
|
||
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
|
||
return r;
|
||
uptr->u5 = 0;
|
||
iostatus |= PUNCH_FLAG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cdp_detach(UNIT * uptr)
|
||
{
|
||
if (uptr->u5 & URCSTA_FULL)
|
||
sim_punch_card(uptr, NULL);
|
||
iostatus &= ~PUNCH_FLAG;
|
||
return sim_card_detach(uptr);
|
||
}
|
||
|
||
t_stat
|
||
cdp_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "B303 Card Punch\n\n");
|
||
fprintf (st, "The B303 Card Punch is only capable of punching text decks, binary decks\n");
|
||
fprintf (st, "where not supported.\n");
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
cdp_description(DEVICE *dptr)
|
||
{
|
||
return "B303 Card Punch";
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
/* Line printer routines
|
||
*/
|
||
|
||
#if NUM_DEVS_LPR > 0
|
||
t_stat
|
||
lpr_setlpp(UNIT *uptr, int32 val, char *cptr, void *desc)
|
||
{
|
||
int i;
|
||
if (cptr == NULL)
|
||
return SCPE_ARG;
|
||
if (uptr == NULL)
|
||
return SCPE_IERR;
|
||
i = 0;
|
||
while(*cptr != '\0') {
|
||
if (*cptr < '0' || *cptr > '9')
|
||
return SCPE_ARG;
|
||
i = (i * 10) + (*cptr++) - '0';
|
||
}
|
||
if (i < 20 || i > 100)
|
||
return SCPE_ARG;
|
||
uptr->capac = i;
|
||
uptr->u4 = 0;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
lpr_getlpp(FILE *st, UNIT *uptr, int32 v, void *desc)
|
||
{
|
||
if (uptr == NULL)
|
||
return SCPE_IERR;
|
||
fprintf(st, "linesperpage=%d", uptr->capac);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
void
|
||
print_line(UNIT * uptr, int unit)
|
||
{
|
||
/* Convert word record into column image */
|
||
/* Check output type, if auto or text, try and convert record to bcd first */
|
||
/* If failed and text report error and dump what we have */
|
||
/* Else if binary or not convertable, dump as image */
|
||
|
||
char out[150]; /* Temp conversion buffer */
|
||
int i;
|
||
int chan = uptr->u5 & URCSTA_CHMASK;
|
||
|
||
if ((uptr->flags & (UNIT_ATT)) == 0)
|
||
return; /* attached? */
|
||
|
||
if (uptr->u3 > 0) {
|
||
/* Try to convert to text */
|
||
memset(out, 0, sizeof(out));
|
||
|
||
/* Scan each column */
|
||
for (i = 0; i < uptr->u3; i++) {
|
||
int bcd = lpr_data[unit].lbuff[i] & 077;
|
||
|
||
out[i] = con_to_ascii[bcd];
|
||
}
|
||
|
||
/* Trim trailing spaces */
|
||
for (--i; i > 0 && out[i] == ' '; i--) ;
|
||
out[i+1] = '\0';
|
||
|
||
sim_debug(DEBUG_DETAIL, &lpr_dev, "lpr print %s\n", out);
|
||
if (uptr->u5 & (URCSTA_DOUBLE << URCSTA_CMD_V)) {
|
||
out[++i] = '\r';
|
||
out[++i] = '\n';
|
||
uptr->u4 ++;
|
||
}
|
||
out[++i] = '\r';
|
||
out[++i] = '\n';
|
||
uptr->u4++;
|
||
out[++i] = '\0';
|
||
|
||
/* Print out buffer */
|
||
sim_fwrite(&out, 1, i, uptr->fileref);
|
||
uptr->u5 &= ~URCSTA_EOF;
|
||
}
|
||
|
||
|
||
switch ((uptr->u5 >> URCSTA_CMD_V) & URCSTA_SKIP) {
|
||
case 0: /* No special skip */
|
||
break;
|
||
case 1:
|
||
case 2: /* Skip to top of form */
|
||
case 12:
|
||
uptr->u4 = uptr->capac+1;
|
||
break;
|
||
|
||
case 3: /* Even lines */
|
||
if ((uptr->u4 & 1) == 1) {
|
||
sim_fwrite("\r", 1, 1, uptr->fileref);
|
||
sim_fwrite("\n", 1, 1, uptr->fileref);
|
||
uptr->u4++;
|
||
uptr->u5 &= ~URCSTA_EOF;
|
||
}
|
||
break;
|
||
case 4: /* Odd lines */
|
||
if ((uptr->u4 & 1) == 0) {
|
||
sim_fwrite("\r", 1, 1, uptr->fileref);
|
||
sim_fwrite("\n", 1, 1, uptr->fileref);
|
||
uptr->u4++;
|
||
uptr->u5 &= ~URCSTA_EOF;
|
||
}
|
||
break;
|
||
case 5: /* Half page */
|
||
while((uptr->u4 != (uptr->capac/2)) ||
|
||
(uptr->u4 != (uptr->capac))) {
|
||
sim_fwrite("\r", 1, 1, uptr->fileref);
|
||
sim_fwrite("\n", 1, 1, uptr->fileref);
|
||
uptr->u4++;
|
||
if (((uint32)uptr->u4) > uptr->capac) {
|
||
uptr->u4 = 1;
|
||
break;
|
||
}
|
||
uptr->u5 &= ~URCSTA_EOF;
|
||
}
|
||
break;
|
||
case 6: /* 1/4 Page */
|
||
while((uptr->u4 != (uptr->capac/4)) ||
|
||
(uptr->u4 != (uptr->capac/2)) ||
|
||
(uptr->u4 != (uptr->capac/2+uptr->capac/4)) ||
|
||
(uptr->u4 != (uptr->capac))) {
|
||
sim_fwrite("\r", 1, 1, uptr->fileref);
|
||
sim_fwrite("\n", 1, 1, uptr->fileref);
|
||
uptr->u4++;
|
||
if (((uint32)uptr->u4) > uptr->capac) {
|
||
uptr->u4 = 1;
|
||
break;
|
||
}
|
||
uptr->u5 &= ~URCSTA_EOF;
|
||
}
|
||
break;
|
||
case 7: /* User defined, now 1 line */
|
||
case 8:
|
||
case 9:
|
||
case 10:
|
||
case 11:
|
||
sim_fwrite("\r", 1, 1, uptr->fileref);
|
||
sim_fwrite("\n", 1, 1, uptr->fileref);
|
||
uptr->u4++;
|
||
break;
|
||
}
|
||
|
||
|
||
if (((uint32)uptr->u4) > uptr->capac) {
|
||
uptr->u4 = 1;
|
||
uptr->u5 |= URCSTA_EOF;
|
||
sim_fwrite("\f", 1, 1, uptr->fileref);
|
||
sim_fseek(uptr->fileref, 0, SEEK_CUR);
|
||
sim_debug(DEBUG_DETAIL, &lpr_dev, "lpr %d page\n", unit);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
t_stat lpr_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc)
|
||
{
|
||
UNIT *uptr;
|
||
int u;
|
||
|
||
if (dev == PRT1_DEV)
|
||
u = 0;
|
||
else if (dev == PRT2_DEV)
|
||
u = 1;
|
||
else
|
||
return SCPE_NXDEV;
|
||
uptr = &lpr_unit[u];
|
||
|
||
/* Are we currently tranfering? */
|
||
if (uptr->u5 & URCSTA_BUSY)
|
||
return SCPE_BUSY;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0)
|
||
return SCPE_UNATT;
|
||
|
||
if (*wc == 0 && (cmd & URCSTA_INHIBIT) == 0)
|
||
*wc = (cmd & URCSTA_DIRECT) ? 17 : 15;
|
||
|
||
/* Remember not to drop the FULL */
|
||
uptr->u5 &= ~((077 << URCSTA_CMD_V) | URCSTA_CHMASK);
|
||
uptr->u5 |= URCSTA_BUSY|chan;
|
||
uptr->u5 |= (cmd & (URCSTA_SKIP|URCSTA_SINGLE|URCSTA_DOUBLE))
|
||
<< URCSTA_CMD_V;
|
||
uptr->u3 = 0;
|
||
sim_debug(DEBUG_CMD, &lpr_dev, "%d: Cmd WRS %d %02o %o\n", u, chan,
|
||
cmd & (URCSTA_SKIP|URCSTA_SINGLE|URCSTA_DOUBLE),uptr->u5);
|
||
sim_activate(uptr, 100);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Handle transfer of data for printer */
|
||
t_stat
|
||
lpr_srv(UNIT *uptr) {
|
||
int chan = URCSTA_CHMASK & uptr->u5;
|
||
int u = (uptr - lpr_unit);
|
||
|
||
if (uptr->u5 & URCSTA_FULL) {
|
||
sim_debug(DEBUG_CMD, &lpr_dev, "lpr %d: done\n", u);
|
||
uptr->u5 &= ~URCSTA_FULL;
|
||
IAR |= (IRQ_3 << u);
|
||
}
|
||
|
||
/* Copy next column over */
|
||
if ((uptr->u5 & URCSTA_BUSY) != 0) {
|
||
if(chan_read_char(chan, &lpr_data[u].lbuff[uptr->u3], 0)) {
|
||
/* Done waiting, print line */
|
||
print_line(uptr, u);
|
||
memset(&lpr_data[u].lbuff[0], 0, 144);
|
||
uptr->u5 |= URCSTA_FULL;
|
||
uptr->u5 &= ~URCSTA_BUSY;
|
||
chan_set_wc(chan, (uptr->u3/8));
|
||
chan_set_end(chan);
|
||
sim_activate(uptr, 20000);
|
||
return SCPE_OK;
|
||
} else {
|
||
sim_debug(DEBUG_DATA, &lpr_dev, "lpr %d: Char < %02o\n", u,
|
||
lpr_data[u].lbuff[uptr->u3]);
|
||
uptr->u3++;
|
||
}
|
||
sim_activate(uptr, 50);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
lpr_attach(UNIT * uptr, char *file)
|
||
{
|
||
t_stat r;
|
||
int u = (uptr - lpr_unit);
|
||
|
||
if ((r = attach_unit(uptr, file)) != SCPE_OK)
|
||
return r;
|
||
uptr->u5 = 0;
|
||
uptr->u4 = 0;
|
||
uptr->u3 = 0;
|
||
iostatus |= PRT1_FLAG << u;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
lpr_detach(UNIT * uptr)
|
||
{
|
||
int u = (uptr - lpr_unit);
|
||
if (uptr->u5 & URCSTA_FULL)
|
||
print_line(uptr, u);
|
||
iostatus &= ~(PRT1_FLAG << u);
|
||
return detach_unit(uptr);
|
||
}
|
||
|
||
t_stat
|
||
lpr_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "B320 Line Printer\n\n");
|
||
fprintf (st, "The system supports up to two line printers, the second one is disabled\n");
|
||
fprintf (st, "by default. The B320 Line printer can be configured to any number of\n");
|
||
fprintf (st, "lines per page with the:\n");
|
||
fprintf (st, " sim> SET LPn LINESPERPAGE=n\n\n");
|
||
fprintf (st, "The default is 59 lines per page. The Line Printer has the following\n");
|
||
fprintf (st, "control tape attached.\n");
|
||
fprintf (st, " Channel 1: Skip to top of page\n");
|
||
fprintf (st, " Channel 2: Skip to top of page\n");
|
||
fprintf (st, " Channel 3: Skip to next even line\n");
|
||
fprintf (st, " Channel 4: Skip to next odd line\n");
|
||
fprintf (st, " Channel 5: Skip to middle or top of page\n");
|
||
fprintf (st, " Channel 6: Skip 1/4 of page\n");
|
||
fprintf (st, " Channel 7: Skip one linee\n");
|
||
fprintf (st, " Channel 8: Skip one linetop of page\n");
|
||
fprintf (st, " Channel 9: Skip one linetop of page\n");
|
||
fprintf (st, " Channel 10: Skip one linetop of page\n");
|
||
fprintf (st, " Channel 11: Skip one linetop of page\n");
|
||
fprintf (st, " Channel 12: Skip to top of page\n");
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
lpr_description(DEVICE *dptr)
|
||
{
|
||
return "B320 Line Printer";
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
|
||
|
||
#if NUM_DEVS_CON > 0
|
||
/*
|
||
* Console printer routines.
|
||
*/
|
||
t_stat
|
||
con_ini(DEVICE *dptr) {
|
||
UNIT *uptr = &con_unit[0];
|
||
uptr->u5 = 0;
|
||
iostatus |= SPO_FLAG;
|
||
if (!sim_is_active(uptr))
|
||
sim_activate(uptr, 1000);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
con_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc)
|
||
{
|
||
UNIT *uptr = &con_unit[0];
|
||
|
||
/* Are we currently tranfering? */
|
||
if (uptr->u5 & (URCSTA_READ|URCSTA_FILL|URCSTA_BUSY|URCSTA_INPUT))
|
||
return SCPE_BUSY;
|
||
|
||
if (cmd & URCSTA_READ) {
|
||
if (uptr->u5 & (URCSTA_INPUT|URCSTA_FILL))
|
||
return SCPE_BUSY;
|
||
/* Activate input so we can get response */
|
||
uptr->u5 = 0;
|
||
uptr->u5 |= URCSTA_INPUT|chan;
|
||
sim_putchar('I');
|
||
sim_putchar(' ');
|
||
sim_debug(DEBUG_CMD, &con_dev, ": Cmd RDS\n");
|
||
uptr->u3 = 0;
|
||
} else {
|
||
if (uptr->u5 & (URCSTA_INPUT|URCSTA_FILL))
|
||
return SCPE_BUSY;
|
||
sim_putchar('R');
|
||
sim_putchar(' ');
|
||
sim_debug(DEBUG_CMD, &con_dev, ": Cmd WRS\n");
|
||
uptr->u5 = 0;
|
||
uptr->u5 |= URCSTA_FILL|chan;
|
||
uptr->u3 = 0;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Handle transfer of data for printer */
|
||
t_stat
|
||
con_srv(UNIT *uptr) {
|
||
t_stat r;
|
||
uint8 ch;
|
||
int chan = uptr->u5 & URCSTA_CHMASK;
|
||
|
||
|
||
uptr->u5 &= ~URCSTA_BUSY; /* Clear busy */
|
||
|
||
/* Copy next column over */
|
||
if (uptr->u5 & URCSTA_FILL) {
|
||
if(chan_read_char(chan, &ch, 0)) {
|
||
sim_putchar('\r');
|
||
sim_putchar('\n');
|
||
sim_debug(DEBUG_EXP, &con_dev, "\n\r");
|
||
uptr->u5 &= ~URCSTA_FILL;
|
||
chan_set_end(chan);
|
||
} else {
|
||
ch &= 077;
|
||
sim_debug(DEBUG_EXP, &con_dev, "%c", con_to_ascii[ch]);
|
||
sim_putchar((int32)con_to_ascii[ch]);
|
||
}
|
||
}
|
||
|
||
if (uptr->u5 & URCSTA_READ) {
|
||
ch = con_data[0].ibuff[con_data[0].outptr++];
|
||
|
||
if(chan_write_char(chan, &ch,
|
||
(con_data[0].inptr == con_data[0].outptr))) {
|
||
sim_putchar('\r');
|
||
sim_putchar('\n');
|
||
sim_debug(DEBUG_EXP, &con_dev, "\n\r");
|
||
uptr->u5 &= ~URCSTA_READ;
|
||
chan_set_end(chan);
|
||
}
|
||
}
|
||
|
||
r = sim_poll_kbd();
|
||
if (r & SCPE_KFLAG) {
|
||
ch = r & 0377;
|
||
if (uptr->u5 & URCSTA_INPUT) {
|
||
/* Handle end of buffer */
|
||
switch (ch) {
|
||
case 033:
|
||
con_data[0].inptr = 0;
|
||
case '\r':
|
||
case '\n':
|
||
uptr->u5 &= ~URCSTA_INPUT;
|
||
uptr->u5 |= URCSTA_READ;
|
||
break;
|
||
case '\b':
|
||
case 0x7f:
|
||
if (con_data[0].inptr != 0) {
|
||
con_data[0].inptr--;
|
||
sim_putchar('\b');
|
||
sim_putchar(' ');
|
||
sim_putchar('\b');
|
||
}
|
||
break;
|
||
default:
|
||
if (con_data[0].inptr < sizeof(con_data[0].ibuff)) {
|
||
ch = ascii_to_con[0177&ch];
|
||
if (ch == 0xff) {
|
||
sim_putchar('\007');
|
||
break;
|
||
}
|
||
sim_putchar((int32)con_to_ascii[ch]);
|
||
con_data[0].ibuff[con_data[0].inptr++] = ch;
|
||
}
|
||
break;
|
||
}
|
||
} else {
|
||
if (ch == 033) {
|
||
IAR |= IRQ_2;
|
||
con_data[0].inptr = 0;
|
||
con_data[0].outptr = 0;
|
||
}
|
||
}
|
||
}
|
||
sim_activate(uptr, 1000);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
con_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "Supervisory Printer\n\n");
|
||
fprintf (st, "This is the interface from the operator to the system. The printer\n");
|
||
fprintf (st, "operated in a half duplex mode. To request the system to accept input\n");
|
||
fprintf (st, "press the <esc> key and wait until the system responds with a line with\n");
|
||
fprintf (st, "I as the first character. When you have finished typing your line, press\n");
|
||
fprintf (st, "return or enter key. Backspace will delete the last character.\n");
|
||
fprintf (st, "All responses from the system are prefixed with a R and blank as the\n");
|
||
fprintf (st, "first character\n");
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
con_description(DEVICE *dptr)
|
||
{
|
||
return "Supervisory Printer";
|
||
}
|
||
|
||
#endif
|
||
|