3B2: LPT Device; MMU and SCSI fixes
This change adds support for printing to an attached text file via the Centronics port of a simulated PORTS feature card. A new device named "LPT" has been added. See "help lpt" for documentation. Additionally, there has been a fix to a bug in the SCSI tape boot implementation and a very minor bug fix to the Rev 3 MMU.
This commit is contained in:
parent
e4ad37eccc
commit
7be9f2f3e8
10 changed files with 253 additions and 87 deletions
|
@ -846,9 +846,9 @@ t_stat cpu_show_cio(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
fprintf(st, "---------------------\n");
|
fprintf(st, "---------------------\n");
|
||||||
for (slot = 0; slot < CIO_SLOTS; slot++) {
|
for (slot = 0; slot < CIO_SLOTS; slot++) {
|
||||||
if (cio[slot].populated) {
|
if (cio[slot].populated) {
|
||||||
fprintf(st, " %2d %s\n", slot, cio[slot].name);
|
fprintf(st, " %2d %s\n", slot + 1, cio[slot].name);
|
||||||
} else {
|
} else {
|
||||||
fprintf(st, " %2d -\n", slot);
|
fprintf(st, " %2d -\n", slot + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,6 +158,7 @@ extern DEVICE timer_dev;
|
||||||
extern DEVICE tod_dev;
|
extern DEVICE tod_dev;
|
||||||
extern DEVICE tti_dev;
|
extern DEVICE tti_dev;
|
||||||
extern DEVICE tto_dev;
|
extern DEVICE tto_dev;
|
||||||
|
extern DEVICE lpt_dev;
|
||||||
#if defined(REV3)
|
#if defined(REV3)
|
||||||
extern DEVICE flt_dev;
|
extern DEVICE flt_dev;
|
||||||
extern DEVICE ha_dev;
|
extern DEVICE ha_dev;
|
||||||
|
|
286
3B2/3b2_ports.c
286
3B2/3b2_ports.c
|
@ -51,8 +51,6 @@
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_stddev.h"
|
||||||
|
|
||||||
#define IO_SCHED 1000
|
|
||||||
|
|
||||||
/* Device and units for PORTS cards
|
/* Device and units for PORTS cards
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
*
|
*
|
||||||
|
@ -100,36 +98,33 @@
|
||||||
#define PORTS_DIAG_CRC5 0x4be7bccc /* Used by SVR 2.0.5 */
|
#define PORTS_DIAG_CRC5 0x4be7bccc /* Used by SVR 2.0.5 */
|
||||||
#define PORTS_DIAG_CRC6 0x3197f6dd /* Used by SVR 2.0.5 */
|
#define PORTS_DIAG_CRC6 0x3197f6dd /* Used by SVR 2.0.5 */
|
||||||
|
|
||||||
#define PORTS_DFLT_LINES 4
|
|
||||||
#define PORTS_DFLT_CARDS 1
|
|
||||||
|
|
||||||
#define LN(slot,port) (ports_slot_ln[(slot)] + (port))
|
#define LN(slot,port) (ports_slot_ln[(slot)] + (port))
|
||||||
#define LSLOT(ln) (ports_ln_slot[ln])
|
#define LSLOT(ln) (ports_ln_slot[ln])
|
||||||
/* #define LN(slot,port) ((PORTS_LINES * ((slot) - ports_base_slot)) + (port)) */
|
|
||||||
/* #define LSLOT(ln) (((ln) / PORTS_LINES) + ports_base_slot) */
|
|
||||||
#define LPORT(ln) ((ln) % PORTS_LINES)
|
#define LPORT(ln) ((ln) % PORTS_LINES)
|
||||||
|
|
||||||
int8 ports_base_slot; /* First slot in our contiguous block */
|
int8 ports_base_slot; /* First slot in our contiguous block */
|
||||||
uint8 ports_int_slot; /* Interrupting card ID */
|
uint8 ports_int_slot; /* Interrupting card ID */
|
||||||
uint8 ports_int_subdev; /* Interrupting subdevice */
|
uint8 ports_int_subdev; /* Interrupting subdevice */
|
||||||
t_bool ports_conf = FALSE; /* Have PORTS cards been configured? */
|
t_bool ports_conf = FALSE; /* Have PORTS cards been configured? */
|
||||||
uint32 ports_crc; /* CRC32 of downloaded memory */
|
uint32 ports_crc; /* CRC32 of downloaded memory */
|
||||||
|
|
||||||
/* Mapping of line number to CIO card slot. Up to 32 lines spread over
|
/* Mapping of line number to CIO card slot. Up to 32 lines spread over 8
|
||||||
8 slots are supported. */
|
slots are supported. */
|
||||||
uint8 ports_ln_slot[MAX_LINES];
|
uint8 ports_ln_slot[MAX_LINES];
|
||||||
|
|
||||||
/* Mapping of slot number to base line number belonging to the card in
|
/* Mapping of slot number to base line number belonging to the card in
|
||||||
that slot. I.e., if there are two PORTS cards, one in slot 3 and
|
that slot. I.e., if there are two PORTS cards, one in slot 3 and one in
|
||||||
one in slot 5, index 3 will have starting line 0, index 5 will have
|
slot 5, index 3 will have starting line 0, index 5 will have starting
|
||||||
starting line 4. */
|
line 4. */
|
||||||
uint32 ports_slot_ln[CIO_SLOTS];
|
uint32 ports_slot_ln[CIO_SLOTS];
|
||||||
|
|
||||||
/* PORTS-specific state for each slot */
|
/* PORTS-specific state for each slot */
|
||||||
PORTS_LINE_STATE *ports_state = NULL;
|
PORTS_LINE_STATE *ports_state = NULL;
|
||||||
|
|
||||||
/* Baud rates determined by the low nybble
|
/* Line-printer state (only one is supported) */
|
||||||
* of the PORT_OPTIONS cflag */
|
PORTS_LINE_STATE lpt_state;
|
||||||
|
|
||||||
|
/* Baud rates determined by the low nybble of the PORT_OPTIONS cflag */
|
||||||
CONST char *ports_baud[16] = {
|
CONST char *ports_baud[16] = {
|
||||||
"75", "110", "134", "150",
|
"75", "110", "134", "150",
|
||||||
"300", "600", "1200", "2000",
|
"300", "600", "1200", "2000",
|
||||||
|
@ -199,6 +194,38 @@ DEVICE ports_dev = {
|
||||||
NULL, /* device description */
|
NULL, /* device description */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UNIT lpt_unit = {
|
||||||
|
UDATA(NULL, UNIT_SEQ|UNIT_ATTABLE|UNIT_TEXT, 0), SERIAL_OUT_WAIT
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE lpt_dev = {
|
||||||
|
"LPT", /* name */
|
||||||
|
&lpt_unit, /* units */
|
||||||
|
NULL, /* registers */
|
||||||
|
NULL, /* modifiers */
|
||||||
|
1, /* # units */
|
||||||
|
16, /* address radix */
|
||||||
|
32, /* address width */
|
||||||
|
1, /* address incr. */
|
||||||
|
16, /* data radix */
|
||||||
|
8, /* data width */
|
||||||
|
NULL, /* examine routine */
|
||||||
|
NULL, /* deposit routine */
|
||||||
|
&lpt_reset, /* reset routine */
|
||||||
|
NULL, /* boot routine */
|
||||||
|
&lpt_attach, /* attach routine */
|
||||||
|
&lpt_detach, /* detach routine */
|
||||||
|
NULL, /* context */
|
||||||
|
DEV_DISABLE|DEV_DIS, /* flags */
|
||||||
|
0, /* debug control flags */
|
||||||
|
NULL, /* debug flag names */
|
||||||
|
NULL, /* memory size change */
|
||||||
|
NULL, /* logical name */
|
||||||
|
&lpt_help, /* help routine */
|
||||||
|
NULL, /* attach help routine */
|
||||||
|
NULL, /* help context */
|
||||||
|
&lpt_description /* device description */
|
||||||
|
};
|
||||||
|
|
||||||
static void cio_irq(uint8 slot, uint8 dev, int32 delay)
|
static void cio_irq(uint8 slot, uint8 dev, int32 delay)
|
||||||
{
|
{
|
||||||
|
@ -207,6 +234,23 @@ static void cio_irq(uint8 slot, uint8 dev, int32 delay)
|
||||||
sim_activate(&ports_unit[2], delay);
|
sim_activate(&ports_unit[2], delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lpt_out(uint8 c)
|
||||||
|
{
|
||||||
|
if (!lpt_state.conn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputc(c, lpt_unit.fileref);
|
||||||
|
|
||||||
|
if (ferror(lpt_unit.fileref)) {
|
||||||
|
sim_perror("LPT I/O error");
|
||||||
|
clearerr(lpt_unit.fileref);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpt_unit.pos++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the number of lines for the PORTS mux. This will add or remove
|
* Set the number of lines for the PORTS mux. This will add or remove
|
||||||
* cards as necessary. The number of lines must be a multiple of 4.
|
* cards as necessary. The number of lines must be a multiple of 4.
|
||||||
|
@ -276,10 +320,22 @@ static void ports_cmd(uint8 slot, cio_entry *rentry, uint8 *rapp_data)
|
||||||
PORTS_OPTIONS opts;
|
PORTS_OPTIONS opts;
|
||||||
char line_config[16];
|
char line_config[16];
|
||||||
uint8 app_data[4] = {0};
|
uint8 app_data[4] = {0};
|
||||||
|
PORTS_LINE_STATE *state;
|
||||||
|
|
||||||
centry.address = rentry->address;
|
centry.address = rentry->address;
|
||||||
cio[slot].op = rentry->opcode;
|
cio[slot].op = rentry->opcode;
|
||||||
ln = LN(slot, rentry->subdevice & 0xf);
|
|
||||||
|
if ((rentry->subdevice & 7) == PORTS_CENTRONICS) {
|
||||||
|
ln = 0;
|
||||||
|
state = &lpt_state;
|
||||||
|
} else {
|
||||||
|
ln = LN(slot, rentry->subdevice & 7);
|
||||||
|
state = &ports_state[ln];
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_debug(TRACE_DBG, &ports_dev,
|
||||||
|
"[ports_cmd] Command: slot %d, subdev %d, opcode 0x%02x\n",
|
||||||
|
slot, rentry->subdevice, rentry->opcode);
|
||||||
|
|
||||||
switch(rentry->opcode) {
|
switch(rentry->opcode) {
|
||||||
case CIO_DLM:
|
case CIO_DLM:
|
||||||
|
@ -378,10 +434,10 @@ static void ports_cmd(uint8 slot, cio_entry *rentry, uint8 *rapp_data)
|
||||||
sim_debug(TRACE_DBG, &ports_dev, " PPC Options: vtime=%02x\n", opts.vtime);
|
sim_debug(TRACE_DBG, &ports_dev, " PPC Options: vtime=%02x\n", opts.vtime);
|
||||||
sim_debug(TRACE_DBG, &ports_dev, " PPC Options: vcount=%02x\n", opts.vcount);
|
sim_debug(TRACE_DBG, &ports_dev, " PPC Options: vcount=%02x\n", opts.vcount);
|
||||||
|
|
||||||
ports_state[ln].iflag = opts.iflag;
|
state->iflag = opts.iflag;
|
||||||
ports_state[ln].oflag = opts.oflag;
|
state->oflag = opts.oflag;
|
||||||
|
|
||||||
if ((rentry->subdevice & 0xf) < PORTS_LINES) {
|
if ((rentry->subdevice & 7) < PORTS_LINES) {
|
||||||
/* Adjust baud rate */
|
/* Adjust baud rate */
|
||||||
sprintf(line_config, "%s-8N1",
|
sprintf(line_config, "%s-8N1",
|
||||||
ports_baud[opts.cflag&0xf]);
|
ports_baud[opts.cflag&0xf]);
|
||||||
|
@ -409,8 +465,7 @@ static void ports_cmd(uint8 slot, cio_entry *rentry, uint8 *rapp_data)
|
||||||
|
|
||||||
centry.opcode = CIO_ULM;
|
centry.opcode = CIO_ULM;
|
||||||
|
|
||||||
/* TODO: It's unknown what the value 0x50 means, but this
|
/* 0x50 (80 decimal) is the expected PROM version */
|
||||||
* is what a real board sends. */
|
|
||||||
app_data[0] = 0x50;
|
app_data[0] = 0x50;
|
||||||
cio_cqueue(slot, CIO_STAT, PPQESIZE, ¢ry, app_data);
|
cio_cqueue(slot, CIO_STAT, PPQESIZE, ¢ry, app_data);
|
||||||
cio_irq(slot, rentry->subdevice, DELAY_VERS);
|
cio_irq(slot, rentry->subdevice, DELAY_VERS);
|
||||||
|
@ -421,7 +476,9 @@ static void ports_cmd(uint8 slot, cio_entry *rentry, uint8 *rapp_data)
|
||||||
"[ports_cmd] PPC CONNECT - subdevice = %02x\n",
|
"[ports_cmd] PPC CONNECT - subdevice = %02x\n",
|
||||||
rentry->subdevice);
|
rentry->subdevice);
|
||||||
|
|
||||||
ports_state[ln].conn = TRUE;
|
if (rentry->subdevice < PORTS_LINES) {
|
||||||
|
ports_state[ln].conn = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
centry.opcode = PPC_CONN;
|
centry.opcode = PPC_CONN;
|
||||||
centry.subdevice = rentry->subdevice;
|
centry.subdevice = rentry->subdevice;
|
||||||
|
@ -437,11 +494,10 @@ static void ports_cmd(uint8 slot, cio_entry *rentry, uint8 *rapp_data)
|
||||||
"[ports_cmd] PPC XMIT - subdevice = %02x, address=%08x, byte_count=%d\n",
|
"[ports_cmd] PPC XMIT - subdevice = %02x, address=%08x, byte_count=%d\n",
|
||||||
rentry->subdevice, rentry->address, rentry->byte_count);
|
rentry->subdevice, rentry->address, rentry->byte_count);
|
||||||
|
|
||||||
/* Set state for xmit */
|
state->tx_addr = rentry->address;
|
||||||
ports_state[ln].tx_addr = rentry->address;
|
state->tx_req_addr = state->tx_addr;
|
||||||
ports_state[ln].tx_req_addr = rentry->address;
|
state->tx_chars = rentry->byte_count + 1;
|
||||||
ports_state[ln].tx_chars = rentry->byte_count + 1;
|
state->tx_req_chars = state->tx_chars;
|
||||||
ports_state[ln].tx_req_chars = rentry->byte_count + 1;
|
|
||||||
|
|
||||||
sim_activate_after(&ports_unit[1], ports_unit[1].wait);
|
sim_activate_after(&ports_unit[1], ports_unit[1].wait);
|
||||||
|
|
||||||
|
@ -490,34 +546,41 @@ static void ports_cmd(uint8 slot, cio_entry *rentry, uint8 *rapp_data)
|
||||||
/*
|
/*
|
||||||
* Update the connection status of the given port.
|
* Update the connection status of the given port.
|
||||||
*/
|
*/
|
||||||
static void ports_update_conn(uint32 ln)
|
static void ports_update_conn(uint8 slot, uint8 subdev)
|
||||||
{
|
{
|
||||||
cio_entry centry = {0};
|
cio_entry centry = {0};
|
||||||
uint8 slot;
|
|
||||||
uint8 app_data[4] = {0};
|
uint8 app_data[4] = {0};
|
||||||
|
uint32 ln = LN(slot, subdev);
|
||||||
|
|
||||||
slot = LSLOT(ln);
|
/* If the card hasn't sysgened, there's no way to write a completion
|
||||||
|
* queue entry */
|
||||||
/* If the card hasn't sysgened, there's no way to write a
|
|
||||||
* completion queue entry */
|
|
||||||
if (cio[slot].sysgen_s != CIO_SYSGEN) {
|
if (cio[slot].sysgen_s != CIO_SYSGEN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ports_ldsc[ln].conn) {
|
sim_debug(TRACE_DBG, &ports_dev, "[ports_update_conn] slot=%d, subdev=%d\n", slot, subdev);
|
||||||
|
|
||||||
|
if (subdev == PORTS_CENTRONICS) {
|
||||||
|
if (!lpt_state.conn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
app_data[0] = AC_CON;
|
app_data[0] = AC_CON;
|
||||||
ports_state[ln].conn = TRUE;
|
|
||||||
} else {
|
} else {
|
||||||
if (ports_state[ln].conn) {
|
if (ports_ldsc[ln].conn) {
|
||||||
app_data[0] = AC_DIS;
|
app_data[0] = AC_CON;
|
||||||
ports_state[ln].conn = FALSE;
|
ports_state[ln].conn = TRUE;
|
||||||
} else {
|
} else {
|
||||||
app_data[0] = 0;
|
if (ports_state[ln].conn) {
|
||||||
|
app_data[0] = AC_DIS;
|
||||||
|
ports_state[ln].conn = FALSE;
|
||||||
|
} else {
|
||||||
|
app_data[0] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
centry.opcode = PPC_ASYNC;
|
centry.opcode = PPC_ASYNC;
|
||||||
centry.subdevice = LPORT(ln);
|
centry.subdevice = subdev;
|
||||||
cio_cqueue(slot, CIO_CMD, PPQESIZE, ¢ry, app_data);
|
cio_cqueue(slot, CIO_CMD, PPQESIZE, ¢ry, app_data);
|
||||||
|
|
||||||
/* Interrupt */
|
/* Interrupt */
|
||||||
|
@ -556,7 +619,7 @@ void ports_full(uint8 slot)
|
||||||
cio_entry rqe = {0};
|
cio_entry rqe = {0};
|
||||||
uint8 app_data[4] = {0};
|
uint8 app_data[4] = {0};
|
||||||
|
|
||||||
for (i = 0; i < PORTS_LINES; i++) {
|
for (i = 0; i < PORTS_RCV_QUEUE; i++) {
|
||||||
if (cio_rqueue(slot, i, PPQESIZE, &rqe, app_data) == SCPE_OK) {
|
if (cio_rqueue(slot, i, PPQESIZE, &rqe, app_data) == SCPE_OK) {
|
||||||
ports_cmd(slot, &rqe, app_data);
|
ports_cmd(slot, &rqe, app_data);
|
||||||
}
|
}
|
||||||
|
@ -576,7 +639,7 @@ t_stat ports_reset(DEVICE *dptr)
|
||||||
sim_set_uname(&ports_unit[1], "PORTS-XMT");
|
sim_set_uname(&ports_unit[1], "PORTS-XMT");
|
||||||
sim_set_uname(&ports_unit[2], "PORTS-CIO");
|
sim_set_uname(&ports_unit[2], "PORTS-CIO");
|
||||||
|
|
||||||
ports_desc.lines = PORTS_DFLT_LINES;
|
ports_desc.lines = PORTS_LINES;
|
||||||
ports_desc.ldsc = ports_ldsc =
|
ports_desc.ldsc = ports_ldsc =
|
||||||
(TMLN *)calloc(ports_desc.lines, sizeof(*ports_ldsc));
|
(TMLN *)calloc(ports_desc.lines, sizeof(*ports_ldsc));
|
||||||
}
|
}
|
||||||
|
@ -641,11 +704,13 @@ t_stat ports_cio_svc(UNIT *uptr)
|
||||||
switch (cio[ports_int_slot].op) {
|
switch (cio[ports_int_slot].op) {
|
||||||
case PPC_CONN:
|
case PPC_CONN:
|
||||||
cio[ports_int_slot].op = PPC_ASYNC;
|
cio[ports_int_slot].op = PPC_ASYNC;
|
||||||
ports_ldsc[LN(ports_int_slot, ports_int_subdev)].rcve = 1;
|
if (ports_int_subdev < PORTS_LINES) {
|
||||||
|
ports_ldsc[LN(ports_int_slot, ports_int_subdev)].rcve = 1;
|
||||||
|
}
|
||||||
sim_activate(&ports_unit[2], DELAY_ASYNC);
|
sim_activate(&ports_unit[2], DELAY_ASYNC);
|
||||||
break;
|
break;
|
||||||
case PPC_ASYNC:
|
case PPC_ASYNC:
|
||||||
ports_update_conn(LN(ports_int_slot, ports_int_subdev));
|
ports_update_conn(ports_int_slot, ports_int_subdev);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -670,14 +735,16 @@ t_stat ports_rcv_svc(UNIT *uptr)
|
||||||
|
|
||||||
ln = tmxr_poll_conn(&ports_desc);
|
ln = tmxr_poll_conn(&ports_desc);
|
||||||
if (ln >= 0) {
|
if (ln >= 0) {
|
||||||
ports_update_conn(ln);
|
/* Possibly connect a newly opened port */
|
||||||
|
ports_update_conn(LSLOT(ln), LPORT(ln));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ln = 0; ln < ports_desc.lines; ln++) {
|
for (ln = 0; ln < ports_desc.lines; ln++) {
|
||||||
slot = LSLOT(ln);
|
slot = LSLOT(ln);
|
||||||
|
|
||||||
if (!ports_ldsc[ln].conn && ports_state[ln].conn) {
|
if (!ports_ldsc[ln].conn && ports_state[ln].conn) {
|
||||||
ports_update_conn(ln);
|
/* Disconnect a connected line, it has been dropped */
|
||||||
|
ports_update_conn(LSLOT(ln), LPORT(ln));
|
||||||
} else if (ports_ldsc[ln].conn && ports_state[ln].conn) {
|
} else if (ports_ldsc[ln].conn && ports_state[ln].conn) {
|
||||||
temp = tmxr_getc_ln(&ports_ldsc[ln]);
|
temp = tmxr_getc_ln(&ports_ldsc[ln]);
|
||||||
|
|
||||||
|
@ -728,7 +795,7 @@ t_stat ports_xmt_svc(UNIT *uptr)
|
||||||
uint8 app_data[4] = {0};
|
uint8 app_data[4] = {0};
|
||||||
uint32 wait = 0x7fffffff;
|
uint32 wait = 0x7fffffff;
|
||||||
|
|
||||||
/* Scan all lines for output */
|
/* Scan all MUX lines for output */
|
||||||
for (ln = 0; ln < ports_desc.lines; ln++) {
|
for (ln = 0; ln < ports_desc.lines; ln++) {
|
||||||
slot = LSLOT(ln);
|
slot = LSLOT(ln);
|
||||||
if (ports_ldsc[ln].conn && ports_state[ln].tx_chars > 0) {
|
if (ports_ldsc[ln].conn && ports_state[ln].tx_chars > 0) {
|
||||||
|
@ -748,30 +815,53 @@ t_stat ports_xmt_svc(UNIT *uptr)
|
||||||
/* Indicate that we're in a CRLF translation */
|
/* Indicate that we're in a CRLF translation */
|
||||||
ports_state[ln].crlf = TRUE;
|
ports_state[ln].crlf = TRUE;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ports_state[ln].crlf = FALSE;
|
||||||
|
|
||||||
break;
|
if (tmxr_putc_ln(&ports_ldsc[ln], c) == SCPE_OK) {
|
||||||
|
wait = MIN(wait, ports_ldsc[ln].txdeltausecs);
|
||||||
|
ports_state[ln].tx_chars--;
|
||||||
|
ports_state[ln].tx_addr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ports_state[ln].tx_chars == 0) {
|
||||||
|
centry.byte_count = ports_state[ln].tx_req_chars;
|
||||||
|
centry.subdevice = LPORT(ln);
|
||||||
|
centry.opcode = PPC_XMIT;
|
||||||
|
centry.address = ports_state[ln].tx_req_addr;
|
||||||
|
app_data[0] = GC_FLU;
|
||||||
|
cio_cqueue(slot, CIO_STAT, PPQESIZE, ¢ry, app_data);
|
||||||
|
CIO_SET_INT(slot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ports_state[ln].crlf = FALSE;
|
/* Scan LPT line for output */
|
||||||
|
if (lpt_state.conn && lpt_state.tx_chars > 0) {
|
||||||
|
tx = TRUE;
|
||||||
|
/* This is a hack -- we just want the slot of the first installed
|
||||||
|
PORTS board */
|
||||||
|
slot = LSLOT(0);
|
||||||
|
wait = MIN(wait, SERIAL_OUT_WAIT);
|
||||||
|
c = pread_b(lpt_state.tx_addr, BUS_PER);
|
||||||
|
|
||||||
if (tmxr_putc_ln(&ports_ldsc[ln], c) == SCPE_OK) {
|
/* The PORTS card optionally handles NL->CRLF */
|
||||||
wait = MIN(wait, ports_ldsc[ln].txdeltausecs);
|
if (c == 0xa && (lpt_state.oflag & ONLCR) && !(lpt_state.crlf)) {
|
||||||
ports_state[ln].tx_chars--;
|
/* Indicate that we're in a CRLF translation */
|
||||||
ports_state[ln].tx_addr++;
|
lpt_state.crlf = TRUE;
|
||||||
sim_debug(IO_DBG, &ports_dev,
|
lpt_out(0xd);
|
||||||
"[ports_xmt_svc] [LINE %d] XMIT: %02x (%c)\n",
|
} else {
|
||||||
ln, c, c);
|
lpt_state.crlf = FALSE;
|
||||||
}
|
lpt_state.tx_chars--;
|
||||||
|
lpt_state.tx_addr++;
|
||||||
if (ports_state[ln].tx_chars == 0) {
|
lpt_out(c);
|
||||||
sim_debug(TRACE_DBG, &ports_dev,
|
if (lpt_state.tx_chars == 0) {
|
||||||
"[ports_xmt_svc] Done with xmit, card=%d port=%d. Interrupting.\n",
|
centry.byte_count = lpt_state.tx_req_chars;
|
||||||
slot, LPORT(ln));
|
centry.subdevice = PORTS_CENTRONICS;
|
||||||
centry.byte_count = ports_state[ln].tx_req_chars;
|
|
||||||
centry.subdevice = LPORT(ln);
|
|
||||||
centry.opcode = PPC_XMIT;
|
centry.opcode = PPC_XMIT;
|
||||||
centry.address = ports_state[ln].tx_req_addr;
|
centry.address = lpt_state.tx_req_addr;
|
||||||
app_data[0] = RC_FLU;
|
app_data[0] = GC_FLU;
|
||||||
cio_cqueue(slot, CIO_STAT, PPQESIZE, ¢ry, app_data);
|
cio_cqueue(slot, CIO_STAT, PPQESIZE, ¢ry, app_data);
|
||||||
CIO_SET_INT(slot);
|
CIO_SET_INT(slot);
|
||||||
}
|
}
|
||||||
|
@ -836,3 +926,59 @@ t_stat ports_detach(UNIT *uptr)
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_stat lpt_reset(DEVICE *dptr)
|
||||||
|
{
|
||||||
|
/* No-op */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat lpt_attach(UNIT *uptr, const char *cptr)
|
||||||
|
{
|
||||||
|
t_stat reason;
|
||||||
|
|
||||||
|
if (ports_dev.flags & DEV_DIS) {
|
||||||
|
return SCPE_NOFNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((reason = attach_unit(uptr, cptr)) == SCPE_OK) {
|
||||||
|
lpt_state.conn = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat lpt_detach(UNIT *uptr)
|
||||||
|
{
|
||||||
|
lpt_state.conn = FALSE;
|
||||||
|
return detach_unit(uptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat lpt_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||||||
|
{
|
||||||
|
fprintf(st, "Line Printer (LPT)\n\n");
|
||||||
|
fprintf(st, "The line printer (LPT) simulates an AT&T 470 120cps line printer\n");
|
||||||
|
fprintf(st, "connected to the Centronics port of the first installed PORTS card. It\n");
|
||||||
|
fprintf(st, "writes text output to an attached file on disk. To use the LPT device,\n");
|
||||||
|
fprintf(st, "first ENABLE it, then ATTACH it to a disk file to be used for text \n");
|
||||||
|
fprintf(st, "output, for example:\n\n");
|
||||||
|
fprintf(st, " SET LPT ENABLE\n");
|
||||||
|
fprintf(st, " ATTACH LPT my_output.txt\n\n");
|
||||||
|
fprintf(st, "To use this device under System V UNIX, set up a printer attached to\n");
|
||||||
|
fprintf(st, "TTY number 5 of the first installed PORTS card.\n\n");
|
||||||
|
fprintf(st, "For example, if the first installed PORTS card has created TTY devices\n");
|
||||||
|
fprintf(st, "/dev/tty21 through /dev/tty25 (where /dev/tty2* indicates that the PORTS\n");
|
||||||
|
fprintf(st, "card is in backplane slot 2), the printer will be on TTY device /dev/tty25.\n\n");
|
||||||
|
fprintf(st, "Please note that the LPT requires at least one PORTS card be configured. It\n");
|
||||||
|
fprintf(st, "will not allow attaching to an output file unless a PORTS card is enabled.\n");
|
||||||
|
fprintf(st, "If you see the output\n\n");
|
||||||
|
fprintf(st, " Command not allowed\n\n");
|
||||||
|
fprintf(st, "when trying to attach the LPT device, it means you have not enabled at\n");
|
||||||
|
fprintf(st, "least one PORTS card.\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *lpt_description(DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return "AT&T 470 120cps Dot Matrix Printer";
|
||||||
|
}
|
||||||
|
|
|
@ -51,16 +51,15 @@
|
||||||
#define PORTS_IPL 10
|
#define PORTS_IPL 10
|
||||||
#define PORTS_VERSION 1
|
#define PORTS_VERSION 1
|
||||||
|
|
||||||
#define MAX_CARDS 8 /* Up to 8 PORTS cards with 32 lines total
|
#define MAX_CARDS 8 /* Up to 8 PORTS cards supported */
|
||||||
supported */
|
#define PORTS_CENTRONICS 4 /* Subdevice 4 is the centronics port */
|
||||||
#define PORTS_LINES 4
|
#define PORTS_LINES 4 /* Subdevices 0-3 are RS232 ports */
|
||||||
#define PORTS_RCV_QUEUE 5
|
#define PORTS_RCV_QUEUE 5 /* Total of 5 receive queues for all ports */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sub-field values for the PPC_DEVICE request entry; these are placed
|
* Sub-field values for the PPC_DEVICE request entry; these are placed in
|
||||||
* in app_data.bt[0] in the PPC_DEVICE application field. The prefix
|
* app_data.bt[0] in the PPC_DEVICE application field. The prefix DR
|
||||||
* DR indicates that this is a code for use in "device" request
|
* indicates that this is a code for use in "device" request entries only.
|
||||||
* entries only.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DR_ENA 1 /* enable a device */
|
#define DR_ENA 1 /* enable a device */
|
||||||
|
@ -222,6 +221,11 @@ t_stat ports_xmt_svc(UNIT *uptr);
|
||||||
t_stat ports_cio_svc(UNIT *uptr);
|
t_stat ports_cio_svc(UNIT *uptr);
|
||||||
t_stat ports_attach(UNIT *uptr, CONST char *cptr);
|
t_stat ports_attach(UNIT *uptr, CONST char *cptr);
|
||||||
t_stat ports_detach(UNIT *uptr);
|
t_stat ports_detach(UNIT *uptr);
|
||||||
|
t_stat lpt_reset (DEVICE *dptr);
|
||||||
|
t_stat lpt_attach (UNIT *uptr, CONST char *ptr);
|
||||||
|
t_stat lpt_detach (UNIT *uptr);
|
||||||
|
t_stat lpt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
|
const char *lpt_description (DEVICE *dptr);
|
||||||
void ports_sysgen(uint8 slot);
|
void ports_sysgen(uint8 slot);
|
||||||
void ports_express(uint8 slot);
|
void ports_express(uint8 slot);
|
||||||
void ports_full(uint8 slot);
|
void ports_full(uint8 slot);
|
||||||
|
|
|
@ -97,6 +97,8 @@
|
||||||
#define MEMID_1M 2
|
#define MEMID_1M 2
|
||||||
#define MEMID_2M 1
|
#define MEMID_2M 1
|
||||||
#define MEMID_4M 3
|
#define MEMID_4M 3
|
||||||
|
#define MMUBASE 0x40000
|
||||||
|
#define MMUSIZE 0x1000
|
||||||
|
|
||||||
/* DMA Controller */
|
/* DMA Controller */
|
||||||
#define DMACBASE 0x48000
|
#define DMACBASE 0x48000
|
||||||
|
|
|
@ -140,9 +140,6 @@
|
||||||
*
|
*
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
#define MMUBASE 0x40000
|
|
||||||
#define MMUSIZE 0x1000
|
|
||||||
|
|
||||||
#define MMU_SRS 0x04 /* Section RAM array size (words) */
|
#define MMU_SRS 0x04 /* Section RAM array size (words) */
|
||||||
#define MMU_SDCS 0x20 /* Segment Descriptor Cache H/L array size
|
#define MMU_SDCS 0x20 /* Segment Descriptor Cache H/L array size
|
||||||
(words) */
|
(words) */
|
||||||
|
|
|
@ -60,6 +60,7 @@ DEVICE *sim_devices[] = {
|
||||||
&if_dev,
|
&if_dev,
|
||||||
&id_dev,
|
&id_dev,
|
||||||
&ports_dev,
|
&ports_dev,
|
||||||
|
&lpt_dev,
|
||||||
&ctc_dev,
|
&ctc_dev,
|
||||||
&ni_dev,
|
&ni_dev,
|
||||||
NULL
|
NULL
|
||||||
|
@ -77,6 +78,7 @@ void full_reset()
|
||||||
id_reset(&id_dev);
|
id_reset(&id_dev);
|
||||||
csr_reset(&csr_dev);
|
csr_reset(&csr_dev);
|
||||||
ports_reset(&ports_dev);
|
ports_reset(&ports_dev);
|
||||||
|
lpt_reset(&lpt_dev);
|
||||||
ctc_reset(&ctc_dev);
|
ctc_reset(&ctc_dev);
|
||||||
ni_reset(&ni_dev);
|
ni_reset(&ni_dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -600,6 +600,10 @@ void mmu_write(uint32 pa, uint32 val, size_t size)
|
||||||
/* Flush all PDC cache entries for this section */
|
/* Flush all PDC cache entries for this section */
|
||||||
for (i = 0; i < MMU_PDCS; i++) {
|
for (i = 0; i < MMU_PDCS; i++) {
|
||||||
if (((mmu_state.pdch[i] >> 24) & 0x3) == index) {
|
if (((mmu_state.pdch[i] >> 24) & 0x3) == index) {
|
||||||
|
sim_debug(MMU_CACHE_DBG, &mmu_dev,
|
||||||
|
"Flushing MMU PDC entry at index %d "
|
||||||
|
"(pdc_lo=%08x pdc_hi=%08x)\n",
|
||||||
|
i, mmu_state.pdcl[i], mmu_state.pdch[i]);
|
||||||
mmu_state.pdch[i] &= ~(PDC_G_MASK);
|
mmu_state.pdch[i] &= ~(PDC_G_MASK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1041,8 +1045,9 @@ uint32 mmu_xlate_addr(uint32 va, uint8 r_acc)
|
||||||
|
|
||||||
succ = mmu_decode_va(va, r_acc, TRUE, &pa);
|
succ = mmu_decode_va(va, r_acc, TRUE, &pa);
|
||||||
|
|
||||||
|
mmu_state.var = va;
|
||||||
|
|
||||||
if (succ == SCPE_OK) {
|
if (succ == SCPE_OK) {
|
||||||
mmu_state.var = va;
|
|
||||||
return pa;
|
return pa;
|
||||||
} else {
|
} else {
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
|
|
|
@ -60,6 +60,7 @@ DEVICE *sim_devices[] = {
|
||||||
&if_dev,
|
&if_dev,
|
||||||
&ha_dev,
|
&ha_dev,
|
||||||
&ports_dev,
|
&ports_dev,
|
||||||
|
&lpt_dev,
|
||||||
&ni_dev,
|
&ni_dev,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -76,5 +77,6 @@ void full_reset()
|
||||||
ha_reset(&ha_dev);
|
ha_reset(&ha_dev);
|
||||||
csr_reset(&csr_dev);
|
csr_reset(&csr_dev);
|
||||||
ports_reset(&ports_dev);
|
ports_reset(&ports_dev);
|
||||||
|
lpt_reset(&lpt_dev);
|
||||||
ni_reset(&ni_dev);
|
ni_reset(&ni_dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -506,7 +506,16 @@ static void ha_boot_tape(UNIT *uptr, uint8 tc)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sim_tape_rdrecf(uptr, buf, §sread, HA_BLKSZ); /* Read block 0 */
|
r = sim_tape_sprecf(uptr, §sread); /* Skip block 0 */
|
||||||
|
|
||||||
|
if (r != SCPE_OK) {
|
||||||
|
sim_debug(HA_TRACE, &ha_dev,
|
||||||
|
"[ha_boot_tape] Could not skip block 0.\n");
|
||||||
|
HA_STAT(tc, HA_CKCON, CIO_SUCCESS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sim_tape_rdrecf(uptr, buf, §sread, HA_BLKSZ); /* Read block 1 */
|
||||||
|
|
||||||
if (r != SCPE_OK) {
|
if (r != SCPE_OK) {
|
||||||
sim_debug(HA_TRACE, &ha_dev,
|
sim_debug(HA_TRACE, &ha_dev,
|
||||||
|
@ -523,8 +532,6 @@ static void ha_boot_tape(UNIT *uptr, uint8 tc)
|
||||||
"[ha_boot_tape] Transfered 512 bytes to 0x%08x\n",
|
"[ha_boot_tape] Transfered 512 bytes to 0x%08x\n",
|
||||||
HA_BOOT_ADDR);
|
HA_BOOT_ADDR);
|
||||||
|
|
||||||
r = sim_tape_sprecf(uptr, §sread); /* Skip block 1 */
|
|
||||||
|
|
||||||
HA_STAT(tc, HA_GOOD, CIO_SUCCESS);
|
HA_STAT(tc, HA_GOOD, CIO_SUCCESS);
|
||||||
|
|
||||||
ha_state.ts[tc].rep.addr = HA_BOOT_ADDR;
|
ha_state.ts[tc].rep.addr = HA_BOOT_ADDR;
|
||||||
|
|
Loading…
Add table
Reference in a new issue