3b2: Initial CONTTY support

This commit is contained in:
Seth Morabito 2017-12-09 21:30:25 -08:00
parent 7cd1b27b08
commit d5f8a84493
4 changed files with 247 additions and 212 deletions

View file

@ -55,8 +55,8 @@ DEVICE dmac_dev = {
dmac_drq_handler dmac_drq_handlers[] = { dmac_drq_handler dmac_drq_handlers[] = {
{DMA_ID_CHAN, IDBASE+ID_DATA_REG, &id_drq, id_drq_handled}, {DMA_ID_CHAN, IDBASE+ID_DATA_REG, &id_drq, id_drq_handled},
{DMA_IF_CHAN, IFBASE+IF_DATA_REG, &if_state.drq, if_drq_handled}, {DMA_IF_CHAN, IFBASE+IF_DATA_REG, &if_state.drq, if_drq_handled},
{DMA_IUA_CHAN, IUBASE+IUA_DATA_REG, &iu_port_a.drq, iua_drq_handled}, {DMA_IUA_CHAN, IUBASE+IUA_DATA_REG, &iu_console.drq, iua_drq_handled},
{DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_port_b.drq, iub_drq_handled}, {DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_contty.drq, iub_drq_handled},
{0, 0, NULL, NULL } {0, 0, NULL, NULL }
}; };

View file

@ -29,6 +29,7 @@
*/ */
#include "3b2_iu.h" #include "3b2_iu.h"
#include "sim_tmxr.h"
/* /*
* The 3B2/400 has two on-board serial ports, labeled CONSOLE and * The 3B2/400 has two on-board serial ports, labeled CONSOLE and
@ -42,12 +43,11 @@
* In addition to the two TX/RX ports, the SCN27681A also has one * In addition to the two TX/RX ports, the SCN27681A also has one
* programmable timer. * programmable timer.
* *
* The SCN2681A UART is represented here by five devices: * The SCN2681A UART is represented here by four devices:
* *
* - Console TTI (Input, port A) * - Console TTI (Input, port A)
* - Console TTO (Output, port A) * - Console TTO (Output, port A)
* - Contty TTI (Input, port B) * - Contty (I/O, port B. Terminal multiplexer with one line)
* - Contty TTO (Output, port B)
* - IU Timer * - IU Timer
*/ */
@ -60,8 +60,8 @@
IU_STATE iu_state; IU_STATE iu_state;
/* The tx/rx state for ports A and B */ /* The tx/rx state for ports A and B */
IU_PORT iu_port_a; IU_PORT iu_console;
IU_PORT iu_port_b; IU_PORT iu_contty;
/* The timer state */ /* The timer state */
IU_TIMER_STATE iu_timer_state; IU_TIMER_STATE iu_timer_state;
@ -112,84 +112,89 @@ BITFIELD conf_bits[] = {
ENDBITS ENDBITS
}; };
/* TTI (Port A) data structures */ /* TTI (Console) data structures */
REG tti_a_reg[] = { REG tti_reg[] = {
{ HRDATADF(STAT, iu_port_a.stat, 8, "Status", sr_bits) }, { HRDATADF(STAT, iu_console.stat, 8, "Status", sr_bits) },
{ HRDATADF(CONF, iu_port_a.conf, 8, "Config", conf_bits) }, { HRDATADF(CONF, iu_console.conf, 8, "Config", conf_bits) },
{ BRDATAD(DATA, iu_port_a.rxbuf, 16, 8, IU_BUF_SIZE, "Data") }, { BRDATAD(DATA, iu_console.rxbuf, 16, 8, IU_BUF_SIZE, "Data") },
{ NULL } { NULL }
}; };
UNIT tti_a_unit = { UDATA(&iu_svc_tti_a, UNIT_IDLE, 0), TMLN_SPD_9600_BPS }; UNIT tti_unit = { UDATA(&iu_svc_tti, UNIT_IDLE, 0), TMLN_SPD_9600_BPS };
DEVICE tti_a_dev = { DEVICE tti_dev = {
"TTIA", &tti_a_unit, tti_a_reg, NULL, "TTI", &tti_unit, tti_reg, NULL,
1, 8, 32, 1, 8, 8, 1, 8, 32, 1, 8, 8,
NULL, NULL, &tti_a_reset, NULL, NULL, &tti_reset,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
DEV_DEBUG, 0, sys_deb_tab DEV_DEBUG, 0, sys_deb_tab
}; };
/* TTO (Port A) data structures */ /* TTO (Console) data structures */
REG tto_a_reg[] = { REG tto_reg[] = {
{ HRDATADF(STAT, iu_port_a.stat, 8, "Status", sr_bits) }, { HRDATADF(STAT, iu_console.stat, 8, "Status", sr_bits) },
{ HRDATADF(ISTAT, iu_state.istat, 8, "Interrupt Status", isr_bits) }, { HRDATADF(ISTAT, iu_state.istat, 8, "Interrupt Status", isr_bits) },
{ HRDATAD(IMR, iu_state.imr, 8, "Interrupt Mask") }, { HRDATAD(IMR, iu_state.imr, 8, "Interrupt Mask") },
{ HRDATADF(ACR, iu_state.acr, 8, "Auxiliary Control Register", acr_bits) }, { HRDATADF(ACR, iu_state.acr, 8, "Auxiliary Control Register", acr_bits) },
{ HRDATAD(DATA, iu_port_a.txbuf, 8, "Data") }, { HRDATAD(DATA, iu_console.txbuf, 8, "Data") },
{ NULL } { NULL }
}; };
UNIT tto_a_unit = { UDATA(&iu_svc_tto_a, TT_MODE_8B, 0), SERIAL_OUT_WAIT }; UNIT tto_unit = { UDATA(&iu_svc_tto, TT_MODE_8B, 0), SERIAL_OUT_WAIT };
DEVICE tto_a_dev = { DEVICE tto_dev = {
"TTOA", &tto_a_unit, tto_a_reg, NULL, "TTO", &tto_unit, tto_reg, NULL,
1, 8, 32, 1, 8, 8, 1, 8, 32, 1, 8, 8,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
DEV_DEBUG, 0, sys_deb_tab DEV_DEBUG, 0, sys_deb_tab
}; };
/* TTI (Port B) data structures */ /* CONTTY data structures */
REG tti_b_reg[] = { /*
{ HRDATADF(STAT, iu_port_b.stat, 8, "Status", sr_bits) }, * The CONTTY "multiplexer" is a bit unusual in that it serves only a
{ HRDATADF(CONF, iu_port_b.conf, 8, "Config", conf_bits) }, * single line, representing the built-in CONTTY port. On a real
{ BRDATAD(DATA, iu_port_b.rxbuf, 16, 8, IU_BUF_SIZE, "Data") }, * 3B2/400, the system board's dual UART serves both CONSOLE and
{ NULL } * CONTTY lines, giving support for two terminals. In the simulator,
}; * the CONSOLE is served by TTI and TTO devices, whereas the CONTTY is
* served by a TMXR multiplexer.
*/
UNIT tti_b_unit = { UDATA(&iu_svc_tti_b, UNIT_IDLE, 0), TMLN_SPD_9600_BPS }; TMLN *contty_ldsc = NULL;
TMXR contty_desc = { 1, 0, 0, NULL };
DEVICE tti_b_dev = { REG contty_reg[] = {
"TTIB", &tti_b_unit, tti_b_reg, NULL, { HRDATADF(STAT, iu_contty.stat, 8, "Status", sr_bits) },
1, 8, 32, 1, 8, 8, { HRDATADF(CONF, iu_contty.conf, 8, "Config", conf_bits) },
NULL, NULL, &tti_b_reset, { BRDATAD(RXDATA, iu_contty.rxbuf, 16, 8, IU_BUF_SIZE, "RX Data") },
NULL, NULL, NULL, NULL, { HRDATAD(TXDATA, iu_contty.txbuf, 8, "TX Data") },
DEV_DEBUG, 0, sys_deb_tab
};
/* TTO (Port B) data structures */
REG tto_b_reg[] = {
{ HRDATADF(STAT, iu_port_b.stat, 8, "Status", sr_bits) },
{ HRDATADF(ISTAT, iu_state.istat, 8, "Interrupt Status", isr_bits) }, { HRDATADF(ISTAT, iu_state.istat, 8, "Interrupt Status", isr_bits) },
{ HRDATAD(IMR, iu_state.imr, 8, "Interrupt Mask") }, { HRDATAD(IMR, iu_state.imr, 8, "Interrupt Mask") },
{ HRDATADF(ACR, iu_state.acr, 8, "Auxiliary Control Register", acr_bits) }, { HRDATADF(ACR, iu_state.acr, 8, "Auxiliary Control Register", acr_bits) },
{ HRDATAD(DATA, iu_port_b.txbuf, 8, "Data") },
{ NULL } { NULL }
}; };
UNIT tto_b_unit = { UDATA(&iu_svc_tto_b, TT_MODE_8B, 0), SERIAL_OUT_WAIT }; UNIT contty_unit[2] = {
{ UDATA(&iu_svc_contty, UNIT_IDLE|UNIT_ATTABLE, 0) },
{ UDATA(&iu_svc_contty_xmt, UNIT_DIS, 0), SERIAL_OUT_WAIT }
};
DEVICE tto_b_dev = { UNIT *contty_rcv_unit = &contty_unit[0];
"TTOB", &tto_b_unit, tto_b_reg, NULL, UNIT *contty_xmt_unit = &contty_unit[1];
DEVICE contty_dev = {
"CONTTY", contty_unit, contty_reg, NULL,
1, 8, 32, 1, 8, 8, 1, 8, 32, 1, 8, 8,
NULL, NULL, NULL, &tmxr_ex, &tmxr_dep, &contty_reset,
NULL, NULL, NULL, NULL, NULL, &contty_attach, &contty_detach,
DEV_DEBUG, 0, sys_deb_tab NULL, DEV_DISABLE|DEV_DEBUG|DEV_MUX,
0, sys_deb_tab, NULL, NULL,
NULL, NULL,
(void *)&contty_desc,
NULL
}; };
/* IU Timer data structures */ /* IU Timer data structures */
@ -209,68 +214,95 @@ DEVICE iu_timer_dev = {
DEV_DEBUG, 0, sys_deb_tab DEV_DEBUG, 0, sys_deb_tab
}; };
t_stat contty_attach(UNIT *uptr, CONST char *cptr)
{
t_stat r = tmxr_attach(&contty_desc, uptr, cptr);
TMLN *lp;
if (r != SCPE_OK) {
tmxr_clear_modem_control_passthru(&contty_desc);
return r;
}
lp = &contty_ldsc[0];
tmxr_set_get_modem_bits(lp, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL);
return SCPE_OK;
}
t_stat contty_detach(UNIT *uptr)
{
t_stat r = tmxr_detach(&contty_desc, uptr);
tmxr_clear_modem_control_passthru(&contty_desc);
return r;
}
void increment_modep_a() void increment_modep_a()
{ {
iu_increment_a = FALSE; iu_increment_a = FALSE;
iu_port_a.modep++; iu_console.modep++;
if (iu_port_a.modep > 1) { if (iu_console.modep > 1) {
iu_port_a.modep = 0; iu_console.modep = 0;
} }
} }
void increment_modep_b() void increment_modep_b()
{ {
iu_increment_b = FALSE; iu_increment_b = FALSE;
iu_port_b.modep++; iu_contty.modep++;
if (iu_port_b.modep > 1) { if (iu_contty.modep > 1) {
iu_port_b.modep = 0; iu_contty.modep = 0;
} }
} }
void iu_txrdy_a_irq() { void iu_txrdy_a_irq() {
if ((iu_state.imr & ISTS_TAI) && if ((iu_state.imr & ISTS_TAI) &&
(iu_port_a.conf & TX_EN) && (iu_console.conf & TX_EN) &&
(iu_port_a.stat & STS_TXR)) { (iu_console.stat & STS_TXR)) {
sim_debug(EXECUTE_MSG, &tto_a_dev,
"Firing IU TTY IRQ 13 ON TX/State Change: PORT A\n");
csr_data |= CSRUART; csr_data |= CSRUART;
} }
} }
void iu_txrdy_b_irq() { void iu_txrdy_b_irq() {
if ((iu_state.imr & ISTS_TBI) && if ((iu_state.imr & ISTS_TBI) &&
(iu_port_b.conf & TX_EN) && (iu_contty.conf & TX_EN) &&
(iu_port_b.stat & STS_TXR)) { (iu_contty.stat & STS_TXR)) {
sim_debug(EXECUTE_MSG, &tto_b_dev,
"Firing IU TTY IRQ 13 ON TX/State Change: PORT B\n");
csr_data |= CSRUART; csr_data |= CSRUART;
} }
} }
t_stat tti_a_reset(DEVICE *dptr) t_stat tti_reset(DEVICE *dptr)
{ {
memset(&iu_state, 0, sizeof(IU_STATE)); memset(&iu_state, 0, sizeof(IU_STATE));
memset(&iu_port_a, 0, sizeof(IU_PORT)); memset(&iu_console, 0, sizeof(IU_PORT));
/* Start the TTI A polling loop */ tmxr_set_console_units(&tti_unit, &tto_unit);
if (!sim_is_active(&tti_a_unit)) {
sim_activate(&tti_a_unit, tti_a_unit.wait); /* Input Port logic is inverted - 0 means set */
iu_state.inprt = ~(IU_DCDA);
/* Start the Console TTI polling loop */
if (!sim_is_active(&tti_unit)) {
sim_activate(&tti_unit, tti_unit.wait);
} }
return SCPE_OK; return SCPE_OK;
} }
t_stat tti_b_reset(DEVICE *dtpr) t_stat contty_reset(DEVICE *dtpr)
{ {
memset(&iu_state, 0, sizeof(IU_STATE)); if (contty_ldsc == NULL) {
memset(&iu_port_b, 0, sizeof(IU_PORT)); contty_desc.ldsc =
contty_ldsc =
(TMLN *)calloc(1, sizeof(*contty_ldsc));
}
/* Start the TTI B polling loop */ /* Start the CONTTY polling loop */
if (!sim_is_active(&tti_b_unit)) { if (!sim_is_active(contty_rcv_unit)) {
sim_activate(&tti_b_unit, tti_b_unit.wait); sim_activate(contty_rcv_unit, contty_rcv_unit->wait);
} }
return SCPE_OK; return SCPE_OK;
@ -285,7 +317,7 @@ t_stat iu_timer_reset(DEVICE *dptr)
/* Service routines */ /* Service routines */
t_stat iu_svc_tti_a(UNIT *uptr) t_stat iu_svc_tti(UNIT *uptr)
{ {
int32 temp; int32 temp;
@ -305,26 +337,17 @@ t_stat iu_svc_tti_a(UNIT *uptr)
return temp; return temp;
} }
sim_debug(READ_MSG, &tti_a_dev, if (iu_console.conf & RX_EN) {
">>> TTIA: Receive %02x (%c)\n", if ((iu_console.stat & STS_FFL) == 0) {
temp & 0xff, temp & 0xff); iu_console.rxbuf[iu_console.w_p] = (temp & 0xff);
iu_console.w_p = (iu_console.w_p + 1) % IU_BUF_SIZE;
if (iu_port_a.conf & RX_EN) { if (iu_console.w_p == iu_contty.w_p) {
if ((iu_port_a.stat & STS_FFL) == 0) { iu_console.stat |= STS_FFL;
iu_port_a.rxbuf[iu_port_a.w_p] = (temp & 0xff);
iu_port_a.w_p = (iu_port_a.w_p + 1) % IU_BUF_SIZE;
if (iu_port_a.w_p == iu_port_b.w_p) {
sim_debug(READ_MSG, &tti_a_dev,
">>> FIFO FULL ON KEYBOARD READ!!!! <<<\n");
iu_port_a.stat |= STS_FFL;
} }
} }
iu_port_a.stat |= STS_RXR; iu_console.stat |= STS_RXR;
iu_state.istat |= ISTS_RAI; iu_state.istat |= ISTS_RAI;
if (iu_state.imr & 0x02) { if (iu_state.imr & 0x02) {
sim_debug(EXECUTE_MSG, &tti_a_dev,
"Firing IRQ 13 ON TTI A RECEIVE (%c)\n",
(temp & 0xff));
csr_data |= CSRUART; csr_data |= CSRUART;
} }
} }
@ -332,23 +355,63 @@ t_stat iu_svc_tti_a(UNIT *uptr)
return SCPE_OK; return SCPE_OK;
} }
t_stat iu_svc_tti_b(UNIT *uptr)
{
sim_clock_coschedule_tmr_abs(uptr, TMR_CLK, 2);
/* TODO: Handle TTIB as a terminal */ t_stat iu_svc_tto(UNIT *uptr)
return SCPE_OK;
}
t_stat iu_svc_tto_a(UNIT *uptr)
{ {
iu_txrdy_a_irq(); iu_txrdy_a_irq();
return SCPE_OK; return SCPE_OK;
} }
t_stat iu_svc_tto_b(UNIT *uptr) t_stat iu_svc_contty(UNIT *uptr)
{ {
int32 temp, ln;
if ((uptr->flags & UNIT_ATT) == 0) {
return SCPE_OK;
}
ln = tmxr_poll_conn(&contty_desc);
if (ln >= 0) {
contty_ldsc[ln].rcve = 1;
/* Set DCR */
iu_state.inprt &= ~(IU_DCDB);
iu_state.ipcr = IU_DCDB;
/* Cause an interrupt */
csr_data |= CSRUART;
}
tmxr_poll_rx(&contty_desc);
if (contty_ldsc[0].conn) {
temp = tmxr_getc_ln(&contty_ldsc[0]);
if (temp & SCPE_BREAK) {
sim_debug(EXECUTE_MSG, &contty_dev,
"*** BREAK RECEIVED ON CONTTY!\n");
}
if (temp) {
if (iu_contty.conf & RX_EN) {
if ((iu_contty.stat & STS_FFL) == 0) {
iu_contty.rxbuf[iu_contty.w_p] = (temp & 0xff);
iu_contty.w_p = (iu_contty.w_p + 1) % IU_BUF_SIZE;
if (iu_contty.w_p == iu_contty.w_p) {
iu_contty.stat |= STS_FFL;
}
}
iu_contty.stat |= STS_RXR;
iu_state.istat |= ISTS_RBI;
if (iu_state.imr & 0x02) {
csr_data |= CSRUART;
}
}
}
}
return sim_clock_coschedule_tmr(uptr, TMR_CLK, 2);
}
t_stat iu_svc_contty_xmt(UNIT *uptr)
{
tmxr_poll_tx(&contty_desc);
iu_txrdy_b_irq(); iu_txrdy_b_irq();
return SCPE_OK; return SCPE_OK;
} }
@ -395,27 +458,24 @@ uint32 iu_read(uint32 pa, size_t size)
switch (reg) { switch (reg) {
case MR12A: case MR12A:
modep = iu_port_a.modep; modep = iu_console.modep;
data = iu_port_a.mode[modep]; data = iu_console.mode[modep];
iu_increment_a = TRUE; iu_increment_a = TRUE;
break; break;
case SRA: case SRA:
data = iu_port_a.stat; data = iu_console.stat;
break; break;
case RHRA: case RHRA:
data = iu_port_a.rxbuf[iu_port_a.r_p]; data = iu_console.rxbuf[iu_console.r_p];
iu_port_a.r_p = (iu_port_a.r_p + 1) % IU_BUF_SIZE; iu_console.r_p = (iu_console.r_p + 1) % IU_BUF_SIZE;
sim_debug(READ_MSG, &tti_a_dev, iu_console.stat &= ~(STS_RXR|STS_FFL);
"[%08x] RHRA = %02x (%c)\n",
R[NUM_PC], (data & 0xff), (data & 0xff));
iu_port_a.stat &= ~(STS_RXR|STS_FFL);
iu_state.istat &= ~ISTS_RAI; iu_state.istat &= ~ISTS_RAI;
csr_data &= ~CSRUART; csr_data &= ~CSRUART;
break; break;
case IPCR: case IPCR:
data = iu_state.ipcr; data = iu_state.ipcr;
/* Reading the port resets the upper four bits */ /* Reading the port resets it */
iu_state.ipcr &= 0x0f; iu_state.ipcr = 0;
csr_data &= ~CSRUART; csr_data &= ~CSRUART;
break; break;
case ISR: case ISR:
@ -428,52 +488,38 @@ uint32 iu_read(uint32 pa, size_t size)
data = iu_timer_state.c_set & 0xff; data = iu_timer_state.c_set & 0xff;
break; break;
case MR12B: case MR12B:
modep = iu_port_b.modep; modep = iu_contty.modep;
data = iu_port_b.mode[modep]; data = iu_contty.mode[modep];
iu_increment_b = TRUE; iu_increment_b = TRUE;
break; break;
case SRB: case SRB:
data = iu_port_b.stat; data = iu_contty.stat;
sim_debug(READ_MSG, &tti_b_dev,
"[%08x] SRB = %02x\n",
R[NUM_PC], (data & 0xff));
break; break;
case RHRB: case RHRB:
data = iu_port_b.rxbuf[iu_port_b.r_p]; data = iu_contty.rxbuf[iu_contty.r_p];
iu_port_b.r_p = (iu_port_b.r_p + 1) % IU_BUF_SIZE; iu_contty.r_p = (iu_contty.r_p + 1) % IU_BUF_SIZE;
sim_debug(READ_MSG, &tti_b_dev, iu_contty.stat &= ~(STS_RXR|STS_FFL);
"[%08x] RHRB = %02x (%c)\n",
R[NUM_PC], (data & 0xff), (data & 0xff));
iu_port_b.stat &= ~(STS_RXR|STS_FFL);
iu_state.istat &= ~ISTS_RBI; iu_state.istat &= ~ISTS_RBI;
break; break;
case INPRT: case INPRT:
/* TODO: Correct behavior for DCD on contty */ data = iu_state.inprt;
/* For now, this enables DCD/DTR on console only */
data = 0x8e;
break; break;
case START_CTR: case START_CTR:
data = 0; data = 0;
iu_state.istat &= ~ISTS_CRI; iu_state.istat &= ~ISTS_CRI;
delay = (uint32) (IU_TIMER_STP * iu_timer_state.c_set); delay = (uint32) (IU_TIMER_STP * iu_timer_state.c_set);
sim_activate_abs(&iu_timer_unit, (int32) DELAY_US(delay)); sim_activate_abs(&iu_timer_unit, (int32) DELAY_US(delay));
sim_debug(READ_MSG, &iu_timer_dev,
"[%08x] Activating IU timer to fire in %04x steps\n",
R[NUM_PC], iu_timer_state.c_set);
break; break;
case STOP_CTR: case STOP_CTR:
data = 0; data = 0;
iu_state.istat &= ~ISTS_CRI; iu_state.istat &= ~ISTS_CRI;
csr_data &= ~CSRUART; csr_data &= ~CSRUART;
sim_cancel(&iu_timer_unit); sim_cancel(&iu_timer_unit);
sim_debug(READ_MSG, &iu_timer_dev,
"[%08x] Cancelling IU timer\n",
R[NUM_PC]);
break; break;
case 17: /* Clear DMAC interrupt */ case 17: /* Clear DMAC interrupt */
data = 0; data = 0;
iu_port_a.drq = FALSE; iu_console.drq = FALSE;
iu_port_b.drq = FALSE; iu_contty.drq = FALSE;
csr_data &= ~CSRDMA; csr_data &= ~CSRDMA;
break; break;
default: default:
@ -493,39 +539,31 @@ void iu_write(uint32 pa, uint32 val, size_t size)
switch (reg) { switch (reg) {
case MR12A: case MR12A:
modep = iu_port_a.modep; modep = iu_console.modep;
iu_port_a.mode[modep] = val & 0xff; iu_console.mode[modep] = val & 0xff;
iu_increment_a = TRUE; iu_increment_a = TRUE;
break; break;
case CSRA: case CSRA:
/* Set baud rate - not implemented */ /* Set baud rate - not implemented */
break; break;
case CRA: /* Command A */ case CRA: /* Command A */
sim_debug(WRITE_MSG, &tti_a_dev,
"[%08x] CRA = %02x\n",
R[NUM_PC], (val & 0xff));
iu_w_cmd(PORT_A, (uint8) val); iu_w_cmd(PORT_A, (uint8) val);
break; break;
case THRA: /* TX/RX Buf A */ case THRA: /* TX/RX Buf A */
sim_debug(WRITE_MSG, &tto_a_dev,
"[%08x] THRA = %02x (%c)\n",
R[NUM_PC], (val & 0xff), (val & 0xff));
/* Loopback mode */ /* Loopback mode */
if ((iu_port_a.mode[1] & 0xc0) == 0x80) { if ((iu_console.mode[1] & 0xc0) == 0x80) {
iu_port_a.txbuf = (uint8) val; iu_console.txbuf = (uint8) val;
/* This is also a Receive */ /* This is also a Receive */
if ((iu_port_a.stat & STS_FFL) == 0) { if ((iu_console.stat & STS_FFL) == 0) {
iu_port_a.rxbuf[iu_port_a.w_p] = (uint8) val; iu_console.rxbuf[iu_console.w_p] = (uint8) val;
iu_port_a.w_p = (iu_port_a.w_p + 1) % IU_BUF_SIZE; iu_console.w_p = (iu_console.w_p + 1) % IU_BUF_SIZE;
if (iu_port_a.w_p == iu_port_a.r_p) { if (iu_console.w_p == iu_contty.r_p) {
sim_debug(WRITE_MSG, &tto_a_dev, iu_console.stat |= STS_FFL;
">>> FIFO FULL ON LOOPBACK THRA! <<<");
iu_port_a.stat |= STS_FFL;
} }
} }
iu_port_a.stat |= STS_RXR; iu_console.stat |= STS_RXR;
iu_state.istat |= ISTS_RAI; iu_state.istat |= ISTS_RAI;
} else { } else {
iu_tx(PORT_A, (uint8) val); iu_tx(PORT_A, (uint8) val);
@ -536,9 +574,6 @@ void iu_write(uint32 pa, uint32 val, size_t size)
iu_state.acr = (uint8) val; iu_state.acr = (uint8) val;
break; break;
case IMR: case IMR:
sim_debug(WRITE_MSG, &tti_a_dev,
"[%08x] IMR = %02x\n",
R[NUM_PC], (val & 0xff));
iu_state.imr = (uint8) val; iu_state.imr = (uint8) val;
csr_data &= ~CSRUART; csr_data &= ~CSRUART;
/* Possibly cause an interrupt */ /* Possibly cause an interrupt */
@ -558,49 +593,50 @@ void iu_write(uint32 pa, uint32 val, size_t size)
iu_timer_state.c_set |= (val & 0xff); iu_timer_state.c_set |= (val & 0xff);
break; break;
case MR12B: case MR12B:
modep = iu_port_b.modep; modep = iu_contty.modep;
iu_port_b.mode[modep] = val & 0xff; iu_contty.mode[modep] = val & 0xff;
iu_increment_b = TRUE; iu_increment_b = TRUE;
break; break;
case CRB: /* Command B */ case CRB: /* Command B */
sim_debug(WRITE_MSG, &tti_b_dev,
"[%08x] CRB = %02x\n",
R[NUM_PC], (val & 0xff));
iu_w_cmd(PORT_B, (uint8) val); iu_w_cmd(PORT_B, (uint8) val);
break; break;
case CSRB: case CSRB:
break; break;
case THRB: /* TX/RX Buf B */ case THRB: /* TX/RX Buf B */
sim_debug(WRITE_MSG, &tto_b_dev,
"[%08x] THRB = %02x (%c)\n",
R[NUM_PC], (val & 0xff), (val & 0xff));
/* Loopback mode */ /* Loopback mode */
if ((iu_port_b.mode[1] & 0xc0) == 0x80) { if ((iu_contty.mode[1] & 0xc0) == 0x80) {
iu_port_a.txbuf = (uint8) val; iu_contty.txbuf = (uint8) val;
/* This is also a Receive */ /* This is also a Receive */
if ((iu_port_b.stat & STS_FFL) == 0) { if ((iu_contty.stat & STS_FFL) == 0) {
iu_port_b.rxbuf[iu_port_b.w_p] = (uint8) val; iu_contty.rxbuf[iu_contty.w_p] = (uint8) val;
iu_port_b.w_p = (iu_port_b.w_p + 1) % IU_BUF_SIZE; iu_contty.w_p = (iu_contty.w_p + 1) % IU_BUF_SIZE;
if (iu_port_b.w_p == iu_port_b.r_p) { if (iu_contty.w_p == iu_contty.r_p) {
sim_debug(WRITE_MSG, &tto_b_dev, iu_contty.stat |= STS_FFL;
">>> FIFO FULL ON LOOPBACK THRB! <<<");
iu_port_b.stat |= STS_FFL;
} }
} }
iu_port_b.stat |= STS_RXR; iu_contty.stat |= STS_RXR;
iu_state.istat |= ISTS_RBI; iu_state.istat |= ISTS_RBI;
} else { } else {
iu_tx(PORT_B, (uint8) val); iu_tx(PORT_B, (uint8) val);
} }
break; break;
case OPCR: case OPCR:
sim_debug(EXECUTE_MSG, &contty_dev,
">>> OPCR written: %02x\n",
(uint8) val);
iu_state.opcr = (uint8) val; iu_state.opcr = (uint8) val;
break; break;
case SOPR: case SOPR:
sim_debug(EXECUTE_MSG, &contty_dev,
">>> SOPR written: %02x\n",
(uint8) val);
break; break;
case ROPR: case ROPR:
sim_debug(EXECUTE_MSG, &contty_dev,
">>> ROPR written: %02x\n",
(uint8) val);
break; break;
default: default:
break; break;
@ -609,15 +645,11 @@ void iu_write(uint32 pa, uint32 val, size_t size)
void iua_drq_handled() void iua_drq_handled()
{ {
sim_debug(EXECUTE_MSG, &tto_a_dev,
"Firing IU IRQ 13 on DRQ (A) Hanlded\n");
csr_data |= CSRDMA; csr_data |= CSRDMA;
} }
void iub_drq_handled() void iub_drq_handled()
{ {
sim_debug(EXECUTE_MSG, &tto_a_dev,
"Firing IU IRQ 13 on DRQ (B) Hanlded\n");
csr_data |= CSRDMA; csr_data |= CSRDMA;
} }
@ -625,13 +657,14 @@ static SIM_INLINE void iu_tx(uint8 portno, uint8 val)
{ {
IU_PORT *p; IU_PORT *p;
UNIT *uptr; UNIT *uptr;
TMLN *lp;
if (portno == 0) { if (portno == 0) {
p = &iu_port_a; p = &iu_console;
uptr = &tto_a_unit; uptr = &tto_unit;
} else { } else {
p = &iu_port_b; p = &iu_contty;
uptr = &tto_b_unit; uptr = contty_xmt_unit;
} }
p->txbuf = val; p->txbuf = val;
@ -643,6 +676,9 @@ static SIM_INLINE void iu_tx(uint8 portno, uint8 val)
if (portno == PORT_A) { if (portno == PORT_A) {
/* Write the character to the SIMH console */ /* Write the character to the SIMH console */
sim_putchar(val); sim_putchar(val);
} else {
lp = &contty_ldsc[0];
tmxr_putc_ln(lp, val);
} }
/* The buffer is now empty, we've transmitted, so set TXR */ /* The buffer is now empty, we've transmitted, so set TXR */
@ -660,9 +696,9 @@ static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 cmd)
IU_PORT *p; IU_PORT *p;
if (portno == 0) { if (portno == 0) {
p = &iu_port_a; p = &iu_console;
} else { } else {
p = &iu_port_b; p = &iu_contty;
} }
/* Enable or disable transmitter */ /* Enable or disable transmitter */

View file

@ -94,10 +94,6 @@
#define SOPR 14 #define SOPR 14
#define ROPR 15 #define ROPR 15
#define UNIT_CONSOLE_TTI 0
#define UNIT_CONSOLE_TTO 1
#define UNIT_IU_TIMER 2
/* Registers - R/W */ /* Registers - R/W */
#define MR12A 0 #define MR12A 0
#define MR12B 8 #define MR12B 8
@ -122,10 +118,9 @@
#define IU_MODE(x) ((x & UM_MASK) >> UM_SHIFT) #define IU_MODE(x) ((x & UM_MASK) >> UM_SHIFT)
extern DEVICE tti_a_dev; extern DEVICE tti_dev;
extern DEVICE tto_a_dev; extern DEVICE tto_dev;
extern DEVICE tti_b_dev; extern DEVICE contty_dev;
extern DEVICE tto_b_dev;
extern DEVICE iu_timer_dev; extern DEVICE iu_timer_dev;
#define IUBASE 0x49000 #define IUBASE 0x49000
@ -150,6 +145,9 @@ extern DEVICE iu_timer_dev;
#define IU_BUF_SIZE 3 #define IU_BUF_SIZE 3
#define IU_DCDA 0x01
#define IU_DCDB 0x02
typedef struct iu_port { typedef struct iu_port {
uint8 stat; /* Port Status */ uint8 stat; /* Port Status */
uint8 cmd; /* Command */ uint8 cmd; /* Command */
@ -177,17 +175,19 @@ typedef struct iu_timer_state {
t_bool c_en; t_bool c_en;
} IU_TIMER_STATE; } IU_TIMER_STATE;
extern IU_PORT iu_port_a; extern IU_PORT iu_console;
extern IU_PORT iu_port_b; extern IU_PORT iu_contty;
/* Function prototypes */ /* Function prototypes */
t_stat tti_a_reset(DEVICE *dptr); t_stat contty_attach(UNIT *uptr, CONST char *cptr);
t_stat tti_b_reset(DEVICE *dptr); t_stat contty_detach(UNIT *uptr);
t_stat tti_reset(DEVICE *dptr);
t_stat contty_reset(DEVICE *dptr);
t_stat iu_timer_reset(DEVICE *dptr); t_stat iu_timer_reset(DEVICE *dptr);
t_stat iu_svc_tti_a(UNIT *uptr); t_stat iu_svc_tti(UNIT *uptr);
t_stat iu_svc_tto_a(UNIT *uptr); t_stat iu_svc_tto(UNIT *uptr);
t_stat iu_svc_tti_b(UNIT *uptr); t_stat iu_svc_contty(UNIT *uptr);
t_stat iu_svc_tto_b(UNIT *uptr); t_stat iu_svc_contty_xmt(UNIT *uptr);
t_stat iu_svc_timer(UNIT *uptr); t_stat iu_svc_timer(UNIT *uptr);
uint32 iu_read(uint32 pa, size_t size); uint32 iu_read(uint32 pa, size_t size);
void iu_write(uint32 pa, uint32 val, size_t size); void iu_write(uint32 pa, uint32 val, size_t size);

View file

@ -54,10 +54,9 @@ DEVICE *sim_devices[] = {
&tod_dev, &tod_dev,
&nvram_dev, &nvram_dev,
&csr_dev, &csr_dev,
&tti_a_dev, &tti_dev,
&tto_a_dev, &tto_dev,
&tti_b_dev, &contty_dev,
&tto_b_dev,
&iu_timer_dev, &iu_timer_dev,
&dmac_dev, &dmac_dev,
&if_dev, &if_dev,
@ -79,8 +78,8 @@ const char *sim_stop_messages[] = {
void full_reset() void full_reset()
{ {
cpu_reset(&cpu_dev); cpu_reset(&cpu_dev);
tti_a_reset(&tti_a_dev); tti_reset(&tti_dev);
tti_b_reset(&tti_b_dev); contty_reset(&contty_dev);
iu_timer_reset(&iu_timer_dev); iu_timer_reset(&iu_timer_dev);
timer_reset(&timer_dev); timer_reset(&timer_dev);
if_reset(&if_dev); if_reset(&if_dev);