AltairZ80: Add support for Z80 Mode 2 interrupts.
Add support for Z80 Mode 2 interrupts to altairz80_cpu.c Also implement interrupts for the WD179x floppd controller.
This commit is contained in:
parent
c73474df8d
commit
81afea160c
3 changed files with 46 additions and 4 deletions
|
@ -241,6 +241,7 @@ UNIT cpu_unit = {
|
||||||
int32 IP_S; /* IP register (8086) */
|
int32 IP_S; /* IP register (8086) */
|
||||||
int32 FLAGS_S; /* flags register (8086) */
|
int32 FLAGS_S; /* flags register (8086) */
|
||||||
int32 SR = 0; /* switch register */
|
int32 SR = 0; /* switch register */
|
||||||
|
int32 vectorInterrupt = 0; /* Vector Interrupt bitfield */
|
||||||
static int32 bankSelect = 0; /* determines selected memory bank */
|
static int32 bankSelect = 0; /* determines selected memory bank */
|
||||||
static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */
|
static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */
|
||||||
static uint32 common_low = 0; /* Common area is in low memory */
|
static uint32 common_low = 0; /* Common area is in low memory */
|
||||||
|
@ -2078,7 +2079,6 @@ void setClockFrequency(const uint32 Value) {
|
||||||
clockHasChanged = TRUE;
|
clockHasChanged = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static t_stat sim_instr_mmu (void) {
|
static t_stat sim_instr_mmu (void) {
|
||||||
extern int32 timerInterrupt;
|
extern int32 timerInterrupt;
|
||||||
extern int32 timerInterruptHandler;
|
extern int32 timerInterruptHandler;
|
||||||
|
@ -2135,7 +2135,7 @@ static t_stat sim_instr_mmu (void) {
|
||||||
SP = SP_S;
|
SP = SP_S;
|
||||||
IX = IX_S;
|
IX = IX_S;
|
||||||
IY = IY_S;
|
IY = IY_S;
|
||||||
specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ;
|
specialProcessing = clockFrequency | timerInterrupt | vectorInterrupt | keyboardInterrupt | sim_brk_summ;
|
||||||
tStates = 0;
|
tStates = 0;
|
||||||
if (rtc_avail) {
|
if (rtc_avail) {
|
||||||
startTime = sim_os_msec();
|
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 */
|
} else /* make sure that sim_os_msec() is not called later */
|
||||||
clockFrequency = startTime = tStatesInSlice = 0;
|
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 */
|
if (specialProcessing) { /* quick check for special processing */
|
||||||
|
@ -2186,6 +2186,35 @@ static t_stat sim_instr_mmu (void) {
|
||||||
PC = timerInterruptHandler & ADDRMASK;
|
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)) {
|
if (keyboardInterrupt && (IFF_S & 1)) {
|
||||||
keyboardInterrupt = FALSE;
|
keyboardInterrupt = FALSE;
|
||||||
specialProcessing = clockFrequency | sim_brk_summ;
|
specialProcessing = clockFrequency | sim_brk_summ;
|
||||||
|
|
|
@ -100,6 +100,8 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PNP_INFO pnp; /* Plug-n-Play Information */
|
PNP_INFO pnp; /* Plug-n-Play Information */
|
||||||
uint16 fdctype; /* Default is 1793 */
|
uint16 fdctype; /* Default is 1793 */
|
||||||
|
uint8 intenable; /* Interrupt Enable */
|
||||||
|
uint8 intvector; /* Interrupt Vector */
|
||||||
uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */
|
uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */
|
||||||
uint8 hld; /* WD179X Head Load Output */
|
uint8 hld; /* WD179X Head Load Output */
|
||||||
uint8 drq; /* WD179X DMA Request Output */
|
uint8 drq; /* WD179X DMA Request Output */
|
||||||
|
@ -131,6 +133,8 @@ typedef struct {
|
||||||
WD179X_DRIVE_INFO drive[WD179X_MAX_DRIVES];
|
WD179X_DRIVE_INFO drive[WD179X_MAX_DRIVES];
|
||||||
} WD179X_INFO;
|
} WD179X_INFO;
|
||||||
|
|
||||||
|
extern int32 vectorInterrupt; /* FDC interrupt pending */
|
||||||
|
|
||||||
static SECTOR_FORMAT sdata;
|
static SECTOR_FORMAT sdata;
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern t_stat set_iobase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
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[] = {
|
static REG wd179x_reg[] = {
|
||||||
{ DRDATAD(FDCTYPE, wd179x_info_data.fdctype, 16, "Controller type"), },
|
{ 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(INTRQ, wd179x_info_data.intrq, 1, "Interrupt Request"), },
|
||||||
{ FLDATAD(HLD, wd179x_info_data.hld, 1, "Head Load"), },
|
{ FLDATAD(HLD, wd179x_info_data.hld, 1, "Head Load"), },
|
||||||
{ FLDATAD(DRQ, wd179x_info_data.drq, 1, "DMA Request"), },
|
{ 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
|
sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT
|
||||||
" RD STATUS = 0x%02x, CMDTYPE=%x\n", PCX, cData, wd179x_info->cmdtype);
|
" RD STATUS = 0x%02x, CMDTYPE=%x\n", PCX, cData, wd179x_info->cmdtype);
|
||||||
wd179x_info->intrq = 0;
|
wd179x_info->intrq = 0;
|
||||||
|
if (wd179x_info->intenable) vectorInterrupt &= ~(1 << wd179x_info->intvector);
|
||||||
break;
|
break;
|
||||||
case WD179X_TRACK:
|
case WD179X_TRACK:
|
||||||
cData = pDrive->track;
|
cData = pDrive->track;
|
||||||
|
@ -946,6 +953,7 @@ static uint8 Do1793Command(uint8 cCommand)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wd179x_info->intrq = 1;
|
wd179x_info->intrq = 1;
|
||||||
|
if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector);
|
||||||
}
|
}
|
||||||
wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */
|
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->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */
|
||||||
wd179x_info->intrq = 1;
|
wd179x_info->intrq = 1;
|
||||||
|
if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector);
|
||||||
wd179x_info->drq = 1;
|
wd179x_info->drq = 1;
|
||||||
break;
|
break;
|
||||||
/* Type II Commands */
|
/* Type II Commands */
|
||||||
|
@ -1006,7 +1015,6 @@ static uint8 Do1793Command(uint8 cCommand)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1043,6 +1051,7 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData)
|
||||||
wd179x_info->fdc_write_track = FALSE;
|
wd179x_info->fdc_write_track = FALSE;
|
||||||
wd179x_info->fdc_datacount = 0;
|
wd179x_info->fdc_datacount = 0;
|
||||||
wd179x_info->fdc_dataindex = 0;
|
wd179x_info->fdc_dataindex = 0;
|
||||||
|
if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector);
|
||||||
|
|
||||||
Do1793Command(cData);
|
Do1793Command(cData);
|
||||||
break;
|
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->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */
|
||||||
wd179x_info->drq = 0;
|
wd179x_info->drq = 0;
|
||||||
wd179x_info->intrq = 1;
|
wd179x_info->intrq = 1;
|
||||||
|
if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector);
|
||||||
|
|
||||||
sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT
|
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);
|
" 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->fdc_status &= ~(WD179X_STAT_BUSY | WD179X_STAT_LOST_DATA); /* Clear BUSY, LOST_DATA */
|
||||||
wd179x_info->drq = 0;
|
wd179x_info->drq = 0;
|
||||||
wd179x_info->intrq = 1;
|
wd179x_info->intrq = 1;
|
||||||
|
if (wd179x_info->intenable) vectorInterrupt |= (1 << wd179x_info->intvector);
|
||||||
|
|
||||||
/* Recalculate disk size */
|
/* Recalculate disk size */
|
||||||
pDrive->uptr->capac = sim_fsize(pDrive->uptr->fileref);
|
pDrive->uptr->capac = sim_fsize(pDrive->uptr->fileref);
|
||||||
|
|
|
@ -55,6 +55,8 @@ extern uint8 wd179x_get_nheads(void);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PNP_INFO pnp; /* Plug-n-Play Information */
|
PNP_INFO pnp; /* Plug-n-Play Information */
|
||||||
uint16 fdctype; /* Default is 1793 */
|
uint16 fdctype; /* Default is 1793 */
|
||||||
|
uint8 intenable; /* Interrupt Enable */
|
||||||
|
uint8 intvector; /* Interrupt Vector */
|
||||||
uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */
|
uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */
|
||||||
uint8 hld; /* WD179X Head Load Output */
|
uint8 hld; /* WD179X Head Load Output */
|
||||||
uint8 drq; /* WD179X DMA Request Output */
|
uint8 drq; /* WD179X DMA Request Output */
|
||||||
|
|
Loading…
Add table
Reference in a new issue