diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c index 8ab9d339..34a96a2d 100644 --- a/AltairZ80/altairz80_cpu.c +++ b/AltairZ80/altairz80_cpu.c @@ -241,6 +241,7 @@ UNIT cpu_unit = { int32 IP_S; /* IP register (8086) */ int32 FLAGS_S; /* flags register (8086) */ int32 SR = 0; /* switch register */ + int32 vectorInterrupt = 0; /* Vector Interrupt bitfield */ static int32 bankSelect = 0; /* determines selected memory bank */ static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ static uint32 common_low = 0; /* Common area is in low memory */ @@ -2078,7 +2079,6 @@ void setClockFrequency(const uint32 Value) { clockHasChanged = TRUE; } - static t_stat sim_instr_mmu (void) { extern int32 timerInterrupt; extern int32 timerInterruptHandler; @@ -2135,7 +2135,7 @@ static t_stat sim_instr_mmu (void) { SP = SP_S; IX = IX_S; IY = IY_S; - specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; + specialProcessing = clockFrequency | timerInterrupt | vectorInterrupt | keyboardInterrupt | sim_brk_summ; tStates = 0; if (rtc_avail) { startTime = sim_os_msec(); @@ -2157,7 +2157,7 @@ static t_stat sim_instr_mmu (void) { } else /* make sure that sim_os_msec() is not called later */ clockFrequency = startTime = tStatesInSlice = 0; } - specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; + specialProcessing = clockFrequency | timerInterrupt | vectorInterrupt | keyboardInterrupt | sim_brk_summ; } if (specialProcessing) { /* quick check for special processing */ @@ -2186,6 +2186,35 @@ static t_stat sim_instr_mmu (void) { PC = timerInterruptHandler & ADDRMASK; } + if ((IM_S == 2) && vectorInterrupt && (IFF_S & 1)) { + int32 vectable = (IR_S & 0xFF00); + int32 vector; + uint32 tempVectorInterrupt = vectorInterrupt; + uint8 intVector = 0; + + while ((tempVectorInterrupt & 1) == 0) { + tempVectorInterrupt >>= 1; + intVector++; + } + + vectorInterrupt &= ~(1 << intVector); + specialProcessing = clockFrequency | sim_brk_summ; + IFF_S = 0; /* disable interrupts */ + CHECK_BREAK_TWO_BYTES_EXTENDED(SP - 2, SP - 1, (vectorInterrupt |= (1 << intVector), IFF_S |= 1)); + if ((GetBYTE(PC) == HALTINSTRUCTION) && ((cpu_unit.flags & UNIT_CPU_STOPONHALT) == 0)) { + PUSH(PC + 1); + PCQ_ENTRY(PC); + } + else { + PUSH(PC); + PCQ_ENTRY(PC - 1); + } + + vector = GetBYTE(vectable + (intVector * 2)+1) << 8; + vector |= GetBYTE(vectable + (intVector * 2)); + PC = vector & ADDRMASK; + } + if (keyboardInterrupt && (IFF_S & 1)) { keyboardInterrupt = FALSE; specialProcessing = clockFrequency | sim_brk_summ; diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c index 82563b28..0b989134 100644 --- a/AltairZ80/wd179x.c +++ b/AltairZ80/wd179x.c @@ -100,6 +100,8 @@ typedef struct { typedef struct { PNP_INFO pnp; /* Plug-n-Play Information */ uint16 fdctype; /* Default is 1793 */ + uint8 intenable; /* Interrupt Enable */ + uint8 intvector; /* Interrupt Vector */ uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */ uint8 hld; /* WD179X Head Load Output */ uint8 drq; /* WD179X DMA Request Output */ @@ -131,6 +133,8 @@ typedef struct { WD179X_DRIVE_INFO drive[WD179X_MAX_DRIVES]; } WD179X_INFO; +extern int32 vectorInterrupt; /* FDC interrupt pending */ + static SECTOR_FORMAT sdata; extern uint32 PCX; extern t_stat set_iobase(UNIT *uptr, int32 val, CONST char *cptr, void *desc); @@ -197,6 +201,8 @@ static UNIT wd179x_unit[] = { static REG wd179x_reg[] = { { DRDATAD(FDCTYPE, wd179x_info_data.fdctype, 16, "Controller type"), }, + { FLDATAD(INTENABLE, wd179x_info_data.intenable, 1, "FDC Interrupt Enable"), }, + { DRDATAD(INTVECTOR, wd179x_info_data.intvector, 8, "FDC Interrupt Vector"), }, { FLDATAD(INTRQ, wd179x_info_data.intrq, 1, "Interrupt Request"), }, { FLDATAD(HLD, wd179x_info_data.hld, 1, "Head Load"), }, { FLDATAD(DRQ, wd179x_info_data.drq, 1, "DMA Request"), }, @@ -542,6 +548,7 @@ uint8 WD179X_Read(const uint32 Addr) sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT " RD STATUS = 0x%02x, CMDTYPE=%x\n", PCX, cData, wd179x_info->cmdtype); wd179x_info->intrq = 0; + if (wd179x_info->intenable) vectorInterrupt &= ~(1 << wd179x_info->intvector); break; case WD179X_TRACK: cData = pDrive->track; @@ -946,6 +953,7 @@ static uint8 Do1793Command(uint8 cCommand) } } else { wd179x_info->intrq = 1; + if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector); } wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */ } @@ -989,6 +997,7 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */ wd179x_info->intrq = 1; + if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector); wd179x_info->drq = 1; break; /* Type II Commands */ @@ -1006,7 +1015,6 @@ static uint8 Do1793Command(uint8 cCommand) break; } - return result; } @@ -1043,6 +1051,7 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->fdc_write_track = FALSE; wd179x_info->fdc_datacount = 0; wd179x_info->fdc_dataindex = 0; + if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector); Do1793Command(cData); break; @@ -1068,6 +1077,7 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */ wd179x_info->drq = 0; wd179x_info->intrq = 1; + if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector); sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Writing sector, T:%2d/S:%d/N:%2d, Len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, 128 << wd179x_info->fdc_sec_len); @@ -1188,6 +1198,7 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY | WD179X_STAT_LOST_DATA); /* Clear BUSY, LOST_DATA */ wd179x_info->drq = 0; wd179x_info->intrq = 1; + if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector); /* Recalculate disk size */ pDrive->uptr->capac = sim_fsize(pDrive->uptr->fileref); diff --git a/AltairZ80/wd179x.h b/AltairZ80/wd179x.h index 17f88e0d..110ac643 100644 --- a/AltairZ80/wd179x.h +++ b/AltairZ80/wd179x.h @@ -55,6 +55,8 @@ extern uint8 wd179x_get_nheads(void); typedef struct { PNP_INFO pnp; /* Plug-n-Play Information */ uint16 fdctype; /* Default is 1793 */ + uint8 intenable; /* Interrupt Enable */ + uint8 intvector; /* Interrupt Vector */ uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */ uint8 hld; /* WD179X Head Load Output */ uint8 drq; /* WD179X DMA Request Output */