/************************************************************************* * * * Copyright (c) 2022 Howard M. Harte. * * https://github.com/hharte * * * * 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 NON- * * INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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 names of The Authors shall * * not be used in advertising or otherwise to promote the sale, use or * * other dealings in this Software without prior written authorization * * from the Authors. * * * * Based on s100_64fdc.c * * * * Module Description: * * Tarbell Double-Density Floppy Controller module for SIMH. * * This module is a wrapper around the wd179x FDC module. * * * * Reference: * * http://www.bitsavers.org/pdf/tarbell/Tarbell_Double_Density_Floppy_Disk_Interface_Jul81.pdf * * *************************************************************************/ #include "altairz80_defs.h" #include "sim_defs.h" #include "wd179x.h" #define DEV_NAME "TDD" /* Debug flags */ #define STATUS_MSG (1 << 0) #define DRIVE_MSG (1 << 1) #define VERBOSE_MSG (1 << 2) #define IRQ_MSG (1 << 3) #define TDD_MAX_DRIVES 4 #define TDD_IO_BASE 0x7C #define TDD_IO_SIZE 0x2 #define TDD_IO_MASK (TDD_IO_SIZE - 1) typedef struct { PNP_INFO pnp; /* Plug and Play */ } TDD_INFO; extern WD179X_INFO_PUB *wd179x_infop; static TDD_INFO tdd_info_data = { { 0x0000, 0, TDD_IO_BASE, TDD_IO_SIZE } }; 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), const char* name, uint8 unmap); extern uint32 PCX; /* external view of PC */ #define TDD_CAPACITY (77*1*26*128) /* Default SSSD 8" (IBM 3740) Disk Capacity */ static t_stat tdd_reset(DEVICE *tdd_dev); static int32 tdd_control(const int32 port, const int32 io, const int32 data); static const char* tdd_description(DEVICE *dptr); #define TDD_FLAG_EOJ (1 << 7) /* End of Job (INTRQ) */ static UNIT tdd_unit[] = { { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TDD_CAPACITY) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TDD_CAPACITY) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TDD_CAPACITY) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TDD_CAPACITY) } }; static REG tdd_reg[] = { { NULL } }; #define TDD_NAME "Tarbell Double-Density FDC" static const char* tdd_description(DEVICE *dptr) { if (dptr == NULL) { return NULL; } return TDD_NAME; } static MTAB tdd_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" }, { 0 } }; /* Debug Flags */ static DEBTAB tdd_dt[] = { { "STATUS", STATUS_MSG, "Status messages" }, { "DRIVE", DRIVE_MSG, "Drive messages" }, { "VERBOSE", VERBOSE_MSG, "Verbose messages" }, { "IRQ", IRQ_MSG, "IRQ messages" }, { NULL, 0 } }; DEVICE tdd_dev = { DEV_NAME, tdd_unit, tdd_reg, tdd_mod, TDD_MAX_DRIVES, 10, 31, 1, TDD_MAX_DRIVES, TDD_MAX_DRIVES, NULL, NULL, &tdd_reset, NULL, &wd179x_attach, &wd179x_detach, &tdd_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0, tdd_dt, NULL, NULL, NULL, NULL, NULL, &tdd_description }; /* Reset routine */ static t_stat tdd_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; if(dptr->flags & DEV_DIS) { /* Disconnect ROM and I/O Ports */ /* Unmap I/O Ports */ sim_map_resource(pnp->io_base, 1, RESOURCE_TYPE_IO, &tdd_control, "tdd_control", TRUE); } else { /* Connect TDD Disk Flags and Control Register */ if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &tdd_control, "tdd_control", FALSE) != 0) { sim_printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); return SCPE_ARG; } } return SCPE_OK; } /* Tarbell pp. 12-5 Disk Control/Status */ static int32 tdd_control(const int32 port, const int32 io, const int32 data) { int32 result = 0; if(io) { /* I/O Write */ if ((port & TDD_IO_MASK) == 0) { wd179x_infop->fdc_head = (data & 0x40) >> 6; wd179x_infop->sel_drive = (data & 0x30) >> 4; wd179x_infop->ddens = (data & 0x08) >> 3; sim_debug(DRIVE_MSG, &tdd_dev, DEV_NAME ": " ADDRESS_FORMAT " WR CTRL(0x%02x) = 0x%02x: Drive: %d, Head: %d, %s-Density.\n", PCX, port, data & 0xFF, wd179x_infop->sel_drive, wd179x_infop->fdc_head, wd179x_infop->ddens == 1 ? "Double" : "Single"); } else { sim_debug(STATUS_MSG, &tdd_dev, DEV_NAME ": " ADDRESS_FORMAT " Write Extended Address, Port 0x%02x=0x%02x\n", PCX, port, data); } } else { /* I/O Read */ if ((port & TDD_IO_MASK) == 0) { result = (wd179x_infop->intrq) ? 0 : TDD_FLAG_EOJ; sim_debug(STATUS_MSG, &tdd_dev, DEV_NAME ": " ADDRESS_FORMAT " Read EOJ, Port 0x%02x Result 0x%02x\n", PCX, port, result); } else { result = (wd179x_infop->drq) ? TDD_FLAG_EOJ : 0; sim_debug(STATUS_MSG, &tdd_dev, DEV_NAME ": " ADDRESS_FORMAT " Read DRQ, Port 0x%02x Result 0x%02x\n", PCX, port, result); } } return result; }