1
0
mirror of https://github.com/simh/simh.git synced 2026-01-15 08:02:40 +00:00

3b2: Refactor IU into 5 devices

This commit is contained in:
Seth Morabito 2017-11-24 08:33:34 -08:00 committed by Mark Pizzolato
parent f6e63892b4
commit b23ebbe312
5 changed files with 422 additions and 169 deletions

View File

@ -55,8 +55,8 @@ DEVICE dmac_dev = {
dmac_drq_handler dmac_drq_handlers[] = {
{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_IUA_CHAN, IUBASE+IUA_DATA_REG, &iu_state.drqa, iua_drq_handled},
{DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_state.drqb, iub_drq_handled},
{DMA_IUA_CHAN, IUBASE+IUA_DATA_REG, &iu_port_a.drq, iua_drq_handled},
{DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_port_b.drq, iub_drq_handled},
{0, 0, NULL, NULL }
};
@ -251,6 +251,8 @@ void dmac_program(uint8 reg, uint8 val)
dma_state.mask |= (1 << channel_id);
} else {
dma_state.mask &= ~(1 << channel_id);
/* Set the appropriate DRQ */
/* *dmac_drq_handlers[channel_id].drq = TRUE; */
}
sim_debug(WRITE_MSG, &dmac_dev,
@ -278,7 +280,7 @@ void dmac_program(uint8 reg, uint8 val)
break;
case 15: /* Write All Mask Register Bits */
sim_debug(WRITE_MSG, &dmac_dev,
"[%08x] Clear DMAC Interrupt. val=%02x\n",
"[%08x] Write DMAC mask (all bits). Val=%02x\n",
R[NUM_PC], val);
dma_state.mask = val & 0xf;
break;

View File

@ -30,25 +30,48 @@
#include "3b2_iu.h"
/*
* The 3B2/400 has two on-board serial ports, labeled CONSOLE and
* CONTTY. The CONSOLE port is (naturally) the system console. The
* CONTTY port serves as a secondary serial port for an additional
* terminal.
*
* These lines are driven by an SCN2681A Dual UART, with two receivers
* and two transmitters.
*
* In addition to the two TX/RX ports, the SCN27681A also has one
* programmable timer.
*
* The SCN2681A UART is represented here by five devices:
*
* - Console TTI (Input, port A)
* - Console TTO (Output, port A)
* - Contty TTI (Input, port B)
* - Contty TTO (Output, port B)
* - IU Timer
*/
/*
* Registers
*/
/* The IU state */
/* The IU state shared between A and B */
IU_STATE iu_state;
/* The tx/rx state for ports A and B */
IU_PORT iu_port_a;
IU_PORT iu_port_b;
/* The timer state */
IU_TIMER_STATE iu_timer_state;
/* Flags for incrementing mode pointers */
t_bool iu_increment_a = FALSE;
t_bool iu_increment_b = FALSE;
extern uint16 csr_data;
UNIT iu_unit[] = {
{ UDATA(&iu_svc_tti, UNIT_IDLE, 0), TMLN_SPD_9600_BPS },
{ UDATA(&iu_svc_tto, TT_MODE_8B, 0), SERIAL_OUT_WAIT },
{ UDATA(&iu_svc_timer, 0, 0) },
{ NULL }
};
BITFIELD sr_bits[] = {
BIT(RXRDY),
BIT(FFULL),
@ -89,86 +112,202 @@ BITFIELD conf_bits[] = {
ENDBITS
};
REG iu_reg[] = {
{ HRDATADF(ISTAT, iu_state.istat, 8, "Interrupt Status", isr_bits) },
{ HRDATAD(IMR, iu_state.imr, 8, "Interrupt Mask") },
{ HRDATADF(ACR, iu_state.acr, 8, "Auxiliary Control Register", acr_bits) },
{ HRDATAD(CTR, iu_state.c_set, 16, "Counter Setting") },
{ HRDATAD(IP, iu_state.inprt, 8, "Input Port") },
{ HRDATADF(STAT_A, iu_state.port[0].stat, 8, "Status (Port A)", sr_bits) },
{ HRDATAD(DATA_A, iu_state.port[0].buf, 8, "Data (Port A)") },
{ HRDATADF(CONF_A, iu_state.port[0].conf, 8, "Config (Port A)", conf_bits) },
{ HRDATADF(STAT_B, iu_state.port[1].stat, 8, "Status (Port B)", sr_bits) },
{ HRDATAD(DATA_B, iu_state.port[1].buf, 8, "Data (Port B)") },
{ HRDATADF(CONF_B, iu_state.port[1].conf, 8, "Config (Port B)", conf_bits) },
/* TTI (Port A) data structures */
REG tti_a_reg[] = {
{ HRDATADF(STAT, iu_port_a.stat, 8, "Status", sr_bits) },
{ HRDATADF(CONF, iu_port_a.conf, 8, "Config", conf_bits) },
{ BRDATAD(DATA, iu_port_a.rxbuf, 16, 8, IU_BUF_SIZE, "Data") },
{ NULL }
};
DEVICE iu_dev = {
"IU", iu_unit, iu_reg, NULL,
3, 8, 32, 1, 8, 8,
NULL, NULL, &iu_reset,
UNIT tti_a_unit = { UDATA(&iu_svc_tti_a, UNIT_IDLE, 0), TMLN_SPD_9600_BPS };
DEVICE tti_a_dev = {
"TTIA", &tti_a_unit, tti_a_reg, NULL,
1, 8, 32, 1, 8, 8,
NULL, NULL, &tti_a_reset,
NULL, NULL, NULL, NULL,
DEV_DEBUG, 0, sys_deb_tab
};
/* TTO (Port A) data structures */
REG tto_a_reg[] = {
{ HRDATADF(STAT, iu_port_a.stat, 8, "Status", sr_bits) },
{ HRDATADF(ISTAT, iu_state.istat, 8, "Interrupt Status", isr_bits) },
{ HRDATAD(IMR, iu_state.imr, 8, "Interrupt Mask") },
{ HRDATADF(ACR, iu_state.acr, 8, "Auxiliary Control Register", acr_bits) },
{ HRDATAD(DATA, iu_port_a.txbuf, 8, "Data") },
{ NULL }
};
UNIT tto_a_unit = { UDATA(&iu_svc_tto_a, TT_MODE_8B, 0), SERIAL_OUT_WAIT };
DEVICE tto_a_dev = {
"TTOA", &tto_a_unit, tto_a_reg, NULL,
1, 8, 32, 1, 8, 8,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
DEV_DEBUG, 0, sys_deb_tab
};
/* TTI (Port B) data structures */
REG tti_b_reg[] = {
{ HRDATADF(STAT, iu_port_b.stat, 8, "Status", sr_bits) },
{ HRDATADF(CONF, iu_port_b.conf, 8, "Config", conf_bits) },
{ BRDATAD(DATA, iu_port_b.rxbuf, 16, 8, IU_BUF_SIZE, "Data") },
{ NULL }
};
UNIT tti_b_unit = { UDATA(&iu_svc_tti_b, UNIT_IDLE, 0), TMLN_SPD_9600_BPS };
DEVICE tti_b_dev = {
"TTIB", &tti_b_unit, tti_b_reg, NULL,
1, 8, 32, 1, 8, 8,
NULL, NULL, &tti_b_reset,
NULL, NULL, NULL, NULL,
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) },
{ HRDATAD(IMR, iu_state.imr, 8, "Interrupt Mask") },
{ HRDATADF(ACR, iu_state.acr, 8, "Auxiliary Control Register", acr_bits) },
{ HRDATAD(DATA, iu_port_b.txbuf, 8, "Data") },
{ NULL }
};
UNIT tto_b_unit = { UDATA(&iu_svc_tto_b, TT_MODE_8B, 0), SERIAL_OUT_WAIT };
DEVICE tto_b_dev = {
"TTOB", &tto_b_unit, tto_b_reg, NULL,
1, 8, 32, 1, 8, 8,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
DEV_DEBUG, 0, sys_deb_tab
};
/* IU Timer data structures */
REG iu_timer_reg[] = {
{ HRDATAD(CTR_SET, iu_timer_state.c_set, 16, "Counter Setting") },
{ NULL }
};
UNIT iu_timer_unit = { UDATA(&iu_svc_timer, 0, 0) };
DEVICE iu_timer_dev = {
"IUTIMER", &iu_timer_unit, iu_timer_reg, NULL,
1, 8, 32, 1, 8, 8,
NULL, NULL, &iu_timer_reset,
NULL, NULL, NULL, NULL,
DEV_DEBUG, 0, sys_deb_tab
};
void increment_modep_a()
{
iu_increment_a = FALSE;
iu_state.port[PORT_A].modep++;
iu_port_a.modep++;
if (iu_state.port[PORT_A].modep > 1) {
iu_state.port[PORT_A].modep = 0;
if (iu_port_a.modep > 1) {
iu_port_a.modep = 0;
}
}
void increment_modep_b()
{
iu_increment_b = FALSE;
iu_state.port[PORT_B].modep++;
iu_port_b.modep++;
if (iu_state.port[PORT_B].modep > 1) {
iu_state.port[PORT_B].modep = 0;
if (iu_port_b.modep > 1) {
iu_port_b.modep = 0;
}
}
void iu_txrdy_irq(uint8 portno) {
uint8 irq_mask = (uint8) (1u << (portno * 4));
if ((iu_state.imr & irq_mask) &&
(iu_state.port[portno].conf & TX_EN) &&
(iu_state.port[portno].stat & STS_TXR)) {
sim_debug(EXECUTE_MSG, &iu_dev,
"Firing IU TTY IRQ 13 ON TX/State Change\n");
void iu_txrdy_a_irq() {
if ((iu_state.imr & ISTS_TAI) &&
(iu_port_a.conf & TX_EN) &&
(iu_port_a.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;
}
}
t_stat iu_reset(DEVICE *dptr)
void iu_txrdy_b_irq() {
if ((iu_state.imr & ISTS_TBI) &&
(iu_port_b.conf & TX_EN) &&
(iu_port_b.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;
}
}
t_stat iu_reset()
{
uint8 portno;
t_stat result;
memset(&iu_state, 0, sizeof(struct iu_state));
iu_state.opcr = 0;
if (!sim_is_active(&iu_unit[UNIT_CONSOLE_TTI])) {
iu_unit[UNIT_CONSOLE_TTI].wait = IU_TTY_DELAY;
sim_activate(&iu_unit[UNIT_CONSOLE_TTI],
iu_unit[UNIT_CONSOLE_TTI].wait);
result = tti_a_reset(&tti_a_dev);
if (result != SCPE_OK) {
return result;
}
for (portno = 0; portno < 2; portno++) {
iu_state.port[portno].buf = 0;
iu_state.port[portno].modep = 0;
iu_state.port[portno].conf = 0;
iu_state.port[portno].stat = 0;
result = tti_b_reset(&tti_b_dev);
if (result != SCPE_OK) {
return result;
}
result = iu_timer_reset(&iu_timer_dev);
if (result != SCPE_OK) {
return result;
}
return SCPE_OK;
}
t_stat iu_svc_tti(UNIT *uptr)
t_stat tti_a_reset(DEVICE *dptr)
{
memset(&iu_state, 0, sizeof(IU_STATE));
memset(&iu_port_a, 0, sizeof(IU_PORT));
/* Start the TTI A polling loop */
if (!sim_is_active(&tti_a_unit)) {
sim_activate(&tti_a_unit, tti_a_unit.wait);
}
return SCPE_OK;
}
t_stat tti_b_reset(DEVICE *dtpr)
{
memset(&iu_state, 0, sizeof(IU_STATE));
memset(&iu_port_b, 0, sizeof(IU_PORT));
/* Start the TTI B polling loop */
if (!sim_is_active(&tti_b_unit)) {
sim_activate(&tti_b_unit, tti_b_unit.wait);
}
return SCPE_OK;
}
t_stat iu_timer_reset(DEVICE *dptr)
{
memset(&iu_timer_state, 0, sizeof(IU_TIMER_STATE));
return SCPE_OK;
}
/* Service routines */
t_stat iu_svc_tti_a(UNIT *uptr)
{
int32 temp;
@ -188,13 +327,24 @@ t_stat iu_svc_tti(UNIT *uptr)
return temp;
}
if (iu_state.port[PORT_A].conf & RX_EN) {
iu_state.port[PORT_A].buf = (temp & 0xff);
iu_state.port[PORT_A].stat |= STS_RXR;
sim_debug(READ_MSG, &tti_a_dev,
">>> TTIA: Receive %02x (%c)\n",
temp & 0xff, temp & 0xff);
if (iu_port_a.conf & RX_EN) {
if ((iu_port_a.stat & STS_FFL == 0) && iu_port_a.w_p == iu_port_a.r_p) {
sim_debug(READ_MSG, &tti_a_dev,
">>> FIFO FULL ON KEYBOARD READ!!!! <<<\n");
iu_port_a.stat |= STS_FFL;
} else {
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;
}
iu_port_a.stat |= STS_RXR;
iu_state.istat |= ISTS_RAI;
if (iu_state.imr & 0x02) {
sim_debug(EXECUTE_MSG, &iu_dev,
"Firing IU TTY IRQ 13 ON RECEIVE (%c)\n",
sim_debug(EXECUTE_MSG, &tti_a_dev,
"Firing IRQ 13 ON TTI A RECEIVE (%c)\n",
(temp & 0xff));
csr_data |= CSRUART;
}
@ -203,16 +353,27 @@ t_stat iu_svc_tti(UNIT *uptr)
return SCPE_OK;
}
t_stat iu_svc_tto(UNIT *uptr)
t_stat iu_svc_tti_b(UNIT *uptr)
{
sim_debug(EXECUTE_MSG, &iu_dev,
"Calling iu_txrdy_irq on iu_svc_tto\n");
sim_clock_coschedule_tmr_abs(uptr, TMR_CLK, 2);
iu_txrdy_irq(PORT_A);
/* TODO: Handle TTIB as a terminal */
return SCPE_OK;
}
t_stat iu_svc_tto_a(UNIT *uptr)
{
iu_txrdy_a_irq();
return SCPE_OK;
}
t_stat iu_svc_tto_b(UNIT *uptr)
{
iu_txrdy_b_irq();
return SCPE_OK;
}
t_stat iu_svc_timer(UNIT *uptr)
{
iu_state.istat |= ISTS_CRI;
@ -255,16 +416,20 @@ uint32 iu_read(uint32 pa, size_t size)
switch (reg) {
case MR12A:
modep = iu_state.port[PORT_A].modep;
data = iu_state.port[PORT_A].mode[modep];
modep = iu_port_a.modep;
data = iu_port_a.mode[modep];
iu_increment_a = TRUE;
break;
case SRA:
data = iu_state.port[PORT_A].stat;
data = iu_port_a.stat;
break;
case RHRA:
data = iu_state.port[PORT_A].buf;
iu_state.port[PORT_A].stat &= ~STS_RXR;
data = iu_port_a.rxbuf[iu_port_a.r_p];
iu_port_a.r_p = (iu_port_a.r_p + 1) % IU_BUF_SIZE;
sim_debug(READ_MSG, &tti_a_dev,
"[%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;
csr_data &= ~CSRUART;
break;
@ -278,22 +443,29 @@ uint32 iu_read(uint32 pa, size_t size)
data = iu_state.istat;
break;
case CTU:
data = (iu_state.c_set >> 8) & 0xff;
data = (iu_timer_state.c_set >> 8) & 0xff;
break;
case CTL:
data = iu_state.c_set & 0xff;
data = iu_timer_state.c_set & 0xff;
break;
case MR12B:
modep = iu_state.port[PORT_B].modep;
data = iu_state.port[PORT_B].mode[modep];
modep = iu_port_b.modep;
data = iu_port_b.mode[modep];
iu_increment_b = TRUE;
break;
case SRB:
data = iu_state.port[PORT_B].stat;
data = iu_port_b.stat;
sim_debug(READ_MSG, &tti_b_dev,
"[%08x] SRB = %02x\n",
R[NUM_PC], (data & 0xff));
break;
case RHRB:
data = iu_state.port[PORT_B].buf;
iu_state.port[PORT_B].stat &= ~STS_RXR;
data = iu_port_b.rxbuf[iu_port_b.r_p];
iu_port_b.r_p = (iu_port_b.r_p + 1) % IU_BUF_SIZE;
sim_debug(READ_MSG, &tti_b_dev,
"[%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;
break;
case INPRT:
@ -304,19 +476,25 @@ uint32 iu_read(uint32 pa, size_t size)
case START_CTR:
data = 0;
iu_state.istat &= ~ISTS_CRI;
delay = (uint32) (IU_TIMER_STP * iu_state.c_set);
sim_activate_abs(&iu_unit[UNIT_IU_TIMER], (int32) DELAY_US(delay));
delay = (uint32) (IU_TIMER_STP * iu_timer_state.c_set);
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;
case STOP_CTR:
data = 0;
iu_state.istat &= ~ISTS_CRI;
csr_data &= ~CSRUART;
sim_cancel(&iu_unit[UNIT_IU_TIMER]);
sim_cancel(&iu_timer_unit);
sim_debug(READ_MSG, &iu_timer_dev,
"[%08x] Cancelling IU timer\n",
R[NUM_PC]);
break;
case 17: /* Clear DMAC interrupt */
data = 0;
iu_state.drqa = FALSE;
iu_state.drqb = FALSE;
iu_port_a.drq = FALSE;
iu_port_b.drq = FALSE;
csr_data &= ~CSRDMA;
break;
default:
@ -336,21 +514,39 @@ void iu_write(uint32 pa, uint32 val, size_t size)
switch (reg) {
case MR12A:
modep = iu_state.port[PORT_A].modep;
iu_state.port[PORT_A].mode[modep] = val & 0xff;
modep = iu_port_a.modep;
iu_port_a.mode[modep] = val & 0xff;
iu_increment_a = TRUE;
break;
case CSRA:
/* Set baud rate - not implemented */
break;
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);
break;
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 */
if ((iu_state.port[PORT_A].mode[1] & 0xc0) == 0x80) {
iu_state.port[PORT_A].buf = (uint8) val;
iu_state.port[PORT_A].stat |= STS_RXR;
if ((iu_port_a.mode[1] & 0xc0) == 0x80) {
iu_port_a.txbuf = (uint8) val;
/* This is also a Receive */
if ((iu_port_a.stat & STS_FFL) == 0) {
iu_port_a.rxbuf[iu_port_a.w_p] = (uint8) val;
iu_port_a.w_p = (iu_port_a.w_p + 1) % IU_BUF_SIZE;
if (iu_port_a.w_p == iu_port_b.r_p) {
sim_debug(WRITE_MSG, &tto_a_dev,
">>> FIFO FULL ON LOOPBACK THRA! <<<");
iu_port_a.stat |= STS_FFL;
}
}
iu_port_a.stat |= STS_RXR;
iu_state.istat |= ISTS_RAI;
} else {
iu_tx(PORT_A, (uint8) val);
@ -361,42 +557,61 @@ void iu_write(uint32 pa, uint32 val, size_t size)
iu_state.acr = (uint8) val;
break;
case IMR:
sim_debug(WRITE_MSG, &tti_a_dev,
"[%08x] IMR = %02x\n",
R[NUM_PC], (val & 0xff));
iu_state.imr = (uint8) val;
csr_data &= ~CSRUART;
/* Possibly cause an interrupt */
sim_debug(EXECUTE_MSG, &iu_dev,
">>> calling iu_txrdy_irq() on IMR write.\n");
iu_txrdy_irq(PORT_A);
iu_txrdy_irq(PORT_B);
iu_txrdy_a_irq(PORT_A);
iu_txrdy_b_irq(PORT_B);
break;
case CTUR: /* Counter/Timer Upper Preset Value */
/* Clear out high byte */
iu_state.c_set &= 0x00ff;
iu_timer_state.c_set &= 0x00ff;
/* Set high byte */
iu_state.c_set |= (val & 0xff) << 8;
iu_timer_state.c_set |= (val & 0xff) << 8;
break;
case CTLR: /* Counter/Timer Lower Preset Value */
/* Clear out low byte */
iu_state.c_set &= 0xff00;
iu_timer_state.c_set &= 0xff00;
/* Set low byte */
iu_state.c_set |= (val & 0xff);
iu_timer_state.c_set |= (val & 0xff);
break;
case MR12B:
modep = iu_state.port[PORT_B].modep;
iu_state.port[PORT_B].mode[modep] = val & 0xff;
modep = iu_port_b.modep;
iu_port_b.mode[modep] = val & 0xff;
iu_increment_b = TRUE;
break;
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);
break;
case CSRB:
break;
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 */
if ((iu_state.port[PORT_B].mode[1] & 0xc0) == 0x80) {
iu_state.port[PORT_B].buf = (uint8) val;
iu_state.port[PORT_B].stat |= STS_RXR;
iu_state.istat |= ISTS_RAI;
if ((iu_port_b.mode[1] & 0xc0) == 0x80) {
iu_port_a.txbuf = (uint8) val;
/* This is also a Receive */
if ((iu_port_b.stat & STS_FFL) == 0) {
iu_port_b.rxbuf[iu_port_b.w_p] = (uint8) val;
iu_port_b.w_p = (iu_port_b.w_p + 1) % IU_BUF_SIZE;
if (iu_port_b.w_p == iu_port_b.r_p) {
sim_debug(WRITE_MSG, &tto_b_dev,
">>> FIFO FULL ON LOOPBACK THRB! <<<");
iu_port_b.stat |= STS_FFL;
}
}
iu_port_b.stat |= STS_RXR;
iu_state.istat |= ISTS_RBI;
} else {
iu_tx(PORT_B, (uint8) val);
}
@ -415,99 +630,115 @@ void iu_write(uint32 pa, uint32 val, size_t size)
void iua_drq_handled()
{
sim_debug(EXECUTE_MSG, &iu_dev,
"Firing IU TTY IRQ 13 On DRQ Handled\n");
sim_debug(EXECUTE_MSG, &tto_a_dev,
"Firing IU IRQ 13 on DRQ (A) Hanlded\n");
csr_data |= CSRDMA;
}
void iub_drq_handled()
{
sim_debug(EXECUTE_MSG, &iu_dev,
">>> DRQB handled.\n");
sim_debug(EXECUTE_MSG, &tto_a_dev,
"Firing IU IRQ 13 on DRQ (B) Hanlded\n");
csr_data |= CSRDMA;
}
static SIM_INLINE void iu_tx(uint8 portno, uint8 val)
{
struct port *p;
IU_PORT *p;
UNIT *uptr;
p = &iu_state.port[portno];
if (portno == 0) {
p = &iu_port_a;
uptr = &tto_a_unit;
} else {
p = &iu_port_b;
uptr = &tto_b_unit;
}
p->buf = val;
p->txbuf = val;
if (p->conf & TX_EN) {
sim_debug(EXECUTE_MSG, &iu_dev,
"[%08x] TRANSMIT: %02x (%c)\n",
R[NUM_PC], val, val);
p->stat &= ~(STS_TXR|STS_TXE);
iu_state.istat &= ~(1 << (portno*4));
/* Write the character to the SIMH console */
sim_putchar(p->buf);
if (portno == PORT_A) {
/* Write the character to the SIMH console */
sim_putchar(val);
}
/* The buffer is now empty, we've transmitted, so set TXR */
p->stat |= STS_TXR;
iu_state.istat |= (1 << (portno*4));
/* Possibly cause an interrupt */
sim_activate_abs(&iu_unit[UNIT_CONSOLE_TTO],
iu_unit[UNIT_CONSOLE_TTO].wait);
sim_activate_abs(uptr, uptr->wait);
}
}
static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 cmd)
{
IU_PORT *p;
if (portno == 0) {
p = &iu_port_a;
} else {
p = &iu_port_b;
}
/* Enable or disable transmitter */
/* Disable always wins, if both are set */
if (cmd & CMD_DTX) {
iu_state.port[portno].conf &= ~TX_EN;
iu_state.port[portno].stat &= ~STS_TXR;
iu_state.port[portno].stat &= ~STS_TXE;
iu_state.drqa = FALSE;
sim_debug(EXECUTE_MSG, &iu_dev,
">>> Disabling transmitter.\n");
p->conf &= ~TX_EN;
p->stat &= ~STS_TXR;
p->stat &= ~STS_TXE;
p->drq = FALSE;
} else if (cmd & CMD_ETX) {
iu_state.port[portno].conf |= TX_EN;
p->conf |= TX_EN;
/* TXE and TXR are always set by an ENABLE */
iu_state.port[portno].stat |= STS_TXR;
iu_state.port[portno].stat |= STS_TXE;
p->stat |= STS_TXR;
p->stat |= STS_TXE;
p->drq = TRUE;
iu_state.istat |= 1 << (portno*4);
iu_state.drqa = TRUE;
sim_debug(EXECUTE_MSG, &iu_dev,
">>> Calling iu_txrdy_irq() on TX Enable\n");
iu_txrdy_irq(portno);
if (portno == 0) {
iu_txrdy_a_irq();
} else {
iu_txrdy_b_irq();
}
}
/* Enable or disable receiver. */
/* Disable always wins, if both are set */
if (cmd & CMD_DRX) {
iu_state.port[portno].conf &= ~RX_EN;
iu_state.port[portno].stat &= ~STS_RXR;
p->conf &= ~RX_EN;
p->stat &= ~STS_RXR;
} else if (cmd & CMD_ERX) {
iu_state.port[portno].conf |= RX_EN;
p->conf |= RX_EN;
}
/* Command register bits 6-4 have special meaning */
switch ((cmd >> CMD_MISC_SHIFT) & CMD_MISC_MASK) {
case 1:
/* Causes the Channel A MR pointer to point to MR1. */
iu_state.port[portno].modep = 0;
p->modep = 0;
break;
case 2:
/* Reset receiver. Resets the Channel's receiver as if a
hardware reset had been applied. The receiver is disabled
and the FIFO is flushed. */
iu_state.port[portno].stat &= ~STS_RXR;
iu_state.port[portno].conf &= ~RX_EN;
iu_state.port[portno].buf = 0;
p->stat &= ~STS_RXR;
p->conf &= ~RX_EN;
p->w_p = 0;
p->r_p = 0;
break;
case 3:
/* Reset transmitter. Resets the Channel's transmitter as if a
hardware reset had been applied. */
iu_state.port[portno].stat &= ~STS_TXR;
iu_state.port[portno].stat &= ~STS_TXE;
iu_state.port[portno].conf &= ~TX_EN;
iu_state.port[portno].buf = 0;
p->stat &= ~STS_TXR;
p->stat &= ~STS_TXE;
p->conf &= ~TX_EN;
p->w_p = 0;
p->r_p = 0;
break;
case 4:
/* Reset error status. Clears the Channel's Received Break,
@ -516,7 +747,7 @@ static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 cmd)
(although RB, PE and FE bits will also be cleared) and in
block mode to clear all error status after a block of data
has been received. */
iu_state.port[portno].stat &= ~(STS_FER|STS_PER|STS_OER);
p->stat &= ~(STS_FER|STS_PER|STS_OER);
break;
case 5:
/* Reset Channel's break change interrupt. Causes the Channel

View File

@ -62,9 +62,6 @@
#define MODE_V_CHM 6 /* Channel mode */
#define MODE_M_CHM 0x3
#define PORT_A 0
#define PORT_B 1
/* Used by the DMAC */
#define IUA_DATA_REG 3
#define IUB_DATA_REG 11
@ -120,11 +117,16 @@
#define UM_MASK 0x70
#define UM_SHIFT 4
#define PORT_A 0
#define PORT_B 1
#define IU_MODE(x) ((x & UM_MASK) >> UM_SHIFT)
extern DEVICE iu_dev;
#define IU_TTY_DELAY 25000
extern DEVICE tti_a_dev;
extern DEVICE tto_a_dev;
extern DEVICE tti_b_dev;
extern DEVICE tto_b_dev;
extern DEVICE iu_timer_dev;
#define IUBASE 0x49000
#define IUSIZE 0x100
@ -146,42 +148,56 @@ extern DEVICE iu_dev;
#define IU_TIMER_STP 4.33792
struct port {
uint8 stat; /* Port Status */
uint8 cmd; /* Command */
uint8 mode[2]; /* Two mode buffers */
uint8 modep; /* Point to mode[0] or mode[1] */
uint8 conf; /* Configuration bits */
uint8 buf; /* Character data */
};
#define IU_BUF_SIZE 3
typedef struct iu_port {
uint8 stat; /* Port Status */
uint8 cmd; /* Command */
uint8 mode[2]; /* Two mode buffers */
uint8 modep; /* Point to mode[0] or mode[1] */
uint8 conf; /* Configuration bits */
uint8 txbuf; /* Transmit Holding Register */
uint8 rxbuf[IU_BUF_SIZE]; /* Receive Holding Register (3 bytes) */
uint8 w_p; /* Buffer Write Pointer */
uint8 r_p; /* Buffer Read Pointer */
t_bool drq; /* DRQ enabled */
} IU_PORT;
typedef struct iu_state {
uint8 istat; /* Interrupt Status */
uint8 imr; /* Interrupt Mask Register */
uint16 c_set; /* Timer / Counter Setting */
int32 c_val; /* Timer / Counter Value */
t_bool c_en; /* Counter Enabled */
t_bool drqa; /* Port A DRQ */
t_bool drqb; /* Port B DRQ */
uint8 acr;
uint8 opcr; /* Output Port Configuration */
uint8 inprt; /* Input Port Data */
uint8 ipcr; /* Input Port Change Register */
struct port port[2]; /* Port A and B */
} IU_STATE;
extern IU_STATE iu_state;
typedef struct iu_timer_state {
uint16 c_set;
t_bool c_en;
} IU_TIMER_STATE;
extern IU_PORT iu_port_a;
extern IU_PORT iu_port_b;
/* Global reset */
extern t_stat iu_reset();
/* Function prototypes */
t_stat iu_reset(DEVICE *dptr);
t_stat iu_svc_tti(UNIT *uptr);
t_stat iu_svc_tto(UNIT *uptr);
t_stat tti_a_reset(DEVICE *dptr);
t_stat tti_b_reset(DEVICE *dptr);
t_stat iu_timer_reset(DEVICE *dptr);
t_stat iu_svc_tti_a(UNIT *uptr);
t_stat iu_svc_tto_a(UNIT *uptr);
t_stat iu_svc_tti_b(UNIT *uptr);
t_stat iu_svc_tto_b(UNIT *uptr);
t_stat iu_svc_timer(UNIT *uptr);
uint32 iu_read(uint32 pa, size_t size);
void iu_write(uint32 pa, uint32 val, size_t size);
void iua_drq_handled();
void iub_drq_handled();
void iu_txrdy_a_irq();
void iu_txrdy_b_irq();
static SIM_INLINE void iu_tx(uint8 portno, uint8 val);
static SIM_INLINE void iu_w_buf(uint8 portno, uint8 val);

View File

@ -54,7 +54,11 @@ DEVICE *sim_devices[] = {
&tod_dev,
&nvram_dev,
&csr_dev,
&iu_dev,
&tti_a_dev,
&tto_a_dev,
&tti_b_dev,
&tto_b_dev,
&iu_timer_dev,
&dmac_dev,
&if_dev,
&id_dev,

View File

@ -151,7 +151,7 @@ void csr_write(uint32 pa, uint32 val, size_t size)
csr_data &= ~CSRPARE;
break;
case 0x0b: /* Set System Reset Request */
iu_reset(&iu_dev);
iu_reset();
cpu_reset(&cpu_dev);
cpu_boot(0, &cpu_dev);
break;