The 'tarbell' device now supports Tarbell model 1011 single density and model 2022 double density floppy disk controllers. The model is selected using the "SET TARBELL MODEL={SD|DD}" command. Also removed some unused local variables.
1455 lines
54 KiB
C
1455 lines
54 KiB
C
/* s100_tarbell.c: Tarbell 1011/2022 Disk Controller
|
|
|
|
Created by Patrick Linstruth (patrick@deltecent.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
|
|
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 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 Patrick Linstruth.
|
|
|
|
|
|
These functions support simulated Tarbell model 1011 single density and
|
|
model 2022 double density floppy disk controllers.
|
|
|
|
The model is selected using the "SET TARBELL MODEL={SD|DD}" command.
|
|
|
|
This device does not support the DMA feature of the double density
|
|
controller. All software using this simulator must use programmed
|
|
I/O.
|
|
*/
|
|
|
|
/* #define DBG_MSG */
|
|
|
|
#include "altairz80_defs.h"
|
|
#include "sim_imd.h"
|
|
|
|
#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), const char* name, uint8 unmap);
|
|
|
|
/* These are needed for DMA. */
|
|
extern void PutByteDMA(const uint32 addr, const uint32 val);
|
|
extern uint8 GetByteDMA(const uint32 addr);
|
|
|
|
#define TARBELL_MAX_ADAPTERS 1
|
|
#define TARBELL_MAX_DRIVES 4
|
|
#define TARBELL_SECTOR_LEN 128
|
|
#define TARBELL_SPT_SD 26
|
|
#define TARBELL_SPT_DD 51
|
|
#define TARBELL_TRACKS 77
|
|
#define TARBELL_CAPACITY (256256) /* Default Tarbell Single Density Disk Capacity */
|
|
#define TARBELL_ROTATION_MS (166) /* 166 milliseconds per revolution */
|
|
#define TARBELL_HEAD_TIMEOUT (TARBELL_ROTATION_MS * 1000 * 2) /* usec * 2 revolutions */
|
|
|
|
#define IBM3740_TRK_HDR_LEN 73
|
|
#define IBM3740_SD_SEC_LEN 186
|
|
#define IBM3740_DD_SEC_LEN 196
|
|
|
|
#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
|
|
|
|
#define TARBELL_MEMBASE 0x0000
|
|
#define TARBELL_MEMSIZE TARBELL_RAM_SIZE
|
|
#define TARBELL_IOBASE 0xF8
|
|
#define TARBELL_IOSIZE_SD 5
|
|
#define TARBELL_IOSIZE_DD 6
|
|
#define TARBELL_DMABASE 0xE0
|
|
#define TARBELL_DMASIZE 16
|
|
|
|
/* 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 FD17XX 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 dataAddrMrk; /* Data Addr Mark Flag */
|
|
uint8 addrActive; /* Address Active */
|
|
} FD17XX_REG;
|
|
|
|
#define FD17XX_STAT_NOTREADY 0x80
|
|
#define FD17XX_STAT_WRITEPROT 0x40
|
|
#define FD17XX_STAT_RTYPEMSB 0x40
|
|
#define FD17XX_STAT_HEADLOAD 0x20
|
|
#define FD17XX_STAT_RTYPELSB 0x20
|
|
#define FD17XX_STAT_WRITEFAULT 0x20
|
|
#define FD17XX_STAT_SEEKERROR 0x10
|
|
#define FD17XX_STAT_NOTFOUND 0x10
|
|
#define FD17XX_STAT_CRCERROR 0x08
|
|
#define FD17XX_STAT_TRACK0 0x04
|
|
#define FD17XX_STAT_LOSTDATA 0x04
|
|
#define FD17XX_STAT_INDEX 0x02
|
|
#define FD17XX_STAT_DRQ 0x02
|
|
#define FD17XX_STAT_BUSY 0x01
|
|
|
|
typedef struct {
|
|
PNP_INFO pnp; /* Plug and Play */
|
|
uint32 dma_base; /* DMA base I/O address */
|
|
uint32 dma_size; /* DMA I/O size */
|
|
uint32 ddEnabled; /* 0=SD,1=DD */
|
|
uint32 headTimeout; /* Head unload timer value */
|
|
uint8 promEnabled; /* PROM is enabled */
|
|
uint8 writeProtect; /* Write Protect is enabled */
|
|
uint8 currentDrive; /* currently selected drive */
|
|
uint8 secsPerTrack; /* sectors per track */
|
|
uint16 bytesPerTrack; /* bytes per track */
|
|
uint8 headLoaded[TARBELL_MAX_DRIVES]; /* Head Loaded */
|
|
uint8 doubleDensity[TARBELL_MAX_DRIVES]; /* true if double density */
|
|
uint8 side[TARBELL_MAX_DRIVES]; /* side 0 or side 1 */
|
|
FD17XX_REG FD17XX; /* FD17XX Registers and Data */
|
|
UNIT *uptr[TARBELL_MAX_DRIVES];
|
|
} TARBELL_INFO;
|
|
|
|
static TARBELL_INFO tarbell_info_data = {
|
|
{ TARBELL_MEMBASE, TARBELL_MEMSIZE, TARBELL_IOBASE, TARBELL_IOSIZE_SD }, TARBELL_DMABASE, TARBELL_DMASIZE
|
|
};
|
|
|
|
static TARBELL_INFO *tarbell_info = &tarbell_info_data;
|
|
|
|
static uint8 sdata[TARBELL_SECTOR_LEN];
|
|
|
|
/* 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_WAIT 0x04
|
|
#define TARBELL_REG_DRVSEL 0x04
|
|
#define TARBELL_REG_DMASTAT 0x05
|
|
#define TARBELL_REG_EXTADDR 0x05
|
|
|
|
/* 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
|
|
|
|
#define TARBELL_DENS_MASK 0x08
|
|
#define TARBELL_DSEL_MASK 0x30
|
|
#define TARBELL_SIDE_MASK 0x40
|
|
|
|
/* 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_dmabase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
static t_stat tarbell_show_dmabase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
static t_stat tarbell_set_prom(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
static t_stat tarbell_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
static t_stat tarbell_set_model(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
static t_stat tarbell_show_model(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
static uint32 secs_per_track(uint8 track);
|
|
static uint32 bytes_per_track(uint8 track);
|
|
static uint32 calculate_tarbell_sec_offset(uint8 track, uint8 sector);
|
|
static void TARBELL_HeadLoad(UNIT *uptr, FD17XX_REG *pFD17XX, uint8 load);
|
|
static uint8 TARBELL_Read(uint32 Addr);
|
|
static uint8 TARBELL_Write(uint32 Addr, int32 data);
|
|
static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, 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 int32 tarbelldev(int32 Addr, int32 rw, int32 data);
|
|
static int32 tarbelldma(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 },
|
|
{ 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[] = {
|
|
{ DRDATAD (DRIVE, tarbell_info_data.currentDrive, 8, "Current drive register"), },
|
|
{ HRDATAD (STATUS, tarbell_info_data.FD17XX.status, 8, "Status register"), },
|
|
{ HRDATAD (COMMAND, tarbell_info_data.FD17XX.command, 8, "Command register"), },
|
|
{ HRDATAD (DATA, tarbell_info_data.FD17XX.data, 8, "Data register"), },
|
|
{ DRDATAD (TRACK, tarbell_info_data.FD17XX.track, 8, "Track register"), },
|
|
{ DRDATAD (SECTOR, tarbell_info_data.FD17XX.sector, 8, "Sector register"), },
|
|
{ DRDATAD (SPT, tarbell_info_data.secsPerTrack, 8, "Sectors per track register"), },
|
|
{ DRDATAD (BPT, tarbell_info_data.bytesPerTrack, 16, "Bytes per track register"), },
|
|
{ DRDATAD (STEPDIR, tarbell_info_data.FD17XX.stepDir, 8, "Last step direction register"), },
|
|
{ DRDATAD (SECCNT, tarbell_info_data.FD17XX.dataCount, 16, "Sector byte count register"), },
|
|
{ DRDATAD (TRKCNT, tarbell_info_data.FD17XX.trkCount, 16, "Track byte count register"), },
|
|
{ FLDATAD (RDACT, tarbell_info_data.FD17XX.readActive, 0, "Read sector active status bit"), },
|
|
{ FLDATAD (WRACT, tarbell_info_data.FD17XX.writeActive, 0, "Write sector active status bit"), },
|
|
{ FLDATAD (RDTACT, tarbell_info_data.FD17XX.readTrkActive, 0, "Read track active status bit"), },
|
|
{ FLDATAD (WRTACT, tarbell_info_data.FD17XX.writeTrkActive, 0, "Write track active status bit"), },
|
|
{ FLDATAD (INTRQ, tarbell_info_data.FD17XX.intrq, 0, "INTRQ status bit"), },
|
|
{ FLDATAD (PROM, tarbell_info_data.promEnabled, 0, "PROM enabled bit"), },
|
|
{ FLDATAD (WRTPROT, tarbell_info_data.writeProtect, 0, "Write protect enabled bit"), },
|
|
{ DRDATAD (HDUNLD, tarbell_info_data.headTimeout, 32, "Head unload timeout"), },
|
|
{ NULL }
|
|
};
|
|
|
|
#define TARBELL_NAME "Tarbell SD/DD Floppy Disk Interface"
|
|
#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)
|
|
|
|
#define UNIT_V_SIO_SLEEP (UNIT_V_UF + 7) /* sleep after keyboard status check */
|
|
#define UNIT_SIO_SLEEP (1 << UNIT_V_SIO_SLEEP)
|
|
|
|
static MTAB tarbell_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
|
{ MTAB_XTD|MTAB_VDV, 0, "DMABASE", "DMABASE",
|
|
&tarbell_set_dmabase, &tarbell_show_dmabase, NULL, "Sets disk controller DMA base address" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "PROM", "PROM={ENABLE|DISABLE}",
|
|
&tarbell_set_prom, &tarbell_show_prom, NULL, "Set/Show PROM enabled/disabled status"},
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "MODEL", "MODEL={SD|DD}",
|
|
&tarbell_set_model, &tarbell_show_model, NULL, "Set/Show the current controller model" },
|
|
{ UNIT_TARBELL_VERBOSE, 0, "QUIET", "QUIET",
|
|
NULL, NULL, NULL, "No verbose messages for unit " TARBELL_SNAME "n" },
|
|
{ UNIT_TARBELL_VERBOSE, UNIT_TARBELL_VERBOSE, "VERBOSE", "VERBOSE",
|
|
NULL, NULL, NULL, "Verbose messages for unit " TARBELL_SNAME "n" },
|
|
{ UNIT_TARBELL_WPROTECT, 0, "WRTENB", "WRTENB", NULL, NULL, NULL,
|
|
"Enables " TARBELL_SNAME "n for writing" },
|
|
{ UNIT_TARBELL_WPROTECT, UNIT_TARBELL_WPROTECT, "WRTPROT", "WRTPROT", NULL, NULL, NULL,
|
|
"Protects " TARBELL_SNAME "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_SNAME, /* 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 */
|
|
static t_stat tarbell_reset(DEVICE *dptr)
|
|
{
|
|
uint8 i;
|
|
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, "tarbellprom", TRUE);
|
|
sim_map_resource(pInfo->pnp.io_base, pInfo->pnp.io_size, RESOURCE_TYPE_IO, &tarbelldev, "tarbelldev", TRUE);
|
|
sim_map_resource(pInfo->dma_base, pInfo->dma_size, RESOURCE_TYPE_IO, &tarbelldma, "tarbelldma", TRUE);
|
|
} else {
|
|
if (sim_map_resource(pInfo->pnp.mem_base, pInfo->pnp.mem_size, RESOURCE_TYPE_MEMORY, &tarbellprom, "tarbellprom", FALSE) != 0) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": Error mapping MEM resource at 0x%04x\n", 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, "tarbelldev", FALSE) != 0) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": Error mapping I/O resource at 0x%02x\n", pInfo->pnp.io_base);
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
/* If simulating a DD, connect DMA ports */
|
|
if (tarbell_info->ddEnabled) {
|
|
if (sim_map_resource(pInfo->dma_base, pInfo->dma_size, RESOURCE_TYPE_IO, &tarbelldma, "tarbelldma", FALSE) != 0) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": Error mapping DMA resource at 0x%02x\n", pInfo->dma_base);
|
|
return SCPE_ARG;
|
|
}
|
|
}
|
|
}
|
|
|
|
pInfo->currentDrive = 0;
|
|
pInfo->promEnabled = TRUE;
|
|
pInfo->writeProtect = FALSE;
|
|
|
|
/* Reset Registers and Interface Controls */
|
|
for (i=0; i < TARBELL_MAX_DRIVES; i++) {
|
|
if (tarbell_info->uptr[i] == NULL) {
|
|
tarbell_info->uptr[i] = &tarbell_dev.units[i];
|
|
}
|
|
|
|
pInfo->FD17XX.track = 0;
|
|
pInfo->FD17XX.sector = 1;
|
|
pInfo->FD17XX.command = 0;
|
|
pInfo->FD17XX.status = 0;
|
|
pInfo->FD17XX.data = 0;
|
|
pInfo->FD17XX.intrq = 0;
|
|
pInfo->FD17XX.stepDir = 1;
|
|
pInfo->FD17XX.dataCount = 0;
|
|
pInfo->FD17XX.trkCount = 0;
|
|
pInfo->FD17XX.addrActive = FALSE;
|
|
pInfo->FD17XX.readActive = FALSE;
|
|
pInfo->FD17XX.readTrkActive = FALSE;
|
|
pInfo->FD17XX.writeActive = FALSE;
|
|
pInfo->FD17XX.writeTrkActive = FALSE;
|
|
pInfo->FD17XX.addrActive = FALSE;
|
|
|
|
tarbell_info->headLoaded[i] = FALSE;
|
|
tarbell_info->doubleDensity[i] = FALSE;
|
|
tarbell_info->side[i] = 0;
|
|
}
|
|
|
|
/*
|
|
** If the SIO device sleeps during checks, the SCP usec timer
|
|
** is no longer accurate and our wait time has to be adjusted
|
|
*/
|
|
pInfo->headTimeout = TARBELL_HEAD_TIMEOUT; /* usec timeout */
|
|
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": reset controller.\n");
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_svc(UNIT *uptr)
|
|
{
|
|
FD17XX_REG *pFD17XX;
|
|
|
|
pFD17XX = &tarbell_info->FD17XX;
|
|
|
|
if (tarbell_info->headLoaded[tarbell_info->currentDrive] == TRUE) {
|
|
TARBELL_HeadLoad(uptr, pFD17XX, FALSE);
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Attach routine */
|
|
static t_stat tarbell_attach(UNIT *uptr, CONST char *cptr)
|
|
{
|
|
char header[4];
|
|
t_stat r;
|
|
unsigned int i = 0;
|
|
|
|
r = attach_unit(uptr, cptr); /* attach unit */
|
|
if (r != SCPE_OK) { /* error? */
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": ATTACH error=%d\n", 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\n", uptr->capac));
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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\n");
|
|
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\n", i, cptr,
|
|
uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",
|
|
uptr->capac);
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* Detach routine */
|
|
static 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.\n", i);
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_set_dmabase(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
uint32 newba;
|
|
t_stat r;
|
|
|
|
if (cptr == NULL || !(tarbell_info->ddEnabled)) {
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
newba = get_uint (cptr, 16, 0xFF, &r);
|
|
|
|
if (r != SCPE_OK) {
|
|
return r;
|
|
}
|
|
|
|
if ((newba > 0xFF) || (newba % tarbell_info->dma_size)) {
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
if (tarbell_dev.flags & DEV_DIS) {
|
|
sim_printf("device not enabled yet.\n");
|
|
tarbell_info->dma_base = newba & ~(tarbell_info->dma_size-1);
|
|
} else {
|
|
tarbell_dev.flags |= DEV_DIS;
|
|
tarbell_reset(&tarbell_dev);
|
|
tarbell_info->dma_base = newba & ~(tarbell_info->dma_size-1);
|
|
tarbell_dev.flags &= ~DEV_DIS;
|
|
tarbell_reset(&tarbell_dev);
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_show_dmabase(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
if (tarbell_info->ddEnabled) {
|
|
fprintf(st, "DMA=0x%02X-0x%02X", tarbell_info->dma_base, tarbell_info->dma_base+tarbell_info->dma_size-1);
|
|
} else {
|
|
fprintf(st, "DMA=N/A");
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_set_model(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
if (!cptr) return SCPE_IERR;
|
|
|
|
/* this assumes that the parameter has already been upcased */
|
|
if (!strcmp(cptr, "DD")) {
|
|
tarbell_info->ddEnabled = TRUE;
|
|
tarbell_info->pnp.io_size = TARBELL_IOSIZE_DD;
|
|
} else if (!strcmp(cptr, "SD")) {
|
|
tarbell_info->ddEnabled = FALSE;
|
|
tarbell_info->pnp.io_size = TARBELL_IOSIZE_SD;
|
|
} else {
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
/* Reset the device if enabled */
|
|
if (!(tarbell_dev.flags & DEV_DIS)) {
|
|
tarbell_dev.flags |= DEV_DIS;
|
|
tarbell_reset(&tarbell_dev);
|
|
tarbell_dev.flags &= ~DEV_DIS;
|
|
tarbell_reset(&tarbell_dev);
|
|
}
|
|
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_show_model(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
fprintf(st, "MODEL=%s", (tarbell_info->ddEnabled) ? "DD" : "SD");
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_set_prom(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
if (!cptr) return SCPE_IERR;
|
|
if (!strlen(cptr)) return SCPE_ARG;
|
|
|
|
/* this assumes that the parameter has already been upcased */
|
|
if (!strncmp(cptr, "ENABLE", strlen(cptr))) {
|
|
tarbell_info->promEnabled = TRUE;
|
|
} else if (!strncmp(cptr, "DISABLE", strlen(cptr))) {
|
|
tarbell_info->promEnabled = FALSE;
|
|
} else {
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
fprintf(st, "%s", (tarbell_info->promEnabled) ? "PROM" : "NOPROM");
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat tarbell_boot(int32 unitno, DEVICE *dptr)
|
|
{
|
|
|
|
PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
|
|
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Booting Controller at 0x%04x\n", pnp->mem_base);
|
|
|
|
*((int32 *) sim_PC->loc) = pnp->mem_base;
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static int32 tarbelldev(int32 Addr, int32 rw, 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(isRead ? RD_DATA_DETAIL_MSG : WR_DATA_DETAIL_MSG, &tarbell_dev, TARBELL_SNAME ": %s track/sector %02d/%03d:\n\t", isRead ? "Read" : "Write", tarbell_info->FD17XX.track, tarbell_info->FD17XX.sector);
|
|
for (i=0; i < TARBELL_SECTOR_LEN; i++) {
|
|
sim_debug(isRead ? RD_DATA_DETAIL_MSG : WR_DATA_DETAIL_MSG, &tarbell_dev, "%02X ", sdata[i]);
|
|
if (((i+1) & 0xf) == 0) {
|
|
sim_debug(isRead ? RD_DATA_DETAIL_MSG : WR_DATA_DETAIL_MSG, &tarbell_dev, "\n\t");
|
|
}
|
|
}
|
|
sim_debug(RD_DATA_DETAIL_MSG|WR_DATA_DETAIL_MSG, &tarbell_dev, "\n");
|
|
}
|
|
|
|
static uint32 secs_per_track(uint8 track)
|
|
{
|
|
/* Track 0 / side 0 is always single density */
|
|
int32 secs = (tarbell_info->doubleDensity[tarbell_info->currentDrive] &&
|
|
(tarbell_info->side[tarbell_info->currentDrive] || track > 0)) ? TARBELL_SPT_DD : TARBELL_SPT_SD;
|
|
|
|
tarbell_info->secsPerTrack = secs;
|
|
|
|
return secs;
|
|
}
|
|
|
|
static uint32 bytes_per_track(uint8 track)
|
|
{
|
|
int32 bytes;
|
|
int32 dd;
|
|
|
|
dd = tarbell_info->doubleDensity[tarbell_info->currentDrive];
|
|
|
|
if (dd) {
|
|
bytes = IBM3740_TRK_HDR_LEN + 247 + (TARBELL_SPT_DD * IBM3740_DD_SEC_LEN);
|
|
} else {
|
|
bytes = IBM3740_TRK_HDR_LEN + 247 + (TARBELL_SPT_SD * IBM3740_SD_SEC_LEN);
|
|
}
|
|
|
|
tarbell_info->bytesPerTrack = bytes;
|
|
|
|
return bytes;
|
|
}
|
|
|
|
static uint32 calculate_tarbell_sec_offset(uint8 track, uint8 sector)
|
|
{
|
|
uint32 offset;
|
|
uint8 dd,ds;
|
|
|
|
dd = tarbell_info->doubleDensity[tarbell_info->currentDrive];
|
|
ds = tarbell_info->side[tarbell_info->currentDrive];
|
|
|
|
/*
|
|
** Side 0: tracks 0-76
|
|
** Side 1: tracks 77-153
|
|
*/
|
|
if (ds) {
|
|
track += 77;
|
|
}
|
|
|
|
/*
|
|
** Calculate track offset
|
|
*/
|
|
if (track==0) {
|
|
offset=0;
|
|
}
|
|
else {
|
|
offset=TARBELL_SPT_SD * TARBELL_SECTOR_LEN; /* Track 0 / Side 0 always SD */
|
|
offset+=(track-1) * secs_per_track(track) * TARBELL_SECTOR_LEN; /* Track 1-153 */
|
|
}
|
|
|
|
/*
|
|
** Add sector offset to track offset
|
|
*/
|
|
offset += (sector-1)*TARBELL_SECTOR_LEN;
|
|
|
|
DBG_PRINT(("TARBELL: OFFSET drive=%d side=%d den=%d track=%03d sector=%03d\n", tarbell_info->currentDrive, ds, dd, track, sector));
|
|
|
|
return (offset);
|
|
}
|
|
|
|
static void TARBELL_HeadLoad(UNIT *uptr, FD17XX_REG *pFD17XX, uint8 load)
|
|
{
|
|
/*
|
|
** If no disk has been attached, uptr will be NULL - return
|
|
*/
|
|
if (uptr == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (load) {
|
|
sim_activate_after_abs(uptr, tarbell_info->headTimeout); /* activate timer */
|
|
|
|
if (tarbell_info->headLoaded[tarbell_info->currentDrive] == FALSE) {
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Drive %d head Loaded.\n", tarbell_info->currentDrive);
|
|
}
|
|
}
|
|
|
|
if (load == FALSE && tarbell_info->headLoaded[tarbell_info->currentDrive] == TRUE) {
|
|
sim_cancel(uptr); /* cancel timer */
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Drive %d head Unloaded.\n", tarbell_info->currentDrive);
|
|
}
|
|
|
|
tarbell_info->headLoaded[tarbell_info->currentDrive] = load;
|
|
}
|
|
|
|
static uint8 TARBELL_Read(uint32 Addr)
|
|
{
|
|
uint8 cData;
|
|
uint8 driveNum;
|
|
FD17XX_REG *pFD17XX;
|
|
UNIT *uptr;
|
|
|
|
cData = 0;
|
|
driveNum = tarbell_info->currentDrive;
|
|
uptr = tarbell_info->uptr[driveNum];
|
|
pFD17XX = &tarbell_info->FD17XX;
|
|
|
|
switch(Addr & 0x07) {
|
|
case TARBELL_REG_STATUS:
|
|
cData = pFD17XX->status;
|
|
break;
|
|
|
|
case TARBELL_REG_TRACK:
|
|
cData = pFD17XX->track;
|
|
break;
|
|
|
|
case TARBELL_REG_DATA:
|
|
/*
|
|
** If a READ operation is currently active, get the next byte
|
|
*/
|
|
if (pFD17XX->readActive) {
|
|
/* Store byte in DATA register */
|
|
pFD17XX->data = sdata[pFD17XX->dataCount++];
|
|
|
|
/* If we reached the end of the sector, terminate command and set INTRQ */
|
|
if (pFD17XX->dataCount == TARBELL_SECTOR_LEN) {
|
|
pFD17XX->readActive = FALSE;
|
|
pFD17XX->dataCount = 0;
|
|
pFD17XX->status = 0x00;
|
|
pFD17XX->intrq = TRUE;
|
|
}
|
|
else {
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Another byte is ready */
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
|
|
}
|
|
else if (pFD17XX->readTrkActive) {
|
|
/* If we reached the end of the track data, terminate command and set INTRQ */
|
|
if (pFD17XX->trkCount == bytes_per_track(pFD17XX->track)) {
|
|
pFD17XX->readTrkActive = FALSE;
|
|
pFD17XX->status = 0x00;
|
|
pFD17XX->intrq = TRUE;
|
|
}
|
|
else {
|
|
pFD17XX->trkCount++;
|
|
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Another byte is ready */
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
|
|
}
|
|
else if (pFD17XX->addrActive) {
|
|
/* Store byte in DATA register */
|
|
pFD17XX->data = sdata[pFD17XX->dataCount++];
|
|
|
|
DBG_PRINT(("TARBELL: READ ADDR data=%03d\n", pFD17XX->data));
|
|
|
|
/* If we reached the end of the address data, terminate command and set INTRQ */
|
|
if (pFD17XX->dataCount > TARBELL_ADDR_CRC2) {
|
|
pFD17XX->addrActive = FALSE;
|
|
pFD17XX->status = 0x00;
|
|
pFD17XX->intrq = TRUE;
|
|
}
|
|
else {
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Another byte is ready */
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
|
|
}
|
|
|
|
cData = pFD17XX->data;
|
|
break;
|
|
|
|
case TARBELL_REG_SECTOR:
|
|
cData = pFD17XX->sector;
|
|
break;
|
|
|
|
case TARBELL_REG_WAIT:
|
|
cData = (pFD17XX->intrq) ? 0x00 : 0x80; /* Bit 7 True if DRQ */
|
|
break;
|
|
|
|
case TARBELL_REG_DMASTAT:
|
|
cData = 0x00; /* Always show DMA is complete */
|
|
break;
|
|
|
|
default:
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READ Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x07);
|
|
cData = 0xff;
|
|
break;
|
|
}
|
|
|
|
DBG_PRINT(("TARBELL: READ COMPLETE currentDrive=%d doubleDensity=%d sector=%03d track=%02d data=%02x\n", tarbell_info->currentDrive, tarbell_info->doubleDensity[tarbell_info->currentDrive], pFD17XX->track, pFD17XX->sector, pFD17XX->data));
|
|
|
|
return (cData);
|
|
}
|
|
|
|
static uint8 TARBELL_Write(uint32 Addr, int32 Data)
|
|
{
|
|
uint8 cData;
|
|
uint8 driveNum;
|
|
int32 rtn;
|
|
UNIT *uptr;
|
|
FD17XX_REG *pFD17XX;
|
|
|
|
sim_debug(CMD_MSG, &tarbell_dev, TARBELL_SNAME ": OUT %02x Data %02x\n", Addr & 0xFF, Data & 0xFF);
|
|
|
|
cData = 0;
|
|
driveNum = tarbell_info->currentDrive;
|
|
uptr = tarbell_info->uptr[driveNum];
|
|
pFD17XX = &tarbell_info->FD17XX;
|
|
|
|
switch(Addr & 0x07) {
|
|
case TARBELL_REG_COMMAND:
|
|
cData = TARBELL_Command(uptr, pFD17XX, Data);
|
|
break;
|
|
|
|
case TARBELL_REG_DATA:
|
|
pFD17XX->data = Data; /* Store byte in DATA register */
|
|
|
|
if (pFD17XX->writeActive) {
|
|
|
|
/* Store DATA register in Sector Buffer */
|
|
sdata[pFD17XX->dataCount++] = pFD17XX->data;
|
|
|
|
/* If we reached the end of the sector, write sector, terminate command and set INTRQ */
|
|
if (pFD17XX->dataCount == TARBELL_SECTOR_LEN) {
|
|
pFD17XX->status = 0x00; /* Clear Status Bits */
|
|
|
|
rtn = TARBELL_WriteSector(uptr, pFD17XX->track, pFD17XX->sector, sdata);
|
|
|
|
showdata(FALSE);
|
|
|
|
if (rtn != TARBELL_SECTOR_LEN) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": sim_fwrite errno=%d\n", errno);
|
|
|
|
pFD17XX->status |= FD17XX_STAT_WRITEFAULT;
|
|
}
|
|
pFD17XX->writeActive = FALSE;
|
|
pFD17XX->dataCount = 0;
|
|
pFD17XX->intrq = TRUE;
|
|
}
|
|
else {
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Ready for another byte */
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
|
|
}
|
|
else if (pFD17XX->writeTrkActive) {
|
|
|
|
if (pFD17XX->dataAddrMrk) {
|
|
/* Store DATA register in Sector Buffer */
|
|
sdata[pFD17XX->dataCount++] = pFD17XX->data;
|
|
|
|
/* If we reached the end of the sector, write sector */
|
|
if (pFD17XX->dataCount == TARBELL_SECTOR_LEN) {
|
|
pFD17XX->status &= ~FD17XX_STAT_WRITEFAULT; /* Clear Status Bit */
|
|
|
|
rtn = TARBELL_WriteSector(uptr, pFD17XX->track, pFD17XX->sector, sdata);
|
|
|
|
if (rtn != TARBELL_SECTOR_LEN) {
|
|
pFD17XX->status |= FD17XX_STAT_WRITEFAULT;
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": WRITE ERROR could not write track %03d sector %03d\n", pFD17XX->track, pFD17XX->sector);
|
|
}
|
|
|
|
DBG_PRINT(("TARBELL: WRITE TRACK drive=%d track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X\n", driveNum, pFD17XX->track, pFD17XX->sector, pFD17XX->trkCount, pFD17XX->dataCount, pFD17XX->data, pFD17XX->status));
|
|
|
|
pFD17XX->dataCount = 0;
|
|
pFD17XX->dataAddrMrk = 0;
|
|
|
|
if (pFD17XX->sector < secs_per_track(pFD17XX->track)) {
|
|
pFD17XX->sector++;
|
|
}
|
|
}
|
|
} else if (pFD17XX->data == 0xFB) {
|
|
pFD17XX->dataAddrMrk = 1;
|
|
DBG_PRINT(("TARBELL: 0xFB Address Mark Found\n"));
|
|
}
|
|
|
|
/*
|
|
** Increment number for bytes written to track
|
|
*/
|
|
pFD17XX->trkCount++;
|
|
|
|
if (pFD17XX->trkCount < bytes_per_track(pFD17XX->track)) {
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Ready for another byte */
|
|
}
|
|
else {
|
|
pFD17XX->status = 0x00; /* Clear Status Bits */
|
|
pFD17XX->intrq = TRUE;
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY; /* Clear BUSY Bit */
|
|
pFD17XX->writeTrkActive = FALSE;
|
|
sim_debug(WR_DATA_MSG, &tarbell_dev, TARBELL_SNAME ": WRITE TRACK COMPLETE track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X\n", pFD17XX->track, pFD17XX->sector, pFD17XX->trkCount, pFD17XX->dataCount, pFD17XX->data, pFD17XX->status);
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, TRUE);
|
|
}
|
|
|
|
DBG_PRINT(("TARBELL: WRITE DATA REG %02X\n", Data));
|
|
break;
|
|
|
|
case TARBELL_REG_TRACK:
|
|
pFD17XX->track = Data;
|
|
DBG_PRINT(("TARBELL: TRACK REG=%d\n", pFD17XX->track));
|
|
break;
|
|
|
|
case TARBELL_REG_SECTOR:
|
|
pFD17XX->sector = Data;
|
|
|
|
DBG_PRINT(("TARBELL: SECTOR REG=%d\n", pFD17XX->sector));
|
|
|
|
break;
|
|
|
|
case TARBELL_REG_DRVSEL:
|
|
/* Drive Select */
|
|
if (tarbell_info->ddEnabled) { /* Tarbell DD Controller */
|
|
cData = (Data & TARBELL_DSEL_MASK) >> 4;
|
|
|
|
/* Density */
|
|
tarbell_info->doubleDensity[cData] = (Data & TARBELL_DENS_MASK) != 0x00;
|
|
|
|
/* Side */
|
|
tarbell_info->side[cData] = (Data & TARBELL_SIDE_MASK) != 0x00;
|
|
|
|
DBG_PRINT(("REG_DRVSEL=%02X\n", Data));
|
|
|
|
} else {
|
|
cData = ~(Data >> 4) & 0x03; /* Tarbell SD drive bits inverted */
|
|
}
|
|
|
|
if (tarbell_info->currentDrive != cData) {
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Current drive now %d\n", cData);
|
|
}
|
|
|
|
tarbell_info->currentDrive = cData;
|
|
|
|
break;
|
|
|
|
case TARBELL_REG_EXTADDR:
|
|
cData = 0x00;
|
|
break;
|
|
|
|
default:
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": WRITE Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x07);
|
|
cData = 0xff;
|
|
break;
|
|
}
|
|
|
|
DBG_PRINT(("TARBELL: WRITE COMPLETE currentDrive=%d doubleDensity=%d sector=%03d track=%02d data=%02x\n", tarbell_info->currentDrive, tarbell_info->doubleDensity[tarbell_info->currentDrive], pFD17XX->track, pFD17XX->sector, pFD17XX->data));
|
|
|
|
return(cData);
|
|
}
|
|
|
|
static uint32 TARBELL_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
|
|
{
|
|
uint32 sec_offset;
|
|
uint32 rtn = 0;
|
|
|
|
if (uptr->fileref == NULL) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC uptr.fileref is NULL!\n");
|
|
return 0;
|
|
}
|
|
|
|
sec_offset = calculate_tarbell_sec_offset(track, sector);
|
|
|
|
sim_debug(RD_DATA_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC track %03d sector %03d at offset %04X\n", track, sector, sec_offset);
|
|
|
|
if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC sim_fseek error.\n");
|
|
return 0;
|
|
}
|
|
|
|
rtn = sim_fread(buffer, 1, TARBELL_SECTOR_LEN, uptr->fileref);
|
|
|
|
return rtn;
|
|
}
|
|
|
|
|
|
static uint32 TARBELL_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
|
|
{
|
|
uint32 sec_offset;
|
|
uint32 rtn = 0;
|
|
|
|
if (uptr->fileref == NULL) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": READSEC uptr.fileref is NULL!\n");
|
|
return 0;
|
|
}
|
|
|
|
sec_offset = calculate_tarbell_sec_offset(track, sector);
|
|
|
|
sim_debug(WR_DATA_MSG, &tarbell_dev, TARBELL_SNAME ": WRITESEC track %03d sector %03d at offset %04X\n", track, sector, sec_offset);
|
|
|
|
if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": WRITESEC sim_fseek error.\n");
|
|
return 0;
|
|
}
|
|
|
|
rtn = sim_fwrite(buffer, 1, TARBELL_SECTOR_LEN, uptr->fileref);
|
|
|
|
return rtn;
|
|
}
|
|
|
|
|
|
static uint8 TARBELL_Command(UNIT *uptr, FD17XX_REG *pFD17XX, int32 Data)
|
|
{
|
|
uint8 cData;
|
|
uint8 newTrack;
|
|
uint8 statusUpdate;
|
|
int32 rtn;
|
|
|
|
cData = 0;
|
|
statusUpdate = TRUE;
|
|
|
|
if (uptr == NULL) {
|
|
return cData;
|
|
}
|
|
|
|
pFD17XX->command = Data;
|
|
|
|
/*
|
|
** Type II-IV Command
|
|
*/
|
|
if (pFD17XX->command & 0x80) {
|
|
pFD17XX->readActive = FALSE;
|
|
pFD17XX->writeActive = FALSE;
|
|
pFD17XX->readTrkActive = FALSE;
|
|
pFD17XX->writeTrkActive = FALSE;
|
|
pFD17XX->addrActive = FALSE;
|
|
pFD17XX->dataCount = 0;
|
|
|
|
pFD17XX->status &= ~FD17XX_STAT_DRQ; /* Reset DRQ */
|
|
}
|
|
|
|
/*
|
|
** Set BUSY for all but Force Interrupt
|
|
*/
|
|
if ((pFD17XX->command & TARBELL_CMD_FORCE_INTR) != TARBELL_CMD_FORCE_INTR) {
|
|
pFD17XX->status |= FD17XX_STAT_BUSY;
|
|
}
|
|
|
|
pFD17XX->intrq = FALSE;
|
|
|
|
switch(pFD17XX->command & 0xf0) {
|
|
case TARBELL_CMD_RESTORE:
|
|
pFD17XX->track = 0;
|
|
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": RESTORE track=%03d\n", pFD17XX->track);
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
|
|
|
|
pFD17XX->status &= ~FD17XX_STAT_SEEKERROR;
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
pFD17XX->status &= ~FD17XX_STAT_DRQ;
|
|
pFD17XX->intrq = TRUE;
|
|
break;
|
|
|
|
case TARBELL_CMD_SEEK:
|
|
newTrack = pFD17XX->data;
|
|
|
|
DBG_PRINT(("TARBELL: TRACK DATA=%d (SEEK)\n", newTrack));
|
|
|
|
pFD17XX->status &= ~FD17XX_STAT_SEEKERROR;
|
|
|
|
if (newTrack < TARBELL_TRACKS) {
|
|
pFD17XX->track = newTrack;
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
|
|
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": SEEK track=%03d\n", pFD17XX->track);
|
|
}
|
|
else {
|
|
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": SEEK ERR track=%03d\n", newTrack);
|
|
}
|
|
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
pFD17XX->status &= ~FD17XX_STAT_DRQ;
|
|
pFD17XX->intrq = TRUE;
|
|
break;
|
|
|
|
case TARBELL_CMD_STEP:
|
|
case TARBELL_CMD_STEPU:
|
|
pFD17XX->status &= ~FD17XX_STAT_SEEKERROR;
|
|
|
|
newTrack = pFD17XX->track + pFD17XX->stepDir;
|
|
|
|
if (newTrack < TARBELL_TRACKS) {
|
|
if (Data & TARBELL_FLAG_U) {
|
|
pFD17XX->track = newTrack;
|
|
}
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP track=%03d\n", pFD17XX->track);
|
|
}
|
|
else {
|
|
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEP ERR track=%03d\n", newTrack);
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
|
|
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
pFD17XX->status &= ~FD17XX_STAT_DRQ;
|
|
pFD17XX->intrq = TRUE;
|
|
break;
|
|
|
|
case TARBELL_CMD_STEPIN:
|
|
case TARBELL_CMD_STEPINU:
|
|
pFD17XX->status &= ~FD17XX_STAT_SEEKERROR;
|
|
|
|
if (pFD17XX->track < TARBELL_TRACKS-1) {
|
|
if (Data & TARBELL_FLAG_U) {
|
|
pFD17XX->track++;
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
|
|
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN track=%03d\n", pFD17XX->track);
|
|
}
|
|
else {
|
|
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPIN ERR track=%03d\n", pFD17XX->track+1);
|
|
}
|
|
|
|
pFD17XX->stepDir = 1;
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
pFD17XX->status &= ~FD17XX_STAT_DRQ;
|
|
pFD17XX->intrq = TRUE;
|
|
break;
|
|
|
|
case TARBELL_CMD_STEPOUT:
|
|
case TARBELL_CMD_STEPOUTU:
|
|
pFD17XX->status &= ~FD17XX_STAT_SEEKERROR;
|
|
|
|
if (pFD17XX->track > 0) {
|
|
if (Data & TARBELL_FLAG_U) {
|
|
pFD17XX->track--;
|
|
}
|
|
|
|
TARBELL_HeadLoad(uptr, pFD17XX, (Data & TARBELL_FLAG_H) ? TRUE : FALSE);
|
|
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT track=%03d\n", pFD17XX->track);
|
|
}
|
|
else {
|
|
pFD17XX->status |= FD17XX_STAT_SEEKERROR;
|
|
sim_debug(SEEK_MSG, &tarbell_dev, TARBELL_SNAME ": STEPOUT ERR track=%03d\n", pFD17XX->track-1);
|
|
}
|
|
|
|
pFD17XX->stepDir = -1;
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
pFD17XX->status &= ~FD17XX_STAT_DRQ;
|
|
pFD17XX->intrq = TRUE;
|
|
break;
|
|
|
|
case TARBELL_CMD_READ:
|
|
|
|
if ((uptr == NULL) || (uptr->fileref == NULL)) {
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": " ADDRESS_FORMAT
|
|
" Drive: %d not attached - read ignored.\n",
|
|
PCX, tarbell_info->currentDrive);
|
|
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
|
|
return cData;
|
|
}
|
|
|
|
rtn = TARBELL_ReadSector(uptr, pFD17XX->track, pFD17XX->sector, sdata);
|
|
|
|
if (rtn == TARBELL_SECTOR_LEN) {
|
|
pFD17XX->readActive = TRUE;
|
|
|
|
showdata(TRUE);
|
|
}
|
|
else {
|
|
sim_debug(ERROR_MSG, &tarbell_dev, TARBELL_SNAME ": sim_fread errno=%d\n", errno);
|
|
|
|
pFD17XX->status |= FD17XX_STAT_NOTFOUND;
|
|
pFD17XX->intrq = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case TARBELL_CMD_WRITE:
|
|
/*
|
|
** If no disk in drive, return
|
|
*/
|
|
if ((uptr == NULL) || (uptr->fileref == NULL)) {
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": " ADDRESS_FORMAT
|
|
" Drive: %d not attached - write ignored.\n",
|
|
PCX, tarbell_info->currentDrive);
|
|
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
}
|
|
|
|
if ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) {
|
|
DBG_PRINT((TARBELL_SNAME ": Disk write protected. uptr->flags=%04x writeProtect=%04x\n", uptr->flags & UNIT_TARBELL_WPROTECT, tarbell_info->writeProtect));
|
|
pFD17XX->intrq = TRUE;
|
|
}
|
|
else {
|
|
pFD17XX->writeActive = TRUE;
|
|
pFD17XX->dataCount = 0;
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Set DRQ */
|
|
}
|
|
|
|
break;
|
|
|
|
case TARBELL_CMD_READ_ADDRESS:
|
|
sdata[TARBELL_ADDR_TRACK]=pFD17XX->track;
|
|
sdata[TARBELL_ADDR_ZEROS]=0;
|
|
sdata[TARBELL_ADDR_SECTOR]=pFD17XX->sector;
|
|
sdata[TARBELL_ADDR_LENGTH]=TARBELL_SECTOR_LEN;
|
|
sdata[TARBELL_ADDR_CRC1]=0;
|
|
sdata[TARBELL_ADDR_CRC2]=0;
|
|
|
|
pFD17XX->addrActive = TRUE;
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Set DRQ */
|
|
|
|
break;
|
|
|
|
case TARBELL_CMD_READ_TRACK:
|
|
pFD17XX->readTrkActive = TRUE;
|
|
pFD17XX->trkCount=0;
|
|
pFD17XX->dataCount=0;
|
|
pFD17XX->sector=1;
|
|
pFD17XX->status |= FD17XX_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\n", uptr->flags & UNIT_TARBELL_WPROTECT, tarbell_info->writeProtect));
|
|
pFD17XX->intrq = TRUE;
|
|
}
|
|
else {
|
|
pFD17XX->writeTrkActive = TRUE;
|
|
pFD17XX->trkCount=0;
|
|
pFD17XX->dataCount=0;
|
|
pFD17XX->sector=1;
|
|
pFD17XX->dataAddrMrk=0;
|
|
pFD17XX->status |= FD17XX_STAT_DRQ; /* Set DRQ */
|
|
}
|
|
break;
|
|
|
|
case TARBELL_CMD_FORCE_INTR:
|
|
if (pFD17XX->status & FD17XX_STAT_BUSY) {
|
|
pFD17XX->status &= ~FD17XX_STAT_BUSY;
|
|
statusUpdate = FALSE;
|
|
}
|
|
|
|
/* Reset Status */
|
|
pFD17XX->dataCount = 0;
|
|
pFD17XX->trkCount = 0;
|
|
pFD17XX->readActive = FALSE;
|
|
pFD17XX->readTrkActive = FALSE;
|
|
pFD17XX->writeActive = FALSE;
|
|
pFD17XX->writeTrkActive = FALSE;
|
|
pFD17XX->addrActive = FALSE;
|
|
|
|
break;
|
|
|
|
default:
|
|
cData=0xFF;
|
|
sim_debug(ERROR_MSG, &tarbell_dev, "TARBELL: UNRECOGNIZED CMD %02X\n", pFD17XX->command);
|
|
pFD17XX->intrq = TRUE;
|
|
break;
|
|
}
|
|
|
|
/**************************/
|
|
/* Update Status Register */
|
|
/**************************/
|
|
|
|
/* drive not ready bit */
|
|
pFD17XX->status &= ~FD17XX_STAT_NOTREADY;
|
|
pFD17XX->status |= (uptr->fileref == NULL) ? FD17XX_STAT_NOTREADY : 0x00;
|
|
|
|
switch(pFD17XX->command & 0xf0) {
|
|
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) {
|
|
pFD17XX->status &= ~FD17XX_STAT_HEADLOAD;
|
|
pFD17XX->status &= ~FD17XX_STAT_WRITEPROT;
|
|
pFD17XX->status &= ~FD17XX_STAT_CRCERROR;
|
|
pFD17XX->status &= ~FD17XX_STAT_TRACK0;
|
|
pFD17XX->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD17XX_STAT_WRITEPROT : 0x00;
|
|
pFD17XX->status |= (pFD17XX->track) ? 0x00 : FD17XX_STAT_TRACK0;
|
|
pFD17XX->status |= (tarbell_info->headLoaded[tarbell_info->currentDrive]) ? FD17XX_STAT_HEADLOAD : 0x00;
|
|
pFD17XX->status |= (pFD17XX->status & FD17XX_STAT_NOTREADY) ? 0x00 : FD17XX_STAT_INDEX; /* Always set Index Flag if Drive Ready */
|
|
}
|
|
break;
|
|
|
|
case TARBELL_CMD_READ:
|
|
pFD17XX->status &= ~FD17XX_STAT_LOSTDATA;
|
|
pFD17XX->status &= ~FD17XX_STAT_NOTFOUND;
|
|
pFD17XX->status &= ~FD17XX_STAT_CRCERROR;
|
|
pFD17XX->status &= ~FD17XX_STAT_RTYPELSB;
|
|
break;
|
|
|
|
case TARBELL_CMD_WRITE:
|
|
pFD17XX->status &= ~FD17XX_STAT_WRITEPROT;
|
|
pFD17XX->status &= ~FD17XX_STAT_LOSTDATA;
|
|
pFD17XX->status &= ~FD17XX_STAT_NOTFOUND;
|
|
pFD17XX->status &= ~FD17XX_STAT_CRCERROR;
|
|
pFD17XX->status &= ~FD17XX_STAT_RTYPELSB;
|
|
pFD17XX->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD17XX_STAT_WRITEPROT : 0x00;
|
|
break;
|
|
|
|
case TARBELL_CMD_READ_ADDRESS:
|
|
pFD17XX->status &= ~0x20;
|
|
pFD17XX->status &= ~0x40;
|
|
pFD17XX->status &= ~FD17XX_STAT_LOSTDATA;
|
|
pFD17XX->status &= ~FD17XX_STAT_NOTFOUND;
|
|
pFD17XX->status &= ~FD17XX_STAT_CRCERROR;
|
|
break;
|
|
|
|
case TARBELL_CMD_READ_TRACK:
|
|
pFD17XX->status &= ~0x08;
|
|
pFD17XX->status &= ~0x10;
|
|
pFD17XX->status &= ~0x20;
|
|
pFD17XX->status &= ~0x40;
|
|
pFD17XX->status &= ~FD17XX_STAT_LOSTDATA;
|
|
break;
|
|
|
|
case TARBELL_CMD_WRITE_TRACK:
|
|
pFD17XX->status &= ~0x08;
|
|
pFD17XX->status &= ~0x10;
|
|
pFD17XX->status &= ~FD17XX_STAT_WRITEPROT;
|
|
pFD17XX->status &= ~FD17XX_STAT_LOSTDATA;
|
|
pFD17XX->status |= ((uptr->flags & UNIT_TARBELL_WPROTECT) || tarbell_info->writeProtect) ? FD17XX_STAT_WRITEPROT : 0x00;
|
|
break;
|
|
}
|
|
|
|
sim_debug(CMD_MSG, &tarbell_dev,
|
|
TARBELL_SNAME ": CMD cmd=%02X drive=%d side=%d track=%03d sector=%03d status=%02X\n",
|
|
pFD17XX->command, tarbell_info->currentDrive,
|
|
tarbell_info->side[tarbell_info->currentDrive],
|
|
pFD17XX->track, pFD17XX->sector, pFD17XX->status);
|
|
|
|
return(cData);
|
|
}
|
|
|
|
static int32 tarbellprom(int32 Addr, int32 rw, int32 Data)
|
|
{
|
|
/*
|
|
** 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, 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
|
|
** the 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;
|
|
sim_debug(STATUS_MSG, &tarbell_dev, TARBELL_SNAME ": Boot PROM disabled.\n");
|
|
}
|
|
|
|
if (tarbell_info->promEnabled == TRUE && Addr < TARBELL_PROM_SIZE) {
|
|
return(tarbell_prom[Addr & TARBELL_PROM_MASK]);
|
|
} else {
|
|
return(tarbell_ram[Addr & TARBELL_RAM_MASK]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int32 tarbelldma(int32 Addr, int32 rw, int32 data)
|
|
{
|
|
return 0x00; /* DMA is not implemented */
|
|
}
|
|
|