simh-testsetgenerator/AltairZ80/s100_tdd.c
2023-05-23 21:44:47 +02:00

179 lines
7.9 KiB
C

/*************************************************************************
* *
* 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 "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;
}