3b2: Refactor DUART and DMA

This change is a major refactor of how DMA and the DUART interact.

DMA implementation can now be overridden by individual devices that
require DMA. Disk and Floppy both continue to use a generic DMA
implementation, but the DUART code replaces the generic DMA with its
own implementation that correctly rate-limits TX. Among other things,
this allows the simulator to work correctly with real serial
terminals. This functionality has been tested on an AT&T 5620 "Blit"
terminal, which can run the 'layers' windowing software from the
simulator.
This commit is contained in:
Seth Morabito 2018-04-11 14:23:25 -07:00
parent da31dfa7a9
commit 177be95e5d
12 changed files with 266 additions and 171 deletions

View file

@ -1,4 +1,4 @@
/* 3b2_cpu.c: AT&T 3B2 Model 400 CPU (WE32100) Implementation
/* 3b2_cpu.c: AT&T 3B2 Model 400 CPU (WE32100) Implementation
Copyright (c) 2017, Seth J. Morabito

View file

@ -329,6 +329,40 @@ extern t_bool cpu_km;
typedef void (*callback)(void);
/* global symbols from the DMAC */
typedef struct {
uint8 page;
uint16 addr; /* Original addr */
uint16 wcount; /* Original wcount */
uint16 addr_c; /* Current addr */
int32 wcount_c; /* Current word-count */
uint16 ptr; /* Pointer into memory */
} dma_channel;
typedef struct {
/* Byte (high/low) flip-flop */
uint8 bff;
/* Address and count registers for channels 0-3 */
dma_channel channels[4];
/* DMAC programmable registers */
uint8 command;
uint8 mode;
uint8 request;
uint8 mask;
uint8 status;
} DMA_STATE;
extern DMA_STATE dma_state;
static SIM_INLINE uint32 dma_address(uint8 channel, uint32 offset, t_bool r) {
uint32 addr;
addr = (PHYS_MEM_BASE + dma_state.channels[channel].addr + offset);
/* The top bit of the page address is a R/W bit, so we mask it here */
addr |= (uint32) (((uint32)dma_state.channels[channel].page & 0x7f) << 16);
return addr;
}
extern DEVICE dmac_dev;
/* global symbols from the CSR */

View file

@ -52,12 +52,12 @@ DEVICE dmac_dev = {
DEV_DEBUG, 0, sys_deb_tab
};
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_console.drq, iua_drq_handled},
{DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_contty.drq, iub_drq_handled},
{0, 0, NULL, NULL }
dmac_dma_handler device_dma_handlers[] = {
{DMA_ID_CHAN, IDBASE+ID_DATA_REG, &id_drq, dmac_generic_dma, id_after_dma},
{DMA_IF_CHAN, IFBASE+IF_DATA_REG, &if_state.drq, dmac_generic_dma, if_after_dma},
{DMA_IUA_CHAN, IUBASE+IUA_DATA_REG, &iu_console.drq, iu_dma, NULL},
{DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_contty.drq, iu_dma, NULL},
{0, 0, NULL, NULL, NULL }
};
t_stat dmac_reset(DEVICE *dptr)
@ -72,6 +72,7 @@ t_stat dmac_reset(DEVICE *dptr)
dma_state.channels[i].wcount = 0;
dma_state.channels[i].addr_c = 0;
dma_state.channels[i].wcount_c = 0;
dma_state.channels[i].ptr = 0;
}
return SCPE_OK;
@ -209,6 +210,7 @@ void dmac_program(uint8 reg, uint8 val)
channel->wcount &= ~(0xff << dma_state.bff * 8);
channel->wcount |= (val & 0xff) << (dma_state.bff * 8);
channel->wcount_c = channel->wcount;
channel->ptr = 0;
sim_debug(WRITE_MSG, &dmac_dev,
"Set word count channel %d byte %d = %08x\n",
chan_num, dma_state.bff, channel->wcount);
@ -268,9 +270,12 @@ void dmac_program(uint8 reg, uint8 val)
dma_state.command = 0;
dma_state.status = 0;
for (i = 0; i < 4; i++) {
dma_state.channels[i].page = 0;
dma_state.channels[i].addr = 0;
dma_state.channels[i].wcount = 0;
dma_state.channels[i].page = 0;
dma_state.channels[i].addr_c = 0;
dma_state.channels[i].wcount_c = 0;
dma_state.channels[i].ptr = 0;
}
break;
case 15: /* Write All Mask Register Bits */
@ -352,69 +357,56 @@ void dmac_write(uint32 pa, uint32 val, size_t size)
}
}
static SIM_INLINE uint32 dma_address(uint8 channel, uint32 offset, t_bool r) {
uint32 addr;
addr = (PHYS_MEM_BASE +
dma_state.channels[channel].addr +
offset);
/* The top bit of the page address is a R/W bit, so we mask it here */
addr |= (uint32) (((uint32)dma_state.channels[channel].page & 0x7f) << 16);
return addr;
}
void dmac_transfer(uint8 channel, uint32 service_address)
void dmac_generic_dma(uint8 channel, uint32 service_address)
{
uint8 data;
int32 i;
uint16 offset;
uint32 addr;
dma_channel *chan = &dma_state.channels[channel];
i = (int32) chan->wcount_c;
/* TODO: This does not handle decrement-mode transfers,
which don't seem to be used in SVR3 */
switch ((dma_state.mode >> 2) & 0xf) {
case DMA_MODE_VERIFY:
sim_debug(EXECUTE_MSG, &dmac_dev,
"[%08x] [dmac_transfer channel=%d] unhandled VERIFY request.\n",
"[%08x] [dmac_generic_dma channel=%d] unhandled VERIFY request.\n",
R[NUM_PC], channel);
break;
case DMA_MODE_WRITE:
sim_debug(EXECUTE_MSG, &dmac_dev,
"[%08x] [dmac_transfer channel=%d] write: %d bytes from %08x\n",
"[%08x] [dmac_generic_dma channel=%d] write: %d bytes from %08x\n",
R[NUM_PC], channel,
chan->wcount + 1,
dma_address(channel, 0, TRUE));
offset = 0;
for (i = chan->wcount; i >= 0; i--) {
addr = dma_address(channel, offset, TRUE);
chan->addr_c = dma_state.channels[channel].addr + offset;
offset++;
for (; i >= 0; i--) {
chan->wcount_c--;
addr = dma_address(channel, chan->ptr, TRUE);
chan->addr_c = dma_state.channels[channel].addr + chan->ptr;
chan->ptr++;
data = pread_b(service_address);
write_b(addr, data);
}
break;
case DMA_MODE_READ:
sim_debug(EXECUTE_MSG, &dmac_dev,
"[%08x] [dmac_transfer channel=%d] read: %d bytes to %08x\n",
"[%08x] [dmac_generic_dma channel=%d] read: %d bytes to %08x\n",
R[NUM_PC], channel,
chan->wcount + 1,
dma_address(channel, 0, TRUE));
offset = 0;
for (i = chan->wcount; i >= 0; i--) {
addr = dma_address(channel, offset++, TRUE);
chan->addr_c = dma_state.channels[channel].addr + offset;
for (; i >= 0; i--) {
chan->wcount_c = i;
addr = dma_address(channel, chan->ptr++, TRUE);
chan->addr_c = dma_state.channels[channel].addr + chan->ptr;
data = pread_b(addr);
write_b(service_address, data);
}
break;
}
/* End of Process must set the IF channel's mask bit */
/* End of Process must set the channel's mask bit */
dma_state.mask |= (1 << channel);
dma_state.status |= (1 << channel);
}
@ -424,16 +416,16 @@ void dmac_transfer(uint8 channel, uint32 service_address)
*/
void dmac_service_drqs()
{
dmac_drq_handler *h;
dmac_dma_handler *h;
for (h = &dmac_drq_handlers[0]; h->drq != NULL; h++) {
for (h = &device_dma_handlers[0]; h->drq != NULL; h++) {
/* Only trigger if the channel has a DRQ set and its channel's
mask bit is 0 */
if (*h->drq && ((dma_state.mask >> h->channel) & 0x1) == 0) {
dmac_transfer(h->channel, h->service_address);
*h->drq = FALSE; /* Immediately clear DRQ state */
if (h->handled_callback != NULL) {
h->handled_callback();
h->dma_handler(h->channel, h->service_address);
/* Each handler is responsible for clearing its own DRQ line! */
if (h->after_dma_callback != NULL) {
h->after_dma_callback();
}
}
}

View file

@ -72,42 +72,19 @@
#define DMA_IF_READ (IFBASE + IF_DATA_REG)
typedef struct {
uint8 page;
uint16 addr; /* Original addr */
uint16 wcount; /* Original wcount */
uint16 addr_c; /* Current addr */
uint16 wcount_c; /* Current word-count */
} dma_channel;
typedef struct {
/* Byte (high/low) flip-flop */
uint8 bff;
/* Address and count registers for channels 0-3 */
dma_channel channels[4];
/* DMAC programmable registers */
uint8 command;
uint8 mode;
uint8 request;
uint8 mask;
uint8 status;
} DMA_STATE;
typedef struct {
uint8 channel;
uint32 service_address;
t_bool *drq;
void (*handled_callback)();
} dmac_drq_handler;
void (*dma_handler)(uint8 channel, uint32 service_address);
void (*after_dma_callback)();
} dmac_dma_handler;
/* DMAC */
t_stat dmac_reset(DEVICE *dptr);
uint32 dmac_read(uint32 pa, size_t size);
void dmac_write(uint32 pa, uint32 val, size_t size);
void dmac_service_drqs();
void dmac_transfer(uint8 channel, uint32 service_address);
void dmac_generic_dma(uint8 channel, uint32 service_address);
#endif

View file

@ -939,7 +939,7 @@ void id_handle_command(uint8 val)
}
}
void id_drq_handled()
void id_after_dma()
{
id_status &= ~ID_STAT_DRQ;
id_drq = FALSE;

View file

@ -155,6 +155,8 @@
#define ID_NUM_UNITS 2
#define DMA_ID_SVC IDBASE+ID_DATA_REG
extern DEVICE id_dev;
extern DEBTAB sys_deb_tab[];
extern t_bool id_drq;
@ -180,9 +182,8 @@ CONST char *id_description(DEVICE *dptr);
t_stat id_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
void id_handle_data(uint8 val);
void id_handle_command(uint8 val);
void id_after_dma();
static SIM_INLINE t_lba id_lba(uint16 cyl, uint8 head, uint8 sec);
void id_drq_handled();
#endif

View file

@ -532,7 +532,8 @@ static SIM_INLINE uint32 if_buf_offset()
return pos;
}
void if_drq_handled()
void if_after_dma()
{
if_state.drq = FALSE;
if_state.status &= ~IF_DRQ;
}

View file

@ -132,7 +132,7 @@ t_stat if_svc(UNIT *uptr);
t_stat if_reset(DEVICE *dptr);
uint32 if_read(uint32 pa, size_t size);
void if_write(uint32 pa, uint32 val, size_t size);
void if_drq_handled();
void if_handle_command();
void if_after_dma();
#endif

View file

@ -121,7 +121,7 @@ REG tti_reg[] = {
{ NULL }
};
UNIT tti_unit = { UDATA(&iu_svc_tti, UNIT_IDLE, 0), TMLN_SPD_19200_BPS };
UNIT tti_unit = { UDATA(&iu_svc_tti, UNIT_IDLE, 0), TMLN_SPD_9600_BPS };
DEVICE tti_dev = {
"TTI", &tti_unit, tti_reg, NULL,
@ -198,13 +198,25 @@ UNIT contty_unit[2] = {
UNIT *contty_rcv_unit = &contty_unit[0];
UNIT *contty_xmt_unit = &contty_unit[1];
DEBTAB contty_deb_tab[] = {
{"EXEC", EXECUTE_MSG, "Execute"},
{"XMT", TMXR_DBG_XMT, "Transmitted Data"},
{"RCV", TMXR_DBG_RCV, "Received Data"},
{"MDM", TMXR_DBG_MDM, "Modem Signals"},
{"CON", TMXR_DBG_CON, "connection activities"},
{"TRC", TMXR_DBG_TRC, "trace routine calls"},
{"ASY", TMXR_DBG_ASY, "Asynchronous Activities"},
{0}
};
DEVICE contty_dev = {
"CONTTY", contty_unit, contty_reg, NULL,
1, 8, 32, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &contty_reset,
NULL, &contty_attach, &contty_detach,
NULL, DEV_DISABLE|DEV_DEBUG|DEV_MUX,
0, sys_deb_tab, NULL, NULL,
0, contty_deb_tab, NULL, NULL,
NULL, NULL,
(void *)&contty_desc,
NULL
@ -235,9 +247,14 @@ uint8 bits_per_char = 7;
t_stat contty_attach(UNIT *uptr, CONST char *cptr)
{
t_stat r = tmxr_attach(&contty_desc, uptr, cptr);
t_stat r;
TMLN *lp;
tmxr_set_modem_control_passthru(&contty_desc);
tmxr_set_line_unit(&contty_desc, 0, contty_rcv_unit);
tmxr_set_line_output_unit(&contty_desc, 0, contty_xmt_unit);
r = tmxr_attach(&contty_desc, uptr, cptr);
if (r != SCPE_OK) {
tmxr_clear_modem_control_passthru(&contty_desc);
return r;
@ -281,6 +298,9 @@ void iu_txrdy_a_irq() {
if ((iu_state.imr & IMR_TXRA) &&
(iu_console.conf & TX_EN) &&
(iu_console.stat & STS_TXR)) {
sim_debug(EXECUTE_MSG, &tto_dev,
"[iu_txrdy_a_irq()] Firing IRQ after transmit of %02x (%c)\n",
(uint8) iu_console.txbuf, (char) iu_console.txbuf);
csr_data |= CSRUART;
}
}
@ -289,6 +309,9 @@ void iu_txrdy_b_irq() {
if ((iu_state.imr & IMR_TXRB) &&
(iu_contty.conf & TX_EN) &&
(iu_contty.stat & STS_TXR)) {
sim_debug(EXECUTE_MSG, &contty_dev,
"[iu_txrdy_b_irq()] Firing IRQ after transmit of %02x (%c)\n",
(uint8) iu_contty.txbuf, (char) iu_contty.txbuf);
csr_data |= CSRUART;
}
}
@ -298,8 +321,6 @@ t_stat tti_reset(DEVICE *dptr)
memset(&iu_state, 0, sizeof(IU_STATE));
memset(&iu_console, 0, sizeof(IU_PORT));
tmxr_set_console_units(&tti_unit, &tto_unit);
/* Input Port logic is inverted - 0 means set */
iu_state.inprt = ~(IU_DCDA);
@ -314,6 +335,7 @@ t_stat tti_reset(DEVICE *dptr)
t_stat contty_reset(DEVICE *dtpr)
{
char line_config[16];
t_stat result;
if (contty_ldsc == NULL) {
contty_desc.ldsc =
@ -321,6 +343,12 @@ t_stat contty_reset(DEVICE *dtpr)
(TMLN *)calloc(1, sizeof(*contty_ldsc));
}
tmxr_set_port_speed_control(&contty_desc);
/* tmxr_set_line_unit(&contty_desc, 0, contty_rcv_unit); */
/* tmxr_set_line_output_unit(&contty_desc, 0, contty_xmt_unit); */
/* tmxr_set_console_units(&tti_unit, &tto_unit); */
memset(&iu_state, 0, sizeof(IU_STATE));
memset(&iu_contty, 0, sizeof(IU_PORT));
brg_reg = 0;
@ -393,7 +421,16 @@ t_stat iu_svc_tti(UNIT *uptr)
t_stat iu_svc_tto(UNIT *uptr)
{
/* If there's more DMA to do, do it */
if (iu_console.dma && ((dma_state.mask >> DMA_IUA_CHAN) & 0x1) == 0) {
iu_dma(DMA_IUA_CHAN, IUBASE+IUA_DATA_REG);
} else {
/* The buffer is now empty, we've transmitted, so set TXR */
iu_console.stat |= STS_TXR;
iu_state.istat |= 1;
iu_txrdy_a_irq();
}
return SCPE_OK;
}
@ -444,8 +481,20 @@ t_stat iu_svc_contty_rcv(UNIT *uptr)
t_stat iu_svc_contty_xmt(UNIT *uptr)
{
dma_channel *chan = &dma_state.channels[DMA_IUB_CHAN];
tmxr_poll_tx(&contty_desc);
if (chan->wcount_c >= 0) {
/* More DMA to do */
iu_dma(DMA_IUB_CHAN, IUBASE+IUB_DATA_REG);
} else {
/* The buffer is now empty, we've transmitted, so set TXR */
iu_contty.stat |= STS_TXR;
iu_state.istat |= 0x10;
iu_txrdy_b_irq();
}
return SCPE_OK;
}
@ -501,9 +550,14 @@ uint32 iu_read(uint32 pa, size_t size)
case RHRA:
data = iu_console.rxbuf[iu_console.r_p];
iu_console.r_p = (iu_console.r_p + 1) % IU_BUF_SIZE;
/* If the FIFO is not empty, we must cause another interrupt
* to continue reading */
if (iu_console.r_p == iu_console.w_p) {
iu_console.stat &= ~(STS_RXR|STS_FFL);
iu_state.istat &= ~ISTS_RAI;
csr_data &= ~CSRUART;
} else {
csr_data |= CSRUART;
}
break;
case IPCR:
data = iu_state.ipcr;
@ -557,8 +611,12 @@ uint32 iu_read(uint32 pa, size_t size)
break;
case 17: /* Clear DMAC interrupt */
data = 0;
/*
iu_console.drq = FALSE;
iu_console.dma = FALSE;
iu_contty.drq = FALSE;
iu_contty.dma = FALSE;
*/
csr_data &= ~CSRDMA;
break;
default:
@ -591,28 +649,8 @@ void iu_write(uint32 pa, uint32 val, size_t size)
iu_w_cmd(PORT_A, bval);
break;
case THRA: /* TX/RX Buf A */
/* Loopback mode */
if ((iu_console.mode[1] & 0xc0) == 0x80) {
iu_console.txbuf = bval;
/* This is also a Receive */
if ((iu_console.stat & STS_FFL) == 0) {
iu_console.rxbuf[iu_console.w_p] = bval;
iu_console.w_p = (iu_console.w_p + 1) % IU_BUF_SIZE;
if (iu_console.w_p == iu_console.r_p) {
iu_console.stat |= STS_FFL;
}
}
iu_console.stat |= STS_RXR;
iu_state.istat |= ISTS_RAI;
if (iu_state.imr & IMR_RXRA) {
csr_data |= CSRUART;
}
} else {
iu_tx(PORT_A, bval);
}
csr_data &= ~CSRUART;
sim_activate_abs(&tto_unit, tto_unit.wait);
break;
case ACR: /* Auxiliary Control Register */
iu_state.acr = bval;
@ -678,27 +716,8 @@ void iu_write(uint32 pa, uint32 val, size_t size)
break;
case THRB: /* TX/RX Buf B */
/* Loopback mode */
if ((iu_contty.mode[1] & 0xc0) == 0x80) {
iu_contty.txbuf = bval;
/* This is also a Receive */
if ((iu_contty.stat & STS_FFL) == 0) {
iu_contty.rxbuf[iu_contty.w_p] = bval;
iu_contty.w_p = (iu_contty.w_p + 1) % IU_BUF_SIZE;
if (iu_contty.w_p == iu_contty.r_p) {
iu_contty.stat |= STS_FFL;
}
}
iu_contty.stat |= STS_RXR;
iu_state.istat |= ISTS_RBI;
if (iu_state.imr & IMR_RXRB) {
csr_data |= CSRUART;
}
} else {
iu_tx(PORT_B, bval);
}
sim_activate_abs(contty_xmt_unit, contty_ldsc[0].txdelta);
break;
case OPCR:
iu_state.opcr = bval;
@ -718,51 +737,60 @@ void iu_write(uint32 pa, uint32 val, size_t size)
}
}
void iua_drq_handled()
t_stat iu_tx(uint8 portno, uint8 val)
{
csr_data |= CSRDMA;
}
void iub_drq_handled()
{
csr_data |= CSRDMA;
}
static SIM_INLINE void iu_tx(uint8 portno, uint8 val)
{
IU_PORT *p;
UNIT *uptr;
TMLN *lp;
if (portno == 0) {
p = &iu_console;
uptr = &tto_unit;
} else {
p = &iu_contty;
uptr = contty_xmt_unit;
}
p->txbuf = val;
IU_PORT *p = (portno == PORT_A) ? &iu_console : &iu_contty;
UNIT *uptr = (portno == PORT_A) ? &tto_unit : contty_xmt_unit;
uint8 ists = (portno == PORT_A) ? ISTS_RAI : ISTS_RBI;
uint8 imr_mask = (portno == PORT_A) ? IMR_RXRA : IMR_RXRB;
int32 c;
t_stat status = SCPE_OK;
if (p->conf & TX_EN) {
if ((p->mode[1] & 0xc0) == 0x80) { /* Loopback mode */
p->txbuf = val;
/* This is also a Receive */
if ((p->stat & STS_FFL) == 0) {
p->rxbuf[p->w_p] = val;
p->w_p = (p->w_p + 1) % IU_BUF_SIZE;
if (p->w_p == p->r_p) {
p->stat |= STS_FFL;
}
}
p->stat |= STS_RXR;
iu_state.istat |= ists;
if (iu_state.imr & imr_mask) {
csr_data |= CSRUART;
}
return SCPE_OK;
} else { /* Direct mode */
c = sim_tt_outcvt(val, TTUF_MODE_8B);
if (c >= 0) {
p->txbuf = c;
p->stat &= ~(STS_TXR|STS_TXE);
iu_state.istat &= ~(1 << (portno*4));
if (portno == PORT_A) {
/* Write the character to the SIMH console */
sim_putchar(val);
sim_debug(EXECUTE_MSG, &tto_dev,
"[iu_tx] CONSOLE transmit %02x (%c)\n",
(uint8) c, (char) c);
status = sim_putchar(c);
} else {
lp = &contty_ldsc[0];
tmxr_putc_ln(lp, val);
sim_debug(EXECUTE_MSG, &contty_dev,
"[iu_tx] CONTTY transmit %02x (%c)\n",
(uint8) c, (char) c);
status = tmxr_putc_ln(&contty_ldsc[0], c);
}
}
}
}
/* 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(uptr, uptr->wait);
}
return status;
}
static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 cmd)
@ -783,6 +811,7 @@ static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 cmd)
p->stat &= ~STS_TXR;
p->stat &= ~STS_TXE;
p->drq = FALSE;
p->dma = FALSE;
} else if (cmd & CMD_ETX) {
p->conf |= TX_EN;
/* TXE and TXR are always set by an ENABLE */
@ -865,3 +894,52 @@ static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 cmd)
break;
}
}
/*
* Initiate DMA transfer or continue one already in progress.
*/
void iu_dma(uint8 channel, uint32 service_address)
{
uint8 data;
uint32 addr;
t_stat status = SCPE_OK;
dma_channel *chan = &dma_state.channels[channel];
UNIT *uptr = (channel == DMA_IUA_CHAN) ? &tto_unit : contty_xmt_unit;
IU_PORT *port = (channel == DMA_IUA_CHAN) ? &iu_console : &iu_contty;
/* Immediate acknowledge of DMA */
port->drq = FALSE;
if (!port->dma) {
/* Set DMA transfer type */
port->dma = 1u << ((dma_state.mode >> 2) & 0xf);
}
if (port->dma == DMA_READ) {
addr = dma_address(channel, chan->ptr, TRUE);
chan->addr_c = chan->addr + chan->ptr + 1;
data = pread_b(addr);
status = iu_tx(channel - 2, data);
if (status == SCPE_OK) {
chan->ptr++;
chan->wcount_c--;
} else if (status == SCPE_LOST) {
chan->ptr = 0;
chan->wcount_c = -1;
}
sim_activate_abs(uptr, uptr->wait);
if (chan->wcount_c >= 0) {
/* Return early so we don't finish DMA */
return;
}
}
/* Done with DMA */
port->dma = DMA_NONE;
dma_state.mask |= (1 << channel);
dma_state.status |= (1 << channel);
csr_data |= CSRDMA;
}

View file

@ -140,6 +140,8 @@ extern DEVICE tto_dev;
extern DEVICE contty_dev;
extern DEVICE iu_timer_dev;
extern int32 tmxr_poll;
#define IUBASE 0x49000
#define IUSIZE 0x100
@ -167,6 +169,11 @@ extern DEVICE iu_timer_dev;
#define IU_DTRA 0x01
#define IU_DTRB 0x02
#define DMA_NONE 0
#define DMA_VERIFY 1
#define DMA_WRITE 2
#define DMA_READ 4
/* Default baud rate generator (9600 baud) */
#define BRG_DEFAULT 11
@ -181,7 +188,8 @@ typedef struct iu_port {
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 */
uint8 dma; /* Currently active DMA mode */
t_bool drq; /* DMA request enabled */
} IU_PORT;
typedef struct iu_state {
@ -212,14 +220,15 @@ t_stat iu_svc_tto(UNIT *uptr);
t_stat iu_svc_contty_rcv(UNIT *uptr);
t_stat iu_svc_contty_xmt(UNIT *uptr);
t_stat iu_svc_timer(UNIT *uptr);
t_stat iu_tx(uint8 portno, uint8 val);
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();
void iu_dma(uint8 channel, uint32 service_address);
static SIM_INLINE void iu_tx(uint8 portno, uint8 val);
static SIM_INLINE void iu_w_buf(uint8 portno, uint8 val);
static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 val);
static SIM_INLINE void iu_update_rxi(uint8 c);

View file

@ -695,8 +695,11 @@ t_stat mmu_decode_va(uint32 va, uint8 r_acc, t_bool fc, uint32 *pa)
if (fc && mmu_check_perm(SD_ACC(sd0), r_acc) != SCPE_OK) {
sim_debug(EXECUTE_MSG, &mmu_dev,
"[%08x] CONTIGUOUS: NO ACCESS TO MEMORY AT %08x.\n"
"\t\tsd0=%08x sd0_addr=%08x\n"
"\t\tcpu_cm=%d acc_req=%x sd_acc=%02x\n",
R[NUM_PC], va, CPU_CM, r_acc, SD_ACC(sd0));
R[NUM_PC], va,
sd0, SD_ADDR(va),
CPU_CM, r_acc, SD_ACC(sd0));
MMU_FAULT(MMU_F_ACC);
return SCPE_NXM;
}

View file

@ -59,7 +59,7 @@ uint32 *NVRAM = NULL;
extern DEVICE cpu_dev;
int32 tmxr_poll = 0;
int32 tmxr_poll = 16667;
/* CSR */