diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c index fe52030c..9afd4ce9 100644 --- a/AltairZ80/altairz80_cpu.c +++ b/AltairZ80/altairz80_cpu.c @@ -547,6 +547,10 @@ static MTAB cpu_mod[] = { NULL, "Sets CPU switcher port for 8080 / Z80 / 8086" }, { UNIT_CPU_SWITCHER, 0, "NOSWITCHER", "NOSWITCHER", &cpu_reset_switcher, &cpu_show_switcher, NULL, "Resets CPU switcher port for 8080 / Z80 / 8086" }, + { UNIT_CPU_PO, UNIT_CPU_PO, "PO", "PO", NULL, NULL, + NULL, "Enable programmed output messages" }, + { UNIT_CPU_PO, 0, "NOPO", "NOPO", NULL, NULL, + NULL, "Disable programmed output messages" }, { MTAB_XTD | MTAB_VDV, 0, NULL, "AZ80", &cpu_set_ramtype, NULL, NULL, "Sets the RAM type to AltairZ80 RAM for 8080 / Z80 / 8086" }, { MTAB_XTD | MTAB_VDV, 1, NULL, "HRAM", &cpu_set_ramtype, @@ -2352,9 +2356,6 @@ static t_stat sim_instr_mmu (void) { } PCX = PC; - INCR(1); - - op = RAM_PP(PC); /* 8080 INT/Z80 Interrupt Mode 0 Instruction to execute (ex. RST0-7) is on the data bus @@ -2377,6 +2378,9 @@ static t_stat sim_instr_mmu (void) { sim_debug(INT_MSG, &cpu_dev, ADDRESS_FORMAT " INT(mode=0 vectorInterrupt=%X intVector=%d op=%02X)\n", PCX, vectorInterrupt, intVector, op); + } else { + INCR(1); + op = RAM_PP(PC); } switch(op) { diff --git a/AltairZ80/altairz80_defs.h b/AltairZ80/altairz80_defs.h index 087e58a5..1667150a 100644 --- a/AltairZ80/altairz80_defs.h +++ b/AltairZ80/altairz80_defs.h @@ -84,6 +84,8 @@ typedef enum { #define UNIT_CPU_STOPONHALT (1 << UNIT_CPU_V_STOPONHALT) #define UNIT_CPU_V_SWITCHER (UNIT_V_UF+6) /* switcher 8086 <--> 8080/Z80 enabled */ #define UNIT_CPU_SWITCHER (1 << UNIT_CPU_V_SWITCHER) +#define UNIT_CPU_V_PO (UNIT_V_UF+7) /* enable programmed output messages */ +#define UNIT_CPU_PO (1 << UNIT_CPU_V_PO) #define ADDRESS_FORMAT "[0x%08x]" diff --git a/AltairZ80/altairz80_sio.c b/AltairZ80/altairz80_sio.c index 95ef5fe1..8b81751e 100644 --- a/AltairZ80/altairz80_sio.c +++ b/AltairZ80/altairz80_sio.c @@ -1168,7 +1168,17 @@ int32 nulldev(const int32 port, const int32 io, const int32 data) { } int32 sr_dev(const int32 port, const int32 io, const int32 data) { - return io == 0 ? SR : 0; + if (io == 0) { + return SR; + } + + /* Simulate IMSAI functionality of displaying the A */ + /* register on the Programmed Output front panel LEDs */ + if (cpu_unit.flags & UNIT_CPU_PO) { + sim_printf("PO: %02X\n", data & 0xff); + } + + return 0; } static int32 toBCD(const int32 x) { diff --git a/AltairZ80/s100_2sio.c b/AltairZ80/s100_2sio.c index 7b7561de..b63d7514 100644 --- a/AltairZ80/s100_2sio.c +++ b/AltairZ80/s100_2sio.c @@ -133,8 +133,9 @@ /* Debug flags */ #define STATUS_MSG (1 << 0) -#define ERROR_MSG (1 << 1) -#define VERBOSE_MSG (1 << 2) +#define IRQ_MSG (1 << 1) +#define ERROR_MSG (1 << 2) +#define VERBOSE_MSG (1 << 3) /* IO Read/Write */ #define IO_RD 0x00 /* IO Read */ @@ -143,18 +144,19 @@ typedef struct { PNP_INFO pnp; /* Must be first */ int32 port; /* Port 0 or 1 */ - int32 conn; /* Connected Status */ + t_bool conn; /* Connected Status */ TMLN *tmln; /* TMLN pointer */ TMXR *tmxr; /* TMXR pointer */ int32 baud; /* Baud rate */ int32 rts; /* RTS Status */ int32 rxb; /* Receive Buffer */ int32 txb; /* Transmit Buffer */ - int32 txp; /* Transmit Pending */ + t_bool txp; /* Transmit Pending */ int32 stb; /* Status Buffer */ int32 ctb; /* Control Buffer */ - int32 rie; /* Rx Int Enable */ - int32 tie; /* Tx Int Enable */ + t_bool rie; /* Rx Int Enable */ + t_bool tie; /* Tx Int Enable */ + t_bool dcdl; /* DCD latch */ uint8 intenable; /* Interrupt Enable */ uint8 intvector; /* Interrupt Vector */ uint8 databus; /* Data Bus Value */ @@ -183,6 +185,7 @@ static int32 m2sio1_io(int32 addr, int32 io, int32 data); static int32 m2sio_io(DEVICE *dptr, int32 addr, int32 io, int32 data); static int32 m2sio_stat(DEVICE *dptr, int32 io, int32 data); static int32 m2sio_data(DEVICE *dptr, int32 io, int32 data); +static void m2sio_int(UNIT *uptr); extern uint32 vectorInterrupt; /* Vector Interrupt bits */ extern uint8 dataBus[MAX_INT_VECTORS]; /* Data bus value */ @@ -190,6 +193,7 @@ extern uint8 dataBus[MAX_INT_VECTORS]; /* Data bus value */ /* Debug Flags */ static DEBTAB m2sio_dt[] = { { "STATUS", STATUS_MSG, "Status messages" }, + { "IRQ", IRQ_MSG, "Interrupt messages" }, { "ERROR", ERROR_MSG, "Error messages" }, { "VERBOSE", VERBOSE_MSG, "Verbose messages" }, { NULL, 0 } @@ -272,7 +276,7 @@ static REG m2sio0_reg[] = { { HRDATAD (M2CTL0, m2sio0_ctx.ctb, 8, "2SIO port 0 control register"), }, { HRDATAD (M2RXD0, m2sio0_ctx.rxb, 8, "2SIO port 0 rx data buffer"), }, { HRDATAD (M2TXD0, m2sio0_ctx.txb, 8, "2SIO port 0 tx data buffer"), }, - { HRDATAD (M2TXP0, m2sio0_ctx.txp, 8, "2SIO port 0 tx data pending"), }, + { FLDATAD (M2TXP0, m2sio0_ctx.txp, 0, "2SIO port 0 tx data pending"), }, { FLDATAD (M2CON0, m2sio0_ctx.conn, 0, "2SIO port 0 connection status"), }, { FLDATAD (M2RIE0, m2sio0_ctx.rie, 0, "2SIO port 0 receive interrupt enable"), }, { FLDATAD (M2TIE0, m2sio0_ctx.tie, 0, "2SIO port 0 transmit interrupt enable"), }, @@ -282,6 +286,7 @@ static REG m2sio0_reg[] = { { FLDATAD (M2DCD0, m2sio0_ctx.stb, 2, "2SIO port 0 DCD status (active low)"), }, { FLDATAD (M2CTS0, m2sio0_ctx.stb, 3, "2SIO port 0 CTS status (active low)"), }, { FLDATAD (M2OVRN0, m2sio0_ctx.stb, 4, "2SIO port 0 OVRN status"), }, + { FLDATAD (DCDL0, m2sio0_ctx.dcdl, 0, "2SIO port 0 DCD latch"), }, { DRDATAD (M2WAIT0, m2sio0_unit[0].wait, 32, "2SIO port 0 wait cycles"), }, { FLDATAD (M2INTEN0, m2sio0_ctx.intenable, 1, "2SIO port 0 Global vectored interrupt enable"), }, { DRDATAD (M2VEC0, m2sio0_ctx.intvector, 8, "2SIO port 0 interrupt vector"), }, @@ -293,7 +298,7 @@ static REG m2sio1_reg[] = { { HRDATAD (M2CTL1, m2sio1_ctx.ctb, 8, "2SIO port 1 control register"), }, { HRDATAD (M2RXD1, m2sio1_ctx.rxb, 8, "2SIO port 1 rx data buffer"), }, { HRDATAD (M2TXD1, m2sio1_ctx.txb, 8, "2SIO port 1 tx data buffer"), }, - { HRDATAD (M2TXP1, m2sio1_ctx.txp, 8, "2SIO port 1 tx data pending"), }, + { FLDATAD (M2TXP1, m2sio1_ctx.txp, 0, "2SIO port 1 tx data pending"), }, { FLDATAD (M2CON1, m2sio1_ctx.conn, 0, "2SIO port 1 connection status"), }, { FLDATAD (M2RIE1, m2sio1_ctx.rie, 0, "2SIO port 1 receive interrupt enable"), }, { FLDATAD (M2TIE1, m2sio1_ctx.tie, 0, "2SIO port 1 transmit interrupt enable"), }, @@ -303,6 +308,7 @@ static REG m2sio1_reg[] = { { FLDATAD (M2DCD1, m2sio1_ctx.stb, 2, "2SIO port 1 DCD status (active low)"), }, { FLDATAD (M2CTS1, m2sio1_ctx.stb, 3, "2SIO port 1 CTS status (active low)"), }, { FLDATAD (M2OVRN1, m2sio1_ctx.stb, 4, "2SIO port 1 OVRN status"), }, + { FLDATAD (DCDL1, m2sio1_ctx.dcdl, 0, "2SIO port 1 DCD latch"), }, { DRDATAD (M2WAIT1, m2sio1_unit[0].wait, 32, "2SIO port 1 wait cycles"), }, { FLDATAD (M2INTEN1, m2sio1_ctx.intenable, 1, "2SIO port 1 Global vectored interrupt enable"), }, { DRDATAD (M2VEC1, m2sio1_ctx.intvector, 8, "2SIO port 1 interrupt vector"), }, @@ -405,8 +411,9 @@ static t_stat m2sio_reset(DEVICE *dptr, int32 (*routine)(const int32, const int3 tmxr_set_modem_control_passthru(xptr->tmxr); /* Reset status registers */ - xptr->stb = 0; - xptr->txp = 0; + xptr->stb = M2SIO_CTS | M2SIO_DCD; + xptr->txp = FALSE; + xptr->dcdl = FALSE; if (dptr->units[0].flags & UNIT_ATT) { m2sio_config_rts(dptr, 1); /* disable RTS */ } @@ -435,7 +442,7 @@ static t_stat m2sio_svc(UNIT *uptr) if (uptr->flags & UNIT_ATT) { if (tmxr_poll_conn(xptr->tmxr) >= 0) { /* poll connection */ - xptr->conn = 1; /* set connected */ + xptr->conn = TRUE; /* set connected */ sim_debug(STATUS_MSG, uptr->dptr, "new connection.\n"); } @@ -450,10 +457,19 @@ static t_stat m2sio_svc(UNIT *uptr) if ((stb ^ xptr->stb) & M2SIO_CTS) { sim_debug(STATUS_MSG, uptr->dptr, "CTS state changed to %s.\n", (xptr->stb & M2SIO_CTS) ? "LOW" : "HIGH"); } - xptr->stb &= ~M2SIO_DCD; - xptr->stb |= ((s & TMXR_MDM_DCD) || (uptr->flags & UNIT_M2SIO_DCD)) ? 0 : M2SIO_DCD; /* Active Low */ - if ((stb ^ xptr->stb) & M2SIO_DCD) { - sim_debug(STATUS_MSG, uptr->dptr, "DCD state changed to %s.\n", (xptr->stb & M2SIO_DCD) ? "LOW" : "HIGH"); + + if (!xptr->dcdl) { + xptr->stb &= ~M2SIO_DCD; + xptr->stb |= ((s & TMXR_MDM_DCD) || (uptr->flags & UNIT_M2SIO_DCD)) ? 0 : M2SIO_DCD; /* Active Low */ + if ((stb ^ xptr->stb) & M2SIO_DCD) { + if ((xptr->stb & M2SIO_DCD) == M2SIO_DCD) { + xptr->dcdl = TRUE; + if (xptr->rie) { + m2sio_int(uptr); + } + } + sim_debug(STATUS_MSG, uptr->dptr, "DCD state changed to %s.\n", (xptr->stb & M2SIO_DCD) ? "LOW" : "HIGH"); + } } /* Enable receiver if DCD is active low */ @@ -465,19 +481,25 @@ static t_stat m2sio_svc(UNIT *uptr) if (uptr->flags & UNIT_ATT) { if (!(xptr->stb & M2SIO_CTS)) { /* Active low */ r = tmxr_putc_ln(xptr->tmln, xptr->txb); - xptr->txp = 0; /* Reset TX Pending */ + xptr->txp = FALSE; /* Reset TX Pending */ } else { r = SCPE_STALL; } } else { r = sim_putchar(xptr->txb); - xptr->txp = 0; /* Reset TX Pending */ + xptr->txp = FALSE; /* Reset TX Pending */ } if (r == SCPE_LOST) { - xptr->conn = 0; /* Connection was lost */ + xptr->conn = FALSE; /* Connection was lost */ sim_debug(STATUS_MSG, uptr->dptr, "lost connection.\n"); } + + /* If TX buffer now empty, send interrupt */ + if ((!xptr->txp) && (xptr->tie)) { + m2sio_int(uptr); + } + } /* Update TDRE if not set and no character pending */ @@ -506,9 +528,8 @@ static t_stat m2sio_svc(UNIT *uptr) xptr->rxb = c & 0xff; xptr->stb |= M2SIO_RDRF; xptr->stb &= ~(M2SIO_FE | M2SIO_OVRN | M2SIO_PE); - if ((xptr->rie) && (xptr->intenable)) { - vectorInterrupt |= (1 << xptr->intvector); - dataBus[xptr->intvector] = xptr->databus; + if (xptr->rie) { + m2sio_int(uptr); } } } @@ -769,15 +790,16 @@ static int32 m2sio_stat(DEVICE *dptr, int32 io, int32 data) if ((data & M2SIO_RESET) == M2SIO_RESET) { sim_debug(STATUS_MSG, dptr, "MC6850 master reset.\n"); xptr->stb &= (M2SIO_CTS | M2SIO_DCD); /* Reset status register */ - xptr->rxb = 0; - xptr->txp = 0; - xptr->tie = 1; - xptr->rie = 1; + xptr->rxb = 0x00; + xptr->txp = FALSE; + xptr->tie = FALSE; + xptr->rie = FALSE; + xptr->dcdl = FALSE; m2sio_config_rts(dptr, 1); /* disable RTS */ } else { /* Interrupt Enable */ - xptr->rie = (data & M2SIO_RIE) == M2SIO_RIE; /* Receive enable */ - xptr->tie = (data & M2SIO_RTSMSK) == M2SIO_RTSLTIE; /* Transmit enable */ + xptr->rie = (data & M2SIO_RIE) == M2SIO_RIE; /* Receive interrupt enable */ + xptr->tie = (data & M2SIO_RTSMSK) == M2SIO_RTSLTIE; /* Transmit interrupt enable */ switch (data & M2SIO_RTSMSK) { case M2SIO_RTSLTIE: case M2SIO_RTSLTID: @@ -812,15 +834,30 @@ static int32 m2sio_data(DEVICE *dptr, int32 io, int32 data) if (io == IO_RD) { r = xptr->rxb; - xptr->stb &= ~(M2SIO_RDRF | M2SIO_FE | M2SIO_OVRN | M2SIO_PE); + xptr->stb &= ~(M2SIO_RDRF | M2SIO_FE | M2SIO_OVRN | M2SIO_PE | M2SIO_IRQ); + xptr->dcdl = FALSE; } else { xptr->txb = data; - xptr->stb &= ~M2SIO_TDRE; - xptr->txp = 1; + xptr->stb &= ~(M2SIO_TDRE | M2SIO_IRQ); + xptr->txp = TRUE; r = 0x00; } return r; } +static void m2sio_int(UNIT *uptr) +{ + M2SIO_CTX *xptr; + + xptr = (M2SIO_CTX *) uptr->dptr->ctxt; + + if (xptr->intenable) { + vectorInterrupt |= (1 << xptr->intvector); + dataBus[xptr->intvector] = xptr->databus; + xptr->stb |= M2SIO_IRQ; + + sim_debug(IRQ_MSG, uptr->dptr, "%s: IRQ Vector=%d Status=%02X\n", sim_uname(uptr), xptr->intvector, xptr->stb); + } +} diff --git a/AltairZ80/s100_pmmi.c b/AltairZ80/s100_pmmi.c index 99bf9d06..78bffcdc 100644 --- a/AltairZ80/s100_pmmi.c +++ b/AltairZ80/s100_pmmi.c @@ -297,7 +297,7 @@ static t_stat pmmi_reset(DEVICE *dptr) static t_stat pmmi_svc(UNIT *uptr) { int32 c,s,ireg2; - t_stat r; + t_stat r = SCPE_OK; uint32 ms; /* Check for new incoming connection */ @@ -358,12 +358,14 @@ static t_stat pmmi_svc(UNIT *uptr) /* TX data */ if (pmmi_ctx.txp) { if (uptr->flags & UNIT_ATT) { - if (!(pmmi_ctx.ireg2 & PMMI_CTS)) { /* Active low */ + /* + ** If CTS active low, send byte + ** otherwise, toss character + */ + if (!(pmmi_ctx.ireg2 & PMMI_CTS)) { r = tmxr_putc_ln(pmmi_ctx.tmln, pmmi_ctx.oreg1); - pmmi_ctx.txp = 0; /* Reset TX Pending */ - } else { - r = SCPE_STALL; } + pmmi_ctx.txp = 0; /* Reset TX Pending */ } else { r = sim_putchar(pmmi_ctx.oreg1); pmmi_ctx.txp = 0; /* Reset TX Pending */ @@ -558,27 +560,12 @@ static t_stat pmmi_config_line(UNIT *uptr) sprintf(config, "%d-%c%c%c", pmmi_ctx.baud, b,p,s); + sim_debug(STATUS_MSG, uptr->dptr, "setting port configuration to '%s'.\n", config); + r = tmxr_set_config_line(pmmi_ctx.tmln, config); - sim_debug(STATUS_MSG, uptr->dptr, "port configuration set to '%s'.\n", config); - - /* - ** AltairZ80 and TMXR refuse to want to play together - ** nicely when the CLOCK register is set to anything - ** other than 0. - ** - ** This work-around is for those of us that may wish - ** to run irrelevant, old software, that use TMXR and - ** rely on some semblance of timing (Remote CP/M, BYE, - ** RBBS, PCGET/PUT, Xmodem, MEX, Modem7, or most - ** other communications software), on contemporary - ** hardware. - ** - ** Serial ports are self-limiting and sockets will run - ** at the clocked CPU speed. - */ - pmmi_ctx.tmln->txbps = 0; /* Get TMXR's rate-limiting out of our way */ - pmmi_ctx.tmln->rxbps = 0; /* Get TMXR's rate-limiting out of our way */ + pmmi_ctx.tmln->txbps = 0; /* Get TMXR out of our way */ + pmmi_ctx.tmln->rxbps = 0; /* Get TMXR out of our way */ return r; } @@ -702,15 +689,15 @@ static int32 pmmi_reg3(int32 io, int32 data) /* Set/Clear DTR */ s = TMXR_MDM_DTR | ((pmmi_dev.units[0].flags & UNIT_PMMI_RTS) ? TMXR_MDM_RTS : 0); if (data & PMMI_DTR) { + sim_debug(STATUS_MSG, &pmmi_dev, "setting DTR HIGH.\n"); tmxr_set_get_modem_bits(pmmi_ctx.tmln, s, 0, NULL); if (pmmi_ctx.oreg0 & PMMI_SH) { pmmi_ctx.ireg2 &= ~PMMI_AP; /* Answer Phone Bit (active low) */ } - sim_debug(STATUS_MSG, &pmmi_dev, "set DTR HIGH.\n"); } else { + sim_debug(STATUS_MSG, &pmmi_dev, "setting DTR LOW.\n"); tmxr_set_get_modem_bits(pmmi_ctx.tmln, 0, s, NULL); pmmi_ctx.ireg2 |= PMMI_AP; - sim_debug(STATUS_MSG, &pmmi_dev, "set DTR LOW.\n"); } } return 0x00;