/************************************************************************* * * * $Id: s100_ss1.c 1997 2008-07-18 05:29:52Z hharte $ * * * * Copyright (c) 2007-2008 Howard M. Harte. * * http://www.hartetec.com * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to * * the following conditions: * * * * The above copyright notice and this permission notice shall be * * included in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY * * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name of Howard M. Harte shall * * not be used in advertising or otherwise to promote the sale, use or * * other dealings in this Software without prior written authorization * * Howard M. Harte. * * * * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * * * * Module Description: * * CompuPro System Support 1 module for SIMH. * * Note this does not include the Boot ROM on the System Support 1 Card * * * * Environment: * * User mode only * * * *************************************************************************/ /*#define DBG_MSG */ #include "altairz80_defs.h" #if defined (_WIN32) #include #endif #include #ifdef DBG_MSG #define DBG_PRINT(args) sim_printf args #else #define DBG_PRINT(args) #endif /* Debug flags */ #define ERROR_MSG (1 << 0) #define TRACE_MSG (1 << 1) #define PIC_MSG (1 << 2) #define TC_MSG (1 << 3) #define RTC_MSG (1 << 4) #define MATH_MSG (1 << 5) #define UART_MSG (1 << 6) #define IRQ_MSG (1 << 7) #define SS1_MAX_TIMERS 3 typedef struct { PNP_INFO pnp; /* Plug and Play */ } SS1_INFO; static SS1_INFO ss1_info_data = { { 0x0, 0, 0x50, 16 } }; extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, int32 (*routine)(const int32, const int32, const int32), uint8 unmap); extern uint32 PCX; static t_stat ss1_reset(DEVICE *ss1_dev); static t_stat ss1_svc (UNIT *uptr); static uint8 SS1_Read(const uint32 Addr); static uint8 SS1_Write(const uint32 Addr, uint8 cData); static int32 ss1dev(const int32 port, const int32 io, const int32 data); void raise_ss1_interrupt(uint8 isr_index); /* SS1 Interrupt Controller notes: * * Msster 8259: * IRQ0 = VI0 * IRQ1 = VI1 - DISK3 Interrupt * IRQ2 = VI2 - IF3 Rx Interrupt * IRQ3 = VI3 - IF3 Tx Interrupt * IRQ4 = VI4 - DISK1A * IRQ5 = VI5 - ? * IRQ6 = VI6 * * * Slave 8259: * IRQ0 = VI7 0x48 * IRQ1 = Timer0 0x49 * IRQ2 = Timer1 0x4A * IRQ3 = Timer2 0x4B * IRQ4 = 9511 SVRQ 0x4C * IRQ5 = 9511 END 0x4D * IRQ6 = 2651 TxRDY 0x4E * IRQ7 = 2651 RxRDY 0x4F */ #define MASTER_PIC 0 #define SLAVE_PIC 1 #define VI0_IRQ_OFFSET 0 #define VI1_IRQ_OFFSET 1 #define VI2_IRQ_OFFSET 2 #define VI3_IRQ_OFFSET 3 #define VI4_IRQ_OFFSET 4 #define VI5_IRQ_OFFSET 5 #define VI6_IRQ_OFFSET 6 #define VI7_IRQ_OFFSET 0 #define TC0_IRQ_OFFSET 1 #define TC1_IRQ_OFFSET 2 #define TC2_IRQ_OFFSET 3 #define MSVRQ_IRQ_OFFSET 4 #define MEND_IRQ_OFFSET 5 #define TXRDY_IRQ_OFFSET 6 #define RXRDY_IRQ_OFFSET 7 typedef struct { uint8 config_cnt; uint8 ICW[5]; uint8 IMR; /* OCW1 = IMR */ uint8 OCW2; uint8 OCW3; uint8 IRR; uint8 ISR; } I8259_REGS; I8259_REGS ss1_pic[2]; /* SS1 Timer notes: * * T0, T1, T2 inputs connected to 2MHz clock on SS1 * T0 IRQ connected to Slave IRQ 1 * T1 IRQ connected to Slave IRQ 2 * T2 IRQ connected to Slave IRQ 3 */ typedef struct { uint16 count[3]; /* Current counter value for each timer. */ uint8 mode[3]; /* Current mode of each timer. */ uint8 bcd[3]; uint8 rl[3]; uint8 CTL; } I8253_REGS; I8253_REGS ss1_tc[1]; #define I8253_CTL_SC_MASK 0xC0 #define I8253_CTL_RL_MASK 0x30 #define I8253_CTL_MODE_MASK 0x0E #define I8253_CTL_BCD 0x01 typedef struct { uint8 digit_sel; uint8 flags; } RTC_REGS; RTC_REGS ss1_rtc[1]; static UNIT ss1_unit[] = { { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) }, { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) }, { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) }, { UDATA (&ss1_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) } }; static REG ss1_reg[] = { { HRDATAD (MPIC_IMR, ss1_pic[MASTER_PIC].IMR, 8, "Master IMR register"), }, { HRDATAD (MPIC_IRR, ss1_pic[MASTER_PIC].IRR, 8, "Master IRR register"), }, { HRDATAD (MPIC_ISR, ss1_pic[MASTER_PIC].ISR, 8, "Master ISR register"), }, { HRDATAD (MPIC_OCW2, ss1_pic[MASTER_PIC].OCW2, 8, "Master OCW2 register"), }, { HRDATAD (MPIC_OCW3, ss1_pic[MASTER_PIC].OCW3, 8, "Master OCW3 register"), }, { HRDATAD (SPIC_IMR, ss1_pic[SLAVE_PIC].IMR, 8, "Slave IMR register"), }, { HRDATAD (SPIC_IRR, ss1_pic[SLAVE_PIC].IRR, 8, "Slave IRR register"), }, { HRDATAD (SPIC_ISR, ss1_pic[SLAVE_PIC].ISR, 8, "Slave ISR register"), }, { HRDATAD (SPIC_OCW2, ss1_pic[SLAVE_PIC].OCW2, 8, "Slave OCW2 register"), }, { HRDATAD (SPIC_OCW3, ss1_pic[SLAVE_PIC].OCW3, 8, "Slave OCW3 register"), }, { HRDATAD (T0_MODE, ss1_tc[0].mode, 3, "Timer 0 mode register"), }, { HRDATAD (T0_COUNT, ss1_tc[0].count, 16, "Timer 0 count register"), }, { HRDATAD (T1_MODE, ss1_tc[1].mode, 3, "Timer 1 mode register"), }, { HRDATAD (T1_COUNT, ss1_tc[1].count, 16, "Timer 1 count register"), }, { HRDATAD (T2_MODE, ss1_tc[2].mode, 3, "Timer 2 mode register"), }, { HRDATAD (T2_COUNT, ss1_tc[2].count, 16, "Timer 2 count register"), }, { HRDATAD (RTC_DIGIT, ss1_rtc[0].digit_sel, 4, "Digit selector register"), }, { HRDATAD (RTC_FLAGS, ss1_rtc[0].flags, 4, "Flags register"), }, { NULL } }; static MTAB ss1_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL, "Sets system support module base address" }, { 0 } }; /* Debug Flags */ static DEBTAB ss1_dt[] = { { "ERROR", ERROR_MSG, "Error messages" }, { "TRACE", TRACE_MSG, "Trace messages" }, { "PIC", PIC_MSG, "PIC messages" }, { "TC", TC_MSG, "TC messages" }, { "RTC", RTC_MSG, "RTC messages" }, { "MATH", MATH_MSG, "Math messages" }, { "UART", UART_MSG, "UART messages" }, { "IRQ", IRQ_MSG, "IRQ messages" }, { NULL, 0 } }; DEVICE ss1_dev = { "SS1", ss1_unit, ss1_reg, ss1_mod, SS1_MAX_TIMERS, 10, 31, 1, SS1_MAX_TIMERS, SS1_MAX_TIMERS, NULL, NULL, &ss1_reset, NULL, NULL, NULL, &ss1_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG, ss1_dt, NULL, "Compupro System Support 1 SS1" }; /* Reset routine */ static t_stat ss1_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &ss1dev, TRUE); } else { /* Connect SS1 at base address */ if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &ss1dev, FALSE) != 0) { sim_printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); return SCPE_ARG; } else { DBG_PRINT(("SS1: Mapped I/O resource at 0x%04x, len=%d\n", pnp->io_base, pnp->io_size)); ss1_unit[0].u4 = 0; ss1_unit[1].u4 = 1; ss1_unit[2].u4 = 2; ss1_unit[3].u4 = 3; ss1_pic[MASTER_PIC].IMR = 0xFF; ss1_pic[SLAVE_PIC].IMR = 0xFF; } } return SCPE_OK; } static int32 ss1dev(const int32 port, const int32 io, const int32 data) { DBG_PRINT(("SS1: IO %s, Port %02x\n", io ? "WR" : "RD", port)); if(io) { SS1_Write(port, data); return 0; } else { return(SS1_Read(port)); } } #define SS1_M8259_L 0x00 #define SS1_M8259_H 0x01 #define SS1_S8259_L 0x02 #define SS1_S8259_H 0x03 #define SS1_8253_TC0 0x04 #define SS1_8253_TC1 0x05 #define SS1_8253_TC2 0x06 #define SS1_8253_CTL 0x07 #define SS1_9511A_DATA 0x08 #define SS1_9511A_CMD 0x09 #define SS1_RTC_CMD 0x0A #define SS1_RTC_DATA 0x0B #define SS1_UART_DATA 0x0C #define SS1_UART_STAT 0x0D #define SS1_UART_MODE 0x0E #define SS1_UART_CMD 0x0F extern int32 sio0d(const int32 port, const int32 io, const int32 data); extern int32 sio0s(const int32 port, const int32 io, const int32 data); static struct tm currentTime; static int32 toBCD(const int32 x); static uint8 SS1_Read(const uint32 Addr) { uint8 cData = 0x00; uint8 sel_pic = MASTER_PIC; uint8 sel_tc = 0; time_t now; switch(Addr & 0x0F) { case SS1_S8259_L: sel_pic = SLAVE_PIC; case SS1_M8259_L: if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x03) { cData = ss1_pic[sel_pic].ISR; sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: %s PIC ISR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); } else if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x02) { cData = ss1_pic[sel_pic].IRR; sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: %s PIC IRR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); } else { cData = 0xFF; } break; case SS1_S8259_H: sel_pic = SLAVE_PIC; case SS1_M8259_H: cData = ss1_pic[sel_pic].IMR; sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].IMR = cData; break; case SS1_8253_CTL: cData = ss1_tc[0].CTL; sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: TC CTL=0x%02x.\n", PCX, cData); break; case SS1_8253_TC2: sel_tc++; case SS1_8253_TC1: sel_tc++; case SS1_8253_TC0: sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: TC [%d]=0x%02x.\n", PCX, sel_tc, cData); break; case SS1_9511A_DATA: case SS1_9511A_CMD: sim_debug(MATH_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: Math Coprocessor not Implemented.\n", PCX); break; case SS1_RTC_CMD: cData = 0xFF; sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: RTC Cmd=0x%02x.\n", PCX, cData); break; case SS1_RTC_DATA: time(&now); currentTime = *localtime(&now); switch(ss1_rtc[0].digit_sel) { case 0: cData = toBCD(currentTime.tm_sec) & 0xF; break; case 1: cData = (toBCD(currentTime.tm_sec) >> 4) & 0xF; break; case 2: cData = toBCD(currentTime.tm_min) & 0xF; break; case 3: cData = (toBCD(currentTime.tm_min) >> 4) & 0xF; break; case 4: cData = toBCD(currentTime.tm_hour) & 0xF; break; case 5: cData = (toBCD(currentTime.tm_hour) >> 4) & 0x3; cData |= 0x08; /* Set to 24-hour format */ break; case 6: cData = toBCD(currentTime.tm_wday) & 0xF; break; case 7: cData = toBCD(currentTime.tm_mday) & 0xF; break; case 8: cData = (toBCD(currentTime.tm_mday) >> 4) & 0xF; break; case 9: cData = toBCD(currentTime.tm_mon+1) & 0xF; break; case 10: cData = (toBCD(currentTime.tm_mon+1) >> 4) & 0xF; break; case 11: cData = toBCD(currentTime.tm_year-22) & 0xF; break; case 12: cData = (toBCD(currentTime.tm_year-22) >> 4) & 0xF; break; default: cData = 0; break; } sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: RTC Data[%x]=0x%02x.\n", PCX, ss1_rtc[0].digit_sel, cData); break; case SS1_UART_DATA: cData = sio0d(Addr, 0, 0); sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: UART Data=0x%02x.\n", PCX, cData); break; case SS1_UART_STAT: cData = sio0s(Addr, 0, 0); sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: UART Stat=0x%02x.\n", PCX, cData); break; case SS1_UART_MODE: case SS1_UART_CMD: sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " RD: UART not Implemented.\n", PCX); break; } return (cData); } uint16 newcount = 0; uint8 bc; static void generate_ss1_interrupt(void); static uint8 SS1_Write(const uint32 Addr, uint8 cData) { uint8 sel_pic = MASTER_PIC; uint8 sel_tc = 0; uint8 sel_timer = 0; switch(Addr & 0x0F) { case SS1_S8259_L: sel_pic = SLAVE_PIC; case SS1_M8259_L: if(cData & 0x10) { sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC ICW1=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].ICW[1] = cData; ss1_pic[sel_pic].config_cnt=1; } else { if(cData & 0x08) { /* OCW3 */ sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC OCW3=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].OCW3 = cData; } else { /* OCW2 */ sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC OCW2=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].OCW2 = cData; } } break; case SS1_S8259_H: sel_pic = SLAVE_PIC; case SS1_M8259_H: if(ss1_pic[sel_pic].config_cnt == 0) { sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].IMR = cData; generate_ss1_interrupt(); } else { ss1_pic[sel_pic].config_cnt++; sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData); ss1_pic[sel_pic].ICW[ss1_pic[sel_pic].config_cnt] = cData; ss1_unit[0].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC0_IRQ_OFFSET; ss1_unit[1].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC1_IRQ_OFFSET; ss1_unit[2].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC2_IRQ_OFFSET; if(ss1_pic[sel_pic].config_cnt == 4) { ss1_pic[sel_pic].config_cnt = 0; } } break; case SS1_8253_CTL: ss1_tc[0].CTL = cData; sel_timer = (ss1_tc[0].CTL & I8253_CTL_SC_MASK) >> 6; sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: TC CTL=0x%02x.\n", PCX, ss1_tc[0].CTL); if(ss1_tc[0].CTL & I8253_CTL_BCD) { sim_debug(ERROR_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Timer %d: BCD Mode not supported: TC CTL=0x%02x.\n", PCX, sel_timer, ss1_tc[0].CTL); } ss1_tc[0].bcd[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_BCD); ss1_tc[0].mode[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_MODE_MASK) >> 1; ss1_tc[0].rl[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_RL_MASK) >> 4; sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Timer %d: Mode: %d, RL=%d, %s.\n", PCX, sel_timer, ss1_tc[0].mode[sel_timer], ss1_tc[0].rl[sel_timer], ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary"); newcount = 0; bc=0; break; case SS1_8253_TC2: sel_tc++; case SS1_8253_TC1: sel_tc++; case SS1_8253_TC0: if(ss1_tc[0].rl[sel_timer] == 3) { if(bc==0) { newcount = cData; } if(bc==1) { newcount |= (cData << 8); sim_activate(&ss1_unit[sel_tc], newcount); } bc++; } if(ss1_tc[0].rl[sel_timer] == 2) { newcount = (cData << 8); sim_activate(&ss1_unit[sel_tc], newcount); } sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: TC [%d]=0x%02x.\n", PCX, sel_tc, cData); if(sel_tc == 0) { } break; case SS1_9511A_DATA: case SS1_9511A_CMD: sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: Math Coprocessor not Implemented.\n", PCX); break; case SS1_RTC_CMD: ss1_rtc[0].digit_sel = cData & 0x0F; ss1_rtc[0].flags = (cData >> 4) & 0x0F; sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: RTC Cmd=0x%02x (%s%s%s SEL=%x)\n", PCX, cData, ss1_rtc[0].flags & 0x4 ? "HOLD " :"", ss1_rtc[0].flags & 0x2 ? "WR" :"", ss1_rtc[0].flags & 0x1 ? "RD" :"", ss1_rtc[0].digit_sel); break; case SS1_RTC_DATA: sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: RTC Data=0x%02x\n", PCX, cData); break; case SS1_UART_DATA: sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: UART Data=0x%02x.\n", PCX, cData); sio0d(Addr, 1, cData); break; case SS1_UART_STAT: sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: UART Stat=0x%02x.\n", PCX, cData); sio0s(Addr, 1, cData); break; case SS1_UART_MODE: case SS1_UART_CMD: sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: UART not Implemented.\n", PCX); break; } return(0); } void raise_ss1_interrupt(uint8 isr_index) { uint8 irq_bit; if(isr_index < 7) { /* VI0-6 on master PIC */ irq_bit = (1 << isr_index); ss1_pic[MASTER_PIC].ISR |= irq_bit; generate_ss1_interrupt(); } else { /* VI7 is on slave PIC */ ss1_pic[SLAVE_PIC].ISR |= 1; generate_ss1_interrupt(); } } extern void cpu_raise_interrupt(uint32 irq); static void generate_ss1_interrupt(void) { uint8 irq, irq_pend, irq_index = 0, irq_bit = 0; uint8 pic; for(pic=MASTER_PIC;pic<=SLAVE_PIC;pic++) { irq_pend = (~ss1_pic[pic].IMR) & ss1_pic[pic].ISR; while(irq_pend) { irq_bit = irq_pend & 1; if(irq_bit) { ss1_pic[pic].IRR |= (irq_bit << irq_index); irq = ss1_pic[pic].ICW[2]+irq_index; sim_debug(IRQ_MSG, &ss1_dev, "Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index); cpu_raise_interrupt(irq); ss1_pic[pic].IRR &= ~(irq_bit << irq_index); ss1_pic[pic].ISR &= ~(irq_bit << irq_index); if(irq_pend & 0x7E) { /* sim_debug(IRQ_MSG, &ss1_dev, "Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index); */ sim_activate(&ss1_unit[3], 1000); /* requeue, because more interrupts are pending. */ } break; } else { irq_index++; irq_pend = irq_pend >> 1; } } } } /* Unit service routine */ /* Unit 0-2 = Timer0-2, Unit3=ISR queue */ static t_stat ss1_svc (UNIT *uptr) { uint8 cData; uint8 irq_bit = 0; /* Handle SS1 UART Rx interrupts here. */ cData = sio0s(0x5D, 0, 0); if(cData & 2) { /* && ((ss1_pic[SLAVE_PIC].IMR & 0x80) == 0)) { */ ss1_pic[SLAVE_PIC].ISR |= 0x80; generate_ss1_interrupt(); sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */ } else if((cData & 1) && ((ss1_pic[SLAVE_PIC].IMR & 0x40) == 0)) { sim_debug(IRQ_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling UART Tx ISR.\n", PCX); ss1_pic[SLAVE_PIC].ISR |= 0x40; generate_ss1_interrupt(); sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */ } else if (uptr->u4 == 0x3) { /* ISR was requeued because additional interrupts were pending. */ generate_ss1_interrupt(); } else { switch(uptr->u4) { case 0: irq_bit = 2; break; case 1: irq_bit = 4; break; case 2: irq_bit = 8; break; } if(ss1_tc[0].mode[uptr->u4] == 0x0) { sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4); ss1_pic[SLAVE_PIC].ISR |= irq_bit; generate_ss1_interrupt(); } if(ss1_tc[0].mode[uptr->u4] == 0x3) { sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4); ss1_pic[SLAVE_PIC].ISR |= irq_bit; generate_ss1_interrupt(); sim_debug(TC_MSG, &ss1_dev, "Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4]); sim_activate(uptr, 33280); } } sim_activate(&ss1_unit[3], 1000000); // requeue, because more interrupts are pending. return SCPE_OK; } static int32 toBCD(const int32 x) { return (x / 10) * 16 + (x % 10); }