/************************************************************************* * * * $Id: s100_if3.c 1991 2008-07-10 16:06:12Z 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" #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 RXIRQ_MSG (1 << 1) #define TXIRQ_MSG (1 << 2) #define UART_MSG (1 << 3) #define USER_MSG (1 << 4) #define IF3_MAX_BOARDS 4 #define UNIT_V_IF3_CONNECT (UNIT_V_UF + 1) /* Connect/Disconnect IF3 unit */ #define UNIT_IF3_CONNECT (1 << UNIT_V_IF3_CONNECT) #define IF3_PORT_BASE 0x300 typedef struct { PNP_INFO pnp; /* Plug and Play */ } IF3_INFO; static IF3_INFO if3_info_data = { { 0x0, 0, 0x10, 8 } }; extern t_stat set_iobase(UNIT *uptr, int32 val, CONST char *cptr, void *desc); extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, CONST 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; 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 t_stat set_if3_connect(UNIT *uptr, int32 val, CONST char *cptr, void *desc); static t_stat if3_reset(DEVICE *if3_dev); static t_stat if3_svc (UNIT *uptr); static uint8 IF3_Read(const uint32 Addr); static uint8 IF3_Write(const uint32 Addr, uint8 cData); static int32 if3dev(const int32 port, const int32 io, const int32 data); static t_stat update_rx_tx_isr (UNIT *uptr); static const char* if3_description(DEVICE *dptr); static UNIT if3_unit[] = { { UDATA (&if3_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE | UNIT_IF3_CONNECT, 0) }, { UDATA (&if3_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) }, { UDATA (&if3_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) }, { UDATA (&if3_svc, UNIT_FIX | UNIT_DISABLE | UNIT_ROABLE, 0) } }; static uint8 if3_user = 0; static uint8 if3_board = 0; static uint8 if3_rimr[IF3_MAX_BOARDS] = { 0, 0, 0, 0 }; static uint8 if3_timr[IF3_MAX_BOARDS] = { 0, 0, 0, 0 }; static uint8 if3_risr[IF3_MAX_BOARDS] = { 0, 0, 0, 0 }; static uint8 if3_tisr[IF3_MAX_BOARDS] = { 0, 0, 0, 0 }; static REG if3_reg[] = { { HRDATAD (USER, if3_user, 3, "IF3 user register"), }, { HRDATAD (BOARD, if3_board, 2, "IF3 board register"), }, { BRDATAD (RIMR, &if3_rimr[0], 16, 8, 4, "IF3 RIMR register array"), }, { BRDATAD (RISR, &if3_risr[0], 16, 8, 4, "IF3 RISR register array"), }, { BRDATAD (TIMR, &if3_timr[0], 16, 8, 4, "IF3 TIMR register array"), }, { BRDATAD (TISR, &if3_tisr[0], 16, 8, 4, "IF3 TISR register array"), }, { NULL } }; #define IF3_NAME "Compupro Interfacer 3" static const char* if3_description(DEVICE *dptr) { return IF3_NAME; } static MTAB if3_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" }, { UNIT_IF3_CONNECT, UNIT_IF3_CONNECT,"INSTALLED", "INSTALLED", &set_if3_connect, NULL, NULL, "Installs board for unit " IF3_NAME "n" }, { UNIT_IF3_CONNECT, 0, "UNINSTALLED","UNINSTALLED", &set_if3_connect, NULL, NULL, "Uninstalls board for unit " IF3_NAME "n" }, { 0 } }; /* Debug Flags */ static DEBTAB if3_dt[] = { { "ERROR", ERROR_MSG, "Error messages" }, { "RXIRQ", RXIRQ_MSG, "RX IRQ messages" }, { "TXIRQ", TXIRQ_MSG, "TX IRQ messages" }, { "UART", UART_MSG, "UART messages" }, { "USER", USER_MSG, "User messages" }, { NULL, 0 } }; DEVICE if3_dev = { "IF3", if3_unit, if3_reg, if3_mod, IF3_MAX_BOARDS, 10, 31, 1, IF3_MAX_BOARDS, IF3_MAX_BOARDS, NULL, NULL, &if3_reset, NULL, NULL, NULL, &if3_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0, if3_dt, NULL, NULL, NULL, NULL, NULL, &if3_description }; static t_stat set_if3_connect(UNIT *uptr, int32 val, CONST char *cptr, void *desc) { if(uptr->flags & UNIT_DISABLE) { sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: not enabled.\n", uptr->u3); return SCPE_OK; } if(val & UNIT_IF3_CONNECT) { sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling started...\n", uptr->u3); sim_activate(uptr, 100000); } else { sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling stopped.\n", uptr->u3); sim_cancel(uptr); } return (SCPE_OK); } /* Reset routine */ static t_stat if3_reset(DEVICE *dptr) { uint8 i; PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ for(i=0;iio_base, pnp->io_size, RESOURCE_TYPE_IO, &if3dev, TRUE); } else { /* Connect IF3 at base address */ if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &if3dev, FALSE) != 0) { sim_printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); return SCPE_ARG; } for(i=0;i> 3; /* guarantees that if3_board < IF3_MAX_BOARDS */ if3_user = cData & 0x7; sim_debug(USER_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART_SEL=0x%02x (Board=%d, Rel_User=%d, User=%d)\n", if3_board, PCX, cData, if3_board, if3_user, cData); break; } return(0); } #define SS1_VI2_INT 2 /* IF3 Rx interrupts tied to VI2 */ #define SS1_VI3_INT 3 /* IF3 Tx interrupts tied to VI3 */ #define IF3_NUM_PORTS 8 /* Number of ports per IF3 board */ extern void raise_ss1_interrupt(uint8 isr_index); /* Unit service routine */ static t_stat if3_svc (UNIT *uptr) { uint8 pending_rx_irqs; uint8 pending_tx_irqs; uint8 board = uptr->u3; update_rx_tx_isr(uptr); pending_rx_irqs = if3_risr[board] & if3_rimr[board]; if(pending_rx_irqs) { sim_debug(RXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Rx IRQ Pending: 0x%02x\n", board, PCX, pending_rx_irqs); raise_ss1_interrupt(SS1_VI2_INT); } pending_tx_irqs = if3_tisr[board] & if3_timr[board]; if(pending_tx_irqs) { sim_debug(TXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Tx IRQ Pending: 0x%02x\n", board, PCX, pending_tx_irqs); raise_ss1_interrupt(SS1_VI3_INT); } sim_activate(&if3_unit[board], 200000); return SCPE_OK; } static t_stat update_rx_tx_isr (UNIT *uptr) { uint8 i; uint8 cData; uint8 board = uptr->u3; if3_risr[board] = 0; if3_tisr[board] = 0; for(i=0;i