From d205582e9ed0877caddbef7d1e2278327ed1e996 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Thu, 5 Dec 2019 16:00:35 -0800 Subject: [PATCH 01/11] Add Tarbell SSSD disk controller --- AltairZ80/altairz80_sys.c | 4 + AltairZ80/s100_tarbell.c | 1074 +++++++++++++++++++++++++++++++++++++ makefile | 3 +- 3 files changed, 1080 insertions(+), 1 deletion(-) create mode 100644 AltairZ80/s100_tarbell.c diff --git a/AltairZ80/altairz80_sys.c b/AltairZ80/altairz80_sys.c index fca85329..150f25b5 100644 --- a/AltairZ80/altairz80_sys.c +++ b/AltairZ80/altairz80_sys.c @@ -66,6 +66,8 @@ extern DEVICE switchcpu_dev; extern DEVICE adcs6_dev; extern DEVICE hdc1001_dev; +extern DEVICE tarbell_dev; + extern DEVICE cromfdc_dev; extern DEVICE wd179x_dev; extern DEVICE n8vem_dev; @@ -115,6 +117,8 @@ DEVICE *sim_devices[] = { &mdsa_dev, &mdsad_dev, /* Seattle Computer Products Devices */ &scp300f_dev, + /* Tarbell Devices */ + &tarbell_dev, /* Vector Graphic Devices */ &fw2_dev, &vfdhd_dev, /* Single-Board Computers */ diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c new file mode 100644 index 00000000..9242534e --- /dev/null +++ b/AltairZ80/s100_tarbell.c @@ -0,0 +1,1074 @@ +/************************************************************************* + * s100_tarbell.c: Tarbell Single Density Disk Controller + * + * Created by Patrick Linstruth + * Based on s100_mdsa.c written by Mike Douglas + * + * Module Description: + * Tarbell 1011 Single Density Disk Controller module for SIMH + * + * Environment: + * User mode only + * + *************************************************************************/ + +/* #define DBG_MSG */ + +#include "altairz80_defs.h" +#include "sim_imd.h" + +#if defined (_WIN32) +#include +#endif + +#ifdef DBG_MSG +#define DBG_PRINT(args) sim_printf args +#else +#define DBG_PRINT(args) +#endif + +extern uint32 PCX; +extern t_stat set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc); +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); + +#define TARBELL_MAX_ADAPTERS 1 +#define TARBELL_MAX_DRIVES 4 +#define TARBELL_SECTOR_LEN 128 +#define TARBELL_SECTORS_PER_TRACK 26 +#define TARBELL_BYTES_PER_TRACK ((TARBELL_SECTORS_PER_TRACK * 186) + 73 + 247) +#define TARBELL_TRACKS 77 +#define TARBELL_CAPACITY (256256) /* Default Tarbell Disk Capacity */ + +#define TARBELL_PROM_SIZE 32 +#define TARBELL_PROM_MASK (TARBELL_PROM_SIZE-1) +#define TARBELL_RAM_SIZE 256 +#define TARBELL_RAM_MASK (TARBELL_RAM_SIZE-1) +#define TARBELL_PROM_READ FALSE +#define TARBELL_PROM_WRITE TRUE + +/* Tarbell PROM is 32 bytes */ +static uint8 tarbell_prom[TARBELL_PROM_SIZE] = { + 0xdb, 0xfc, 0xaf, 0x6f, 0x67, 0x3c, 0xd3, 0xfa, + 0x3e, 0x8c, 0xd3, 0xf8, 0xdb, 0xfc, 0xb7, 0xf2, + 0x19, 0x00, 0xdb, 0xfb, 0x77, 0x23, 0xc3, 0x0c, + 0x00, 0xdb, 0xf8, 0xb7, 0xca, 0x7d, 0x00, 0x76 +}; + +static uint8 tarbell_ram[TARBELL_RAM_SIZE]; + +/* +** Western Digital FD1771 Registers and Interface Controls +*/ +typedef struct { + uint8 track; /* Track Register */ + uint8 sector; /* Sector Register */ + uint8 command; /* Command Register */ + uint8 status; /* Status Register */ + uint8 data; /* Data Register */ + uint8 intrq; /* Interrupt Request */ + int8 stepDir; /* Last Step Direction */ + uint32 dataCount; /* Number of data bytes transferred from controller for current sector/address */ + uint32 trkCount; /* Number of data bytes transferred from controller for current track */ + uint8 readActive; /* Read Active */ + uint8 readTrkActive; /* Read Track Active */ + uint8 writeActive; /* Write Active */ + uint8 writeTrkActive; /* Write Track Active */ + uint8 addrActive; /* Address Active */ +} FD1771_REG; + +#define FD1771_STAT_NOTREADY 0x80 +#define FD1771_STAT_WRITEPROT 0x40 +#define FD1771_STAT_RTYPEMSB 0x40 +#define FD1771_STAT_HEADLOAD 0x20 +#define FD1771_STAT_RTYPELSB 0x20 +#define FD1771_STAT_WRITEFAULT 0x20 +#define FD1771_STAT_SEEKERROR 0x10 +#define FD1771_STAT_NOTFOUND 0x10 +#define FD1771_STAT_CRCERROR 0x08 +#define FD1771_STAT_TRACK0 0x04 +#define FD1771_STAT_LOSTDATA 0x04 +#define FD1771_STAT_INDEX 0x02 +#define FD1771_STAT_DRQ 0x02 +#define FD1771_STAT_BUSY 0x01 + +typedef struct { +} TARBELL_DRIVE_STATUS; + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint8 promEnabled; /* PROM is enabled */ + uint8 writeProtect; /* Write Protect is enabled */ + uint8 currentDrive; /* currently selected drive */ + FD1771_REG FD1771; /* FD1771 */ + UNIT *uptr[TARBELL_MAX_DRIVES]; +} TARBELL_INFO; + +#define TARBELL_PNP_MEMBASE 0x0000 +#define TARBELL_PNP_MEMSIZE TARBELL_RAM_SIZE +#define TARBELL_PNP_IOBASE 0xF8 +#define TARBELL_PNP_IOSIZE 5 + +static TARBELL_INFO tarbell_info_data = { { TARBELL_PNP_MEMBASE, TARBELL_PNP_MEMSIZE, TARBELL_PNP_IOBASE, TARBELL_PNP_IOSIZE } }; +static TARBELL_INFO *tarbell_info = &tarbell_info_data; + +static uint8 sdata[TARBELL_SECTOR_LEN]; +static uint32 stepCleared = TRUE; /* true when step bit has returned to zero */ + +/* Tarbell Registers */ +#define TARBELL_REG_STATUS 0x00 +#define TARBELL_REG_COMMAND 0x00 +#define TARBELL_REG_TRACK 0x01 +#define TARBELL_REG_SECTOR 0x02 +#define TARBELL_REG_DATA 0x03 +#define TARBELL_REG_EXT 0x04 + +/* Tarbell Commands */ +#define TARBELL_CMD_RESTORE 0x00 +#define TARBELL_CMD_SEEK 0x10 +#define TARBELL_CMD_STEP 0x20 +#define TARBELL_CMD_STEPU (TARBELL_CMD_STEP | TARBELL_FLAG_U) +#define TARBELL_CMD_STEPIN 0x40 +#define TARBELL_CMD_STEPINU (TARBELL_CMD_STEPIN | TARBELL_FLAG_U) +#define TARBELL_CMD_STEPOUT 0x60 +#define TARBELL_CMD_STEPOUTU (TARBELL_CMD_STEPOUT | TARBELL_FLAG_U) +#define TARBELL_CMD_READ 0x80 +#define TARBELL_CMD_READM (TARBELL_CMD_READM | TARBELL_FLAG_M) +#define TARBELL_CMD_WRITE 0xA0 +#define TARBELL_CMD_WRITEM (TARBELL_CMD_WRITEM | TARBELL_FLAG_M) +#define TARBELL_CMD_READ_ADDRESS 0xC0 +#define TARBELL_CMD_READ_TRACK 0xE0 +#define TARBELL_CMD_WRITE_TRACK 0xF0 +#define TARBELL_CMD_FORCE_INTR 0xD0 + +#define TARBELL_FLAG_V 0x04 +#define TARBELL_FLAG_H 0x08 +#define TARBELL_FLAG_U 0x10 +#define TARBELL_FLAG_M 0x10 +#define TARBELL_FLAG_B 0x08 +#define TARBELL_FLAG_S 0x01 +#define TARBELL_FLAG_E 0x04 + +#define TARBELL_FLAG_A1A0_FB 0x00 +#define TARBELL_FLAG_A1A0_FA 0x01 +#define TARBELL_FLAG_A1A0_F9 0x02 +#define TARBELL_FLAG_A1A0_F8 0x03 + +#define TARBELL_FLAG_I0 0x01 +#define TARBELL_FLAG_I1 0x02 +#define TARBELL_FLAG_I2 0x04 +#define TARBELL_FLAG_I3 0x08 + +#define TARBELL_FLAG_R1R0_6MS 0x00 +#define TARBELL_FLAG_R1R0_10ms 0x02 +#define TARBELL_FLAG_R1R0_20ms 0x03 + +#define TARBELL_ADDR_TRACK 0x00 +#define TARBELL_ADDR_ZEROS 0x01 +#define TARBELL_ADDR_SECTOR 0x02 +#define TARBELL_ADDR_LENGTH 0x03 +#define TARBELL_ADDR_CRC1 0x04 +#define TARBELL_ADDR_CRC2 0x05 + +/* Local function prototypes */ +static t_stat tarbell_reset(DEVICE *tarbell_dev); +static t_stat tarbell_attach(UNIT *uptr, CONST char *cptr); +static t_stat tarbell_detach(UNIT *uptr); +static t_stat tarbell_boot(int32 unitno, DEVICE *dptr); +static t_stat tarbell_set_prom(UNIT *uptr, int32 value, CONST char *cptr, void *desc); +static uint8 TARBELL_Read(const uint32 Addr); +static uint8 TARBELL_Write(const uint32 Addr, int32 data); +static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 data); +static uint32 TARBELL_ReadSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer); +static uint32 TARBELL_WriteSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer); +static const char* tarbell_description(DEVICE *dptr); +static void showdata(int32 isRead); +static void showregs(FD1771_REG *pFD1771); + +static int32 tarbelldev(const int32 Addr, const int32 rw, const int32 data); +static int32 tarbellprom(const int32 Addr, const int32 rw, const int32 data); + +static UNIT tarbell_unit[TARBELL_MAX_DRIVES] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) } +}; + +static REG tarbell_reg[] = { + { NULL } +}; + +#define TARBELL_NAME "Tarbell 1011 Single Density Controller" +#define TARBELL_SNAME "TARBELL" + +static const char* tarbell_description(DEVICE *dptr) { + return TARBELL_NAME; +} + +#define UNIT_V_TARBELL_VERBOSE (UNIT_V_UF + 0) /* VERBOSE / QUIET */ +#define UNIT_TARBELL_VERBOSE (1 << UNIT_V_TARBELL_VERBOSE) +#define UNIT_V_TARBELL_WPROTECT (UNIT_V_UF + 1) /* WRTENB / WRTPROT */ +#define UNIT_TARBELL_WPROTECT (1 << UNIT_V_TARBELL_WPROTECT) + +static MTAB tarbell_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", + &set_iobase, &show_iobase, NULL, "Sets disk controller IO base address" }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "PROM", &tarbell_set_prom, + NULL, NULL, "Enable Tarbell boot PROM"}, + { MTAB_XTD | MTAB_VDV, 0, NULL, "NOPROM", &tarbell_set_prom, + NULL, NULL, "Disable Tarbell boot PROM" }, + { UNIT_TARBELL_VERBOSE, 0, "QUIET", "QUIET", + NULL, NULL, NULL, "No verbose messages for unit " TARBELL_NAME "n" }, + { UNIT_TARBELL_VERBOSE, UNIT_TARBELL_VERBOSE, "VERBOSE", "VERBOSE", + NULL, NULL, NULL, "Verbose messages for unit " TARBELL_NAME "n" }, + { UNIT_TARBELL_WPROTECT, 0, "WRTENB", "WRTENB", NULL, NULL, NULL, + "Enables " TARBELL_NAME "n for writing" }, + { UNIT_TARBELL_WPROTECT, UNIT_TARBELL_WPROTECT, "WRTPROT", "WRTPROT", NULL, NULL, NULL, + "Protects " TARBELL_NAME "n from writing" }, + { 0 } +}; + +/* Debug flags */ +#define ERROR_MSG (1 << 0) +#define SEEK_MSG (1 << 1) +#define CMD_MSG (1 << 2) +#define RD_DATA_MSG (1 << 3) +#define WR_DATA_MSG (1 << 4) +#define STATUS_MSG (1 << 5) +#define RD_DATA_DETAIL_MSG (1 << 6) +#define WR_DATA_DETAIL_MSG (1 << 7) + +/* Debug Flags */ +static DEBTAB tarbell_dt[] = { + { "ERROR", ERROR_MSG, "Error messages" }, + { "SEEK", SEEK_MSG, "Seek messages" }, + { "CMD", CMD_MSG, "Command messages" }, + { "READ", RD_DATA_MSG, "Read messages" }, + { "WRITE", WR_DATA_MSG, "Write messages" }, + { "STATUS", STATUS_MSG, "Status messages" }, + { "RDDETAIL", RD_DATA_DETAIL_MSG, "Read detail messages" }, + { "WRDETAIL", WR_DATA_DETAIL_MSG, "Write detail messags" }, + { NULL, 0 } +}; + +DEVICE tarbell_dev = { + "TARBELL", /* name */ + tarbell_unit, /* unit */ + tarbell_reg, /* registers */ + tarbell_mod, /* modifiers */ + TARBELL_MAX_DRIVES, /* # units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* addr increment */ + TARBELL_MAX_DRIVES, /* data radix */ + TARBELL_MAX_DRIVES, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &tarbell_reset, /* reset routine */ + &tarbell_boot, /* boot routine */ + &tarbell_attach, /* attach routine */ + &tarbell_detach, /* detach routine */ + &tarbell_info_data, /* context */ + (DEV_DISABLE | DEV_DIS | DEV_DEBUG), /* flags */ + ERROR_MSG, /* debug control */ + tarbell_dt, /* debug flags */ + NULL, /* mem size routine */ + NULL, /* logical name */ + NULL, /* help */ + NULL, /* attach help */ + NULL, /* context for help */ + &tarbell_description /* description */ +}; + +/* Reset routine */ +t_stat tarbell_reset(DEVICE *dptr) +{ + uint8 i; + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + TARBELL_INFO *pInfo = (TARBELL_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pInfo->pnp.mem_base, pInfo->pnp.mem_size, RESOURCE_TYPE_MEMORY, &tarbellprom, TRUE); + sim_map_resource(pInfo->pnp.io_base, pInfo->pnp.io_size, RESOURCE_TYPE_IO, &tarbelldev, TRUE); + } else { + if(sim_map_resource(pInfo->pnp.mem_base, pInfo->pnp.mem_size, RESOURCE_TYPE_MEMORY, &tarbellprom, FALSE) != 0) { + DBG_PRINT(("%s: error mapping MEM resource at 0x%04x" NLP, __FUNCTION__, pInfo->pnp.mem_base)); + return SCPE_ARG; + } + /* Connect I/O Ports at base address */ + if(sim_map_resource(pInfo->pnp.io_base, pInfo->pnp.io_size, RESOURCE_TYPE_IO, &tarbelldev, FALSE) != 0) { + DBG_PRINT(("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pInfo->pnp.io_base)); + return SCPE_ARG; + } + } + + /* Enable PROM */ + pInfo->promEnabled = TRUE; + pInfo->writeProtect = FALSE; + + /* Reset Registers and Interface Controls */ + pInfo->FD1771.track = 0; + pInfo->FD1771.sector = 0; + pInfo->FD1771.command = 0; + pInfo->FD1771.status = 0; + pInfo->FD1771.data = 0; + pInfo->FD1771.intrq = 0; + pInfo->FD1771.stepDir = 1; + pInfo->FD1771.dataCount = 0; + pInfo->FD1771.trkCount = 0; + pInfo->FD1771.addrActive = FALSE; + pInfo->FD1771.readActive = FALSE; + pInfo->FD1771.readTrkActive = FALSE; + pInfo->FD1771.writeActive = FALSE; + pInfo->FD1771.writeTrkActive = FALSE; + pInfo->FD1771.addrActive = FALSE; + + return SCPE_OK; +} + +/* Attach routine */ +t_stat tarbell_attach(UNIT *uptr, CONST char *cptr) +{ + char header[4]; + t_stat r; + unsigned int i = 0; + + DBG_PRINT(("TARBELL: ATTACH" NLP)); + + r = attach_unit(uptr, cptr); /* attach unit */ + if(r != SCPE_OK) { /* error? */ + DBG_PRINT(("TARBELL: ATTACH error=%d" NLP, r)); + return r; + } + + /* Determine length of this disk */ + if(sim_fsize(uptr->fileref) != 0) { + uptr->capac = sim_fsize(uptr->fileref); + } else { + uptr->capac = TARBELL_CAPACITY; + } + + DBG_PRINT(("TARBELL: ATTACH uptr->capac=%d" NLP, uptr->capac)); + + for (i = 0; i < TARBELL_MAX_DRIVES; i++) { + tarbell_info->uptr[i] = &tarbell_dev.units[i]; + } + + for (i = 0; i < TARBELL_MAX_DRIVES; i++) { + if(tarbell_dev.units[i].fileref == uptr->fileref) { + break; + } + } + + /* Default for new file is DSK */ + uptr->u3 = IMAGE_TYPE_DSK; + + if(uptr->capac > 0) { + char *rtn = fgets(header, 4, uptr->fileref); + if((rtn != NULL) && (strncmp(header, "CPT", 3) == 0)) { + sim_printf("CPT images not yet supported" NLP); + uptr->u3 = IMAGE_TYPE_CPT; + tarbell_detach(uptr); + return SCPE_OPENERR; + } else { + uptr->u3 = IMAGE_TYPE_DSK; + } + } + + if (uptr->flags & UNIT_TARBELL_VERBOSE) { + sim_printf(TARBELL_SNAME "%d, attached to '%s', type=%s, len=%d" NLP, i, cptr, + uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + } + + return SCPE_OK; +} + + +/* Detach routine */ +t_stat tarbell_detach(UNIT *uptr) +{ + t_stat r; + int8 i; + + for (i = 0; i < TARBELL_MAX_DRIVES; i++) { + if(tarbell_dev.units[i].fileref == uptr->fileref) { + break; + } + } + + if (i >= TARBELL_MAX_DRIVES) { + return SCPE_ARG; + } + + DBG_PRINT(("Detach TARBELL%d\n", i)); + + r = detach_unit(uptr); /* detach unit */ + + if (r != SCPE_OK) { + return r; + } + + tarbell_dev.units[i].fileref = NULL; + + if (uptr->flags & UNIT_TARBELL_VERBOSE) { + sim_printf(TARBELL_SNAME "%d detached." NLP, i); + } + + return SCPE_OK; +} + +static t_stat tarbell_set_prom(UNIT *uptr, int32 value, CONST char *cptr, void *desc) +{ + tarbell_info->promEnabled = (uint8) value; + + return SCPE_OK; +} + +static t_stat tarbell_boot(int32 unitno, DEVICE *dptr) +{ + + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + DBG_PRINT(("Booting TARBELL Controller at 0x%04x" NLP, pnp->mem_base)); + + *((int32 *) sim_PC->loc) = pnp->mem_base; + + return SCPE_OK; +} + +static int32 tarbelldev(const int32 Addr, const int32 rw, const int32 data) +{ + if (rw == 0) { /* Read */ + return(TARBELL_Read(Addr)); + } else { /* Write */ + return(TARBELL_Write(Addr, data)); + } +} + +static void showdata(int32 isRead) { + int32 i; + sim_debug(RD_DATA_DETAIL_MSG|WR_DATA_DETAIL_MSG, &tarbell_dev, TARBELL_SNAME ": %s sector:" NLP "\t", isRead ? "Read" : "Write"); + for (i=0; i < TARBELL_SECTOR_LEN; i++) { + sim_debug(RD_DATA_DETAIL_MSG|WR_DATA_DETAIL_MSG, &tarbell_dev, "%02X ", sdata[i]); + if (((i+1) & 0xf) == 0) { + sim_debug(RD_DATA_DETAIL_MSG|WR_DATA_DETAIL_MSG, &tarbell_dev, NLP "\t"); + } + } + sim_debug(RD_DATA_DETAIL_MSG|WR_DATA_DETAIL_MSG, &tarbell_dev, NLP); +} + +static void showregs(FD1771_REG *pFD1771) +{ + DBG_PRINT(("TARBELL: DRV=%d PE=%d AA=%d RA=%d WA=%d DC=%03d CMD=%02Xh DATA=%02Xh TRK=%03d SEC=%03d STAT=%02X" NLP, + tarbell_info->currentDrive, tarbell_info->promEnabled, pFD1771->addrActive, pFD1771->readActive, pFD1771->writeActive, pFD1771->dataCount, + pFD1771->command, pFD1771->data, pFD1771->track, pFD1771->sector, pFD1771->status)); +} + + +static uint32 calculate_tarbell_sec_offset(uint8 track, uint8 sector) +{ + uint32 offset; + + offset = ((track * (TARBELL_SECTOR_LEN * TARBELL_SECTORS_PER_TRACK)) + ((sector-1) * TARBELL_SECTOR_LEN)); + + DBG_PRINT(("TARBELL: CALC track=%d sector=%d offset=%04X" NLP, track, sector, offset)); + + return (offset); +} + +static uint8 TARBELL_Read(const uint32 Addr) +{ + uint8 cData; + uint8 driveNum; + FD1771_REG *pFD1771; + UNIT *uptr; + int32 rtn; + + cData = 0; + uptr = tarbell_info->uptr[tarbell_info->currentDrive]; + pFD1771 = &tarbell_info->FD1771; + + switch(Addr & 0x07) { + case TARBELL_REG_STATUS: + cData = pFD1771->status; + break; + + case TARBELL_REG_TRACK: + cData = pFD1771->track; + break; + + case TARBELL_REG_DATA: + /* + ** If a READ operation is currently active, get the next byte + */ + if (pFD1771->readActive) { + /* Store byte in DATA register */ + pFD1771->data = sdata[pFD1771->dataCount++]; + + /* If we reached the end of the sector, terminate command and set INTRQ */ + if (pFD1771->dataCount == TARBELL_SECTOR_LEN) { + pFD1771->readActive = FALSE; + pFD1771->dataCount = 0; + pFD1771->status = 0x00; + pFD1771->intrq = TRUE; + + showregs(pFD1771); + } + else { + pFD1771->status |= FD1771_STAT_DRQ; /* Another byte is ready */ + } + + } + else if (pFD1771->addrActive) { + /* Store byte in DATA register */ + pFD1771->data = sdata[pFD1771->dataCount++]; + + DBG_PRINT(("TARBELL: READ ADDR data=%03d" NLP, pFD1771->data)); + + /* If we reached the end of the address data, terminate command and set INTRQ */ + if (pFD1771->dataCount > TARBELL_ADDR_CRC2) { + pFD1771->addrActive = FALSE; + pFD1771->status = 0x00; + pFD1771->intrq = TRUE; + + showregs(pFD1771); + } + else { + pFD1771->status |= FD1771_STAT_DRQ; /* Another byte is ready */ + } + } + + cData = pFD1771->data; + break; + + case TARBELL_REG_SECTOR: + cData = pFD1771->sector; + break; + + case TARBELL_REG_EXT: + cData = (pFD1771->intrq) ? 0x00 : 0x80; /* Bit 7 True if DRQ */ + break; + + default: + DBG_PRINT(("TARBELL: READ INVALID Address %02x (%02x)" NLP, Addr & 0xFF, Addr & 0x07)); + cData = 0xff; + break; + } + + return (cData); +} + +static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) +{ + uint8 cData; + uint8 driveNum; + int32 rtn; + UNIT *uptr; + FD1771_REG *pFD1771; + + DBG_PRINT(("TARBELL: WRITE Address %02x Data %02x" NLP, Addr & 0xFF, Data & 0xFF)); + + cData = 0; + uptr = tarbell_info->uptr[tarbell_info->currentDrive]; + pFD1771 = &tarbell_info->FD1771; + + switch(Addr & 0x07) { + case TARBELL_REG_COMMAND: + cData = TARBELL_Command(uptr, pFD1771, Data); + break; + + case TARBELL_REG_DATA: + pFD1771->data = Data; /* Store byte in DATA register */ + + if (pFD1771->writeActive) { + + /* Store DATA register in Sector Buffer */ + sdata[pFD1771->dataCount++] = pFD1771->data; + + /* If we reached the end of the sector, write sector, terminate command and set INTRQ */ + if (pFD1771->dataCount == TARBELL_SECTOR_LEN) { + pFD1771->status = 0x00; /* Clear Status Bits */ + + rtn = TARBELL_WriteSector(uptr, pFD1771->track, pFD1771->sector, sdata); + + if (rtn != TARBELL_SECTOR_LEN) { + pFD1771->status |= FD1771_STAT_WRITEFAULT; + } + pFD1771->writeActive = FALSE; + pFD1771->dataCount = 0; + pFD1771->intrq = TRUE; + + showregs(pFD1771); + } + else { + pFD1771->status |= FD1771_STAT_DRQ; /* Ready for another byte */ + } + + } + else if (pFD1771->writeTrkActive) { + + /* + ** Increment number for bytes written to track + */ + pFD1771->trkCount++; + + if (pFD1771->data == 0xE5) { + + /* Store DATA register in Sector Buffer */ + sdata[pFD1771->dataCount++] = pFD1771->data; + + /* If we reached the end of the sector, write sector, terminate command and set INTRQ */ + if (pFD1771->dataCount == TARBELL_SECTOR_LEN) { + pFD1771->status &= ~FD1771_STAT_WRITEFAULT; /* Clear Status Bit */ + + rtn = TARBELL_WriteSector(uptr, pFD1771->track, pFD1771->sector, sdata); + + if (rtn != TARBELL_SECTOR_LEN) { + pFD1771->status |= FD1771_STAT_WRITEFAULT; + } + + pFD1771->sector++; + pFD1771->dataCount = 0; + pFD1771->status &= ~FD1771_STAT_BUSY; /* Clear BUSY Bit */ + + DBG_PRINT(("TARBELL: WRITE TRACK track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X" NLP, pFD1771->track, pFD1771->sector, pFD1771->trkCount, pFD1771->dataCount, pFD1771->data, pFD1771->status)); + + showregs(pFD1771); + } + } + + if (pFD1771->trkCount < TARBELL_BYTES_PER_TRACK) { + pFD1771->status |= FD1771_STAT_DRQ; /* Ready for another byte */ + } + else { + pFD1771->status = 0x00; /* Clear Status Bits */ + pFD1771->intrq = TRUE; /* Simulate reaching index hole */ + DBG_PRINT(("TARBELL: WRITE TRACK track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X" NLP, pFD1771->track, pFD1771->sector, pFD1771->trkCount, pFD1771->dataCount, pFD1771->data, pFD1771->status)); + } + +// showregs(pFD1771); + } + + DBG_PRINT(("TARBELL: WRITE DATA REG %02X" NLP, Data)); + break; + + case TARBELL_REG_TRACK: + pFD1771->track = Data; + DBG_PRINT(("TARBELL: TRACK REG=%d" NLP, pFD1771->track)); + break; + + case TARBELL_REG_SECTOR: + if (Data > TARBELL_SECTORS_PER_TRACK) { + pFD1771->sector = 1; + } + + pFD1771->sector = Data; + + DBG_PRINT(("TARBELL: SECTOR REG=%d" NLP, pFD1771->sector)); + + break; + + case TARBELL_REG_EXT: + cData = ~(Data >> 4) & 0x03; + if (cData < TARBELL_MAX_DRIVES) { + tarbell_info->currentDrive = cData; + } + else { + DBG_PRINT(("TARBELL: INVALID drive=%02x (%02x)" NLP, Data, cData)); + } + break; + + default: + DBG_PRINT(("TARBELL: INVALID Address %02x (%02x)" NLP, Addr & 0xFF, Addr & 0x07)); + cData = 0xff; + break; + } + + DBG_PRINT(("TARBELL: COMPLETE currentDrive=%d sector=%02x data=%02x" NLP, tarbell_info->currentDrive, pFD1771->sector, pFD1771->data)); + + return(cData); +} + +static uint32 TARBELL_ReadSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer) +{ + uint32 sec_offset; + uint32 rtn = 0; + + if (uptr->fileref == NULL) { + DBG_PRINT((".fileref is NULL!" NLP)); + return 0; + } + + sec_offset = calculate_tarbell_sec_offset(track, sector); + + DBG_PRINT(("TARBELL: READSEC track %d sector %d at offset %04X" NLP, track, sector, sec_offset)); + + if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) { + DBG_PRINT(("TARBELL: " ADDRESS_FORMAT " READ: sim_fseek error." NLP, PCX)); + return 0; + } + + rtn = sim_fread(buffer, 1, TARBELL_SECTOR_LEN, uptr->fileref); + + return rtn; +} + + +static uint32 TARBELL_WriteSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer) +{ + uint32 sec_offset; + uint32 rtn = 0; + + if (uptr->fileref == NULL) { + DBG_PRINT((".fileref is NULL!" NLP)); + return 0; + } + + sec_offset = calculate_tarbell_sec_offset(track, sector); + + DBG_PRINT(("TARBELL: WRTSEC track %d sector %d at offset %04X" NLP, track, sector, sec_offset)); + + if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) { + DBG_PRINT(("TARBELL: " ADDRESS_FORMAT " READ: sim_fseek error." NLP, PCX)); + return 0; + } + + rtn = sim_fwrite(buffer, 1, TARBELL_SECTOR_LEN, uptr->fileref); + + return rtn; +} + + +static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) +{ + uint8 cData; + uint8 newTrack; + uint8 statusUpdate; + int32 rtn; + + cData = 0; + rtn=0; + statusUpdate = TRUE; + + DBG_PRINT(("TARBELL: COMMAND Data=%02x" NLP, Data & 0xFF)); + + pFD1771->command = (Data & 0xF0); + + pFD1771->status |= FD1771_STAT_BUSY; + pFD1771->intrq = FALSE; + + /* + ** Type II-IV Command + */ + if (pFD1771->command & 0x80) { + pFD1771->readActive = FALSE; + pFD1771->writeActive = FALSE; + pFD1771->readTrkActive = FALSE; + pFD1771->writeTrkActive = FALSE; + pFD1771->addrActive = FALSE; + pFD1771->dataCount = 0; + + pFD1771->status &= ~FD1771_STAT_DRQ; /* Reset DRQ */ + } + + /* + ** Set BUSY for all but Force Interrupt + */ + if ((pFD1771->command & TARBELL_CMD_FORCE_INTR) == TARBELL_CMD_FORCE_INTR) { + pFD1771->status |= FD1771_STAT_BUSY; + } + + switch(pFD1771->command) { + case TARBELL_CMD_RESTORE: + pFD1771->track = 0; + + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": RESTORE track=%03d" NLP, pFD1771->track); + + pFD1771->status &= ~FD1771_STAT_SEEKERROR; + pFD1771->status &= ~FD1771_STAT_BUSY; + pFD1771->status &= ~FD1771_STAT_DRQ; + pFD1771->intrq = TRUE; + break; + + case TARBELL_CMD_SEEK: + newTrack = pFD1771->data; + + DBG_PRINT(("TARBELL: TRACK DATA=%d (SEEK)" NLP, newTrack)); + + pFD1771->status &= ~FD1771_STAT_SEEKERROR; + + if (newTrack < TARBELL_TRACKS) { + pFD1771->track = newTrack; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": SEEK track=%03d" NLP, pFD1771->track); + } + else { + pFD1771->status |= FD1771_STAT_SEEKERROR; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": SEEK ERR track=%03d" NLP, newTrack); + } + + pFD1771->status &= ~FD1771_STAT_BUSY; + pFD1771->status &= ~FD1771_STAT_DRQ; + pFD1771->intrq = TRUE; + break; + + case TARBELL_CMD_STEP: + case TARBELL_CMD_STEPU: + pFD1771->status &= ~FD1771_STAT_SEEKERROR; + + newTrack = pFD1771->track + pFD1771->stepDir; + + if (newTrack < TARBELL_TRACKS-1) { + pFD1771->track = newTrack; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP track=%03d" NLP, pFD1771->track); + } + else { + pFD1771->status |= FD1771_STAT_SEEKERROR; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP ERR track=%03d" NLP, newTrack); + } + + pFD1771->status &= ~FD1771_STAT_BUSY; + pFD1771->status &= ~FD1771_STAT_DRQ; + pFD1771->intrq = TRUE; + break; + + case TARBELL_CMD_STEPIN: + case TARBELL_CMD_STEPINU: + pFD1771->status &= ~FD1771_STAT_SEEKERROR; + + if (pFD1771->track < TARBELL_TRACKS) { + pFD1771->track++; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN track=%03d" NLP, pFD1771->track); + } + else { + pFD1771->status |= FD1771_STAT_SEEKERROR; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN ERR track=%03d" NLP, pFD1771->track+1); + } + + pFD1771->stepDir = 1; + pFD1771->status &= ~FD1771_STAT_BUSY; + pFD1771->status &= ~FD1771_STAT_DRQ; + pFD1771->intrq = TRUE; + break; + + case TARBELL_CMD_STEPOUT: + case TARBELL_CMD_STEPOUTU: + pFD1771->status &= ~FD1771_STAT_SEEKERROR; + + if (pFD1771->track > 0) { + pFD1771->track--; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT track=%03d" NLP, pFD1771->track); + } + else { + pFD1771->status |= FD1771_STAT_SEEKERROR; + sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT ERR track=%03d" NLP, pFD1771->track-1); + } + + pFD1771->stepDir = -1; + pFD1771->status &= ~FD1771_STAT_BUSY; + pFD1771->status &= ~FD1771_STAT_DRQ; + pFD1771->intrq = TRUE; + break; + + case TARBELL_CMD_READ: + + if ((uptr == NULL) || (uptr->fileref == NULL)) { + DBG_PRINT(("TARBELL: " ADDRESS_FORMAT + " Drive: %d not attached - read ignored." NLP, + PCX, tarbell_info->currentDrive)); + + pFD1771->status &= ~FD1771_STAT_BUSY; + + return cData; + } + + rtn = TARBELL_ReadSector(uptr, pFD1771->track, pFD1771->sector, sdata); + + if (rtn == TARBELL_SECTOR_LEN) { + pFD1771->readActive = TRUE; + + showdata(TRUE); + } + else { + DBG_PRINT(("TARBELL: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX)); + + pFD1771->status |= FD1771_STAT_NOTFOUND; + pFD1771->intrq = TRUE; + } + + break; + + case TARBELL_CMD_WRITE: + if ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) { + DBG_PRINT((TARBELL_SNAME ": Disk write protected. uptr->flags=%04x writeProtect=%04x" NLP, uptr->flags & UNIT_TARBELL_WPROTECT, tarbell_info->writeProtect)); + pFD1771->intrq = TRUE; + } + else { + pFD1771->writeActive = TRUE; + pFD1771->dataCount = 0; + pFD1771->status |= FD1771_STAT_DRQ; /* Set DRQ */ + } + + break; + + case TARBELL_CMD_READ_ADDRESS: + sdata[TARBELL_ADDR_TRACK]=pFD1771->track; + sdata[TARBELL_ADDR_ZEROS]=0; + sdata[TARBELL_ADDR_SECTOR]=pFD1771->sector; + sdata[TARBELL_ADDR_LENGTH]=TARBELL_SECTOR_LEN; + sdata[TARBELL_ADDR_CRC1]=0; + sdata[TARBELL_ADDR_CRC2]=0; + + pFD1771->addrActive = TRUE; + pFD1771->status |= FD1771_STAT_DRQ; /* Set DRQ */ + + break; + + case TARBELL_CMD_READ_TRACK: + pFD1771->readTrkActive = TRUE; + pFD1771->trkCount=0; + pFD1771->dataCount=0; + pFD1771->sector=1; + pFD1771->status |= FD1771_STAT_DRQ; /* Set DRQ */ + break; + + case TARBELL_CMD_WRITE_TRACK: + if ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) { + DBG_PRINT((TARBELL_SNAME ": Disk write protected. uptr->flags=%04x writeProtect=%04x" NLP, uptr->flags & UNIT_TARBELL_WPROTECT, tarbell_info->writeProtect)); + pFD1771->intrq = TRUE; + } + else { + pFD1771->writeTrkActive = TRUE; + pFD1771->trkCount=0; + pFD1771->dataCount=0; + pFD1771->sector=1; + pFD1771->status |= FD1771_STAT_DRQ; /* Set DRQ */ + } + break; + + case TARBELL_CMD_FORCE_INTR: + if (pFD1771->status & FD1771_STAT_BUSY) { + pFD1771->status &= ~FD1771_STAT_BUSY; + statusUpdate = FALSE; + } + + /* Reset Status */ + pFD1771->dataCount = 0; + pFD1771->readActive = FALSE; + pFD1771->readTrkActive = FALSE; + pFD1771->writeActive = FALSE; + pFD1771->writeTrkActive = FALSE; + pFD1771->addrActive = FALSE; + + break; + + default: + cData=0xFF; + sim_debug(ERROR_MSG, &tarbell_dev, "TARBELL: UNRECOGNIZED CMD %02X" NLP, pFD1771->command); + break; + } + + /**************************/ + /* Update Status Register */ + /**************************/ + + switch(pFD1771->command) { + case TARBELL_CMD_RESTORE: + case TARBELL_CMD_SEEK: + case TARBELL_CMD_STEP: + case TARBELL_CMD_STEPU: + case TARBELL_CMD_STEPIN: + case TARBELL_CMD_STEPINU: + case TARBELL_CMD_STEPOUT: + case TARBELL_CMD_STEPOUTU: + case TARBELL_CMD_FORCE_INTR: + if (statusUpdate) { + pFD1771->status &= ~FD1771_STAT_WRITEPROT; + pFD1771->status &= ~FD1771_STAT_HEADLOAD; + pFD1771->status &= ~FD1771_STAT_CRCERROR; + pFD1771->status &= ~FD1771_STAT_TRACK0; + pFD1771->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD1771_STAT_WRITEPROT : 0x00; + pFD1771->status |= (pFD1771->track) ? 0x00 : FD1771_STAT_TRACK0; + pFD1771->status |= FD1771_STAT_INDEX; + } + break; + + case TARBELL_CMD_READ: + pFD1771->status &= ~FD1771_STAT_LOSTDATA; + pFD1771->status &= ~FD1771_STAT_NOTFOUND; + pFD1771->status &= ~FD1771_STAT_CRCERROR; + break; + + case TARBELL_CMD_WRITE: + pFD1771->status &= ~FD1771_STAT_WRITEPROT; + pFD1771->status &= ~FD1771_STAT_LOSTDATA; + pFD1771->status &= ~FD1771_STAT_NOTFOUND; + pFD1771->status &= ~FD1771_STAT_CRCERROR; + pFD1771->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD1771_STAT_WRITEPROT : 0x00; + break; + + case TARBELL_CMD_READ_ADDRESS: + pFD1771->status &= ~FD1771_STAT_LOSTDATA; + pFD1771->status &= ~FD1771_STAT_NOTFOUND; + pFD1771->status &= ~FD1771_STAT_CRCERROR; + break; + + case TARBELL_CMD_READ_TRACK: + pFD1771->status &= ~FD1771_STAT_LOSTDATA; + pFD1771->status &= ~FD1771_STAT_NOTFOUND; + pFD1771->status &= ~FD1771_STAT_CRCERROR; + break; + + case TARBELL_CMD_WRITE_TRACK: + pFD1771->status &= ~FD1771_STAT_WRITEPROT; + pFD1771->status &= ~FD1771_STAT_LOSTDATA; + pFD1771->status &= ~FD1771_STAT_NOTFOUND; + pFD1771->status &= ~FD1771_STAT_WRITEFAULT; + pFD1771->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD1771_STAT_WRITEPROT : 0x00; + break; + } + + DBG_PRINT(("TARBELL: COMPLETE track=%d sector=%d status=%02x" NLP, pFD1771->track, pFD1771->sector, pFD1771->status)); + + return(cData); +} + +static int32 tarbellprom(const int32 Addr, const int32 rw, const int32 Data) +{ +/* DBG_PRINT(("TARBELL: ROM %s, Addr %04x" NLP, rw ? "WR" : "RD", Addr)); */ + + /* + ** The Tarbell controller overlays the first 32 bytes of RAM with a PROM. + ** The PROM is enabled/disabled with switch position 7: + ** ON = ENABLED + ** OFF = DISABLED + ** + ** If the PROM is enabled, writes to 0x0000-0x001F are written to RAM + ** The PROM is disabled if the controller detects a memory read with bit A5 enabled, + ** which can't be implemented because Examine reads 6 bytes at a time. We will disable + ** PROM if address 0x0025 is read. Hack. + */ + + if (rw == TARBELL_PROM_WRITE) { + tarbell_ram[Addr & TARBELL_RAM_MASK] = Data; + return 0; + } else { + if (Addr >= 0x0025 && tarbell_info->promEnabled == TRUE) { + tarbell_info->promEnabled = FALSE; + DBG_PRINT(("TARBELL: disabled PROM" NLP)); + } + + if (tarbell_info->promEnabled == TRUE && Addr < TARBELL_PROM_SIZE) { +/* DBG_PRINT(("TARBELL: reading PROM" NLP)); */ + return(tarbell_prom[Addr & TARBELL_PROM_MASK]); + } else { +/* DBG_PRINT(("TARBELL: reading RAM" NLP)); */ + return(tarbell_ram[Addr & TARBELL_RAM_MASK]); + } + } +} + diff --git a/makefile b/makefile index ba1d9c76..895e5fd4 100644 --- a/makefile +++ b/makefile @@ -1688,6 +1688,7 @@ ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \ ${ALTAIRZ80D}/s100_mdsad.c ${ALTAIRZ80D}/s100_selchan.c \ ${ALTAIRZ80D}/s100_ss1.c ${ALTAIRZ80D}/s100_64fdc.c \ ${ALTAIRZ80D}/s100_scp300f.c \ + ${ALTAIRZ80D}/s100_tarbell.c \ ${ALTAIRZ80D}/wd179x.c ${ALTAIRZ80D}/s100_hdc1001.c \ ${ALTAIRZ80D}/s100_if3.c ${ALTAIRZ80D}/s100_adcs6.c \ ${ALTAIRZ80D}/m68kcpu.c ${ALTAIRZ80D}/m68kdasm.c \ @@ -2102,7 +2103,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ scelbi 3b2 i701 i704 i7010 i7070 i7080 i7090 \ sigma uc15 pdp10-ka pdp10-ki pdp6 -all : ${ALL} +all : altairz80 EXPERIMENTAL = cdc1700 From 6efda7cbea9dc1e7118891b62b4fc3f33a01b011 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Thu, 5 Dec 2019 17:02:27 -0800 Subject: [PATCH 02/11] Clean up DBG_PRING and sim_debug messages. --- AltairZ80/s100_tarbell.c | 49 ++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index 9242534e..11baa408 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -296,12 +296,12 @@ t_stat tarbell_reset(DEVICE *dptr) sim_map_resource(pInfo->pnp.io_base, pInfo->pnp.io_size, RESOURCE_TYPE_IO, &tarbelldev, TRUE); } else { if(sim_map_resource(pInfo->pnp.mem_base, pInfo->pnp.mem_size, RESOURCE_TYPE_MEMORY, &tarbellprom, FALSE) != 0) { - DBG_PRINT(("%s: error mapping MEM resource at 0x%04x" NLP, __FUNCTION__, pInfo->pnp.mem_base)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": Error mapping MEM resource at 0x%04x" NLP, pInfo->pnp.mem_base); return SCPE_ARG; } /* Connect I/O Ports at base address */ if(sim_map_resource(pInfo->pnp.io_base, pInfo->pnp.io_size, RESOURCE_TYPE_IO, &tarbelldev, FALSE) != 0) { - DBG_PRINT(("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pInfo->pnp.io_base)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": Error mapping I/O resource at 0x%02x" NLP, pInfo->pnp.io_base); return SCPE_ARG; } } @@ -337,11 +337,9 @@ t_stat tarbell_attach(UNIT *uptr, CONST char *cptr) t_stat r; unsigned int i = 0; - DBG_PRINT(("TARBELL: ATTACH" NLP)); - r = attach_unit(uptr, cptr); /* attach unit */ if(r != SCPE_OK) { /* error? */ - DBG_PRINT(("TARBELL: ATTACH error=%d" NLP, r)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": ATTACH error=%d" NLP, r); return r; } @@ -434,7 +432,7 @@ static t_stat tarbell_boot(int32 unitno, DEVICE *dptr) PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; - DBG_PRINT(("Booting TARBELL Controller at 0x%04x" NLP, pnp->mem_base)); + sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Booting Controller at 0x%04x" NLP, pnp->mem_base); *((int32 *) sim_PC->loc) = pnp->mem_base; @@ -555,7 +553,7 @@ static uint8 TARBELL_Read(const uint32 Addr) break; default: - DBG_PRINT(("TARBELL: READ INVALID Address %02x (%02x)" NLP, Addr & 0xFF, Addr & 0x07)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READ Invalid I/O Address %02x (%02x)" NLP, Addr & 0xFF, Addr & 0x07); cData = 0xff; break; } @@ -648,7 +646,7 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) else { pFD1771->status = 0x00; /* Clear Status Bits */ pFD1771->intrq = TRUE; /* Simulate reaching index hole */ - DBG_PRINT(("TARBELL: WRITE TRACK track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X" NLP, pFD1771->track, pFD1771->sector, pFD1771->trkCount, pFD1771->dataCount, pFD1771->data, pFD1771->status)); + sim_debug(WR_DATA_MSG, &tarbell_dev, TARBELL_SNAME ": WRITE TRACK track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X" NLP, pFD1771->track, pFD1771->sector, pFD1771->trkCount, pFD1771->dataCount, pFD1771->data, pFD1771->status); } // showregs(pFD1771); @@ -679,12 +677,12 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) tarbell_info->currentDrive = cData; } else { - DBG_PRINT(("TARBELL: INVALID drive=%02x (%02x)" NLP, Data, cData)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": Invalid Drive Number drive=%02x (%02x)" NLP, Data, cData); } break; default: - DBG_PRINT(("TARBELL: INVALID Address %02x (%02x)" NLP, Addr & 0xFF, Addr & 0x07)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": WRITE Invalid I/O Address %02x (%02x)" NLP, Addr & 0xFF, Addr & 0x07); cData = 0xff; break; } @@ -700,16 +698,16 @@ static uint32 TARBELL_ReadSector(UNIT *uptr, uint16 track, uint16 sector, uint8 uint32 rtn = 0; if (uptr->fileref == NULL) { - DBG_PRINT((".fileref is NULL!" NLP)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC uptr.fileref is NULL!" NLP); return 0; } sec_offset = calculate_tarbell_sec_offset(track, sector); - DBG_PRINT(("TARBELL: READSEC track %d sector %d at offset %04X" NLP, track, sector, sec_offset)); + sim_debug(RD_DATA_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC track %03d sector %03d at offset %04X" NLP, track, sector, sec_offset); if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) { - DBG_PRINT(("TARBELL: " ADDRESS_FORMAT " READ: sim_fseek error." NLP, PCX)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC sim_fseek error." NLP); return 0; } @@ -725,16 +723,16 @@ static uint32 TARBELL_WriteSector(UNIT *uptr, uint16 track, uint16 sector, uint8 uint32 rtn = 0; if (uptr->fileref == NULL) { - DBG_PRINT((".fileref is NULL!" NLP)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC uptr.fileref is NULL!" NLP); return 0; } sec_offset = calculate_tarbell_sec_offset(track, sector); - DBG_PRINT(("TARBELL: WRTSEC track %d sector %d at offset %04X" NLP, track, sector, sec_offset)); + sim_debug(WR_DATA_MSG, &tarbell_dev, TARBELL_SNAME ": WRITESEC track %03d sector %03d at offset %04X" NLP, track, sector, sec_offset); if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) { - DBG_PRINT(("TARBELL: " ADDRESS_FORMAT " READ: sim_fseek error." NLP, PCX)); + sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": WRITESEC sim_fseek error." NLP); return 0; } @@ -755,8 +753,6 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) rtn=0; statusUpdate = TRUE; - DBG_PRINT(("TARBELL: COMMAND Data=%02x" NLP, Data & 0xFF)); - pFD1771->command = (Data & 0xF0); pFD1771->status |= FD1771_STAT_BUSY; @@ -1032,25 +1028,26 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) break; } - DBG_PRINT(("TARBELL: COMPLETE track=%d sector=%d status=%02x" NLP, pFD1771->track, pFD1771->sector, pFD1771->status)); + sim_debug(CMD_MSG, &tarbell_dev, TARBELL_SNAME ": CMD cmd=%02X track=%03d sector=%03d status=%02X" NLP, + pFD1771->command, pFD1771->track, pFD1771->sector, pFD1771->status); return(cData); } static int32 tarbellprom(const int32 Addr, const int32 rw, const int32 Data) { -/* DBG_PRINT(("TARBELL: ROM %s, Addr %04x" NLP, rw ? "WR" : "RD", Addr)); */ - /* ** The Tarbell controller overlays the first 32 bytes of RAM with a PROM. ** The PROM is enabled/disabled with switch position 7: ** ON = ENABLED ** OFF = DISABLED ** - ** If the PROM is enabled, writes to 0x0000-0x001F are written to RAM + ** If the PROM is enabled, writes to 0x0000-0x001F are written to RAM, reads are + ** from the PROM. + ** ** The PROM is disabled if the controller detects a memory read with bit A5 enabled, ** which can't be implemented because Examine reads 6 bytes at a time. We will disable - ** PROM if address 0x0025 is read. Hack. + ** the PROM if address >= 0x0025 is read. Hack. */ if (rw == TARBELL_PROM_WRITE) { @@ -1058,15 +1055,13 @@ static int32 tarbellprom(const int32 Addr, const int32 rw, const int32 Data) return 0; } else { if (Addr >= 0x0025 && tarbell_info->promEnabled == TRUE) { - tarbell_info->promEnabled = FALSE; - DBG_PRINT(("TARBELL: disabled PROM" NLP)); + tarbell_info->promEnabled = FALSE; + sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Boot PROM disabled." NLP); } if (tarbell_info->promEnabled == TRUE && Addr < TARBELL_PROM_SIZE) { -/* DBG_PRINT(("TARBELL: reading PROM" NLP)); */ return(tarbell_prom[Addr & TARBELL_PROM_MASK]); } else { -/* DBG_PRINT(("TARBELL: reading RAM" NLP)); */ return(tarbell_ram[Addr & TARBELL_RAM_MASK]); } } From 91b6807499aa6ce9a2bb150a348309ca109cd465 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Thu, 5 Dec 2019 19:40:29 -0800 Subject: [PATCH 03/11] Added head load/unload with unload timer --- AltairZ80/s100_tarbell.c | 121 ++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 13 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index 11baa408..14c43d5e 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -42,6 +42,8 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ #define TARBELL_BYTES_PER_TRACK ((TARBELL_SECTORS_PER_TRACK * 186) + 73 + 247) #define TARBELL_TRACKS 77 #define TARBELL_CAPACITY (256256) /* Default Tarbell Disk Capacity */ +#define TARBELL_ROTATION_MS 50 +#define TARBELL_HEAD_TIMEOUT (TARBELL_ROTATION_MS * 2) #define TARBELL_PROM_SIZE 32 #define TARBELL_PROM_MASK (TARBELL_PROM_SIZE-1) @@ -78,6 +80,9 @@ typedef struct { uint8 writeActive; /* Write Active */ uint8 writeTrkActive; /* Write Track Active */ uint8 addrActive; /* Address Active */ + uint8 driveNotReady; /* Drive Not Ready */ + uint8 headLoaded; /* Head Loaded */ + uint32 headUnlTime; /* Time to unload head */ } FD1771_REG; #define FD1771_STAT_NOTREADY 0x80 @@ -175,10 +180,12 @@ static uint32 stepCleared = TRUE; /* true when step bit has returned to zero * /* Local function prototypes */ static t_stat tarbell_reset(DEVICE *tarbell_dev); +static t_stat tarbell_svc(UNIT *uptr); static t_stat tarbell_attach(UNIT *uptr, CONST char *cptr); static t_stat tarbell_detach(UNIT *uptr); static t_stat tarbell_boot(int32 unitno, DEVICE *dptr); static t_stat tarbell_set_prom(UNIT *uptr, int32 value, CONST char *cptr, void *desc); +static void TARBELL_HeadLoad(UNIT *uptr, FD1771_REG *pFD1771, uint8 load); static uint8 TARBELL_Read(const uint32 Addr); static uint8 TARBELL_Write(const uint32 Addr, int32 data); static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 data); @@ -192,10 +199,10 @@ static int32 tarbelldev(const int32 Addr, const int32 rw, const int32 data); static int32 tarbellprom(const int32 Addr, const int32 rw, const int32 data); static UNIT tarbell_unit[TARBELL_MAX_DRIVES] = { - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY) } + { UDATA (tarbell_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY), 10000 }, + { UDATA (tarbell_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY), 10000 }, + { UDATA (tarbell_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY), 10000 }, + { UDATA (tarbell_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY), 10000 } }; static REG tarbell_reg[] = { @@ -326,6 +333,27 @@ t_stat tarbell_reset(DEVICE *dptr) pInfo->FD1771.writeActive = FALSE; pInfo->FD1771.writeTrkActive = FALSE; pInfo->FD1771.addrActive = FALSE; + pInfo->FD1771.headLoaded = FALSE; + pInfo->FD1771.driveNotReady = TRUE; + + return SCPE_OK; +} + +static t_stat tarbell_svc(UNIT *uptr) +{ + uint32 now; + + /* + ** Get current msec time + */ + now = sim_os_msec(); + + if (now < tarbell_info->FD1771.headUnlTime) { + sim_activate(uptr, 100000); /* restart timer */ + } + else if (tarbell_info->FD1771.headLoaded == TRUE) { + TARBELL_HeadLoad(uptr, &tarbell_info->FD1771, FALSE); + } return SCPE_OK; } @@ -383,6 +411,11 @@ t_stat tarbell_attach(UNIT *uptr, CONST char *cptr) uptr->capac); } + /* + ** Clear Not Ready Flag + */ + tarbell_info->FD1771.driveNotReady = FALSE; + return SCPE_OK; } @@ -417,6 +450,11 @@ t_stat tarbell_detach(UNIT *uptr) sim_printf(TARBELL_SNAME "%d detached." NLP, i); } + /* + ** Set Not Ready Flag + */ + tarbell_info->FD1771.driveNotReady = TRUE; + return SCPE_OK; } @@ -479,6 +517,26 @@ static uint32 calculate_tarbell_sec_offset(uint8 track, uint8 sector) return (offset); } +static void TARBELL_HeadLoad(UNIT *uptr, FD1771_REG *pFD1771, uint8 load) +{ + sim_cancel(uptr); /* cancel timer */ + + if (load) { + pFD1771->headUnlTime = sim_os_msec() + TARBELL_HEAD_TIMEOUT; + sim_activate(uptr, 100000); /* activate timer */ + } + + if (load == TRUE && pFD1771->headLoaded == FALSE) { + sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Head Loaded." NLP); + } + + if (load == FALSE && pFD1771->headLoaded == TRUE) { + sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Head Unloaded." NLP); + } + + tarbell_info->FD1771.headLoaded = load; +} + static uint8 TARBELL_Read(const uint32 Addr) { uint8 cData; @@ -521,6 +579,7 @@ static uint8 TARBELL_Read(const uint32 Addr) pFD1771->status |= FD1771_STAT_DRQ; /* Another byte is ready */ } + TARBELL_HeadLoad(uptr, pFD1771, TRUE); } else if (pFD1771->addrActive) { /* Store byte in DATA register */ @@ -539,6 +598,8 @@ static uint8 TARBELL_Read(const uint32 Addr) else { pFD1771->status |= FD1771_STAT_DRQ; /* Another byte is ready */ } + + TARBELL_HeadLoad(uptr, pFD1771, TRUE); } cData = pFD1771->data; @@ -607,6 +668,7 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) pFD1771->status |= FD1771_STAT_DRQ; /* Ready for another byte */ } + TARBELL_HeadLoad(uptr, pFD1771, TRUE); } else if (pFD1771->writeTrkActive) { @@ -649,7 +711,7 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) sim_debug(WR_DATA_MSG, &tarbell_dev, TARBELL_SNAME ": WRITE TRACK track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X" NLP, pFD1771->track, pFD1771->sector, pFD1771->trkCount, pFD1771->dataCount, pFD1771->data, pFD1771->status); } -// showregs(pFD1771); + TARBELL_HeadLoad(uptr, pFD1771, TRUE); } DBG_PRINT(("TARBELL: WRITE DATA REG %02X" NLP, Data)); @@ -785,6 +847,10 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": RESTORE track=%03d" NLP, pFD1771->track); + if (Data & TARBELL_FLAG_H) { + TARBELL_HeadLoad(uptr, pFD1771, TRUE); + } + pFD1771->status &= ~FD1771_STAT_SEEKERROR; pFD1771->status &= ~FD1771_STAT_BUSY; pFD1771->status &= ~FD1771_STAT_DRQ; @@ -807,6 +873,10 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": SEEK ERR track=%03d" NLP, newTrack); } + if (Data & TARBELL_FLAG_H) { + TARBELL_HeadLoad(uptr, pFD1771, TRUE); + } + pFD1771->status &= ~FD1771_STAT_BUSY; pFD1771->status &= ~FD1771_STAT_DRQ; pFD1771->intrq = TRUE; @@ -819,7 +889,9 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) newTrack = pFD1771->track + pFD1771->stepDir; if (newTrack < TARBELL_TRACKS-1) { - pFD1771->track = newTrack; + if (Data & TARBELL_FLAG_U) { + pFD1771->track = newTrack; + } sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP track=%03d" NLP, pFD1771->track); } else { @@ -827,6 +899,10 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP ERR track=%03d" NLP, newTrack); } + if (Data & TARBELL_FLAG_H) { + TARBELL_HeadLoad(uptr, pFD1771, TRUE); + } + pFD1771->status &= ~FD1771_STAT_BUSY; pFD1771->status &= ~FD1771_STAT_DRQ; pFD1771->intrq = TRUE; @@ -837,7 +913,9 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) pFD1771->status &= ~FD1771_STAT_SEEKERROR; if (pFD1771->track < TARBELL_TRACKS) { - pFD1771->track++; + if (Data & TARBELL_FLAG_U) { + pFD1771->track++; + } sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN track=%03d" NLP, pFD1771->track); } else { @@ -845,6 +923,10 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN ERR track=%03d" NLP, pFD1771->track+1); } + if (Data & TARBELL_FLAG_H) { + TARBELL_HeadLoad(uptr, pFD1771, TRUE); + } + pFD1771->stepDir = 1; pFD1771->status &= ~FD1771_STAT_BUSY; pFD1771->status &= ~FD1771_STAT_DRQ; @@ -856,7 +938,9 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) pFD1771->status &= ~FD1771_STAT_SEEKERROR; if (pFD1771->track > 0) { - pFD1771->track--; + if (Data & TARBELL_FLAG_U) { + pFD1771->track--; + } sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT track=%03d" NLP, pFD1771->track); } else { @@ -864,6 +948,10 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT ERR track=%03d" NLP, pFD1771->track-1); } + if (Data & TARBELL_FLAG_H) { + TARBELL_HeadLoad(uptr, pFD1771, TRUE); + } + pFD1771->stepDir = -1; pFD1771->status &= ~FD1771_STAT_BUSY; pFD1771->status &= ~FD1771_STAT_DRQ; @@ -972,6 +1060,8 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) /* Update Status Register */ /**************************/ + pFD1771->status |= (pFD1771->driveNotReady) ? FD1771_STAT_NOTREADY : 0x00; + switch(pFD1771->command) { case TARBELL_CMD_RESTORE: case TARBELL_CMD_SEEK: @@ -984,12 +1074,12 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) case TARBELL_CMD_FORCE_INTR: if (statusUpdate) { pFD1771->status &= ~FD1771_STAT_WRITEPROT; - pFD1771->status &= ~FD1771_STAT_HEADLOAD; pFD1771->status &= ~FD1771_STAT_CRCERROR; pFD1771->status &= ~FD1771_STAT_TRACK0; pFD1771->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD1771_STAT_WRITEPROT : 0x00; pFD1771->status |= (pFD1771->track) ? 0x00 : FD1771_STAT_TRACK0; - pFD1771->status |= FD1771_STAT_INDEX; + pFD1771->status |= (pFD1771->headLoaded) ? FD1771_STAT_HEADLOAD : 0x00; + pFD1771->status |= FD1771_STAT_INDEX; /* Always set Index Flag if Drive Ready */ } break; @@ -1008,21 +1098,26 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) break; case TARBELL_CMD_READ_ADDRESS: + pFD1771->status &= ~0x20; + pFD1771->status &= ~0x40; pFD1771->status &= ~FD1771_STAT_LOSTDATA; pFD1771->status &= ~FD1771_STAT_NOTFOUND; pFD1771->status &= ~FD1771_STAT_CRCERROR; break; case TARBELL_CMD_READ_TRACK: + pFD1771->status &= ~0x08; + pFD1771->status &= ~0x10; + pFD1771->status &= ~0x20; + pFD1771->status &= ~0x40; pFD1771->status &= ~FD1771_STAT_LOSTDATA; - pFD1771->status &= ~FD1771_STAT_NOTFOUND; - pFD1771->status &= ~FD1771_STAT_CRCERROR; break; case TARBELL_CMD_WRITE_TRACK: + pFD1771->status &= ~0x08; + pFD1771->status &= ~0x10; pFD1771->status &= ~FD1771_STAT_WRITEPROT; pFD1771->status &= ~FD1771_STAT_LOSTDATA; - pFD1771->status &= ~FD1771_STAT_NOTFOUND; pFD1771->status &= ~FD1771_STAT_WRITEFAULT; pFD1771->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD1771_STAT_WRITEPROT : 0x00; break; From 90f164d06fbd0fdc4faf4473bbed3b37d53f1367 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Thu, 5 Dec 2019 20:06:13 -0800 Subject: [PATCH 04/11] Created a separate FD1771_REG for each drive (UNIT) --- AltairZ80/s100_tarbell.c | 66 ++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index 14c43d5e..b39cb6ce 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -108,7 +108,7 @@ typedef struct { uint8 promEnabled; /* PROM is enabled */ uint8 writeProtect; /* Write Protect is enabled */ uint8 currentDrive; /* currently selected drive */ - FD1771_REG FD1771; /* FD1771 */ + FD1771_REG FD1771[TARBELL_MAX_DRIVES]; /* FD1771 Registers and Data */ UNIT *uptr[TARBELL_MAX_DRIVES]; } TARBELL_INFO; @@ -318,41 +318,46 @@ t_stat tarbell_reset(DEVICE *dptr) pInfo->writeProtect = FALSE; /* Reset Registers and Interface Controls */ - pInfo->FD1771.track = 0; - pInfo->FD1771.sector = 0; - pInfo->FD1771.command = 0; - pInfo->FD1771.status = 0; - pInfo->FD1771.data = 0; - pInfo->FD1771.intrq = 0; - pInfo->FD1771.stepDir = 1; - pInfo->FD1771.dataCount = 0; - pInfo->FD1771.trkCount = 0; - pInfo->FD1771.addrActive = FALSE; - pInfo->FD1771.readActive = FALSE; - pInfo->FD1771.readTrkActive = FALSE; - pInfo->FD1771.writeActive = FALSE; - pInfo->FD1771.writeTrkActive = FALSE; - pInfo->FD1771.addrActive = FALSE; - pInfo->FD1771.headLoaded = FALSE; - pInfo->FD1771.driveNotReady = TRUE; + for (int i=0; i < TARBELL_MAX_DRIVES; i++) { + pInfo->FD1771[i].track = 0; + pInfo->FD1771[i].sector = 1; + pInfo->FD1771[i].command = 0; + pInfo->FD1771[i].status = 0; + pInfo->FD1771[i].data = 0; + pInfo->FD1771[i].intrq = 0; + pInfo->FD1771[i].stepDir = 1; + pInfo->FD1771[i].dataCount = 0; + pInfo->FD1771[i].trkCount = 0; + pInfo->FD1771[i].addrActive = FALSE; + pInfo->FD1771[i].readActive = FALSE; + pInfo->FD1771[i].readTrkActive = FALSE; + pInfo->FD1771[i].writeActive = FALSE; + pInfo->FD1771[i].writeTrkActive = FALSE; + pInfo->FD1771[i].addrActive = FALSE; + pInfo->FD1771[i].headLoaded = FALSE; + pInfo->FD1771[i].driveNotReady = TRUE; + } return SCPE_OK; } static t_stat tarbell_svc(UNIT *uptr) { + FD1771_REG *pFD1771; uint32 now; + pFD1771 = &tarbell_info->FD1771[tarbell_info->currentDrive]; + /* ** Get current msec time */ now = sim_os_msec(); - if (now < tarbell_info->FD1771.headUnlTime) { + if (now < pFD1771->headUnlTime) { sim_activate(uptr, 100000); /* restart timer */ } - else if (tarbell_info->FD1771.headLoaded == TRUE) { - TARBELL_HeadLoad(uptr, &tarbell_info->FD1771, FALSE); + else if (pFD1771->headLoaded == TRUE) { + TARBELL_HeadLoad(uptr, pFD1771, FALSE); } return SCPE_OK; @@ -414,7 +419,7 @@ t_stat tarbell_attach(UNIT *uptr, CONST char *cptr) /* ** Clear Not Ready Flag */ - tarbell_info->FD1771.driveNotReady = FALSE; + tarbell_info->FD1771[i].driveNotReady = FALSE; return SCPE_OK; } @@ -453,7 +458,7 @@ t_stat tarbell_detach(UNIT *uptr) /* ** Set Not Ready Flag */ - tarbell_info->FD1771.driveNotReady = TRUE; + tarbell_info->FD1771[i].driveNotReady = TRUE; return SCPE_OK; } @@ -527,14 +532,14 @@ static void TARBELL_HeadLoad(UNIT *uptr, FD1771_REG *pFD1771, uint8 load) } if (load == TRUE && pFD1771->headLoaded == FALSE) { - sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Head Loaded." NLP); + sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Drive %d head Loaded." NLP, tarbell_info->currentDrive); } if (load == FALSE && pFD1771->headLoaded == TRUE) { - sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Head Unloaded." NLP); + sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Drive %d head Unloaded." NLP, tarbell_info->currentDrive); } - tarbell_info->FD1771.headLoaded = load; + pFD1771->headLoaded = load; } static uint8 TARBELL_Read(const uint32 Addr) @@ -547,7 +552,7 @@ static uint8 TARBELL_Read(const uint32 Addr) cData = 0; uptr = tarbell_info->uptr[tarbell_info->currentDrive]; - pFD1771 = &tarbell_info->FD1771; + pFD1771 = &tarbell_info->FD1771[tarbell_info->currentDrive]; switch(Addr & 0x07) { case TARBELL_REG_STATUS: @@ -634,7 +639,7 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) cData = 0; uptr = tarbell_info->uptr[tarbell_info->currentDrive]; - pFD1771 = &tarbell_info->FD1771; + pFD1771 = &tarbell_info->FD1771[tarbell_info->currentDrive]; switch(Addr & 0x07) { case TARBELL_REG_COMMAND: @@ -737,6 +742,7 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) cData = ~(Data >> 4) & 0x03; if (cData < TARBELL_MAX_DRIVES) { tarbell_info->currentDrive = cData; + sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Current drive now %d" NLP, tarbell_info->currentDrive); } else { sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": Invalid Drive Number drive=%02x (%02x)" NLP, Data, cData); @@ -1123,8 +1129,8 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) break; } - sim_debug(CMD_MSG, &tarbell_dev, TARBELL_SNAME ": CMD cmd=%02X track=%03d sector=%03d status=%02X" NLP, - pFD1771->command, pFD1771->track, pFD1771->sector, pFD1771->status); + sim_debug(CMD_MSG, &tarbell_dev, TARBELL_SNAME ": CMD drive=%d cmd=%02X track=%03d sector=%03d status=%02X" NLP, + tarbell_info->currentDrive, pFD1771->command, pFD1771->track, pFD1771->sector, pFD1771->status); return(cData); } From fcf52d9d388dc683fa9ad3716f183c55b0fb02f1 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Thu, 5 Dec 2019 20:08:23 -0800 Subject: [PATCH 05/11] Fix all generation --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 895e5fd4..6990f5fc 100644 --- a/makefile +++ b/makefile @@ -2103,7 +2103,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ scelbi 3b2 i701 i704 i7010 i7070 i7080 i7090 \ sigma uc15 pdp10-ka pdp10-ki pdp6 -all : altairz80 +all : ${ALL} EXPERIMENTAL = cdc1700 From 357e72bf93d3d55ff8772c60b29be1e66b987704 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Fri, 6 Dec 2019 10:20:44 -0800 Subject: [PATCH 06/11] Removed unused TARBELL_DRIVE_STATUS struct --- AltairZ80/s100_tarbell.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index b39cb6ce..61564582 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -100,9 +100,6 @@ typedef struct { #define FD1771_STAT_DRQ 0x02 #define FD1771_STAT_BUSY 0x01 -typedef struct { -} TARBELL_DRIVE_STATUS; - typedef struct { PNP_INFO pnp; /* Plug and Play */ uint8 promEnabled; /* PROM is enabled */ From 9e68ad06cae48d208f46077a64ab5f074f47c52b Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Fri, 6 Dec 2019 10:58:48 -0800 Subject: [PATCH 07/11] Add S100_TARBELL.C to ALTAIRZ80 descrip.mms --- descrip.mms | 1 + 1 file changed, 1 insertion(+) diff --git a/descrip.mms b/descrip.mms index 6acbcaef..45d0fcbd 100644 --- a/descrip.mms +++ b/descrip.mms @@ -366,6 +366,7 @@ ALTAIRZ80_SOURCE2 = $(ALTAIRZ80_DIR)S100_DISK1A.C,$(ALTAIRZ80_DIR)S100_DISK2.C,\ $(ALTAIRZ80_DIR)WD179X.C,$(ALTAIRZ80_DIR)S100_DISK3.C,\ $(ALTAIRZ80_DIR)S100_ADCS6.C,$(ALTAIRZ80_DIR)S100_HDC1001.C,\ $(ALTAIRZ80_DIR)S100_IF3.C,$(ALTAIRZ80_DIR)ALTAIRZ80_MHDSK.C,\ + $(ALTAIRZ80_DIR)S100_TARBELL.C,\ $(ALTAIRZ80_DIR)M68KCPU.C,$(ALTAIRZ80_DIR)M68KDASM.C,\ $(ALTAIRZ80_DIR)M68KOPAC.C,$(ALTAIRZ80_DIR)M68KOPDM.C,\ $(ALTAIRZ80_DIR)M68KOPNZ.C,$(ALTAIRZ80_DIR)M68KOPS.C,$(ALTAIRZ80_DIR)M68KSIM.C From 8dabce41b9b4c0fcf0144f87a78898468ca90a98 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Sat, 7 Dec 2019 17:20:46 -0800 Subject: [PATCH 08/11] Remove #include #ifdef --- AltairZ80/s100_tarbell.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index 61564582..c789c4de 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -17,10 +17,6 @@ #include "altairz80_defs.h" #include "sim_imd.h" -#if defined (_WIN32) -#include -#endif - #ifdef DBG_MSG #define DBG_PRINT(args) sim_printf args #else From 5b761735f7cce14b0b1dac8d535be0ea3ff4abb3 Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Sat, 7 Dec 2019 20:08:12 -0800 Subject: [PATCH 09/11] Fix Windows compiler warnings / errors --- AltairZ80/s100_tarbell.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index c789c4de..cff771ce 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -182,8 +182,8 @@ static void TARBELL_HeadLoad(UNIT *uptr, FD1771_REG *pFD1771, uint8 load); static uint8 TARBELL_Read(const uint32 Addr); static uint8 TARBELL_Write(const uint32 Addr, int32 data); static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 data); -static uint32 TARBELL_ReadSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer); -static uint32 TARBELL_WriteSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer); +static uint32 TARBELL_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer); +static uint32 TARBELL_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer); static const char* tarbell_description(DEVICE *dptr); static void showdata(int32 isRead); static void showregs(FD1771_REG *pFD1771); @@ -311,7 +311,7 @@ t_stat tarbell_reset(DEVICE *dptr) pInfo->writeProtect = FALSE; /* Reset Registers and Interface Controls */ - for (int i=0; i < TARBELL_MAX_DRIVES; i++) { + for (i=0; i < TARBELL_MAX_DRIVES; i++) { pInfo->FD1771[i].track = 0; pInfo->FD1771[i].sector = 1; pInfo->FD1771[i].command = 0; @@ -753,7 +753,7 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) return(cData); } -static uint32 TARBELL_ReadSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer) +static uint32 TARBELL_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer) { uint32 sec_offset; uint32 rtn = 0; @@ -778,7 +778,7 @@ static uint32 TARBELL_ReadSector(UNIT *uptr, uint16 track, uint16 sector, uint8 } -static uint32 TARBELL_WriteSector(UNIT *uptr, uint16 track, uint16 sector, uint8 *buffer) +static uint32 TARBELL_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer) { uint32 sec_offset; uint32 rtn = 0; From 5a3a5354379a23ecc804de7213188ee27ef17f7d Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Sat, 7 Dec 2019 20:12:51 -0800 Subject: [PATCH 10/11] Updated top comment block --- AltairZ80/s100_tarbell.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index cff771ce..3bdc5606 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -1,16 +1,29 @@ -/************************************************************************* - * s100_tarbell.c: Tarbell Single Density Disk Controller - * - * Created by Patrick Linstruth - * Based on s100_mdsa.c written by Mike Douglas - * - * Module Description: - * Tarbell 1011 Single Density Disk Controller module for SIMH - * - * Environment: - * User mode only - * - *************************************************************************/ +/* s100_tarbell.c: Tarbell 1011 SSSD Disk Controller + + Created by Patrick Linstruth (patrick@deltecent.com) + Based on s100_mdsa.c written by Mike Douglas + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. +*/ /* #define DBG_MSG */ From dde74c25b43b608a547d45e200c139291ab9a64a Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Sun, 8 Dec 2019 22:08:13 -0800 Subject: [PATCH 11/11] Fixed -Wall warnings Corrected name in comment block --- AltairZ80/s100_tarbell.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/AltairZ80/s100_tarbell.c b/AltairZ80/s100_tarbell.c index 3bdc5606..0e790200 100644 --- a/AltairZ80/s100_tarbell.c +++ b/AltairZ80/s100_tarbell.c @@ -20,9 +20,9 @@ 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 Peter Schorn shall not + Except as contained in this notice, the name of Patrick Linstruth shall not be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. + in this Software without prior written authorization from Patrick Linstruth. */ /* #define DBG_MSG */ @@ -127,7 +127,6 @@ static TARBELL_INFO tarbell_info_data = { { TARBELL_PNP_MEMBASE, TARBELL_PNP_MEM static TARBELL_INFO *tarbell_info = &tarbell_info_data; static uint8 sdata[TARBELL_SECTOR_LEN]; -static uint32 stepCleared = TRUE; /* true when step bit has returned to zero */ /* Tarbell Registers */ #define TARBELL_REG_STATUS 0x00 @@ -192,17 +191,17 @@ static t_stat tarbell_detach(UNIT *uptr); static t_stat tarbell_boot(int32 unitno, DEVICE *dptr); static t_stat tarbell_set_prom(UNIT *uptr, int32 value, CONST char *cptr, void *desc); static void TARBELL_HeadLoad(UNIT *uptr, FD1771_REG *pFD1771, uint8 load); -static uint8 TARBELL_Read(const uint32 Addr); -static uint8 TARBELL_Write(const uint32 Addr, int32 data); -static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 data); +static uint8 TARBELL_Read(uint32 Addr); +static uint8 TARBELL_Write(uint32 Addr, int32 data); +static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, int32 data); static uint32 TARBELL_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer); static uint32 TARBELL_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer); static const char* tarbell_description(DEVICE *dptr); static void showdata(int32 isRead); static void showregs(FD1771_REG *pFD1771); -static int32 tarbelldev(const int32 Addr, const int32 rw, const int32 data); -static int32 tarbellprom(const int32 Addr, const int32 rw, const int32 data); +static int32 tarbelldev(int32 Addr, int32 rw, int32 data); +static int32 tarbellprom(int32 Addr, int32 rw, int32 data); static UNIT tarbell_unit[TARBELL_MAX_DRIVES] = { { UDATA (tarbell_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, TARBELL_CAPACITY), 10000 }, @@ -301,7 +300,6 @@ DEVICE tarbell_dev = { t_stat tarbell_reset(DEVICE *dptr) { uint8 i; - PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; TARBELL_INFO *pInfo = (TARBELL_INFO *)dptr->ctxt; if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ @@ -488,7 +486,7 @@ static t_stat tarbell_boot(int32 unitno, DEVICE *dptr) return SCPE_OK; } -static int32 tarbelldev(const int32 Addr, const int32 rw, const int32 data) +static int32 tarbelldev(int32 Addr, int32 rw, int32 data) { if (rw == 0) { /* Read */ return(TARBELL_Read(Addr)); @@ -548,17 +546,17 @@ static void TARBELL_HeadLoad(UNIT *uptr, FD1771_REG *pFD1771, uint8 load) pFD1771->headLoaded = load; } -static uint8 TARBELL_Read(const uint32 Addr) +static uint8 TARBELL_Read(uint32 Addr) { uint8 cData; uint8 driveNum; FD1771_REG *pFD1771; UNIT *uptr; - int32 rtn; cData = 0; - uptr = tarbell_info->uptr[tarbell_info->currentDrive]; - pFD1771 = &tarbell_info->FD1771[tarbell_info->currentDrive]; + driveNum = tarbell_info->currentDrive; + uptr = tarbell_info->uptr[driveNum]; + pFD1771 = &tarbell_info->FD1771[driveNum]; switch(Addr & 0x07) { case TARBELL_REG_STATUS: @@ -633,7 +631,7 @@ static uint8 TARBELL_Read(const uint32 Addr) return (cData); } -static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) +static uint8 TARBELL_Write(uint32 Addr, int32 Data) { uint8 cData; uint8 driveNum; @@ -644,8 +642,9 @@ static uint8 TARBELL_Write(const uint32 Addr, const int32 Data) DBG_PRINT(("TARBELL: WRITE Address %02x Data %02x" NLP, Addr & 0xFF, Data & 0xFF)); cData = 0; - uptr = tarbell_info->uptr[tarbell_info->currentDrive]; - pFD1771 = &tarbell_info->FD1771[tarbell_info->currentDrive]; + driveNum = tarbell_info->currentDrive; + uptr = tarbell_info->uptr[driveNum]; + pFD1771 = &tarbell_info->FD1771[driveNum]; switch(Addr & 0x07) { case TARBELL_REG_COMMAND: @@ -816,7 +815,7 @@ static uint32 TARBELL_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 * } -static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) +static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, int32 Data) { uint8 cData; uint8 newTrack; @@ -1141,7 +1140,7 @@ static uint8 TARBELL_Command(UNIT *uptr, FD1771_REG *pFD1771, const int32 Data) return(cData); } -static int32 tarbellprom(const int32 Addr, const int32 rw, const int32 Data) +static int32 tarbellprom(int32 Addr, int32 rw, int32 Data) { /* ** The Tarbell controller overlays the first 32 bytes of RAM with a PROM.