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:
parent
da31dfa7a9
commit
177be95e5d
12 changed files with 266 additions and 171 deletions
|
@ -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
|
Copyright (c) 2017, Seth J. Morabito
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,40 @@ extern t_bool cpu_km;
|
||||||
typedef void (*callback)(void);
|
typedef void (*callback)(void);
|
||||||
|
|
||||||
/* global symbols from the DMAC */
|
/* 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;
|
extern DEVICE dmac_dev;
|
||||||
|
|
||||||
/* global symbols from the CSR */
|
/* global symbols from the CSR */
|
||||||
|
|
|
@ -52,12 +52,12 @@ DEVICE dmac_dev = {
|
||||||
DEV_DEBUG, 0, sys_deb_tab
|
DEV_DEBUG, 0, sys_deb_tab
|
||||||
};
|
};
|
||||||
|
|
||||||
dmac_drq_handler dmac_drq_handlers[] = {
|
dmac_dma_handler device_dma_handlers[] = {
|
||||||
{DMA_ID_CHAN, IDBASE+ID_DATA_REG, &id_drq, id_drq_handled},
|
{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, if_drq_handled},
|
{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, iua_drq_handled},
|
{DMA_IUA_CHAN, IUBASE+IUA_DATA_REG, &iu_console.drq, iu_dma, NULL},
|
||||||
{DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_contty.drq, iub_drq_handled},
|
{DMA_IUB_CHAN, IUBASE+IUB_DATA_REG, &iu_contty.drq, iu_dma, NULL},
|
||||||
{0, 0, NULL, NULL }
|
{0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
t_stat dmac_reset(DEVICE *dptr)
|
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].wcount = 0;
|
||||||
dma_state.channels[i].addr_c = 0;
|
dma_state.channels[i].addr_c = 0;
|
||||||
dma_state.channels[i].wcount_c = 0;
|
dma_state.channels[i].wcount_c = 0;
|
||||||
|
dma_state.channels[i].ptr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -209,6 +210,7 @@ void dmac_program(uint8 reg, uint8 val)
|
||||||
channel->wcount &= ~(0xff << dma_state.bff * 8);
|
channel->wcount &= ~(0xff << dma_state.bff * 8);
|
||||||
channel->wcount |= (val & 0xff) << (dma_state.bff * 8);
|
channel->wcount |= (val & 0xff) << (dma_state.bff * 8);
|
||||||
channel->wcount_c = channel->wcount;
|
channel->wcount_c = channel->wcount;
|
||||||
|
channel->ptr = 0;
|
||||||
sim_debug(WRITE_MSG, &dmac_dev,
|
sim_debug(WRITE_MSG, &dmac_dev,
|
||||||
"Set word count channel %d byte %d = %08x\n",
|
"Set word count channel %d byte %d = %08x\n",
|
||||||
chan_num, dma_state.bff, channel->wcount);
|
chan_num, dma_state.bff, channel->wcount);
|
||||||
|
@ -268,9 +270,12 @@ void dmac_program(uint8 reg, uint8 val)
|
||||||
dma_state.command = 0;
|
dma_state.command = 0;
|
||||||
dma_state.status = 0;
|
dma_state.status = 0;
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
|
dma_state.channels[i].page = 0;
|
||||||
dma_state.channels[i].addr = 0;
|
dma_state.channels[i].addr = 0;
|
||||||
dma_state.channels[i].wcount = 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;
|
break;
|
||||||
case 15: /* Write All Mask Register Bits */
|
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) {
|
void dmac_generic_dma(uint8 channel, uint32 service_address)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
uint8 data;
|
uint8 data;
|
||||||
int32 i;
|
int32 i;
|
||||||
uint16 offset;
|
|
||||||
uint32 addr;
|
uint32 addr;
|
||||||
|
|
||||||
dma_channel *chan = &dma_state.channels[channel];
|
dma_channel *chan = &dma_state.channels[channel];
|
||||||
|
|
||||||
|
i = (int32) chan->wcount_c;
|
||||||
|
|
||||||
/* TODO: This does not handle decrement-mode transfers,
|
/* TODO: This does not handle decrement-mode transfers,
|
||||||
which don't seem to be used in SVR3 */
|
which don't seem to be used in SVR3 */
|
||||||
|
|
||||||
switch ((dma_state.mode >> 2) & 0xf) {
|
switch ((dma_state.mode >> 2) & 0xf) {
|
||||||
case DMA_MODE_VERIFY:
|
case DMA_MODE_VERIFY:
|
||||||
sim_debug(EXECUTE_MSG, &dmac_dev,
|
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);
|
R[NUM_PC], channel);
|
||||||
break;
|
break;
|
||||||
case DMA_MODE_WRITE:
|
case DMA_MODE_WRITE:
|
||||||
sim_debug(EXECUTE_MSG, &dmac_dev,
|
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,
|
R[NUM_PC], channel,
|
||||||
chan->wcount + 1,
|
chan->wcount + 1,
|
||||||
dma_address(channel, 0, TRUE));
|
dma_address(channel, 0, TRUE));
|
||||||
offset = 0;
|
for (; i >= 0; i--) {
|
||||||
for (i = chan->wcount; i >= 0; i--) {
|
chan->wcount_c--;
|
||||||
addr = dma_address(channel, offset, TRUE);
|
addr = dma_address(channel, chan->ptr, TRUE);
|
||||||
chan->addr_c = dma_state.channels[channel].addr + offset;
|
chan->addr_c = dma_state.channels[channel].addr + chan->ptr;
|
||||||
offset++;
|
chan->ptr++;
|
||||||
data = pread_b(service_address);
|
data = pread_b(service_address);
|
||||||
write_b(addr, data);
|
write_b(addr, data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DMA_MODE_READ:
|
case DMA_MODE_READ:
|
||||||
sim_debug(EXECUTE_MSG, &dmac_dev,
|
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,
|
R[NUM_PC], channel,
|
||||||
chan->wcount + 1,
|
chan->wcount + 1,
|
||||||
dma_address(channel, 0, TRUE));
|
dma_address(channel, 0, TRUE));
|
||||||
offset = 0;
|
for (; i >= 0; i--) {
|
||||||
for (i = chan->wcount; i >= 0; i--) {
|
chan->wcount_c = i;
|
||||||
addr = dma_address(channel, offset++, TRUE);
|
addr = dma_address(channel, chan->ptr++, TRUE);
|
||||||
chan->addr_c = dma_state.channels[channel].addr + offset;
|
chan->addr_c = dma_state.channels[channel].addr + chan->ptr;
|
||||||
data = pread_b(addr);
|
data = pread_b(addr);
|
||||||
write_b(service_address, data);
|
write_b(service_address, data);
|
||||||
}
|
}
|
||||||
break;
|
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.mask |= (1 << channel);
|
||||||
dma_state.status |= (1 << channel);
|
dma_state.status |= (1 << channel);
|
||||||
}
|
}
|
||||||
|
@ -424,16 +416,16 @@ void dmac_transfer(uint8 channel, uint32 service_address)
|
||||||
*/
|
*/
|
||||||
void dmac_service_drqs()
|
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
|
/* Only trigger if the channel has a DRQ set and its channel's
|
||||||
mask bit is 0 */
|
mask bit is 0 */
|
||||||
if (*h->drq && ((dma_state.mask >> h->channel) & 0x1) == 0) {
|
if (*h->drq && ((dma_state.mask >> h->channel) & 0x1) == 0) {
|
||||||
dmac_transfer(h->channel, h->service_address);
|
h->dma_handler(h->channel, h->service_address);
|
||||||
*h->drq = FALSE; /* Immediately clear DRQ state */
|
/* Each handler is responsible for clearing its own DRQ line! */
|
||||||
if (h->handled_callback != NULL) {
|
if (h->after_dma_callback != NULL) {
|
||||||
h->handled_callback();
|
h->after_dma_callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,42 +72,19 @@
|
||||||
|
|
||||||
#define DMA_IF_READ (IFBASE + IF_DATA_REG)
|
#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 {
|
typedef struct {
|
||||||
uint8 channel;
|
uint8 channel;
|
||||||
uint32 service_address;
|
uint32 service_address;
|
||||||
t_bool *drq;
|
t_bool *drq;
|
||||||
void (*handled_callback)();
|
void (*dma_handler)(uint8 channel, uint32 service_address);
|
||||||
} dmac_drq_handler;
|
void (*after_dma_callback)();
|
||||||
|
} dmac_dma_handler;
|
||||||
|
|
||||||
/* DMAC */
|
/* DMAC */
|
||||||
t_stat dmac_reset(DEVICE *dptr);
|
t_stat dmac_reset(DEVICE *dptr);
|
||||||
uint32 dmac_read(uint32 pa, size_t size);
|
uint32 dmac_read(uint32 pa, size_t size);
|
||||||
void dmac_write(uint32 pa, uint32 val, size_t size);
|
void dmac_write(uint32 pa, uint32 val, size_t size);
|
||||||
void dmac_service_drqs();
|
void dmac_service_drqs();
|
||||||
void dmac_transfer(uint8 channel, uint32 service_address);
|
void dmac_generic_dma(uint8 channel, uint32 service_address);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -939,7 +939,7 @@ void id_handle_command(uint8 val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void id_drq_handled()
|
void id_after_dma()
|
||||||
{
|
{
|
||||||
id_status &= ~ID_STAT_DRQ;
|
id_status &= ~ID_STAT_DRQ;
|
||||||
id_drq = FALSE;
|
id_drq = FALSE;
|
||||||
|
|
|
@ -155,6 +155,8 @@
|
||||||
|
|
||||||
#define ID_NUM_UNITS 2
|
#define ID_NUM_UNITS 2
|
||||||
|
|
||||||
|
#define DMA_ID_SVC IDBASE+ID_DATA_REG
|
||||||
|
|
||||||
extern DEVICE id_dev;
|
extern DEVICE id_dev;
|
||||||
extern DEBTAB sys_deb_tab[];
|
extern DEBTAB sys_deb_tab[];
|
||||||
extern t_bool id_drq;
|
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);
|
t_stat id_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
void id_handle_data(uint8 val);
|
void id_handle_data(uint8 val);
|
||||||
void id_handle_command(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);
|
static SIM_INLINE t_lba id_lba(uint16 cyl, uint8 head, uint8 sec);
|
||||||
|
|
||||||
void id_drq_handled();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -532,7 +532,8 @@ static SIM_INLINE uint32 if_buf_offset()
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_drq_handled()
|
void if_after_dma()
|
||||||
{
|
{
|
||||||
|
if_state.drq = FALSE;
|
||||||
if_state.status &= ~IF_DRQ;
|
if_state.status &= ~IF_DRQ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ t_stat if_svc(UNIT *uptr);
|
||||||
t_stat if_reset(DEVICE *dptr);
|
t_stat if_reset(DEVICE *dptr);
|
||||||
uint32 if_read(uint32 pa, size_t size);
|
uint32 if_read(uint32 pa, size_t size);
|
||||||
void if_write(uint32 pa, uint32 val, size_t size);
|
void if_write(uint32 pa, uint32 val, size_t size);
|
||||||
void if_drq_handled();
|
|
||||||
void if_handle_command();
|
void if_handle_command();
|
||||||
|
void if_after_dma();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
262
3B2/3b2_iu.c
262
3B2/3b2_iu.c
|
@ -121,7 +121,7 @@ REG tti_reg[] = {
|
||||||
{ NULL }
|
{ 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 = {
|
DEVICE tti_dev = {
|
||||||
"TTI", &tti_unit, tti_reg, NULL,
|
"TTI", &tti_unit, tti_reg, NULL,
|
||||||
|
@ -198,13 +198,25 @@ UNIT contty_unit[2] = {
|
||||||
UNIT *contty_rcv_unit = &contty_unit[0];
|
UNIT *contty_rcv_unit = &contty_unit[0];
|
||||||
UNIT *contty_xmt_unit = &contty_unit[1];
|
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 = {
|
DEVICE contty_dev = {
|
||||||
"CONTTY", contty_unit, contty_reg, NULL,
|
"CONTTY", contty_unit, contty_reg, NULL,
|
||||||
1, 8, 32, 1, 8, 8,
|
1, 8, 32, 1, 8, 8,
|
||||||
&tmxr_ex, &tmxr_dep, &contty_reset,
|
&tmxr_ex, &tmxr_dep, &contty_reset,
|
||||||
NULL, &contty_attach, &contty_detach,
|
NULL, &contty_attach, &contty_detach,
|
||||||
NULL, DEV_DISABLE|DEV_DEBUG|DEV_MUX,
|
NULL, DEV_DISABLE|DEV_DEBUG|DEV_MUX,
|
||||||
0, sys_deb_tab, NULL, NULL,
|
0, contty_deb_tab, NULL, NULL,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
(void *)&contty_desc,
|
(void *)&contty_desc,
|
||||||
NULL
|
NULL
|
||||||
|
@ -235,9 +247,14 @@ uint8 bits_per_char = 7;
|
||||||
|
|
||||||
t_stat contty_attach(UNIT *uptr, CONST char *cptr)
|
t_stat contty_attach(UNIT *uptr, CONST char *cptr)
|
||||||
{
|
{
|
||||||
t_stat r = tmxr_attach(&contty_desc, uptr, cptr);
|
t_stat r;
|
||||||
TMLN *lp;
|
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) {
|
if (r != SCPE_OK) {
|
||||||
tmxr_clear_modem_control_passthru(&contty_desc);
|
tmxr_clear_modem_control_passthru(&contty_desc);
|
||||||
return r;
|
return r;
|
||||||
|
@ -281,6 +298,9 @@ void iu_txrdy_a_irq() {
|
||||||
if ((iu_state.imr & IMR_TXRA) &&
|
if ((iu_state.imr & IMR_TXRA) &&
|
||||||
(iu_console.conf & TX_EN) &&
|
(iu_console.conf & TX_EN) &&
|
||||||
(iu_console.stat & STS_TXR)) {
|
(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;
|
csr_data |= CSRUART;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,6 +309,9 @@ void iu_txrdy_b_irq() {
|
||||||
if ((iu_state.imr & IMR_TXRB) &&
|
if ((iu_state.imr & IMR_TXRB) &&
|
||||||
(iu_contty.conf & TX_EN) &&
|
(iu_contty.conf & TX_EN) &&
|
||||||
(iu_contty.stat & STS_TXR)) {
|
(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;
|
csr_data |= CSRUART;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,8 +321,6 @@ t_stat tti_reset(DEVICE *dptr)
|
||||||
memset(&iu_state, 0, sizeof(IU_STATE));
|
memset(&iu_state, 0, sizeof(IU_STATE));
|
||||||
memset(&iu_console, 0, sizeof(IU_PORT));
|
memset(&iu_console, 0, sizeof(IU_PORT));
|
||||||
|
|
||||||
tmxr_set_console_units(&tti_unit, &tto_unit);
|
|
||||||
|
|
||||||
/* Input Port logic is inverted - 0 means set */
|
/* Input Port logic is inverted - 0 means set */
|
||||||
iu_state.inprt = ~(IU_DCDA);
|
iu_state.inprt = ~(IU_DCDA);
|
||||||
|
|
||||||
|
@ -314,6 +335,7 @@ t_stat tti_reset(DEVICE *dptr)
|
||||||
t_stat contty_reset(DEVICE *dtpr)
|
t_stat contty_reset(DEVICE *dtpr)
|
||||||
{
|
{
|
||||||
char line_config[16];
|
char line_config[16];
|
||||||
|
t_stat result;
|
||||||
|
|
||||||
if (contty_ldsc == NULL) {
|
if (contty_ldsc == NULL) {
|
||||||
contty_desc.ldsc =
|
contty_desc.ldsc =
|
||||||
|
@ -321,6 +343,12 @@ t_stat contty_reset(DEVICE *dtpr)
|
||||||
(TMLN *)calloc(1, sizeof(*contty_ldsc));
|
(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_state, 0, sizeof(IU_STATE));
|
||||||
memset(&iu_contty, 0, sizeof(IU_PORT));
|
memset(&iu_contty, 0, sizeof(IU_PORT));
|
||||||
brg_reg = 0;
|
brg_reg = 0;
|
||||||
|
@ -393,7 +421,16 @@ t_stat iu_svc_tti(UNIT *uptr)
|
||||||
|
|
||||||
t_stat iu_svc_tto(UNIT *uptr)
|
t_stat iu_svc_tto(UNIT *uptr)
|
||||||
{
|
{
|
||||||
iu_txrdy_a_irq();
|
/* 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;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,8 +481,20 @@ t_stat iu_svc_contty_rcv(UNIT *uptr)
|
||||||
|
|
||||||
t_stat iu_svc_contty_xmt(UNIT *uptr)
|
t_stat iu_svc_contty_xmt(UNIT *uptr)
|
||||||
{
|
{
|
||||||
|
dma_channel *chan = &dma_state.channels[DMA_IUB_CHAN];
|
||||||
|
|
||||||
tmxr_poll_tx(&contty_desc);
|
tmxr_poll_tx(&contty_desc);
|
||||||
iu_txrdy_b_irq();
|
|
||||||
|
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;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,9 +550,14 @@ uint32 iu_read(uint32 pa, size_t size)
|
||||||
case RHRA:
|
case RHRA:
|
||||||
data = iu_console.rxbuf[iu_console.r_p];
|
data = iu_console.rxbuf[iu_console.r_p];
|
||||||
iu_console.r_p = (iu_console.r_p + 1) % IU_BUF_SIZE;
|
iu_console.r_p = (iu_console.r_p + 1) % IU_BUF_SIZE;
|
||||||
iu_console.stat &= ~(STS_RXR|STS_FFL);
|
/* If the FIFO is not empty, we must cause another interrupt
|
||||||
iu_state.istat &= ~ISTS_RAI;
|
* to continue reading */
|
||||||
csr_data &= ~CSRUART;
|
if (iu_console.r_p == iu_console.w_p) {
|
||||||
|
iu_console.stat &= ~(STS_RXR|STS_FFL);
|
||||||
|
iu_state.istat &= ~ISTS_RAI;
|
||||||
|
} else {
|
||||||
|
csr_data |= CSRUART;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IPCR:
|
case IPCR:
|
||||||
data = iu_state.ipcr;
|
data = iu_state.ipcr;
|
||||||
|
@ -557,8 +611,12 @@ uint32 iu_read(uint32 pa, size_t size)
|
||||||
break;
|
break;
|
||||||
case 17: /* Clear DMAC interrupt */
|
case 17: /* Clear DMAC interrupt */
|
||||||
data = 0;
|
data = 0;
|
||||||
|
/*
|
||||||
iu_console.drq = FALSE;
|
iu_console.drq = FALSE;
|
||||||
|
iu_console.dma = FALSE;
|
||||||
iu_contty.drq = FALSE;
|
iu_contty.drq = FALSE;
|
||||||
|
iu_contty.dma = FALSE;
|
||||||
|
*/
|
||||||
csr_data &= ~CSRDMA;
|
csr_data &= ~CSRDMA;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -591,28 +649,8 @@ void iu_write(uint32 pa, uint32 val, size_t size)
|
||||||
iu_w_cmd(PORT_A, bval);
|
iu_w_cmd(PORT_A, bval);
|
||||||
break;
|
break;
|
||||||
case THRA: /* TX/RX Buf A */
|
case THRA: /* TX/RX Buf A */
|
||||||
/* Loopback mode */
|
iu_tx(PORT_A, bval);
|
||||||
if ((iu_console.mode[1] & 0xc0) == 0x80) {
|
sim_activate_abs(&tto_unit, tto_unit.wait);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
case ACR: /* Auxiliary Control Register */
|
case ACR: /* Auxiliary Control Register */
|
||||||
iu_state.acr = bval;
|
iu_state.acr = bval;
|
||||||
|
@ -678,27 +716,8 @@ void iu_write(uint32 pa, uint32 val, size_t size)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case THRB: /* TX/RX Buf B */
|
case THRB: /* TX/RX Buf B */
|
||||||
/* Loopback mode */
|
iu_tx(PORT_B, bval);
|
||||||
if ((iu_contty.mode[1] & 0xc0) == 0x80) {
|
sim_activate_abs(contty_xmt_unit, contty_ldsc[0].txdelta);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case OPCR:
|
case OPCR:
|
||||||
iu_state.opcr = bval;
|
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;
|
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;
|
||||||
void iub_drq_handled()
|
uint8 imr_mask = (portno == PORT_A) ? IMR_RXRA : IMR_RXRB;
|
||||||
{
|
int32 c;
|
||||||
csr_data |= CSRDMA;
|
t_stat status = SCPE_OK;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (p->conf & TX_EN) {
|
if (p->conf & TX_EN) {
|
||||||
p->stat &= ~(STS_TXR|STS_TXE);
|
if ((p->mode[1] & 0xc0) == 0x80) { /* Loopback mode */
|
||||||
iu_state.istat &= ~(1 << (portno*4));
|
p->txbuf = val;
|
||||||
|
|
||||||
if (portno == PORT_A) {
|
/* This is also a Receive */
|
||||||
/* Write the character to the SIMH console */
|
if ((p->stat & STS_FFL) == 0) {
|
||||||
sim_putchar(val);
|
p->rxbuf[p->w_p] = val;
|
||||||
} else {
|
p->w_p = (p->w_p + 1) % IU_BUF_SIZE;
|
||||||
lp = &contty_ldsc[0];
|
if (p->w_p == p->r_p) {
|
||||||
tmxr_putc_ln(lp, val);
|
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_debug(EXECUTE_MSG, &tto_dev,
|
||||||
|
"[iu_tx] CONSOLE transmit %02x (%c)\n",
|
||||||
|
(uint8) c, (char) c);
|
||||||
|
status = sim_putchar(c);
|
||||||
|
} else {
|
||||||
|
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)
|
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_TXR;
|
||||||
p->stat &= ~STS_TXE;
|
p->stat &= ~STS_TXE;
|
||||||
p->drq = FALSE;
|
p->drq = FALSE;
|
||||||
|
p->dma = FALSE;
|
||||||
} else if (cmd & CMD_ETX) {
|
} else if (cmd & CMD_ETX) {
|
||||||
p->conf |= TX_EN;
|
p->conf |= TX_EN;
|
||||||
/* TXE and TXR are always set by an ENABLE */
|
/* 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;
|
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;
|
||||||
|
}
|
||||||
|
|
13
3B2/3b2_iu.h
13
3B2/3b2_iu.h
|
@ -140,6 +140,8 @@ extern DEVICE tto_dev;
|
||||||
extern DEVICE contty_dev;
|
extern DEVICE contty_dev;
|
||||||
extern DEVICE iu_timer_dev;
|
extern DEVICE iu_timer_dev;
|
||||||
|
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
|
||||||
#define IUBASE 0x49000
|
#define IUBASE 0x49000
|
||||||
#define IUSIZE 0x100
|
#define IUSIZE 0x100
|
||||||
|
|
||||||
|
@ -167,6 +169,11 @@ extern DEVICE iu_timer_dev;
|
||||||
#define IU_DTRA 0x01
|
#define IU_DTRA 0x01
|
||||||
#define IU_DTRB 0x02
|
#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) */
|
/* Default baud rate generator (9600 baud) */
|
||||||
#define BRG_DEFAULT 11
|
#define BRG_DEFAULT 11
|
||||||
|
|
||||||
|
@ -181,7 +188,8 @@ typedef struct iu_port {
|
||||||
uint8 rxbuf[IU_BUF_SIZE]; /* Receive Holding Register (3 bytes) */
|
uint8 rxbuf[IU_BUF_SIZE]; /* Receive Holding Register (3 bytes) */
|
||||||
uint8 w_p; /* Buffer Write Pointer */
|
uint8 w_p; /* Buffer Write Pointer */
|
||||||
uint8 r_p; /* Buffer Read 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;
|
} IU_PORT;
|
||||||
|
|
||||||
typedef struct iu_state {
|
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_rcv(UNIT *uptr);
|
||||||
t_stat iu_svc_contty_xmt(UNIT *uptr);
|
t_stat iu_svc_contty_xmt(UNIT *uptr);
|
||||||
t_stat iu_svc_timer(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);
|
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);
|
||||||
void iua_drq_handled();
|
void iua_drq_handled();
|
||||||
void iub_drq_handled();
|
void iub_drq_handled();
|
||||||
void iu_txrdy_a_irq();
|
void iu_txrdy_a_irq();
|
||||||
void iu_txrdy_b_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_buf(uint8 portno, uint8 val);
|
||||||
static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 val);
|
static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 val);
|
||||||
static SIM_INLINE void iu_update_rxi(uint8 c);
|
static SIM_INLINE void iu_update_rxi(uint8 c);
|
||||||
|
|
|
@ -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) {
|
if (fc && mmu_check_perm(SD_ACC(sd0), r_acc) != SCPE_OK) {
|
||||||
sim_debug(EXECUTE_MSG, &mmu_dev,
|
sim_debug(EXECUTE_MSG, &mmu_dev,
|
||||||
"[%08x] CONTIGUOUS: NO ACCESS TO MEMORY AT %08x.\n"
|
"[%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",
|
"\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);
|
MMU_FAULT(MMU_F_ACC);
|
||||||
return SCPE_NXM;
|
return SCPE_NXM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ uint32 *NVRAM = NULL;
|
||||||
|
|
||||||
extern DEVICE cpu_dev;
|
extern DEVICE cpu_dev;
|
||||||
|
|
||||||
int32 tmxr_poll = 0;
|
int32 tmxr_poll = 16667;
|
||||||
|
|
||||||
/* CSR */
|
/* CSR */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue