simh-testsetgenerator/AltairZ80/s100_dj2d.c

2521 lines
98 KiB
C

/* s100_dj2d.c: Morrow DISK JOCKEY 2D/B Floppy Disk Interface
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 the original Morrow DISK JOCKEY 2D (Model A) and
Model B disk controllers.
The model is selected using the "SET DJ2D MODEL={A|B}" command. The default
is the Model B.
DJ2D units:
DJ2D0 - Drive A
DJ2D1 - Drive B
DJ2D3 - Drive C
DJ2D4 - Drive D
DJ2D5 - Serial Port
*/
/* #define DBG_MSG */
#include "altairz80_defs.h"
#include "sim_imd.h"
#include "sim_tmxr.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 uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap);
extern DEVICE *find_dev (const char *cptr);
extern uint32 getClockFrequency(void);
extern void setClockFrequency(const uint32 Value);
#define DJ2D_MAX_ADAPTERS 1
#define DJ2D_MAX_DRIVES 4
#define DJ2D_UNITS DJ2D_MAX_DRIVES+1
#define DJ2D_SIO_UNIT DJ2D_UNITS-1
#define DJ2D_TRACKS 77
#define DJ2D_TIMER 1 /* 1ms timer */
#define DJ2D_ROTATION_MS 166 /* 166 milliseconds per revolution */
#define DJ2D_HEAD_TIMEOUT (DJ2D_ROTATION_MS / DJ2D_TIMER * 6) /* 6 revolutions */
#define DJ2D_INDEX_TIMEOUT (DJ2D_ROTATION_MS / DJ2D_TIMER) /* 1 revolution */
#define DJ2D_BUSY_TIMEOUT 2 /* 2 timer ticks */
#define DJ2D_BAUD 19200 /* Default baud rate */
enum { FMT_SD, FMT_256, FMT_512, FMT_1024, FMT_UNKNOWN };
static uint32 dj2d_image_size[] = {256256, 509184, 587008, 625920, 0};
static uint32 dj2d_2s_image_size[] = {512512, 1021696, 1178368, 1256704, 0};
static uint16 dj2d_sector_len[] = {128, 256, 512, 1024, 0};
static uint16 dj2d_spt[] = {26, 26, 15, 8, 0};
static uint16 dj2d_track_len[] = {5000, 9800, 10300, 9700, 0};
#define DJ2D_MEM_READ FALSE
#define DJ2D_MEM_WRITE TRUE
#define DJ2D_PROM_BASE 0xe000
#define DJ2D_PROM_SIZE 1024
#define DJ2D_PROM_MASK (DJ2D_PROM_SIZE-1)
#define DJ2D_MEM_BASE DJ2D_PROM_BASE + DJ2D_PROM_SIZE
#define DJ2D_MEM_SIZE 1024 /* Must be on a page boundary */
#define DJ2D_MEM_MASK (DJ2D_MEM_SIZE-1)
static uint8 dj2d_mem[DJ2D_MEM_SIZE];
/* DJ2D PROM is 1016 bytes following by 8 memory-mapped I/O bytes */
static uint8 dj2d_proma_e000[DJ2D_PROM_SIZE] = {
0xc3, 0x61, 0xe0, 0xc3, 0xff, 0xe0, 0xc3, 0xf0,
0xe0, 0xc3, 0x6f, 0xe1, 0xc3, 0xa0, 0xe1, 0xc3,
0x93, 0xe1, 0xc3, 0x56, 0xe1, 0xc3, 0xa9, 0xe1,
0xc3, 0xfc, 0xe1, 0xc3, 0x4b, 0xe1, 0xc3, 0x0e,
0xe1, 0xc3, 0x19, 0xe1, 0xc3, 0x43, 0xe1, 0xc3,
0x1f, 0xe1, 0xc3, 0xdb, 0xe0, 0xc3, 0xbf, 0xe3,
0xc3, 0xde, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x31, 0xfa, 0xe6, 0x21, 0xe1, 0xe6, 0x11,
0xeb, 0xe2, 0x06, 0x04, 0x1a, 0xbe, 0xc2, 0x7a,
0xe0, 0x23, 0x13, 0x05, 0xc2, 0x6c, 0xe0, 0xc3,
0x7d, 0xe0, 0xcd, 0xe9, 0xe3, 0x21, 0x01, 0x00,
0xe5, 0x2e, 0x03, 0xe5, 0x26, 0xff, 0xe5, 0xe5,
0xe5, 0xe5, 0x21, 0x00, 0x00, 0xe5, 0x33, 0x26,
0x08, 0xe5, 0x26, 0xfe, 0xe5, 0x26, 0xe7, 0xe5,
0x26, 0x18, 0xe5, 0x3e, 0x03, 0x32, 0xfa, 0xe3,
0x3e, 0xd0, 0x32, 0xfc, 0xe3, 0xaf, 0xcd, 0x25,
0xe3, 0xd2, 0xb7, 0xe0, 0x3e, 0x1e, 0x32, 0xea,
0xe6, 0xcd, 0xe9, 0xe3, 0xc3, 0xa5, 0xe0, 0x3e,
0x3e, 0x32, 0xea, 0xe6, 0x36, 0x03, 0xe1, 0xcd,
0xa2, 0xe3, 0xc1, 0xc5, 0xd5, 0x2a, 0xed, 0xe2,
0xe5, 0x2a, 0xeb, 0xe2, 0xe5, 0x00, 0xc5, 0x06,
0x0a, 0xc5, 0xcd, 0xa9, 0xe1, 0xc1, 0xd0, 0x05,
0xc2, 0xd1, 0xe0, 0x0e, 0x3f, 0x11, 0xc3, 0xa2,
0x1b, 0x7a, 0xb3, 0xc2, 0xe0, 0xe0, 0x3e, 0x20,
0xa9, 0x32, 0xf9, 0xe3, 0x4f, 0xc3, 0xdd, 0xe0,
0x3a, 0xf9, 0xe3, 0xe6, 0x08, 0xc2, 0xf0, 0xe0,
0x79, 0x2f, 0x32, 0xf8, 0xe3, 0x2f, 0xc9, 0x3a,
0xf9, 0xe3, 0xe6, 0x04, 0xc2, 0xff, 0xe0, 0x3a,
0xf8, 0xe3, 0x2f, 0xe6, 0x7f, 0xc9, 0x3a, 0xf9,
0xe3, 0xe6, 0x04, 0xc0, 0xcd, 0xff, 0xe0, 0xb9,
0xc9, 0x3a, 0xf9, 0xe3, 0xe6, 0x04, 0xc9, 0x3a,
0xfe, 0xe3, 0x47, 0x3a, 0xfd, 0xe3, 0x4f, 0x3a,
0xf6, 0xe6, 0x2f, 0xe6, 0x01, 0x0f, 0x57, 0x3a,
0xf7, 0xe6, 0x07, 0x07, 0x07, 0x82, 0x57, 0x3a,
0xfd, 0xe6, 0x17, 0x17, 0x82, 0x57, 0x3a, 0xec,
0xe6, 0x82, 0xc9, 0xe5, 0x2a, 0xe7, 0xe6, 0x44,
0x4d, 0xe1, 0xc9, 0x3e, 0xfc, 0x81, 0x3e, 0x10,
0xd8, 0x79, 0x32, 0xeb, 0xe6, 0xc9, 0x21, 0x08,
0x20, 0x09, 0xd2, 0x68, 0xe1, 0x21, 0x00, 0x1c,
0x09, 0xda, 0x68, 0xe1, 0x37, 0x3e, 0x10, 0xc9,
0x60, 0x69, 0x22, 0xe7, 0xe6, 0xaf, 0xc9, 0xcd,
0x7b, 0xe1, 0xf5, 0x9f, 0x32, 0xf9, 0xe6, 0xf1,
0xc3, 0x2a, 0xe2, 0xcd, 0xef, 0xe2, 0xd8, 0xaf,
0x32, 0xed, 0xe6, 0x32, 0xe9, 0xe6, 0x21, 0x00,
0x00, 0x3e, 0x09, 0xcd, 0x6c, 0xe3, 0xe6, 0x04,
0xc0, 0x37, 0xc9, 0xaf, 0xb1, 0x37, 0xc8, 0x79,
0xfe, 0x1b, 0x3f, 0xd8, 0x32, 0xf8, 0xe6, 0xc9,
0x79, 0xfe, 0x4d, 0x3f, 0xd8, 0x32, 0xf9, 0xe6,
0xc9, 0xcd, 0x35, 0xe2, 0xe1, 0x3e, 0x40, 0xbb,
0xca, 0xe8, 0xe1, 0xe5, 0x19, 0x19, 0xe5, 0xf9,
0x1b, 0x21, 0xff, 0xe3, 0x3e, 0x80, 0x32, 0xfc,
0xe3, 0x46, 0x4e, 0xc5, 0x46, 0x1d, 0xc2, 0xc2,
0xe1, 0x15, 0xf2, 0xc2, 0xe1, 0x4e, 0xc5, 0x31,
0xc6, 0xe6, 0xe1, 0xd1, 0x2b, 0x46, 0x1a, 0x77,
0x78, 0x12, 0x13, 0x7d, 0xbb, 0xc2, 0xd4, 0xe1,
0x7c, 0xba, 0xc2, 0xd4, 0xe1, 0xc3, 0x18, 0xe2,
0x07, 0x4f, 0x11, 0xff, 0xe3, 0x3e, 0x80, 0x32,
0xfc, 0xe3, 0x1a, 0x77, 0x23, 0x0d, 0xc2, 0xf2,
0xe1, 0xc3, 0x18, 0xe2, 0xcd, 0x35, 0xe2, 0xe1,
0xf9, 0x1b, 0x21, 0xff, 0xe3, 0x3e, 0xa0, 0x32,
0xfc, 0xe3, 0xc1, 0x71, 0x70, 0xc1, 0x71, 0x1d,
0xc2, 0x0c, 0xe2, 0x15, 0xf2, 0x0c, 0xe2, 0x70,
0x3a, 0xfc, 0xe3, 0x1f, 0xda, 0x18, 0xe2, 0x17,
0xe6, 0xdf, 0xca, 0x26, 0xe2, 0x37, 0x2a, 0xca,
0xe6, 0xf9, 0xf5, 0x3a, 0xf6, 0xe6, 0xee, 0x10,
0x32, 0xfa, 0xe3, 0xf1, 0xc9, 0xd1, 0x21, 0x00,
0x00, 0x39, 0x31, 0xcc, 0xe6, 0xe5, 0x2a, 0xe7,
0xe6, 0xe5, 0xd5, 0x21, 0x26, 0xe2, 0xe5, 0xcd,
0xef, 0xe2, 0xd8, 0x3a, 0xfd, 0xe3, 0x3c, 0xcc,
0x7b, 0xe1, 0xda, 0x9f, 0xe2, 0x21, 0xfd, 0xe3,
0x3a, 0xf9, 0xe6, 0xbe, 0x23, 0x23, 0x77, 0x79,
0x32, 0xfa, 0xe3, 0xca, 0x7d, 0xe2, 0xaf, 0x32,
0xe9, 0xe6, 0x3a, 0xfa, 0xe3, 0xe6, 0x08, 0x7f,
0x1f, 0x1f, 0xc6, 0x18, 0x21, 0x00, 0x00, 0xcd,
0x6c, 0xe3, 0xda, 0x9f, 0xe2, 0x3a, 0xe9, 0xe6,
0xb7, 0xc2, 0xc9, 0xe2, 0x06, 0x02, 0x3e, 0x1d,
0xcd, 0x67, 0xe3, 0xe6, 0x99, 0xca, 0xa5, 0xe2,
0x3a, 0xf6, 0xe6, 0xee, 0x01, 0x32, 0xf6, 0xe6,
0x32, 0xfa, 0xe3, 0x05, 0xc2, 0x86, 0xe2, 0xcd,
0x6f, 0xe1, 0xc3, 0x9e, 0xe3, 0x06, 0x0a, 0x11,
0xff, 0xe3, 0x21, 0xfa, 0xe6, 0x3e, 0xc4, 0x32,
0xfc, 0xe3, 0x1a, 0x77, 0x2c, 0xc2, 0xb2, 0xe2,
0x21, 0xfc, 0xe3, 0xcd, 0x7e, 0xe3, 0xb7, 0xca,
0xc9, 0xe2, 0x05, 0xc2, 0xa7, 0xe2, 0xc3, 0x9f,
0xe2, 0x3a, 0xfd, 0xe6, 0x4f, 0x06, 0x00, 0x21,
0xeb, 0xe2, 0x09, 0x3a, 0xf8, 0xe6, 0x47, 0x86,
0x3e, 0x10, 0xd8, 0xe1, 0x78, 0x32, 0xfe, 0xe3,
0x21, 0x40, 0x00, 0x0d, 0x54, 0x5d, 0xf8, 0x29,
0xc3, 0xe3, 0xe2, 0xe5, 0xe5, 0xf0, 0xf7, 0x21,
0xeb, 0xe6, 0x4e, 0x23, 0x5e, 0x71, 0x23, 0x7b,
0xb9, 0x7e, 0x36, 0x04, 0x23, 0xca, 0x25, 0xe3,
0xe5, 0x16, 0x00, 0x42, 0x19, 0x19, 0x3a, 0xf6,
0xe6, 0x77, 0x23, 0x11, 0xfd, 0xe3, 0x1a, 0x77,
0xe1, 0x09, 0x09, 0x7e, 0x32, 0xf6, 0xe6, 0x23,
0x7e, 0x12, 0x3e, 0x7f, 0x07, 0x0d, 0xf2, 0x1c,
0xe3, 0x32, 0xea, 0xe6, 0xaf, 0x21, 0xfa, 0xe3,
0xa6, 0x32, 0xe9, 0xe6, 0xf5, 0x3a, 0xea, 0xe6,
0x4f, 0x3a, 0xf7, 0xe6, 0x2f, 0xa1, 0x32, 0xf9,
0xe3, 0x3a, 0xf6, 0xe6, 0x4f, 0x3a, 0xf9, 0xe6,
0xd6, 0x01, 0x9f, 0x3d, 0x2f, 0xb1, 0x77, 0xee,
0x02, 0x4f, 0xf1, 0xc2, 0x59, 0xe3, 0xe5, 0x2a,
0xe5, 0xe6, 0x2b, 0x7c, 0xb5, 0xc2, 0x52, 0xe3,
0xe1, 0x7e, 0xe6, 0x20, 0xc8, 0x3a, 0xf6, 0xe6,
0xf6, 0x18, 0x77, 0x3e, 0x80, 0x37, 0xc9, 0x2a,
0xe5, 0xe6, 0x29, 0x29, 0xeb, 0x21, 0xfc, 0xe3,
0xc3, 0x76, 0xe3, 0xc3, 0xef, 0xe2, 0x00, 0x00,
0x77, 0x7e, 0x1f, 0xd2, 0x79, 0xe3, 0x7e, 0x1f,
0x7e, 0xd0, 0x1b, 0x7a, 0xb3, 0xc2, 0x7e, 0xe3,
0xe5, 0x23, 0x56, 0x3a, 0xf6, 0xe6, 0xee, 0x04,
0x32, 0xfa, 0xe3, 0xee, 0x04, 0xe3, 0x32, 0xfa,
0xe3, 0x36, 0xd0, 0xe3, 0x72, 0xe1, 0x3e, 0x11,
0x37, 0xc9, 0x11, 0x00, 0x00, 0x21, 0xfa, 0xe3,
0x0e, 0x10, 0x7e, 0xa1, 0xc2, 0xaa, 0xe3, 0x7e,
0xa1, 0xca, 0xaf, 0xe3, 0x13, 0xe3, 0xe3, 0xe3,
0xe3, 0x7e, 0xa1, 0xc2, 0xb4, 0xe3, 0xc9, 0x79,
0xe6, 0x01, 0x2f, 0x47, 0x21, 0xeb, 0xe6, 0x5e,
0x16, 0x00, 0x23, 0x7e, 0xab, 0xf5, 0x23, 0x23,
0x19, 0x19, 0x7e, 0xf6, 0x01, 0xa0, 0x77, 0xf1,
0xc0, 0x7e, 0x32, 0xf6, 0xe6, 0xc9, 0x79, 0xe6,
0x01, 0x17, 0x17, 0x17, 0x17, 0x32, 0xf7, 0xe6,
0xc9, 0x21, 0x00, 0x00, 0x2b, 0x7c, 0xb5, 0xe3,
0xe3, 0xc2, 0xec, 0xe3, 0xc9, 0xe0, 0x00, 0xc3,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static uint8 dj2d_proma_f800[DJ2D_PROM_SIZE] = {
0xc3, 0x61, 0xf8, 0xc3, 0xff, 0xf8, 0xc3, 0xf0,
0xf8, 0xc3, 0x6f, 0xf9, 0xc3, 0xa0, 0xf9, 0xc3,
0x93, 0xf9, 0xc3, 0x56, 0xf9, 0xc3, 0xa9, 0xf9,
0xc3, 0xfc, 0xf9, 0xc3, 0x4b, 0xf9, 0xc3, 0x0e,
0xf9, 0xc3, 0x19, 0xf9, 0xc3, 0x43, 0xf9, 0xc3,
0x1f, 0xf9, 0xc3, 0xdb, 0xf8, 0xc3, 0xbf, 0xfb,
0xc3, 0xde, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x31, 0xfa, 0xfe, 0x21, 0xe1, 0xfe, 0x11,
0xeb, 0xfa, 0x06, 0x04, 0x1a, 0xbe, 0xc2, 0x7a,
0xf8, 0x23, 0x13, 0x05, 0xc2, 0x6c, 0xf8, 0xc3,
0x7d, 0xf8, 0xcd, 0xe9, 0xfb, 0x21, 0x01, 0x00,
0xe5, 0x2e, 0x03, 0xe5, 0x26, 0xff, 0xe5, 0xe5,
0xe5, 0xe5, 0x21, 0x00, 0x00, 0xe5, 0x33, 0x26,
0x08, 0xe5, 0x26, 0xfe, 0xe5, 0x26, 0xff, 0xe5,
0x26, 0x18, 0xe5, 0x3e, 0x03, 0x32, 0xfa, 0xfb,
0x3e, 0xd0, 0x32, 0xfc, 0xfb, 0xaf, 0xcd, 0x25,
0xfb, 0xd2, 0xb7, 0xf8, 0x3e, 0x1e, 0x32, 0xea,
0xfe, 0xcd, 0xe9, 0xfb, 0xc3, 0xa5, 0xf8, 0x3e,
0x3e, 0x32, 0xea, 0xfe, 0x36, 0x03, 0xe1, 0xcd,
0xa2, 0xfb, 0xc1, 0xc5, 0xd5, 0x2a, 0xed, 0xfa,
0xe5, 0x2a, 0xeb, 0xfa, 0xe5, 0x00, 0xc5, 0x06,
0x0a, 0xc5, 0xcd, 0xa9, 0xf9, 0xc1, 0xd0, 0x05,
0xc2, 0xd1, 0xf8, 0x0e, 0x3f, 0x11, 0xc3, 0xa2,
0x1b, 0x7a, 0xb3, 0xc2, 0xe0, 0xf8, 0x3e, 0x20,
0xa9, 0x32, 0xf9, 0xfb, 0x4f, 0xc3, 0xdd, 0xf8,
0x3a, 0xf9, 0xfb, 0xe6, 0x08, 0xc2, 0xf0, 0xf8,
0x79, 0x2f, 0x32, 0xf8, 0xfb, 0x2f, 0xc9, 0x3a,
0xf9, 0xfb, 0xe6, 0x04, 0xc2, 0xff, 0xf8, 0x3a,
0xf8, 0xfb, 0x2f, 0xe6, 0x7f, 0xc9, 0x3a, 0xf9,
0xfb, 0xe6, 0x04, 0xc0, 0xcd, 0xff, 0xf8, 0xb9,
0xc9, 0x3a, 0xf9, 0xfb, 0xe6, 0x04, 0xc9, 0x3a,
0xfe, 0xfb, 0x47, 0x3a, 0xfd, 0xfb, 0x4f, 0x3a,
0xf6, 0xfe, 0x2f, 0xe6, 0x01, 0x0f, 0x57, 0x3a,
0xf7, 0xfe, 0x07, 0x07, 0x07, 0x82, 0x57, 0x3a,
0xfd, 0xfe, 0x17, 0x17, 0x82, 0x57, 0x3a, 0xec,
0xfe, 0x82, 0xc9, 0xe5, 0x2a, 0xe7, 0xfe, 0x44,
0x4d, 0xe1, 0xc9, 0x3e, 0xfc, 0x81, 0x3e, 0x10,
0xd8, 0x79, 0x32, 0xeb, 0xfe, 0xc9, 0x21, 0x08,
0x08, 0x09, 0xd2, 0x68, 0xf9, 0x21, 0x00, 0x04,
0x09, 0xda, 0x68, 0xf9, 0x37, 0x3e, 0x10, 0xc9,
0x60, 0x69, 0x22, 0xe7, 0xfe, 0xaf, 0xc9, 0xcd,
0x7b, 0xf9, 0xf5, 0x9f, 0x32, 0xf9, 0xfe, 0xf1,
0xc3, 0x2a, 0xfa, 0xcd, 0xef, 0xfa, 0xd8, 0xaf,
0x32, 0xed, 0xfe, 0x32, 0xe9, 0xfe, 0x21, 0x00,
0x00, 0x3e, 0x09, 0xcd, 0x6c, 0xfb, 0xe6, 0x04,
0xc0, 0x37, 0xc9, 0xaf, 0xb1, 0x37, 0xc8, 0x79,
0xfe, 0x1b, 0x3f, 0xd8, 0x32, 0xf8, 0xfe, 0xc9,
0x79, 0xfe, 0x4d, 0x3f, 0xd8, 0x32, 0xf9, 0xfe,
0xc9, 0xcd, 0x35, 0xfa, 0xe1, 0x3e, 0x40, 0xbb,
0xca, 0xe8, 0xf9, 0xe5, 0x19, 0x19, 0xe5, 0xf9,
0x1b, 0x21, 0xff, 0xfb, 0x3e, 0x80, 0x32, 0xfc,
0xfb, 0x46, 0x4e, 0xc5, 0x46, 0x1d, 0xc2, 0xc2,
0xf9, 0x15, 0xf2, 0xc2, 0xf9, 0x4e, 0xc5, 0x31,
0xc6, 0xfe, 0xe1, 0xd1, 0x2b, 0x46, 0x1a, 0x77,
0x78, 0x12, 0x13, 0x7d, 0xbb, 0xc2, 0xd4, 0xf9,
0x7c, 0xba, 0xc2, 0xd4, 0xf9, 0xc3, 0x18, 0xfa,
0x07, 0x4f, 0x11, 0xff, 0xfb, 0x3e, 0x80, 0x32,
0xfc, 0xfb, 0x1a, 0x77, 0x23, 0x0d, 0xc2, 0xf2,
0xf9, 0xc3, 0x18, 0xfa, 0xcd, 0x35, 0xfa, 0xe1,
0xf9, 0x1b, 0x21, 0xff, 0xfb, 0x3e, 0xa0, 0x32,
0xfc, 0xfb, 0xc1, 0x71, 0x70, 0xc1, 0x71, 0x1d,
0xc2, 0x0c, 0xfa, 0x15, 0xf2, 0x0c, 0xfa, 0x70,
0x3a, 0xfc, 0xfb, 0x1f, 0xda, 0x18, 0xfa, 0x17,
0xe6, 0xdf, 0xca, 0x26, 0xfa, 0x37, 0x2a, 0xca,
0xfe, 0xf9, 0xf5, 0x3a, 0xf6, 0xfe, 0xee, 0x10,
0x32, 0xfa, 0xfb, 0xf1, 0xc9, 0xd1, 0x21, 0x00,
0x00, 0x39, 0x31, 0xcc, 0xfe, 0xe5, 0x2a, 0xe7,
0xfe, 0xe5, 0xd5, 0x21, 0x26, 0xfa, 0xe5, 0xcd,
0xef, 0xfa, 0xd8, 0x3a, 0xfd, 0xfb, 0x3c, 0xcc,
0x7b, 0xf9, 0xda, 0x9f, 0xfa, 0x21, 0xfd, 0xfb,
0x3a, 0xf9, 0xfe, 0xbe, 0x23, 0x23, 0x77, 0x79,
0x32, 0xfa, 0xfb, 0xca, 0x7d, 0xfa, 0xaf, 0x32,
0xe9, 0xfe, 0x3a, 0xfa, 0xfb, 0xe6, 0x08, 0x7f,
0x1f, 0x1f, 0xc6, 0x18, 0x21, 0x00, 0x00, 0xcd,
0x6c, 0xfb, 0xda, 0x9f, 0xfa, 0x3a, 0xe9, 0xfe,
0xb7, 0xc2, 0xc9, 0xfa, 0x06, 0x02, 0x3e, 0x1d,
0xcd, 0x67, 0xfb, 0xe6, 0x99, 0xca, 0xa5, 0xfa,
0x3a, 0xf6, 0xfe, 0xee, 0x01, 0x32, 0xf6, 0xfe,
0x32, 0xfa, 0xfb, 0x05, 0xc2, 0x86, 0xfa, 0xcd,
0x6f, 0xf9, 0xc3, 0x9e, 0xfb, 0x06, 0x0a, 0x11,
0xff, 0xfb, 0x21, 0xfa, 0xfe, 0x3e, 0xc4, 0x32,
0xfc, 0xfb, 0x1a, 0x77, 0x2c, 0xc2, 0xb2, 0xfa,
0x21, 0xfc, 0xfb, 0xcd, 0x7e, 0xfb, 0xb7, 0xca,
0xc9, 0xfa, 0x05, 0xc2, 0xa7, 0xfa, 0xc3, 0x9f,
0xfa, 0x3a, 0xfd, 0xfe, 0x4f, 0x06, 0x00, 0x21,
0xeb, 0xfa, 0x09, 0x3a, 0xf8, 0xfe, 0x47, 0x86,
0x3e, 0x10, 0xd8, 0xe1, 0x78, 0x32, 0xfe, 0xfb,
0x21, 0x40, 0x00, 0x0d, 0x54, 0x5d, 0xf8, 0x29,
0xc3, 0xe3, 0xfa, 0xe5, 0xe5, 0xf0, 0xf7, 0x21,
0xeb, 0xfe, 0x4e, 0x23, 0x5e, 0x71, 0x23, 0x7b,
0xb9, 0x7e, 0x36, 0x04, 0x23, 0xca, 0x25, 0xfb,
0xe5, 0x16, 0x00, 0x42, 0x19, 0x19, 0x3a, 0xf6,
0xfe, 0x77, 0x23, 0x11, 0xfd, 0xfb, 0x1a, 0x77,
0xe1, 0x09, 0x09, 0x7e, 0x32, 0xf6, 0xfe, 0x23,
0x7e, 0x12, 0x3e, 0x7f, 0x07, 0x0d, 0xf2, 0x1c,
0xfb, 0x32, 0xea, 0xfe, 0xaf, 0x21, 0xfa, 0xfb,
0xa6, 0x32, 0xe9, 0xfe, 0xf5, 0x3a, 0xea, 0xfe,
0x4f, 0x3a, 0xf7, 0xfe, 0x2f, 0xa1, 0x32, 0xf9,
0xfb, 0x3a, 0xf6, 0xfe, 0x4f, 0x3a, 0xf9, 0xfe,
0xd6, 0x01, 0x9f, 0x3d, 0x2f, 0xb1, 0x77, 0xee,
0x02, 0x4f, 0xf1, 0xc2, 0x59, 0xfb, 0xe5, 0x2a,
0xe5, 0xfe, 0x2b, 0x7c, 0xb5, 0xc2, 0x52, 0xfb,
0xe1, 0x7e, 0xe6, 0x20, 0xc8, 0x3a, 0xf6, 0xfe,
0xf6, 0x18, 0x77, 0x3e, 0x80, 0x37, 0xc9, 0x2a,
0xe5, 0xfe, 0x29, 0x29, 0xeb, 0x21, 0xfc, 0xfb,
0xc3, 0x76, 0xfb, 0xc3, 0xef, 0xfa, 0x00, 0x00,
0x77, 0x7e, 0x1f, 0xd2, 0x79, 0xfb, 0x7e, 0x1f,
0x7e, 0xd0, 0x1b, 0x7a, 0xb3, 0xc2, 0x7e, 0xfb,
0xe5, 0x23, 0x56, 0x3a, 0xf6, 0xfe, 0xee, 0x04,
0x32, 0xfa, 0xfb, 0xee, 0x04, 0xe3, 0x32, 0xfa,
0xfb, 0x36, 0xd0, 0xe3, 0x72, 0xe1, 0x3e, 0x11,
0x37, 0xc9, 0x11, 0x00, 0x00, 0x21, 0xfa, 0xfb,
0x0e, 0x10, 0x7e, 0xa1, 0xc2, 0xaa, 0xfb, 0x7e,
0xa1, 0xca, 0xaf, 0xfb, 0x13, 0xe3, 0xe3, 0xe3,
0xe3, 0x7e, 0xa1, 0xc2, 0xb4, 0xfb, 0xc9, 0x79,
0xe6, 0x01, 0x2f, 0x47, 0x21, 0xeb, 0xfe, 0x5e,
0x16, 0x00, 0x23, 0x7e, 0xab, 0xf5, 0x23, 0x23,
0x19, 0x19, 0x7e, 0xf6, 0x01, 0xa0, 0x77, 0xf1,
0xc0, 0x7e, 0x32, 0xf6, 0xfe, 0xc9, 0x79, 0xe6,
0x01, 0x17, 0x17, 0x17, 0x17, 0x32, 0xf7, 0xfe,
0xc9, 0x21, 0x00, 0x00, 0x2b, 0x7c, 0xb5, 0xe3,
0xe3, 0xc2, 0xec, 0xfb, 0xc9, 0xf8, 0x00, 0xc3,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static uint8 dj2d_promb_e000[DJ2D_PROM_SIZE] = {
0xc3, 0x69, 0xe0, 0xc3, 0xe9, 0xe0, 0xc3, 0xda,
0xe0, 0xc3, 0x5a, 0xe1, 0xc3, 0x8b, 0xe1, 0xc3,
0x81, 0xe1, 0xc3, 0x43, 0xe1, 0xc3, 0xdd, 0xe1,
0xc3, 0xbc, 0xe1, 0xc3, 0x3c, 0xe1, 0xc3, 0xf8,
0xe0, 0xc3, 0x03, 0xe1, 0xc3, 0x34, 0xe1, 0xc3,
0x09, 0xe1, 0xc3, 0xc5, 0xe0, 0xc3, 0xb3, 0xe3,
0xc3, 0xe5, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x31, 0xfa, 0xe7, 0xcd, 0xd2, 0xe3, 0x21,
0x01, 0x00, 0xe5, 0x2e, 0x09, 0xe5, 0x26, 0xff,
0xe5, 0xe5, 0xe5, 0xe5, 0x21, 0x08, 0x00, 0xe5,
0x2e, 0x7e, 0xe5, 0x2e, 0x08, 0xe5, 0x26, 0x18,
0xe5, 0x3e, 0x7f, 0x32, 0xf9, 0xe3, 0x3e, 0xd0,
0x32, 0xfc, 0xe3, 0xaf, 0xcd, 0x1b, 0xe3, 0xd2,
0xa5, 0xe0, 0x3e, 0x01, 0x32, 0xf6, 0xe7, 0xcd,
0xd2, 0xe3, 0xc3, 0x93, 0xe0, 0x3e, 0x09, 0x32,
0xf6, 0xe7, 0xcd, 0x96, 0xe3, 0xc1, 0x01, 0x00,
0xe7, 0xc5, 0xd5, 0x21, 0x00, 0x00, 0xe5, 0x00,
0xc5, 0x06, 0x0c, 0xc5, 0xcd, 0xdd, 0xe1, 0xc1,
0xd0, 0x05, 0xc2, 0xbb, 0xe0, 0x0e, 0x09, 0x11,
0xc3, 0xa2, 0x1b, 0x7a, 0xb3, 0xc2, 0xca, 0xe0,
0x3e, 0x08, 0xa9, 0x4f, 0x32, 0xfa, 0xe3, 0xc3,
0xc7, 0xe0, 0x3a, 0xf9, 0xe3, 0xe6, 0x08, 0xc2,
0xda, 0xe0, 0x79, 0x2f, 0x32, 0xf8, 0xe3, 0x2f,
0xc9, 0x3a, 0xf9, 0xe3, 0xe6, 0x04, 0xc2, 0xe9,
0xe0, 0x3a, 0xf8, 0xe3, 0x2f, 0xe6, 0x7f, 0xc9,
0x3a, 0xf9, 0xe3, 0xe6, 0x04, 0xc0, 0xcd, 0xe9,
0xe0, 0xb9, 0xc9, 0x3a, 0xf9, 0xe3, 0xe6, 0x04,
0xc9, 0x21, 0xfd, 0xe3, 0x4e, 0x23, 0x46, 0x3a,
0xf6, 0xe7, 0x2f, 0xe6, 0x01, 0x0f, 0x57, 0x3a,
0xf7, 0xe7, 0x07, 0x07, 0x07, 0xb2, 0x57, 0x3a,
0xe8, 0xe7, 0xee, 0x08, 0x17, 0x17, 0x82, 0x57,
0x3a, 0xfd, 0xe7, 0x17, 0x17, 0xb2, 0x57, 0x3a,
0xec, 0xe7, 0x82, 0xc9, 0xe5, 0x2a, 0xe6, 0xe7,
0x44, 0x4d, 0xe1, 0xc9, 0x79, 0xe6, 0x03, 0x32,
0xeb, 0xe7, 0xc9, 0x21, 0x00, 0x1c, 0x09, 0xda,
0x54, 0xe1, 0x21, 0x08, 0x20, 0x09, 0xd2, 0x54,
0xe1, 0x3e, 0x10, 0xc9, 0x60, 0x69, 0x22, 0xe6,
0xe7, 0xc9, 0xcd, 0xe3, 0xe2, 0xd8, 0xcd, 0x70,
0xe1, 0xf5, 0x9f, 0x32, 0xf9, 0xe7, 0x32, 0xfd,
0xe3, 0xaf, 0x32, 0xed, 0xe7, 0xc3, 0x23, 0xe2,
0xaf, 0x32, 0xe9, 0xe7, 0x21, 0x00, 0x00, 0x3e,
0x09, 0xcd, 0x62, 0xe3, 0xe6, 0x04, 0xc0, 0x37,
0xc9, 0xaf, 0xb1, 0x37, 0xc8, 0xe6, 0x3f, 0x32,
0xf8, 0xe7, 0xc9, 0x79, 0xfe, 0x4d, 0x3f, 0xd8,
0x32, 0xf9, 0xe7, 0xc9, 0x32, 0xe3, 0xe7, 0xcd,
0x96, 0xe3, 0x0e, 0x01, 0x79, 0x32, 0xfe, 0xe3,
0x3a, 0xf8, 0xe7, 0xb9, 0xc8, 0x3e, 0x80, 0xcd,
0x5d, 0xe3, 0xda, 0x20, 0xe2, 0x0c, 0xc3, 0x9c,
0xe1, 0x32, 0xfc, 0xe3, 0x48, 0x11, 0xff, 0xe3,
0x2a, 0xe6, 0xe7, 0xc9, 0xcd, 0x33, 0xe2, 0xda,
0x22, 0xe2, 0x3e, 0xa0, 0xcd, 0xb1, 0xe1, 0x7e,
0x23, 0x12, 0x7e, 0x23, 0x12, 0x7e, 0x23, 0x12,
0x0d, 0x7e, 0x23, 0x12, 0xc2, 0xc7, 0xe1, 0x21,
0xc2, 0xe1, 0xc3, 0xfb, 0xe1, 0xcd, 0x33, 0xe2,
0xda, 0x22, 0xe2, 0x3e, 0x80, 0xcd, 0xb1, 0xe1,
0x1a, 0x77, 0x23, 0x1a, 0x77, 0x23, 0x1a, 0x77,
0x23, 0x0d, 0x1a, 0x77, 0x23, 0xc2, 0xe8, 0xe1,
0x21, 0xe3, 0xe1, 0xe5, 0x21, 0xfc, 0xe3, 0xcd,
0x6c, 0xe3, 0xe6, 0x5f, 0xca, 0x21, 0xe2, 0xfe,
0x10, 0xc2, 0x20, 0xe2, 0x3a, 0xe2, 0xe7, 0x3d,
0xfa, 0x17, 0xe2, 0x32, 0xe2, 0xe7, 0xc9, 0x3a,
0xe3, 0xe7, 0x3d, 0xf2, 0x94, 0xe1, 0x3e, 0x10,
0x37, 0xe1, 0xf5, 0x3a, 0xf6, 0xe7, 0xee, 0x04,
0x32, 0xfa, 0xe3, 0x3a, 0xea, 0xe7, 0x32, 0xf9,
0xe3, 0xf1, 0xc9, 0xcd, 0xe3, 0xe2, 0xd8, 0x3a,
0xfd, 0xe3, 0x3c, 0xcc, 0x70, 0xe1, 0xd8, 0x21,
0xfd, 0xe3, 0x3a, 0xf9, 0xe7, 0xbe, 0x23, 0x23,
0x77, 0x79, 0x32, 0xf9, 0xe3, 0xca, 0x6a, 0xe2,
0xaf, 0x32, 0xe9, 0xe7, 0x3a, 0xfa, 0xe3, 0xe6,
0x08, 0x32, 0xe8, 0xe7, 0x1f, 0x1f, 0x1f, 0xc6,
0x18, 0x21, 0x00, 0x00, 0xcd, 0x62, 0xe3, 0xda,
0x8e, 0xe2, 0x3a, 0xe9, 0xe7, 0xb7, 0xc2, 0xb9,
0xe2, 0x06, 0x02, 0x3e, 0x1d, 0xcd, 0x5d, 0xe3,
0xe6, 0x99, 0x57, 0xca, 0x95, 0xe2, 0x3a, 0xf6,
0xe7, 0xee, 0x01, 0x32, 0xf6, 0xe7, 0x32, 0xfa,
0xe3, 0x05, 0xc2, 0x73, 0xe2, 0x7a, 0x37, 0xf5,
0xcd, 0x70, 0xe1, 0xf1, 0xc9, 0x06, 0x0a, 0x11,
0xff, 0xe3, 0x21, 0xfa, 0xe7, 0x3e, 0xc4, 0x32,
0xfc, 0xe3, 0x1a, 0x77, 0x2c, 0xc2, 0xa2, 0xe2,
0x21, 0xfc, 0xe3, 0xcd, 0x6c, 0xe3, 0xb7, 0xca,
0xb9, 0xe2, 0x05, 0xc2, 0x97, 0xe2, 0xc3, 0x8e,
0xe2, 0x3a, 0xfd, 0xe7, 0x4f, 0x06, 0x00, 0x21,
0xdf, 0xe2, 0x09, 0x3a, 0xf8, 0xe7, 0x47, 0x86,
0x3e, 0x10, 0xd8, 0x78, 0x32, 0xfe, 0xe3, 0x3e,
0x20, 0x21, 0x05, 0x05, 0x22, 0xe2, 0xe7, 0x0d,
0x47, 0xf8, 0x17, 0xb7, 0xc3, 0xd7, 0xe2, 0xd5,
0xd5, 0xf0, 0xf7, 0x21, 0xeb, 0xe7, 0x4e, 0x23,
0x5e, 0x71, 0x23, 0x7b, 0xb9, 0x7e, 0x36, 0x01,
0xca, 0x1b, 0xe3, 0x23, 0xe5, 0x16, 0x00, 0x42,
0x19, 0x19, 0x3a, 0xf6, 0xe7, 0x77, 0x23, 0x11,
0xfd, 0xe3, 0x1a, 0x77, 0xe1, 0x09, 0x09, 0x7e,
0x32, 0xf6, 0xe7, 0x23, 0x7e, 0x12, 0x3e, 0x7f,
0x07, 0x0d, 0xf2, 0x10, 0xe3, 0xe6, 0x7f, 0x32,
0xea, 0xe7, 0xaf, 0x21, 0xfa, 0xe3, 0xa6, 0x32,
0xe9, 0xe7, 0xf5, 0x3a, 0xea, 0xe7, 0x4f, 0x3a,
0xf7, 0xe7, 0x2f, 0xa1, 0x32, 0xf9, 0xe3, 0xee,
0x40, 0x4f, 0x3a, 0xf6, 0xe7, 0x47, 0x3a, 0xf9,
0xe7, 0xd6, 0x01, 0x9f, 0x3d, 0x2f, 0xb0, 0x77,
0xf1, 0xc2, 0x4f, 0xe3, 0xe5, 0x2a, 0xe4, 0xe7,
0x2b, 0x7c, 0xb5, 0xc2, 0x48, 0xe3, 0xe1, 0x7e,
0xe6, 0x80, 0xc0, 0x3a, 0xf6, 0xe7, 0xf6, 0x06,
0x77, 0x3e, 0x80, 0x37, 0xc9, 0x2a, 0xe4, 0xe7,
0x29, 0x29, 0xeb, 0x21, 0xfc, 0xe3, 0x77, 0x7e,
0x1f, 0xd2, 0x67, 0xe3, 0x7e, 0x1f, 0x7e, 0xd0,
0xc3, 0x76, 0xe3, 0xc3, 0xe3, 0xe2, 0x1b, 0x7a,
0xb3, 0xc2, 0x6c, 0xe3, 0x5e, 0xe5, 0x23, 0x56,
0x3a, 0xea, 0xe7, 0xee, 0x80, 0x32, 0xf9, 0xe3,
0xee, 0xc0, 0xe3, 0x32, 0xf9, 0xe3, 0x36, 0xd0,
0xe3, 0x72, 0xe1, 0x7b, 0x37, 0xc9, 0x11, 0x00,
0x00, 0x21, 0xfa, 0xe3, 0x0e, 0x10, 0x7e, 0xa1,
0xca, 0x9e, 0xe3, 0x7e, 0xa1, 0xc2, 0xa3, 0xe3,
0x13, 0xe3, 0xe3, 0xe3, 0xe3, 0x7e, 0xa1, 0xca,
0xa8, 0xe3, 0xc9, 0x79, 0xe6, 0x01, 0x2f, 0x47,
0x21, 0xeb, 0xe7, 0x5e, 0x16, 0x00, 0x23, 0x7e,
0xab, 0xf5, 0x23, 0x23, 0x19, 0x19, 0x7e, 0xf6,
0x01, 0xa0, 0x77, 0xf1, 0xc0, 0x7e, 0x32, 0xf6,
0xe7, 0xc9, 0x21, 0x00, 0x00, 0x2b, 0x7c, 0xb5,
0xe3, 0xe3, 0xc2, 0xd5, 0xe3, 0xc9, 0xe5, 0x21,
0xe2, 0xe3, 0xe9, 0xe1, 0xc9, 0x79, 0xe6, 0x01,
0x17, 0x17, 0x17, 0x17, 0x32, 0xf7, 0xe7, 0xc9,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x00, 0xe0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static uint8 dj2d_promb_f800[DJ2D_PROM_SIZE] = {
0xc3, 0x69, 0xf8, 0xc3, 0xe9, 0xf8, 0xc3, 0xda,
0xf8, 0xc3, 0x5a, 0xf9, 0xc3, 0x8b, 0xf9, 0xc3,
0x81, 0xf9, 0xc3, 0x43, 0xf9, 0xc3, 0xdd, 0xf9,
0xc3, 0xbc, 0xf9, 0xc3, 0x3c, 0xf9, 0xc3, 0xf8,
0xf8, 0xc3, 0x03, 0xf9, 0xc3, 0x34, 0xf9, 0xc3,
0x09, 0xf9, 0xc3, 0xc5, 0xf8, 0xc3, 0xb3, 0xfb,
0xc3, 0xe5, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x31, 0xfa, 0xff, 0xcd, 0xd2, 0xfb, 0x21,
0x01, 0x00, 0xe5, 0x2e, 0x09, 0xe5, 0x26, 0xff,
0xe5, 0xe5, 0xe5, 0xe5, 0x21, 0x08, 0x00, 0xe5,
0x2e, 0x7e, 0xe5, 0x2e, 0x08, 0xe5, 0x26, 0x18,
0xe5, 0x3e, 0x7f, 0x32, 0xf9, 0xfb, 0x3e, 0xd0,
0x32, 0xfc, 0xfb, 0xaf, 0xcd, 0x1b, 0xfb, 0xd2,
0xa5, 0xf8, 0x3e, 0x01, 0x32, 0xf6, 0xff, 0xcd,
0xd2, 0xfb, 0xc3, 0x93, 0xf8, 0x3e, 0x09, 0x32,
0xf6, 0xff, 0xcd, 0x96, 0xfb, 0xc1, 0x01, 0x00,
0xff, 0xc5, 0xd5, 0x21, 0x00, 0x00, 0xe5, 0x00,
0xc5, 0x06, 0x0c, 0xc5, 0xcd, 0xdd, 0xf9, 0xc1,
0xd0, 0x05, 0xc2, 0xbb, 0xf8, 0x0e, 0x09, 0x11,
0xc3, 0xa2, 0x1b, 0x7a, 0xb3, 0xc2, 0xca, 0xf8,
0x3e, 0x08, 0xa9, 0x4f, 0x32, 0xfa, 0xfb, 0xc3,
0xc7, 0xf8, 0x3a, 0xf9, 0xfb, 0xe6, 0x08, 0xc2,
0xda, 0xf8, 0x79, 0x2f, 0x32, 0xf8, 0xfb, 0x2f,
0xc9, 0x3a, 0xf9, 0xfb, 0xe6, 0x04, 0xc2, 0xe9,
0xf8, 0x3a, 0xf8, 0xfb, 0x2f, 0xe6, 0x7f, 0xc9,
0x3a, 0xf9, 0xfb, 0xe6, 0x04, 0xc0, 0xcd, 0xe9,
0xf8, 0xb9, 0xc9, 0x3a, 0xf9, 0xfb, 0xe6, 0x04,
0xc9, 0x21, 0xfd, 0xfb, 0x4e, 0x23, 0x46, 0x3a,
0xf6, 0xff, 0x2f, 0xe6, 0x01, 0x0f, 0x57, 0x3a,
0xf7, 0xff, 0x07, 0x07, 0x07, 0xb2, 0x57, 0x3a,
0xe8, 0xff, 0xee, 0x08, 0x17, 0x17, 0x82, 0x57,
0x3a, 0xfd, 0xff, 0x17, 0x17, 0xb2, 0x57, 0x3a,
0xec, 0xff, 0x82, 0xc9, 0xe5, 0x2a, 0xe6, 0xff,
0x44, 0x4d, 0xe1, 0xc9, 0x79, 0xe6, 0x03, 0x32,
0xeb, 0xff, 0xc9, 0x21, 0x00, 0x04, 0x09, 0xda,
0x54, 0xf9, 0x21, 0x08, 0x08, 0x09, 0xd2, 0x54,
0xf9, 0x3e, 0x10, 0xc9, 0x60, 0x69, 0x22, 0xe6,
0xff, 0xc9, 0xcd, 0xe3, 0xfa, 0xd8, 0xcd, 0x70,
0xf9, 0xf5, 0x9f, 0x32, 0xf9, 0xff, 0x32, 0xfd,
0xfb, 0xaf, 0x32, 0xed, 0xff, 0xc3, 0x23, 0xfa,
0xaf, 0x32, 0xe9, 0xff, 0x21, 0x00, 0x00, 0x3e,
0x09, 0xcd, 0x62, 0xfb, 0xe6, 0x04, 0xc0, 0x37,
0xc9, 0xaf, 0xb1, 0x37, 0xc8, 0xe6, 0x3f, 0x32,
0xf8, 0xff, 0xc9, 0x79, 0xfe, 0x4d, 0x3f, 0xd8,
0x32, 0xf9, 0xff, 0xc9, 0x32, 0xe3, 0xff, 0xcd,
0x96, 0xfb, 0x0e, 0x01, 0x79, 0x32, 0xfe, 0xfb,
0x3a, 0xf8, 0xff, 0xb9, 0xc8, 0x3e, 0x80, 0xcd,
0x5d, 0xfb, 0xda, 0x20, 0xfa, 0x0c, 0xc3, 0x9c,
0xf9, 0x32, 0xfc, 0xfb, 0x48, 0x11, 0xff, 0xfb,
0x2a, 0xe6, 0xff, 0xc9, 0xcd, 0x33, 0xfa, 0xda,
0x22, 0xfa, 0x3e, 0xa0, 0xcd, 0xb1, 0xf9, 0x7e,
0x23, 0x12, 0x7e, 0x23, 0x12, 0x7e, 0x23, 0x12,
0x0d, 0x7e, 0x23, 0x12, 0xc2, 0xc7, 0xf9, 0x21,
0xc2, 0xf9, 0xc3, 0xfb, 0xf9, 0xcd, 0x33, 0xfa,
0xda, 0x22, 0xfa, 0x3e, 0x80, 0xcd, 0xb1, 0xf9,
0x1a, 0x77, 0x23, 0x1a, 0x77, 0x23, 0x1a, 0x77,
0x23, 0x0d, 0x1a, 0x77, 0x23, 0xc2, 0xe8, 0xf9,
0x21, 0xe3, 0xf9, 0xe5, 0x21, 0xfc, 0xfb, 0xcd,
0x6c, 0xfb, 0xe6, 0x5f, 0xca, 0x21, 0xfa, 0xfe,
0x10, 0xc2, 0x20, 0xfa, 0x3a, 0xe2, 0xff, 0x3d,
0xfa, 0x17, 0xfa, 0x32, 0xe2, 0xff, 0xc9, 0x3a,
0xe3, 0xff, 0x3d, 0xf2, 0x94, 0xf9, 0x3e, 0x10,
0x37, 0xe1, 0xf5, 0x3a, 0xf6, 0xff, 0xee, 0x04,
0x32, 0xfa, 0xfb, 0x3a, 0xea, 0xff, 0x32, 0xf9,
0xfb, 0xf1, 0xc9, 0xcd, 0xe3, 0xfa, 0xd8, 0x3a,
0xfd, 0xfb, 0x3c, 0xcc, 0x70, 0xf9, 0xd8, 0x21,
0xfd, 0xfb, 0x3a, 0xf9, 0xff, 0xbe, 0x23, 0x23,
0x77, 0x79, 0x32, 0xf9, 0xfb, 0xca, 0x6a, 0xfa,
0xaf, 0x32, 0xe9, 0xff, 0x3a, 0xfa, 0xfb, 0xe6,
0x08, 0x32, 0xe8, 0xff, 0x1f, 0x1f, 0x1f, 0xc6,
0x18, 0x21, 0x00, 0x00, 0xcd, 0x62, 0xfb, 0xda,
0x8e, 0xfa, 0x3a, 0xe9, 0xff, 0xb7, 0xc2, 0xb9,
0xfa, 0x06, 0x02, 0x3e, 0x1d, 0xcd, 0x5d, 0xfb,
0xe6, 0x99, 0x57, 0xca, 0x95, 0xfa, 0x3a, 0xf6,
0xff, 0xee, 0x01, 0x32, 0xf6, 0xff, 0x32, 0xfa,
0xfb, 0x05, 0xc2, 0x73, 0xfa, 0x7a, 0x37, 0xf5,
0xcd, 0x70, 0xf9, 0xf1, 0xc9, 0x06, 0x0a, 0x11,
0xff, 0xfb, 0x21, 0xfa, 0xff, 0x3e, 0xc4, 0x32,
0xfc, 0xfb, 0x1a, 0x77, 0x2c, 0xc2, 0xa2, 0xfa,
0x21, 0xfc, 0xfb, 0xcd, 0x6c, 0xfb, 0xb7, 0xca,
0xb9, 0xfa, 0x05, 0xc2, 0x97, 0xfa, 0xc3, 0x8e,
0xfa, 0x3a, 0xfd, 0xff, 0x4f, 0x06, 0x00, 0x21,
0xdf, 0xfa, 0x09, 0x3a, 0xf8, 0xff, 0x47, 0x86,
0x3e, 0x10, 0xd8, 0x78, 0x32, 0xfe, 0xfb, 0x3e,
0x20, 0x21, 0x05, 0x05, 0x22, 0xe2, 0xff, 0x0d,
0x47, 0xf8, 0x17, 0xb7, 0xc3, 0xd7, 0xfa, 0xd5,
0xd5, 0xf0, 0xf7, 0x21, 0xeb, 0xff, 0x4e, 0x23,
0x5e, 0x71, 0x23, 0x7b, 0xb9, 0x7e, 0x36, 0x01,
0xca, 0x1b, 0xfb, 0x23, 0xe5, 0x16, 0x00, 0x42,
0x19, 0x19, 0x3a, 0xf6, 0xff, 0x77, 0x23, 0x11,
0xfd, 0xfb, 0x1a, 0x77, 0xe1, 0x09, 0x09, 0x7e,
0x32, 0xf6, 0xff, 0x23, 0x7e, 0x12, 0x3e, 0x7f,
0x07, 0x0d, 0xf2, 0x10, 0xfb, 0xe6, 0x7f, 0x32,
0xea, 0xff, 0xaf, 0x21, 0xfa, 0xfb, 0xa6, 0x32,
0xe9, 0xff, 0xf5, 0x3a, 0xea, 0xff, 0x4f, 0x3a,
0xf7, 0xff, 0x2f, 0xa1, 0x32, 0xf9, 0xfb, 0xee,
0x40, 0x4f, 0x3a, 0xf6, 0xff, 0x47, 0x3a, 0xf9,
0xff, 0xd6, 0x01, 0x9f, 0x3d, 0x2f, 0xb0, 0x77,
0xf1, 0xc2, 0x4f, 0xfb, 0xe5, 0x2a, 0xe4, 0xff,
0x2b, 0x7c, 0xb5, 0xc2, 0x48, 0xfb, 0xe1, 0x7e,
0xe6, 0x80, 0xc0, 0x3a, 0xf6, 0xff, 0xf6, 0x06,
0x77, 0x3e, 0x80, 0x37, 0xc9, 0x2a, 0xe4, 0xff,
0x29, 0x29, 0xeb, 0x21, 0xfc, 0xfb, 0x77, 0x7e,
0x1f, 0xd2, 0x67, 0xfb, 0x7e, 0x1f, 0x7e, 0xd0,
0xc3, 0x76, 0xfb, 0xc3, 0xe3, 0xfa, 0x1b, 0x7a,
0xb3, 0xc2, 0x6c, 0xfb, 0x5e, 0xe5, 0x23, 0x56,
0x3a, 0xea, 0xff, 0xee, 0x80, 0x32, 0xf9, 0xfb,
0xee, 0xc0, 0xe3, 0x32, 0xf9, 0xfb, 0x36, 0xd0,
0xe3, 0x72, 0xe1, 0x7b, 0x37, 0xc9, 0x11, 0x00,
0x00, 0x21, 0xfa, 0xfb, 0x0e, 0x10, 0x7e, 0xa1,
0xca, 0x9e, 0xfb, 0x7e, 0xa1, 0xc2, 0xa3, 0xfb,
0x13, 0xe3, 0xe3, 0xe3, 0xe3, 0x7e, 0xa1, 0xca,
0xa8, 0xfb, 0xc9, 0x79, 0xe6, 0x01, 0x2f, 0x47,
0x21, 0xeb, 0xff, 0x5e, 0x16, 0x00, 0x23, 0x7e,
0xab, 0xf5, 0x23, 0x23, 0x19, 0x19, 0x7e, 0xf6,
0x01, 0xa0, 0x77, 0xf1, 0xc0, 0x7e, 0x32, 0xf6,
0xff, 0xc9, 0x21, 0x00, 0x00, 0x2b, 0x7c, 0xb5,
0xe3, 0xe3, 0xc2, 0xd5, 0xfb, 0xc9, 0xe5, 0x21,
0xe2, 0xfb, 0xe9, 0xe1, 0xc9, 0x79, 0xe6, 0x01,
0x17, 0x17, 0x17, 0x17, 0x32, 0xf7, 0xff, 0xc9,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x00, 0xf8,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
/* PROM selection (default E000) */
uint8 *dj2d_prom = dj2d_promb_e000;
/*
** Western Digital WD1791 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 */
uint8 drq; /* Data Request */
uint8 index; /* Index */
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 idAddrMrk; /* ID Addr Mark Flag */
uint8 dataAddrMrk; /* Data Addr Mark Flag */
uint8 addrActive; /* Address Active */
} WD1791_REG;
/*
** Disk Jockey 2D Registers
*/
typedef struct {
uint8 uart_rxd; /* UART rx data register */
uint8 uart_txd; /* UART tx data register */
uint8 uart_txp; /* UART tx data pending */
uint8 uart_status; /* UART status register */
uint16 uart_baud; /* UART baud rate */
uint8 status; /* Disk Jockey status register */
uint8 control; /* Disk Jockey control register */
uint8 function; /* Disk Jockey function register */
uint8 led; /* Disk Jockey LED status */
} DJ2D_REG;
#define WD1791_STAT_NOTREADY 0x80
#define WD1791_STAT_WRITEPROT 0x40
#define WD1791_STAT_RTYPEMSB 0x40
#define WD1791_STAT_HEADLOAD 0x20
#define WD1791_STAT_RTYPELSB 0x20
#define WD1791_STAT_WRITEFAULT 0x20
#define WD1791_STAT_SEEKERROR 0x10
#define WD1791_STAT_NOTFOUND 0x10
#define WD1791_STAT_CRCERROR 0x08
#define WD1791_STAT_TRACK0 0x04
#define WD1791_STAT_LOSTDATA 0x04
#define WD1791_STAT_INDEX 0x02
#define WD1791_STAT_DRQ 0x02
#define WD1791_STAT_BUSY 0x01
static TMLN dj2d_tmln[] = { /* line descriptors */
{ 0 }
};
static TMXR dj2d_tmxr = { /* multiplexer descriptor */
1, /* number of terminal lines */
0, /* listening port (reserved) */
0, /* master socket (reserved) */
dj2d_tmln, /* line descriptor array */
NULL, /* line connection order */
NULL /* multiplexer device (derived internally) */
};
typedef struct {
uint32 io_base; /* NOT USED */
uint32 io_size; /* NOT USED */
uint32 mem_base; /* Memory Base Address */
uint32 mem_size; /* Memory Address space requirement */
uint32 prom_base; /* PROM Base Address */
uint32 prom_size; /* PROM Address space requirement */
int32 conn; /* Connected Status */
TMLN *tmln; /* TMLN pointer */
TMXR *tmxr; /* TMXR pointer */
uint8 modelB; /* Model B? */
uint8 promEnabled; /* PROM is enabled */
uint32 ticks; /* Timer ticks */
uint32 sioticks; /* SIO Timer ticks */
uint16 headTimeout; /* Head unload timer tick value */
uint16 indexTimeout; /* Index timer tick value */
uint16 busyTimeout; /* Busy timer tick value */
uint8 writeProtect; /* Write Protect is enabled */
uint8 currentDrive; /* currently selected drive */
uint8 secsPerTrack; /* sectors per track */
uint16 bytesPerTrack; /* bytes per track */
uint8 sides2[DJ2D_MAX_DRIVES]; /* double sided flag */
uint8 headLoaded[DJ2D_MAX_DRIVES]; /* Head Loaded */
uint8 format[DJ2D_MAX_DRIVES]; /* Attached disk format */
uint16 sectorLen[DJ2D_MAX_DRIVES]; /* Attached disk sector length */
uint8 side[DJ2D_MAX_DRIVES]; /* side 0 or 1 */
WD1791_REG WD1791; /* WD1791 Registers and Data */
DJ2D_REG DJ2D; /* DJ2D Registers and Data */
UNIT *uptr[DJ2D_UNITS];
} DJ2D_INFO;
static DJ2D_INFO dj2d_info_data = {
0, 0,
DJ2D_MEM_BASE, DJ2D_MEM_SIZE,
DJ2D_PROM_BASE, DJ2D_PROM_SIZE,
0, dj2d_tmln, &dj2d_tmxr,
TRUE, TRUE,
0, 0, 0, 0, 0, 0, 0, 0, 0,
{0, 0, 0, 0}
};
static DJ2D_INFO *dj2d_info = &dj2d_info_data;
static uint8 sdata[1024]; /* Sector data buffer */
/* DJ2D Registers */
#define DJ2D_REG_BASE (DJ2D_PROM_BASE + 0x03f8)
#define DJ2D_REG_UART_DATA 0x00 /* Register 0 */
#define DJ2D_REG_UART_STATUS 0x01 /* Register 1 */
#define DJ2D_REG_2D_CONTROL 0x01 /* Register 1 */
#define DJ2D_REG_2D_FUNCTION 0x02 /* Register 2 */
#define DJ2D_REG_2D_STATUS 0x02 /* Register 2 */
#define DJ2D_REG_1791_STATUS 0x04 /* Register 4 */
#define DJ2D_REG_1791_COMMAND 0x04 /* Register 4 */
#define DJ2D_REG_1791_TRACK 0x05 /* Register 5 */
#define DJ2D_REG_1791_SECTOR 0x06 /* Register 6 */
#define DJ2D_REG_1791_DATA 0x07 /* Register 7 */
/* DJ2D MODEL A/B */
#define DJ2D_STAT_PE 0x01 /* Parity Error */
#define DJ2D_STAT_OE 0x02 /* Overrun Error */
#define DJ2D_STAT_DR 0x04 /* Data Ready */
#define DJ2D_STAT_TBRE 0x08 /* TBRE */
#define DJ2D_STAT_FE 0x10 /* Framing Error */
/* DJ2D MODEL B */
#define DJ2D_STAT_HEAD 0x01 /* HEAD */
#define DJ2D_STAT_DATARQ 0x02 /* DATARQ */
#define DJ2D_STAT_INTRQ 0x04 /* INTRQ */
#define DJ2D_STAT_N2SIDED 0x08 /* NOT 2 SIDED */
#define DJ2D_STAT_INDEX 0x10 /* INDEX */
#define DJ2D_STAT_READY 0x80 /* READY */
#define DJ2D_CTRL_DSEL 0x0f /* Drive Select Mask */
#define DJ2D_CTRL_SIDE0 0x10 /* Side 0 Select */
#define DJ2D_CTRL_INTDSBL 0x20 /* Interrupt Disable */
#define DJ2D_CTRL_AENBL 0x40 /* AENBL */
#define DJ2D_CTRL_RESET 0x80 /* Reset 1791 */
#define DJ2D_FUNC_SINGLE 0x01 /* Single Density */
#define DJ2D_FUNC_HDMASK 0x06 /* Head Mask */
#define DJ2D_FUNC_HDLOAD 0x00 /* Head Loaded */
#define DJ2D_FUNC_HDUNLD 0x06 /* Head Unloaded */
#define DJ2D_FUNC_LEDOFF 0x08 /* LED Off */
/* DJ2D MODEL A */
#define DJ2DA_STAT_INTRQ 0x01 /* INTRQ */
#define DJ2DA_STAT_DATARQ 0x02 /* DATARQ */
#define DJ2DA_STAT_HEAD 0x04 /* HEAD */
#define DJ2DA_STAT_N2SIDED 0x08 /* NOT 2 SIDED */
#define DJ2DA_STAT_NINDEX 0x10 /* NOT INDEX */
#define DJ2DA_STAT_NREADY 0x20 /* NOT READY */
#define DJ2DA_CTRL_DSEL 0x0f /* Drive Select Mask */
#define DJ2DA_CTRL_SIDE0 0x10 /* Side 0 Select */
#define DJ2DA_CTRL_LEDOFF 0x20 /* LED Off */
#define DJ2DA_FUNC_SINGLE 0x01 /* Single Density */
#define DJ2DA_FUNC_AENBL 0x02 /* AENBL */
#define DJ2DA_FUNC_CLRFDC 0x04 /* Reset 1791 */
#define DJ2DA_FUNC_HDMASK 0x18 /* Head Mask */
#define DJ2DA_FUNC_HDLOAD 0x00 /* Head Loaded */
#define DJ2DA_FUNC_HDUNLD 0x18 /* Head Unloaded */
#define DJ2DA_FUNC_VCOFF 0x20 /* VCOFF */
/* WD1791 Commands */
#define WD1791_CMD_RESTORE 0x00
#define WD1791_CMD_SEEK 0x10
#define WD1791_CMD_STEP 0x20
#define WD1791_CMD_STEPU (WD1791_CMD_STEP | WD1791_FLAG_U)
#define WD1791_CMD_STEPIN 0x40
#define WD1791_CMD_STEPINU (WD1791_CMD_STEPIN | WD1791_FLAG_U)
#define WD1791_CMD_STEPOUT 0x60
#define WD1791_CMD_STEPOUTU (WD1791_CMD_STEPOUT | WD1791_FLAG_U)
#define WD1791_CMD_READ 0x80
#define WD1791_CMD_READM (WD1791_CMD_READ | WD1791_FLAG_M)
#define WD1791_CMD_WRITE 0xA0
#define WD1791_CMD_WRITEM (WD1791_CMD_WRITE | WD1791_FLAG_M)
#define WD1791_CMD_READ_ADDRESS 0xC0
#define WD1791_CMD_READ_TRACK 0xE0
#define WD1791_CMD_WRITE_TRACK 0xF0
#define WD1791_CMD_FORCE_INTR 0xD0
#define WD1791_FLAG_V 0x04
#define WD1791_FLAG_H 0x08
#define WD1791_FLAG_U 0x10
#define WD1791_FLAG_M 0x10
#define WD1791_FLAG_B 0x08
#define WD1791_FLAG_S 0x01
#define WD1791_FLAG_E 0x04
#define WD1791_FLAG_A1A0_FB 0x00
#define WD1791_FLAG_A1A0_FA 0x01
#define WD1791_FLAG_A1A0_F9 0x02
#define WD1791_FLAG_A1A0_F8 0x03
#define WD1791_FLAG_I0 0x01
#define WD1791_FLAG_I1 0x02
#define WD1791_FLAG_I2 0x04
#define WD1791_FLAG_I3 0x08
#define WD1791_FLAG_R1R0_6MS 0x00
#define WD1791_FLAG_R1R0_10ms 0x02
#define WD1791_FLAG_R1R0_20ms 0x03
#define WD1791_ADDR_TRACK 0x00
#define WD1791_ADDR_ZEROS 0x01
#define WD1791_ADDR_SECTOR 0x02
#define WD1791_ADDR_LENGTH 0x03
#define WD1791_ADDR_CRC1 0x04
#define WD1791_ADDR_CRC2 0x05
/* Local function prototypes */
static t_stat dj2d_reset(DEVICE *dj2d_dev);
static t_stat dj2d_svc(UNIT *uptr);
static t_stat dj2d_sio_svc(UNIT *uptr);
static t_stat dj2d_attach(UNIT *uptr, CONST char *cptr);
static t_stat dj2d_detach(UNIT *uptr);
static t_stat dj2d_boot(int32 unitno, DEVICE *dptr);
static t_stat dj2d_set_prombase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat dj2d_show_prombase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat dj2d_set_model(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat dj2d_show_model(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat dj2d_set_prom(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat dj2d_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat dj2d_set_sides(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat dj2d_show_sides(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat dj2d_set_baud(UNIT *uptr, int32 value, const char *cptr, void *desc);
static t_stat dj2d_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc);
static t_stat dj2d_config_line(void);
static uint16 sector_len(uint8 drive, uint8 track);
static uint32 secs_per_track(uint8 track);
static uint32 bytes_per_track(uint8 track);
static t_offset calculate_dj2d_sec_offset(uint8 track, uint8 sector);
static void DJ2D_HeadLoad(UNIT *uptr, WD1791_REG *pWD1791, uint8 load);
static void DJ2D_LED(DJ2D_REG *pDJ2D, int status);
static uint8 DJ2D_Read(uint32 Addr);
static uint8 DJ2D_Write(uint32 Addr, int32 data);
static const char * DJ2D_CommandString(uint8 command);
static uint8 DJ2D_Command(UNIT *uptr, WD1791_REG *pWD1791, int32 data);
static uint32 DJ2D_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer);
static uint32 DJ2D_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer);
static const char* dj2d_description(DEVICE *dptr);
static void showdata(int32 isRead);
static int32 dj2dprom(int32 Addr, int32 rw, int32 data);
static int32 dj2dmem(int32 Addr, int32 rw, int32 data);
static UNIT dj2d_unit[DJ2D_UNITS] = {
{ UDATA (dj2d_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, 0), 10000 },
{ UDATA (dj2d_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, 0), 10000 },
{ UDATA (dj2d_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, 0), 10000 },
{ UDATA (dj2d_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, 0), 10000 },
{ UDATA (dj2d_sio_svc, UNIT_ATTABLE + UNIT_DISABLE, 0), 10000 }
};
static REG dj2d_reg[] = {
{ DRDATAD (DRIVE, dj2d_info_data.currentDrive, 8, "Current drive register"), },
{ HRDATAD (STATUS, dj2d_info_data.WD1791.status, 8, "Status register"), },
{ HRDATAD (COMMAND, dj2d_info_data.WD1791.command, 8, "Command register"), },
{ HRDATAD (DATA, dj2d_info_data.WD1791.data, 8, "Data register"), },
{ DRDATAD (TRACK, dj2d_info_data.WD1791.track, 8, "Track register"), },
{ DRDATAD (SECTOR, dj2d_info_data.WD1791.sector, 8, "Sector register"), },
{ DRDATAD (SPT, dj2d_info_data.secsPerTrack, 8, "Sectors per track register"), },
{ DRDATAD (BPT, dj2d_info_data.bytesPerTrack, 16, "Bytes per track register"), },
{ DRDATAD (STEPDIR, dj2d_info_data.WD1791.stepDir, 8, "Last step direction register"), },
{ DRDATAD (SECCNT, dj2d_info_data.WD1791.dataCount, 16, "Sector byte count register"), },
{ DRDATAD (TRKCNT, dj2d_info_data.WD1791.trkCount, 16, "Track byte count register"), },
{ FLDATAD (RDACT, dj2d_info_data.WD1791.readActive, 0, "Read sector active status bit"), },
{ FLDATAD (WRACT, dj2d_info_data.WD1791.writeActive, 0, "Write sector active status bit"), },
{ FLDATAD (RDTACT, dj2d_info_data.WD1791.readTrkActive, 0, "Read track active status bit"), },
{ FLDATAD (WRTACT, dj2d_info_data.WD1791.writeTrkActive, 0, "Write track active status bit"), },
{ FLDATAD (INTRQ, dj2d_info_data.WD1791.intrq, 0, "INTRQ status bit"), },
{ FLDATAD (DRQ, dj2d_info_data.WD1791.drq, 0, "DRQ status bit"), },
{ FLDATAD (PROM, dj2d_info_data.promEnabled, 0, "PROM enabled bit"), },
{ FLDATAD (WRTPROT, dj2d_info_data.writeProtect, 0, "Write protect enabled bit"), },
{ DRDATAD (TICKS, dj2d_info_data.ticks, 32, "Timer ticks"), },
{ DRDATAD (SIOTICKS, dj2d_info_data.sioticks, 32, "SIO timer ticks"), },
{ DRDATAD (HEAD, dj2d_info_data.headTimeout, 16, "Head unload timeout"), },
{ DRDATAD (INDEX, dj2d_info_data.indexTimeout, 16, "Index timeout"), },
{ DRDATAD (BUSY, dj2d_info_data.busyTimeout, 16, "Busy timeout"), },
{ HRDATAD (DJSTAT, dj2d_info_data.DJ2D.status, 8, "DJ2D status register"), },
{ HRDATAD (DJCTRL, dj2d_info_data.DJ2D.control, 8, "DJ2D control register"), },
{ HRDATAD (DJFUNC, dj2d_info_data.DJ2D.function, 8, "DJ2D function register"), },
{ HRDATAD (URXD, dj2d_info_data.DJ2D.uart_rxd, 8, "UART RX data register"), },
{ HRDATAD (UTXD, dj2d_info_data.DJ2D.uart_txd, 8, "UART TX data register"), },
{ HRDATAD (UTXP, dj2d_info_data.DJ2D.uart_txp, 8, "UART TX data pending"), },
{ HRDATAD (USTAT, dj2d_info_data.DJ2D.uart_status, 8, "UART status register"), },
{ DRDATAD (BAUD, dj2d_info_data.DJ2D.uart_baud, 16, "UART baud rate"), },
{ FLDATAD (LED, dj2d_info_data.DJ2D.led, 0, "LED status"), },
{ NULL }
};
#define DJ2D_NAME "DISK JOCKEY 2D/B Floppy Disk Controller"
#define DJ2D_SNAME "DJ2D"
static const char* dj2d_description(DEVICE *dptr) {
return DJ2D_NAME;
}
#define UNIT_V_DJ2D_WPROTECT (UNIT_V_UF + 0) /* WRTENB / WRTPROT */
#define UNIT_DJ2D_WPROTECT (1 << UNIT_V_DJ2D_WPROTECT)
/* Terminal multiplexer library descriptors */
static MTAB dj2d_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "PROM", "PROM={ENABLE|DISABLE}",
&dj2d_set_prom, &dj2d_show_prom, NULL, "Set/Show PROM enabled/disabled status"},
{ MTAB_XTD|MTAB_VDV, 0, "PROMBASE", "PROMBASE",
&dj2d_set_prombase, &dj2d_show_prombase, NULL, "Sets PROM base address" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "MODEL", "MODEL={A|B}",
&dj2d_set_model, &dj2d_show_model, NULL, "Set/Show the current controller model" },
{ MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "SIDES", "SIDES={1|2}",
&dj2d_set_sides, &dj2d_show_sides, NULL, "Set/Show the current drive sides" },
{ UNIT_DJ2D_WPROTECT, 0, "WRTENB", "WRTENB", NULL, NULL, NULL,
"Enables " DJ2D_SNAME "n for writing" },
{ UNIT_DJ2D_WPROTECT, UNIT_DJ2D_WPROTECT, "WRTPROT", "WRTPROT", NULL, NULL, NULL,
"Protects " DJ2D_SNAME "n from writing" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "BAUD", "BAUD", &dj2d_set_baud, &dj2d_show_baud,
NULL, "Set baud rate (default=19200)" },
{ 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)
#define VERBOSE_MSG (1 << 8)
#define DEBUG_MSG (1 << 9)
/* Debug Flags */
static DEBTAB dj2d_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" },
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
{ "DEBUG", DEBUG_MSG, "Debug messages" },
{ NULL, 0 }
};
DEVICE dj2d_dev = {
DJ2D_SNAME, /* name */
dj2d_unit, /* unit */
dj2d_reg, /* registers */
dj2d_mod, /* modifiers */
DJ2D_UNITS, /* # units */
10, /* address radix */
31, /* address width */
1, /* addr increment */
DJ2D_UNITS, /* data radix */
DJ2D_UNITS, /* data width */
NULL, /* examine routine */
NULL, /* deposit routine */
&dj2d_reset, /* reset routine */
&dj2d_boot, /* boot routine */
&dj2d_attach, /* attach routine */
&dj2d_detach, /* detach routine */
&dj2d_info_data, /* context */
(DEV_DISABLE | DEV_DIS | DEV_DEBUG), /* flags */
ERROR_MSG, /* debug control */
dj2d_dt, /* debug flags */
NULL, /* mem size routine */
NULL, /* logical name */
NULL, /* help */
NULL, /* attach help */
NULL, /* context for help */
&dj2d_description /* description */
};
/* Reset routine */
static t_stat dj2d_reset(DEVICE *dptr)
{
uint8 i;
DJ2D_INFO *pInfo = (DJ2D_INFO *)dptr->ctxt;
for (i = 0; i < DJ2D_UNITS; i++) {
if (dj2d_info->uptr[i] == NULL) {
dj2d_info->uptr[i] = &dj2d_dev.units[i];
}
}
if (dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
sim_map_resource(pInfo->prom_base, pInfo->prom_size, RESOURCE_TYPE_MEMORY, &dj2dprom, "dj2dprom", TRUE);
sim_map_resource(pInfo->mem_base, pInfo->mem_size, RESOURCE_TYPE_MEMORY, &dj2dmem, "dj2dmem", TRUE);
/* Cancel timers */
sim_cancel(dj2d_info->uptr[0]);
sim_cancel(dj2d_info->uptr[DJ2D_SIO_UNIT]);
} else {
if (sim_map_resource(pInfo->prom_base, pInfo->prom_size, RESOURCE_TYPE_MEMORY, &dj2dprom, "dj2dprom", FALSE) != 0) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": Error mapping PROM resource at 0x%04x\n", pInfo->prom_base);
return SCPE_ARG;
}
if (sim_map_resource(pInfo->mem_base, pInfo->mem_size, RESOURCE_TYPE_MEMORY, &dj2dmem, "dj2dmem", FALSE) != 0) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": Error mapping MEM resource at 0x%04x\n", pInfo->mem_base);
return SCPE_ARG;
}
/* Start timer for unit 0 (we only need 1 timer for all drive units) */
dj2d_info->indexTimeout = DJ2D_ROTATION_MS;
sim_activate_after(dj2d_info->uptr[0], DJ2D_TIMER * 1000);
/* Start timer for SIO unit */
sim_activate_after(dj2d_info->uptr[DJ2D_SIO_UNIT], 500); /* activate 500 us timer */
/* Disable clockFrequency if it's set */
if (getClockFrequency()) {
setClockFrequency(0);
sim_printf(DJ2D_SNAME ": CPU CLOCK register not supported. Use THROTTLE.\n");
}
/* Configure the serial interface */
dj2d_config_line();
}
/* Reset Registers */
pInfo->currentDrive = 0;
pInfo->promEnabled = TRUE;
pInfo->writeProtect = FALSE;
pInfo->DJ2D.uart_status = DJ2D_STAT_TBRE;
pInfo->DJ2D.uart_txp = FALSE;
pInfo->DJ2D.uart_baud = DJ2D_BAUD;
pInfo->DJ2D.led = FALSE;
pInfo->WD1791.track = 0;
pInfo->WD1791.sector = 1;
pInfo->WD1791.command = 0;
pInfo->WD1791.status = 0;
pInfo->WD1791.data = 0;
pInfo->WD1791.drq = FALSE;
pInfo->WD1791.index = FALSE;
pInfo->WD1791.intrq = FALSE;
pInfo->WD1791.stepDir = 1;
pInfo->WD1791.dataCount = 0;
pInfo->WD1791.trkCount = 0;
pInfo->WD1791.addrActive = FALSE;
pInfo->WD1791.readActive = FALSE;
pInfo->WD1791.readTrkActive = FALSE;
pInfo->WD1791.writeActive = FALSE;
pInfo->WD1791.writeTrkActive = FALSE;
pInfo->WD1791.addrActive = FALSE;
for (i = 0; i < DJ2D_MAX_DRIVES; i++) {
dj2d_info->headLoaded[i] = FALSE;
}
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": reset controller.\n");
return SCPE_OK;
}
static t_stat dj2d_sio_svc(UNIT *uptr)
{
int32 c;
t_stat r;
dj2d_info->sioticks++;
/* Check for new incoming connection */
if (uptr->flags & UNIT_ATT) {
if (tmxr_poll_conn(dj2d_info->tmxr) >= 0) { /* poll connection */
dj2d_info->conn = 1; /* set connected */
sim_debug(STATUS_MSG, uptr->dptr, "new connection.\n");
}
}
/* TX byte pending? */
if (dj2d_info->DJ2D.uart_txp) {
if (uptr->flags & UNIT_ATT) {
r = tmxr_putc_ln(dj2d_info->tmln, dj2d_info->DJ2D.uart_txd);
} else {
r = sim_putchar(dj2d_info->DJ2D.uart_txd);
}
dj2d_info->DJ2D.uart_txp = FALSE;
if (r == SCPE_LOST) {
dj2d_info->conn = 0; /* Connection was lost */
sim_debug(STATUS_MSG, uptr->dptr, "lost connection.\n");
}
}
/* Update TBRE */
if (!(dj2d_info->DJ2D.uart_status & DJ2D_STAT_TBRE)) {
if (uptr->flags & UNIT_ATT) {
tmxr_poll_tx(dj2d_info->tmxr);
dj2d_info->DJ2D.uart_status |= (tmxr_txdone_ln(dj2d_info->tmln) && dj2d_info->conn) ? DJ2D_STAT_TBRE : 0;
} else {
dj2d_info->DJ2D.uart_status |= DJ2D_STAT_TBRE;
}
}
/* Check for Data if RX buffer empty */
if (!(dj2d_info->DJ2D.uart_status & DJ2D_STAT_DR)) {
if (uptr->flags & UNIT_ATT) {
tmxr_poll_rx(dj2d_info->tmxr);
c = tmxr_getc_ln(dj2d_info->tmln);
} else {
c = sim_poll_kbd();
}
if (c & (TMXR_VALID | SCPE_KFLAG)) {
dj2d_info->DJ2D.uart_rxd = c & 0xff;
dj2d_info->DJ2D.uart_status |= DJ2D_STAT_DR;
dj2d_info->DJ2D.uart_status &= ~(DJ2D_STAT_FE | DJ2D_STAT_OE | DJ2D_STAT_PE);
}
}
/* Restart timer */
sim_activate_after(uptr, 500); /* reactivate 500 us timer */
return SCPE_OK;
}
static t_stat dj2d_svc(UNIT *uptr)
{
WD1791_REG *pWD1791;
pWD1791 = &dj2d_info->WD1791;
dj2d_info->ticks++;
if (dj2d_info->headTimeout) {
if (!(--dj2d_info->headTimeout)) {
DJ2D_HeadLoad(uptr, pWD1791, FALSE);
}
}
if (dj2d_info->indexTimeout) {
if (!(--dj2d_info->indexTimeout)) {
pWD1791->index = FALSE;
dj2d_info->indexTimeout = DJ2D_INDEX_TIMEOUT;
} else {
pWD1791->index = TRUE;
}
}
if (dj2d_info->busyTimeout) {
if (!(--dj2d_info->busyTimeout)) {
pWD1791->status &= ~WD1791_STAT_BUSY;
pWD1791->drq = FALSE;
pWD1791->intrq = TRUE;
}
}
/* Restart timer */
sim_activate_after(uptr, DJ2D_TIMER * 1000); /* activate timer */
return SCPE_OK;
}
/*
** Verify that prombase is within valid range
** before calling set_membase
*/
static t_stat dj2d_set_prombase(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 newba;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
newba = get_uint (cptr, 16, 0xFFFF, &r);
if (r != SCPE_OK)
return r;
if ((newba != 0xe000) && (newba != 0xf800)) {
sim_printf(DJ2D_SNAME ": Valid options are E000,F800\n");
return SCPE_ARG;
}
/*
** Release previous memory maps
*/
sim_map_resource(dj2d_info->prom_base, dj2d_info->prom_size, RESOURCE_TYPE_MEMORY, &dj2dprom, "dj2dprom", TRUE);
sim_map_resource(dj2d_info->mem_base, dj2d_info->mem_size, RESOURCE_TYPE_MEMORY, &dj2dmem, "dj2dmem", TRUE);
dj2d_info->prom_base = newba;
dj2d_info->mem_base = newba+DJ2D_PROM_SIZE;
if (sim_map_resource(dj2d_info->prom_base, dj2d_info->prom_size, RESOURCE_TYPE_MEMORY, &dj2dprom, "dj2dprom", FALSE) != 0) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": Error mapping PROM resource at 0x%04x\n", dj2d_info->prom_base);
return SCPE_ARG;
}
if (sim_map_resource(dj2d_info->mem_base, dj2d_info->mem_size, RESOURCE_TYPE_MEMORY, &dj2dmem, "dj2dmem", FALSE) != 0) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": Error mapping MEM resource at 0x%04x\n", dj2d_info->mem_base);
return SCPE_ARG;
}
if (newba == 0xe000) {
if (dj2d_info->modelB) {
dj2d_prom = dj2d_promb_e000;
} else {
dj2d_prom = dj2d_proma_e000;
}
} else {
if (dj2d_info->modelB) {
dj2d_prom = dj2d_promb_f800;
} else {
dj2d_prom = dj2d_proma_f800;
}
}
return dj2d_reset(&dj2d_dev);
}
/* Show Base Address routine */
t_stat dj2d_show_prombase(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr;
DJ2D_INFO *pInfo;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
return SCPE_IERR;
pInfo = (DJ2D_INFO *) dptr->ctxt;
if(pInfo->promEnabled) {
fprintf(st, "PROM=0x%04X-0x%04X", pInfo->prom_base, pInfo->prom_base+pInfo->prom_size-9);
fprintf(st, ", REG=0x%04X-0x%04X", pInfo->prom_base+pInfo->prom_size-8, pInfo->prom_base+pInfo->prom_size-1);
fprintf(st, ", RAM=0x%04X-0x%04X", pInfo->mem_base, pInfo->mem_base+pInfo->mem_size-1);
}
return SCPE_OK;
}
static t_stat dj2d_set_model(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
char base[5];
if (!cptr) return SCPE_IERR;
/* this assumes that the parameter has already been upcased */
if (!strcmp(cptr, "B")) {
dj2d_info->modelB = TRUE;
} else if (!strcmp(cptr, "A")) {
dj2d_info->modelB = FALSE;
} else {
return SCPE_ARG;
}
sprintf(base, "%04x", dj2d_info->prom_base);
dj2d_set_prombase(uptr, dj2d_info->prom_base, base, "PROMBASE");
return SCPE_OK;
}
static t_stat dj2d_show_model(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
fprintf(st, "MODEL=%s", (dj2d_info->modelB) ? "B" : "A");
return SCPE_OK;
}
static t_stat dj2d_set_sides(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int i;
if (!cptr) return SCPE_IERR;
for (i = 0; i < DJ2D_MAX_DRIVES; i++) {
if (dj2d_info->uptr[i] == uptr) {
break;
}
}
/* this assumes that the parameter has already been upcased */
if (i < DJ2D_MAX_DRIVES) {
if (!strcmp(cptr, "1")) {
dj2d_info->sides2[i] = FALSE;
} else if (!strcmp(cptr, "2")) {
dj2d_info->sides2[i] = TRUE;
} else {
return SCPE_ARG;
}
return SCPE_OK;
}
return SCPE_ARG;
}
static t_stat dj2d_show_sides(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int i;
for (i = 0; i < DJ2D_MAX_DRIVES; i++) {
if (dj2d_info->uptr[i] == uptr) {
fprintf(st, "SIDES=%d", (dj2d_info->sides2[i]) ? 2 : 1);
break;
}
}
return SCPE_OK;
}
/* Attach routine */
static t_stat dj2d_attach(UNIT *uptr, CONST char *cptr)
{
char header[4];
t_stat r;
int i,f;
/* Attaching to serial interface? */
if (uptr == &dj2d_dev.units[DJ2D_SIO_UNIT]) {
if ((r = tmxr_attach(dj2d_info->tmxr, uptr, cptr)) == SCPE_OK) {
dj2d_info->tmln->rcve = 1;
sim_debug(VERBOSE_MSG, uptr->dptr, "attached '%s' to serial interface.\n", cptr);
}
return r;
}
r = attach_unit(uptr, cptr); /* attach unit */
if (r != SCPE_OK) { /* error? */
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": ATTACH error=%d\n", r);
return r;
}
for (i = 0; i < DJ2D_MAX_DRIVES; i++) {
if (dj2d_dev.units[i].fileref == uptr->fileref) {
break;
}
}
if (i >= DJ2D_MAX_DRIVES) {
return SCPE_ARG;
}
uptr->capac = sim_fsize(uptr->fileref);
/* Default is 1024 byte sectors */
dj2d_info->format[i] = FMT_1024;
dj2d_info->sectorLen[i] = dj2d_sector_len[FMT_1024];
dj2d_info->sides2[i] = FALSE;
for (f = 0; f < FMT_UNKNOWN; f++) {
if (uptr->capac == dj2d_image_size[f]) {
dj2d_info->format[i] = f;
dj2d_info->sectorLen[i] = dj2d_sector_len[f];
dj2d_info->sides2[i] = FALSE;
} else if (uptr->capac == dj2d_2s_image_size[f]) {
dj2d_info->format[i] = f;
dj2d_info->sectorLen[i] = dj2d_sector_len[f];
dj2d_info->sides2[i] = TRUE;
}
}
sim_debug(DEBUG_MSG, &dj2d_dev, DJ2D_SNAME ": ATTACH drive=%d uptr->capac=%d format=%d sectorLen=%d 2sided=%d\n", i, uptr->capac, dj2d_info->format[i], dj2d_info->sectorLen[i], dj2d_info->sides2[i]);
/* 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;
dj2d_detach(uptr);
return SCPE_OPENERR;
}
}
sim_debug(VERBOSE_MSG, uptr->dptr, DJ2D_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 dj2d_detach(UNIT *uptr)
{
t_stat r;
int8 i;
for (i = 0; i < DJ2D_UNITS; i++) {
if (dj2d_dev.units[i].fileref == uptr->fileref) {
break;
}
}
if (i >= DJ2D_UNITS) {
return SCPE_ARG;
}
r = detach_unit(uptr); /* detach unit */
if (r != SCPE_OK) {
return r;
}
dj2d_dev.units[i].fileref = NULL;
dj2d_info->WD1791.index = TRUE;
dj2d_info->indexTimeout = 0;
sim_debug(VERBOSE_MSG, uptr->dptr, DJ2D_SNAME "%d: detached\n", i);
return SCPE_OK;
}
static t_stat dj2d_set_baud(UNIT *uptr, int32 value, const char *cptr, void *desc)
{
int32 baud;
t_stat r = SCPE_ARG;
/* Force serial interface unit */
uptr = &dj2d_dev.units[DJ2D_SIO_UNIT];
if (!(uptr->flags & UNIT_ATT)) {
return SCPE_UNATT;
}
if (cptr != NULL) {
if (sscanf(cptr, "%d", &baud)) {
switch (baud) {
case 110:
case 1200:
case 9600:
case 19200:
dj2d_info->DJ2D.uart_baud = baud;
r = dj2d_config_line();
break;
default:
break;
}
}
}
return r;
}
static t_stat dj2d_show_baud(FILE *st, UNIT *uptr, int32 value, const void *desc)
{
if (uptr->flags & UNIT_ATT) {
fprintf(st, "Baud rate: %d", dj2d_info->DJ2D.uart_baud);
}
return SCPE_OK;
}
static t_stat dj2d_config_line()
{
char config[20];
const char *fmt;
t_stat r = SCPE_IERR;
fmt = "8N1";
sprintf(config, "%d-%s", dj2d_info->DJ2D.uart_baud, fmt);
r = tmxr_set_config_line(dj2d_info->tmln, config);
sim_debug(STATUS_MSG, &dj2d_dev, "port configuration set to '%s'.\n", config);
return r;
}
static t_stat dj2d_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))) {
sim_map_resource(dj2d_info->prom_base, dj2d_info->prom_size,
RESOURCE_TYPE_MEMORY, &dj2dprom, "dj2dprom", FALSE);
dj2d_info->promEnabled = TRUE;
} else if (!strncmp(cptr, "DISABLE", strlen(cptr))) {
dj2d_info->promEnabled = FALSE;
sim_map_resource(dj2d_info->prom_base, dj2d_info->prom_size,
RESOURCE_TYPE_MEMORY, &dj2dprom, "dj2dprom", TRUE);
} else {
return SCPE_ARG;
}
return SCPE_OK;
}
static t_stat dj2d_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (dj2d_info->promEnabled) {
fprintf(st, "PROM");
} else {
fprintf(st, "NOPROM");
}
return SCPE_OK;
}
static t_stat dj2d_boot(int32 unitno, DEVICE *dptr)
{
DJ2D_INFO *pInfo = (DJ2D_INFO *)dptr->ctxt;
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": Booting Controller at 0x%04x\n", pInfo->prom_base);
*((int32 *) sim_PC->loc) = pInfo->prom_base;
return SCPE_OK;
}
static void showdata(int32 isRead) {
int32 i;
sim_debug(isRead ? RD_DATA_DETAIL_MSG : WR_DATA_DETAIL_MSG, &dj2d_dev, DJ2D_SNAME ": %s track/sector %02d/%03d:\n\t", isRead ? "Read" : "Write", dj2d_info->WD1791.track, dj2d_info->WD1791.sector);
for (i = 0; i < sector_len(dj2d_info->currentDrive, dj2d_info->WD1791.track); i++) {
sim_debug(isRead ? RD_DATA_DETAIL_MSG : WR_DATA_DETAIL_MSG, &dj2d_dev, "%02X ", sdata[i]);
if (((i+1) & 0xf) == 0) {
sim_debug(isRead ? RD_DATA_DETAIL_MSG : WR_DATA_DETAIL_MSG, &dj2d_dev, "\n\t");
}
}
if (isRead) {
sim_debug(RD_DATA_DETAIL_MSG, &dj2d_dev, "\n");
} else {
sim_debug(WR_DATA_DETAIL_MSG, &dj2d_dev, "\n");
}
}
static uint16 sector_len(uint8 drive, uint8 track)
{
if (track == 0) { /* Track 0 is always SD */
return(dj2d_sector_len[FMT_SD]);
}
return(dj2d_info->sectorLen[drive]);
}
static uint32 secs_per_track(uint8 track)
{
if (track == 0) {
dj2d_info->secsPerTrack = (uint8)dj2d_spt[FMT_SD];
} else {
dj2d_info->secsPerTrack = (uint8)dj2d_spt[dj2d_info->format[dj2d_info->currentDrive]];
}
return dj2d_info->secsPerTrack;
}
static uint32 bytes_per_track(uint8 track)
{
int8 format;
format = dj2d_info->format[dj2d_info->currentDrive];
if (track == 0) {
dj2d_info->bytesPerTrack = dj2d_track_len[FMT_SD];
} else {
dj2d_info->bytesPerTrack = dj2d_track_len[format];
}
return dj2d_info->bytesPerTrack;
}
static t_offset calculate_dj2d_sec_offset(uint8 track, uint8 sector)
{
t_offset offset;
uint8 ds;
uint8 format;
ds = dj2d_info->side[dj2d_info->currentDrive];
format = dj2d_info->format[dj2d_info->currentDrive];
/*
** Side 0: tracks 0-76
** Side 1: tracks 77-153
*/
if (ds) {
track += 77;
}
/*
** Calculate track offset
*/
if (track == 0) { /* Track 0 is always SD */
offset = 0;
format = FMT_SD;
} else {
offset = (t_offset)(dj2d_spt[FMT_SD]) * (t_offset)(dj2d_sector_len[FMT_SD]); /* Track 0 / Side 0 always SD */
offset += (t_offset)(track-1) * (t_offset)(dj2d_spt[format]) * (t_offset)(dj2d_sector_len[format]); /* Track 1-153 */
}
/*
** Add sector offset to track offset
*/
offset += (t_offset)(sector-1) * (t_offset)(dj2d_sector_len[format]);
sim_debug(DEBUG_MSG, &dj2d_dev, DJ2D_SNAME ": OFFSET=%08llx drive=%d side=%d format=%d track=%03d sector=%03d\r\n", offset, dj2d_info->currentDrive, ds, dj2d_info->format[dj2d_info->currentDrive], track, sector);
return (offset);
}
static void DJ2D_HeadLoad(UNIT *uptr, WD1791_REG *pWD1791, uint8 load)
{
/*
** If no disk has been attached, uptr will be NULL - return
*/
if (uptr == NULL) {
return;
}
if (load) {
dj2d_info->headTimeout = DJ2D_HEAD_TIMEOUT;
if (dj2d_info->headLoaded[dj2d_info->currentDrive] == FALSE) {
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": Drive %d head Loaded.\n", dj2d_info->currentDrive);
}
} else {
dj2d_info->headTimeout = 0;
if (dj2d_info->headLoaded[dj2d_info->currentDrive] == TRUE) {
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": Drive %d head Unloaded.\n", dj2d_info->currentDrive);
}
}
dj2d_info->headLoaded[dj2d_info->currentDrive] = load;
}
static void DJ2D_LED(DJ2D_REG *pDJ2D, int status)
{
if (pDJ2D->led != status) {
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": LED %s.\n", (status) ? "ON" : "OFF");
}
pDJ2D->led = status;
}
static uint8 DJ2D_Read(uint32 Addr)
{
uint8 cData;
uint8 driveNum;
WD1791_REG *pWD1791;
DJ2D_REG *pDJ2D;
UNIT *uptr;
driveNum = dj2d_info->currentDrive;
uptr = dj2d_info->uptr[driveNum];
pWD1791 = &dj2d_info->WD1791;
pDJ2D = &dj2d_info->DJ2D;
switch(Addr & 0x07) {
case DJ2D_REG_UART_DATA: /* Read character from UART */
if (pDJ2D->uart_status & DJ2D_STAT_DR) {
cData = ~pDJ2D->uart_rxd; /* Inverted */
pDJ2D->uart_status &= ~DJ2D_STAT_DR;
} else {
cData = 0xff;
}
break;
case DJ2D_REG_UART_STATUS:
cData = ~pDJ2D->uart_status; /* Inverted */
break;
case DJ2D_REG_2D_STATUS:
if (dj2d_info->modelB) {
cData = (pWD1791->intrq) ? DJ2D_STAT_INTRQ : 0;
cData |= (pWD1791->drq) ? DJ2D_STAT_DATARQ : 0;
cData |= (pWD1791->index) ? DJ2D_STAT_INDEX : 0;
cData |= (dj2d_info->headLoaded[dj2d_info->currentDrive]) ? DJ2D_STAT_HEAD : 0;
cData |= (pWD1791->status & WD1791_STAT_NOTREADY) ? 0 : DJ2D_STAT_READY;
cData |= (dj2d_info->sides2[dj2d_info->currentDrive]) ? 0 : DJ2D_STAT_N2SIDED;
} else {
cData = (pWD1791->intrq) ? DJ2DA_STAT_INTRQ : 0;
cData |= (pWD1791->drq) ? DJ2DA_STAT_DATARQ : 0;
cData |= (pWD1791->index) ? 0 : DJ2DA_STAT_NINDEX;
cData |= (dj2d_info->headLoaded[dj2d_info->currentDrive]) ? DJ2DA_STAT_HEAD : 0;
cData |= (pWD1791->status & WD1791_STAT_NOTREADY) ? DJ2DA_STAT_NREADY : 0;
cData |= (dj2d_info->sides2[dj2d_info->currentDrive]) ? 0 : DJ2D_STAT_N2SIDED;
}
if (pDJ2D->status != cData) {
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": 2D_STATUS=%02X\n", cData);
}
pDJ2D->status = cData;
break;
case DJ2D_REG_1791_STATUS:
cData = pWD1791->status;
break;
case DJ2D_REG_1791_TRACK:
cData = pWD1791->track;
break;
case DJ2D_REG_1791_DATA:
/*
** If a READ operation is currently active, get the next byte
*/
if (pWD1791->readActive) {
/* Store byte in DATA register */
pWD1791->data = sdata[pWD1791->dataCount++];
/* If we reached the end of the sector, terminate command and set INTRQ */
if (pWD1791->dataCount == sector_len(driveNum, pWD1791->track)) {
pWD1791->readActive = FALSE;
pWD1791->dataCount = 0;
pWD1791->status = 0x00;
pWD1791->drq = FALSE;
pWD1791->intrq = TRUE;
}
DJ2D_HeadLoad(uptr, pWD1791, TRUE);
} else if (pWD1791->readTrkActive) {
/* If we reached the end of the track data, terminate command and set INTRQ */
if (pWD1791->trkCount == bytes_per_track(pWD1791->track)) {
pWD1791->readTrkActive = FALSE;
pWD1791->status = 0x00;
pWD1791->drq = FALSE;
pWD1791->intrq = TRUE;
} else {
pWD1791->trkCount++;
}
DJ2D_HeadLoad(uptr, pWD1791, TRUE);
} else if (pWD1791->addrActive) {
/* Store byte in DATA register */
pWD1791->data = sdata[pWD1791->dataCount++];
/* If we reached the end of the address data, terminate command and set INTRQ */
if (pWD1791->dataCount > WD1791_ADDR_CRC2) {
pWD1791->addrActive = FALSE;
pWD1791->status = 0x00;
pWD1791->drq = FALSE;
pWD1791->intrq = TRUE;
}
DJ2D_HeadLoad(uptr, pWD1791, TRUE);
}
cData = pWD1791->data;
break;
case DJ2D_REG_1791_SECTOR:
cData = pWD1791->sector;
break;
default:
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": READ REG Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x07);
cData = 0xff;
break;
}
sim_debug(DEBUG_MSG, &dj2d_dev, DJ2D_SNAME ": READ REG currentDrive=%d format=%d track=%02d sector=%02d data=%02x status=%02x\n", dj2d_info->currentDrive, dj2d_info->format[dj2d_info->currentDrive], pWD1791->track, pWD1791->sector, pWD1791->data, pWD1791->status);
return (cData);
}
static uint8 DJ2D_Write(uint32 Addr, int32 Data)
{
uint8 cData;
uint8 driveNum;
int32 rtn;
UNIT *uptr;
WD1791_REG *pWD1791;
DJ2D_REG *pDJ2D;
Data &= 0xff;
sim_debug(CMD_MSG, &dj2d_dev, DJ2D_SNAME ": OUT %04X Data %02X\n", Addr, Data);
cData = 0;
driveNum = dj2d_info->currentDrive;
uptr = dj2d_info->uptr[driveNum];
pWD1791 = &dj2d_info->WD1791;
pDJ2D = &dj2d_info->DJ2D;
switch(Addr & 0x07) {
case DJ2D_REG_UART_DATA:
pDJ2D->uart_txd = ~Data; /* Character is inverted */
pDJ2D->uart_txp = TRUE;
pDJ2D->uart_status &= ~DJ2D_STAT_TBRE;
break;
case DJ2D_REG_1791_COMMAND:
cData = DJ2D_Command(uptr, pWD1791, Data);
break;
case DJ2D_REG_2D_FUNCTION:
pDJ2D->function = Data;
if (dj2d_info->modelB) {
switch (Data & DJ2D_FUNC_HDMASK) {
case DJ2D_FUNC_HDLOAD:
DJ2D_HeadLoad(uptr, pWD1791, TRUE);
break;
case DJ2D_FUNC_HDUNLD:
DJ2D_HeadLoad(uptr, pWD1791, FALSE);
break;
default:
break;
}
DJ2D_LED(pDJ2D, !(Data & DJ2D_FUNC_LEDOFF));
} else {
switch (Data & DJ2DA_FUNC_HDMASK) {
case DJ2DA_FUNC_HDLOAD:
DJ2D_HeadLoad(uptr, pWD1791, TRUE);
break;
case DJ2DA_FUNC_HDUNLD:
DJ2D_HeadLoad(uptr, pWD1791, FALSE);
break;
default:
break;
}
}
break;
case DJ2D_REG_1791_DATA:
pWD1791->data = Data; /* Store byte in DATA register */
if (pWD1791->writeActive) {
/* Store DATA register in Sector Buffer */
sdata[pWD1791->dataCount++] = pWD1791->data;
/* If we reached the end of the sector, write sector, terminate command and set INTRQ */
if (pWD1791->dataCount == sector_len(driveNum, pWD1791->track)) {
pWD1791->status = 0x00; /* Clear Status Bits */
rtn = DJ2D_WriteSector(uptr, pWD1791->track, pWD1791->sector, sdata);
showdata(FALSE);
if (rtn != sector_len(driveNum, pWD1791->track)) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": sim_fwrite errno=%d\n", errno);
pWD1791->status |= WD1791_STAT_WRITEFAULT;
}
pWD1791->writeActive = FALSE;
pWD1791->dataCount = 0;
pWD1791->drq = FALSE;
pWD1791->intrq = TRUE;
}
DJ2D_HeadLoad(uptr, pWD1791, TRUE);
} else if (pWD1791->writeTrkActive) {
if (pWD1791->idAddrMrk) {
if (++pWD1791->dataCount == 4) { /* Sector Len */
dj2d_info->sectorLen[dj2d_info->currentDrive] = dj2d_sector_len[pWD1791->data];
dj2d_info->format[dj2d_info->currentDrive] = pWD1791->data;
pWD1791->idAddrMrk = 0;
pWD1791->dataCount = 0;
}
} else if (pWD1791->dataAddrMrk) {
/* Store DATA register in Sector Buffer */
sdata[pWD1791->dataCount++] = pWD1791->data;
/* If we reached the end of the sector, write sector */
if (pWD1791->dataCount == sector_len(driveNum, pWD1791->track)) {
pWD1791->status &= ~WD1791_STAT_WRITEFAULT; /* Clear Status Bit */
showdata(FALSE);
rtn = DJ2D_WriteSector(uptr, pWD1791->track, pWD1791->sector, sdata);
if (rtn != sector_len(driveNum, pWD1791->track)) {
pWD1791->status |= WD1791_STAT_WRITEFAULT;
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": WRITE ERROR could not write track %03d sector %03d\n", pWD1791->track, pWD1791->sector);
}
sim_debug(DEBUG_MSG, &dj2d_dev, DJ2D_SNAME ": WRITE TRACK drive=%d track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X\n", driveNum, pWD1791->track, pWD1791->sector, pWD1791->trkCount, pWD1791->dataCount, pWD1791->data, pWD1791->status);
pWD1791->dataCount = 0;
pWD1791->idAddrMrk = FALSE;
pWD1791->dataAddrMrk = FALSE;
if (pWD1791->sector < secs_per_track(pWD1791->track)) {
pWD1791->sector++;
}
}
} else if (pWD1791->data == 0xFE) {
pWD1791->idAddrMrk = TRUE;
} else if (pWD1791->data == 0xFB) {
pWD1791->dataAddrMrk = TRUE;
}
/*
** Increment number for bytes written to track
*/
pWD1791->trkCount++;
if (pWD1791->trkCount == bytes_per_track(pWD1791->track)) {
pWD1791->status = 0x00; /* Clear Status Bits */
pWD1791->drq = FALSE;
pWD1791->intrq = TRUE;
pWD1791->writeTrkActive = FALSE;
sim_debug(WR_DATA_MSG, &dj2d_dev, DJ2D_SNAME ": WRITE TRACK COMPLETE track=%03d sector=%03d trkcount=%d datacount=%d data=%02X status=%02X\n", pWD1791->track, pWD1791->sector, pWD1791->trkCount, pWD1791->dataCount, pWD1791->data, pWD1791->status);
}
DJ2D_HeadLoad(uptr, pWD1791, TRUE);
}
break;
case DJ2D_REG_1791_TRACK:
pWD1791->track = Data;
break;
case DJ2D_REG_1791_SECTOR:
pWD1791->sector = Data;
break;
case DJ2D_REG_2D_CONTROL:
pDJ2D->control = Data & 0xff;
/* Drive Select */
switch (~Data & DJ2D_CTRL_DSEL) {
case 0x01:
cData = 0;
break;
case 0x02:
cData = 1;
break;
case 0x04:
cData = 2;
break;
case 0x08:
cData = 3;
break;
}
/* Side */
if (dj2d_info->sides2[cData]) {
dj2d_info->side[cData] = (Data & DJ2D_CTRL_SIDE0) == 0x00;
} else {
dj2d_info->side[cData] = FALSE;
}
if (dj2d_info->currentDrive != cData) {
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": Current drive now %d side %d\n", cData, dj2d_info->side[cData]);
}
dj2d_info->currentDrive = cData;
if (dj2d_info->modelB) {
if (Data & DJ2D_CTRL_RESET) {
/* Reset 1791 */
pWD1791->status = 0x00;
pWD1791->track = 0;
pWD1791->dataCount = 0;
pWD1791->trkCount = 0;
pWD1791->readActive = FALSE;
pWD1791->readTrkActive = FALSE;
pWD1791->writeActive = FALSE;
pWD1791->writeTrkActive = FALSE;
pWD1791->addrActive = FALSE;
pWD1791->dataAddrMrk = FALSE;
pWD1791->idAddrMrk = FALSE;
pWD1791->drq = FALSE;
pWD1791->intrq = FALSE;
}
} else {
DJ2D_LED(pDJ2D, !(Data & DJ2DA_CTRL_LEDOFF));
}
break;
default:
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": WRITE Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x07);
cData = 0xff;
break;
}
sim_debug(DEBUG_MSG, &dj2d_dev, DJ2D_SNAME ": WRITE REG currentDrive=%d format=%d track=%02d sector=%02d data=%02x status=%02x\n", dj2d_info->currentDrive, dj2d_info->format[dj2d_info->currentDrive], pWD1791->track, pWD1791->sector, pWD1791->data, pWD1791->status);
return(cData);
}
static uint32 DJ2D_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
{
uint32 sec_offset;
uint32 rtn = 0;
uint32 len;
if (uptr->fileref == NULL) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": READSEC uptr.fileref is NULL!\n");
return 0;
}
sec_offset = (uint32)calculate_dj2d_sec_offset(track, sector);
len = sector_len(dj2d_info->currentDrive, track);
sim_debug(RD_DATA_MSG, &dj2d_dev, DJ2D_SNAME ": READSEC track %03d sector %03d at offset %04X len %d\n", track, sector, sec_offset, len);
if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": READSEC sim_fseek error.\n");
return 0;
}
rtn = sim_fread(buffer, 1, len, uptr->fileref);
return rtn;
}
static uint32 DJ2D_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
{
t_offset sec_offset;
uint32 len;
uint32 rtn = 0;
if (uptr->fileref == NULL) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": READSEC uptr.fileref is NULL!\n");
return 0;
}
sec_offset = calculate_dj2d_sec_offset(track, sector);
len = sector_len(dj2d_info->currentDrive, track);
if (sim_fseek(uptr->fileref, (t_addr)sec_offset, SEEK_SET) != 0) {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": WRITESEC sim_fseek error.\n");
return 0;
}
rtn = sim_fwrite(buffer, 1, len, uptr->fileref);
sim_debug(WR_DATA_MSG, &dj2d_dev, DJ2D_SNAME ": WRITESEC track %03d sector %03d at offset %08llX len %d rtn=%d\n", track, sector, sec_offset, len, rtn);
return rtn;
}
static const char * DJ2D_CommandString(uint8 command)
{
switch (command & 0xf0) {
case WD1791_CMD_RESTORE:
return "RESTORE";
case WD1791_CMD_SEEK:
return "SEEK";
case WD1791_CMD_STEP:
return "STEP";
case WD1791_CMD_STEPU:
return "STEP U";
case WD1791_CMD_STEPIN:
return "STEP IN";
case WD1791_CMD_STEPINU:
return "STEP IN U";
case WD1791_CMD_STEPOUT:
return "STEP OUT";
case WD1791_CMD_STEPOUTU:
return "STEP OUT U";
case WD1791_CMD_READ:
return "READ";
case WD1791_CMD_WRITE:
return "WRITE";
case WD1791_CMD_WRITEM:
return "WRITE M";
case WD1791_CMD_READ_ADDRESS:
return "READ ADDRESS";
case WD1791_CMD_READ_TRACK:
return "READ TRACK";
case WD1791_CMD_WRITE_TRACK:
return "WRITE TRACK";
case WD1791_CMD_FORCE_INTR:
return "FORCE INTR";
default:
break;
}
return "UNRECOGNIZED COMMAND";
}
static uint8 DJ2D_Command(UNIT *uptr, WD1791_REG *pWD1791, int32 Data)
{
uint8 cData;
uint8 newTrack;
uint8 statusUpdate;
int32 rtn;
cData = 0;
statusUpdate = TRUE;
if (uptr == NULL) {
return cData;
}
pWD1791->command = Data;
/*
** Type II-IV Command
*/
if (pWD1791->command & 0x80) {
pWD1791->readActive = FALSE;
pWD1791->writeActive = FALSE;
pWD1791->readTrkActive = FALSE;
pWD1791->writeTrkActive = FALSE;
pWD1791->addrActive = FALSE;
pWD1791->dataCount = 0;
pWD1791->status &= ~WD1791_STAT_DRQ; /* Reset DRQ */
pWD1791->drq = FALSE;
}
/*
** Set BUSY for all but Force Interrupt
*/
if ((pWD1791->command & WD1791_CMD_FORCE_INTR) != WD1791_CMD_FORCE_INTR) {
pWD1791->status |= WD1791_STAT_BUSY;
dj2d_info->busyTimeout = DJ2D_BUSY_TIMEOUT;
}
pWD1791->intrq = FALSE;
switch(pWD1791->command & 0xf0) {
case WD1791_CMD_RESTORE:
pWD1791->track = 0;
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": RESTORE track=%03d\n", pWD1791->track);
DJ2D_HeadLoad(uptr, pWD1791, (Data & WD1791_FLAG_H) ? TRUE : FALSE);
pWD1791->status &= ~WD1791_STAT_SEEKERROR;
pWD1791->status &= ~WD1791_STAT_DRQ;
pWD1791->drq = FALSE;
break;
case WD1791_CMD_SEEK:
newTrack = pWD1791->data;
pWD1791->status &= ~WD1791_STAT_SEEKERROR;
if (newTrack < DJ2D_TRACKS) {
pWD1791->track = newTrack;
DJ2D_HeadLoad(uptr, pWD1791, (Data & WD1791_FLAG_H) ? TRUE : FALSE);
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": SEEK track=%03d\n", pWD1791->track);
} else {
pWD1791->status |= WD1791_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": SEEK ERR track=%03d\n", newTrack);
}
pWD1791->status &= ~WD1791_STAT_DRQ;
pWD1791->drq = FALSE;
break;
case WD1791_CMD_STEP:
case WD1791_CMD_STEPU:
pWD1791->status &= ~WD1791_STAT_SEEKERROR;
newTrack = pWD1791->track + pWD1791->stepDir;
if (newTrack < DJ2D_TRACKS) {
if (Data & WD1791_FLAG_U) {
pWD1791->track = newTrack;
}
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": STEP track=%03d\n", pWD1791->track);
} else {
pWD1791->status |= WD1791_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": STEP ERR track=%03d\n", newTrack);
}
DJ2D_HeadLoad(uptr, pWD1791, (Data & WD1791_FLAG_H) ? TRUE : FALSE);
pWD1791->status &= ~WD1791_STAT_DRQ;
pWD1791->drq = FALSE;
break;
case WD1791_CMD_STEPIN:
case WD1791_CMD_STEPINU:
pWD1791->status &= ~WD1791_STAT_SEEKERROR;
if (pWD1791->track < DJ2D_TRACKS-1) {
if (Data & WD1791_FLAG_U) {
pWD1791->track++;
}
DJ2D_HeadLoad(uptr, pWD1791, (Data & WD1791_FLAG_H) ? TRUE : FALSE);
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": STEPIN track=%03d\n", pWD1791->track);
} else {
pWD1791->status |= WD1791_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": STEPIN ERR track=%03d\n", pWD1791->track+1);
}
pWD1791->stepDir = 1;
pWD1791->status &= ~WD1791_STAT_DRQ;
pWD1791->drq = FALSE;
break;
case WD1791_CMD_STEPOUT:
case WD1791_CMD_STEPOUTU:
pWD1791->status &= ~WD1791_STAT_SEEKERROR;
if (pWD1791->track > 0) {
if (Data & WD1791_FLAG_U) {
pWD1791->track--;
}
DJ2D_HeadLoad(uptr, pWD1791, (Data & WD1791_FLAG_H) ? TRUE : FALSE);
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": STEPOUT track=%03d\n", pWD1791->track);
} else {
pWD1791->status |= WD1791_STAT_SEEKERROR;
sim_debug(SEEK_MSG, &dj2d_dev, DJ2D_SNAME ": STEPOUT ERR track=%03d\n", pWD1791->track-1);
}
pWD1791->stepDir = -1;
pWD1791->status &= ~WD1791_STAT_DRQ;
pWD1791->drq = FALSE;
break;
case WD1791_CMD_READ:
if ((uptr == NULL) || (uptr->fileref == NULL)) {
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": " ADDRESS_FORMAT
" Drive: %d not attached - read ignored.\n",
PCX, dj2d_info->currentDrive);
return cData;
}
rtn = DJ2D_ReadSector(uptr, pWD1791->track, pWD1791->sector, sdata);
if (rtn == sector_len(dj2d_info->currentDrive, pWD1791->track)) {
pWD1791->readActive = TRUE;
pWD1791->drq = TRUE;
dj2d_info->busyTimeout = 0; /* BUSY not cleared until all bytes read */
showdata(TRUE);
} else {
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": sim_fread errno=%d rtn=%d len=%d\n", errno, rtn, sector_len(dj2d_info->currentDrive, pWD1791->track));
pWD1791->status |= WD1791_STAT_NOTFOUND;
pWD1791->intrq = TRUE;
}
break;
case WD1791_CMD_WRITE:
/*
** If no disk in drive, return
*/
if ((uptr == NULL) || (uptr->fileref == NULL)) {
sim_debug(STATUS_MSG, &dj2d_dev, DJ2D_SNAME ": " ADDRESS_FORMAT
" Drive: %d not attached - write ignored.\n",
PCX, dj2d_info->currentDrive);
}
if ((uptr->flags & UNIT_DJ2D_WPROTECT) || dj2d_info->writeProtect) {
sim_debug(VERBOSE_MSG, &dj2d_dev, DJ2D_SNAME ": Disk write protected. uptr->flags=%04x writeProtect=%04x\n", uptr->flags & UNIT_DJ2D_WPROTECT, dj2d_info->writeProtect);
pWD1791->intrq = TRUE;
} else {
dj2d_info->busyTimeout = 0; /* BUSY not cleared until all bytes written */
pWD1791->writeActive = TRUE;
pWD1791->dataCount = 0;
pWD1791->drq = TRUE;
}
break;
case WD1791_CMD_READ_ADDRESS:
sdata[WD1791_ADDR_TRACK] = pWD1791->track;
sdata[WD1791_ADDR_ZEROS] = 0;
sdata[WD1791_ADDR_SECTOR] = pWD1791->sector;
sdata[WD1791_ADDR_LENGTH] = (pWD1791->track) ? dj2d_info->format[dj2d_info->currentDrive] : 0;
sdata[WD1791_ADDR_CRC1] = 0;
sdata[WD1791_ADDR_CRC2] = 0;
pWD1791->addrActive = TRUE;
pWD1791->drq = TRUE;
break;
case WD1791_CMD_READ_TRACK:
dj2d_info->busyTimeout = 0; /* BUSY not cleared until all bytes read */
pWD1791->readTrkActive = TRUE;
pWD1791->trkCount = 0;
pWD1791->dataCount = 0;
pWD1791->sector = 1;
pWD1791->drq = TRUE;
break;
case WD1791_CMD_WRITE_TRACK:
if ((uptr->flags & UNIT_DJ2D_WPROTECT) || dj2d_info->writeProtect) {
sim_debug(DEBUG_MSG, &dj2d_dev, DJ2D_SNAME ": Disk write protected. uptr->flags=%04x writeProtect=%04x\n", uptr->flags & UNIT_DJ2D_WPROTECT, dj2d_info->writeProtect);
pWD1791->intrq = TRUE;
} else {
dj2d_info->busyTimeout = 0; /* BUSY not cleared until all bytes written */
pWD1791->writeTrkActive = TRUE;
pWD1791->trkCount = 0;
pWD1791->dataCount = 0;
pWD1791->sector = 1;
pWD1791->idAddrMrk = 0;
pWD1791->dataAddrMrk = 0;
pWD1791->drq = TRUE;
}
break;
case WD1791_CMD_FORCE_INTR:
if (pWD1791->status & WD1791_STAT_BUSY) {
pWD1791->status &= ~WD1791_STAT_BUSY;
dj2d_info->busyTimeout = 0;
statusUpdate = FALSE;
}
/* Reset Status */
pWD1791->dataCount = 0;
pWD1791->trkCount = 0;
pWD1791->readActive = FALSE;
pWD1791->readTrkActive = FALSE;
pWD1791->writeActive = FALSE;
pWD1791->writeTrkActive = FALSE;
pWD1791->addrActive = FALSE;
break;
default:
cData = 0xFF;
sim_debug(ERROR_MSG, &dj2d_dev, DJ2D_SNAME ": UNRECOGNIZED CMD %02X\n", pWD1791->command);
pWD1791->intrq = TRUE;
break;
}
/**************************/
/* Update Status Register */
/**************************/
/* drive not ready bit */
pWD1791->status &= ~WD1791_STAT_NOTREADY;
pWD1791->status |= (uptr->fileref == NULL) ? WD1791_STAT_NOTREADY : 0x00;
/* DRQ bit */
pWD1791->status &= ~WD1791_STAT_DRQ;
pWD1791->status |= (pWD1791->drq) ? WD1791_STAT_DRQ : 0x00;
switch(pWD1791->command & 0xf0) {
case WD1791_CMD_RESTORE:
case WD1791_CMD_SEEK:
case WD1791_CMD_STEP:
case WD1791_CMD_STEPU:
case WD1791_CMD_STEPIN:
case WD1791_CMD_STEPINU:
case WD1791_CMD_STEPOUT:
case WD1791_CMD_STEPOUTU:
case WD1791_CMD_FORCE_INTR:
if (statusUpdate) {
pWD1791->status &= ~WD1791_STAT_HEADLOAD;
pWD1791->status &= ~WD1791_STAT_WRITEPROT;
pWD1791->status &= ~WD1791_STAT_CRCERROR;
pWD1791->status &= ~WD1791_STAT_TRACK0;
pWD1791->status &= ~WD1791_STAT_INDEX;
pWD1791->status |= ((uptr->flags & UNIT_DJ2D_WPROTECT) || dj2d_info->writeProtect) ? WD1791_STAT_WRITEPROT : 0x00;
pWD1791->status |= (pWD1791->track) ? 0x00 : WD1791_STAT_TRACK0;
pWD1791->status |= (dj2d_info->headLoaded[dj2d_info->currentDrive]) ? WD1791_STAT_HEADLOAD : 0x00;
pWD1791->status |= (pWD1791->index) ? WD1791_STAT_INDEX : 0x00;
}
break;
case WD1791_CMD_READ:
pWD1791->status &= ~WD1791_STAT_LOSTDATA;
pWD1791->status &= ~WD1791_STAT_NOTFOUND;
pWD1791->status &= ~WD1791_STAT_CRCERROR;
pWD1791->status &= ~WD1791_STAT_RTYPELSB;
break;
case WD1791_CMD_WRITE:
pWD1791->status &= ~WD1791_STAT_WRITEPROT;
pWD1791->status &= ~WD1791_STAT_LOSTDATA;
pWD1791->status &= ~WD1791_STAT_NOTFOUND;
pWD1791->status &= ~WD1791_STAT_CRCERROR;
pWD1791->status &= ~WD1791_STAT_RTYPELSB;
pWD1791->status |= ((uptr->flags & UNIT_DJ2D_WPROTECT) || dj2d_info->writeProtect) ? WD1791_STAT_WRITEPROT : 0x00;
break;
case WD1791_CMD_READ_ADDRESS:
pWD1791->status &= ~0x20;
pWD1791->status &= ~0x40;
pWD1791->status &= ~WD1791_STAT_LOSTDATA;
pWD1791->status &= ~WD1791_STAT_NOTFOUND;
pWD1791->status &= ~WD1791_STAT_CRCERROR;
break;
case WD1791_CMD_READ_TRACK:
pWD1791->status &= ~0x08;
pWD1791->status &= ~0x10;
pWD1791->status &= ~0x20;
pWD1791->status &= ~0x40;
pWD1791->status &= ~WD1791_STAT_LOSTDATA;
break;
case WD1791_CMD_WRITE_TRACK:
pWD1791->status &= ~0x08;
pWD1791->status &= ~0x10;
pWD1791->status &= ~WD1791_STAT_WRITEPROT;
pWD1791->status &= ~WD1791_STAT_LOSTDATA;
pWD1791->status |= ((uptr->flags & UNIT_DJ2D_WPROTECT) || dj2d_info->writeProtect) ? WD1791_STAT_WRITEPROT : 0x00;
break;
}
sim_debug(CMD_MSG, &dj2d_dev,
DJ2D_SNAME ": CMD cmd=%02X (%s) drive=%d side=%d track=%03d sector=%03d status=%02X\n",
pWD1791->command, DJ2D_CommandString(pWD1791->command), dj2d_info->currentDrive,
dj2d_info->side[dj2d_info->currentDrive],
pWD1791->track, pWD1791->sector, pWD1791->status);
return(cData);
}
/*
** The DJ2D has 1016 bytes of PROM followed by 8 memory-mapped
** I/O registers.
*/
static int32 dj2dprom(int32 Addr, int32 rw, int32 Data)
{
/*
** Check for memory-mapped I/O
*/
if ((Addr & DJ2D_REG_BASE) == DJ2D_REG_BASE) {
if (rw == DJ2D_MEM_READ) { /* Read */
return(DJ2D_Read(Addr));
} else { /* Write */
return(DJ2D_Write(Addr, Data));
}
}
/*
** Read from PROM
*/
if (rw == DJ2D_MEM_READ) {
return(dj2d_prom[Addr & DJ2D_PROM_MASK]);
}
/*
** Writes are ignored and return 0xff
*/
return 0xff;
}
/*
** The DJ2D has 1K of RAM following the PROM
*/
static int32 dj2dmem(int32 Addr, int32 rw, int32 Data)
{
if (rw == DJ2D_MEM_WRITE) {
dj2d_mem[Addr & DJ2D_MEM_MASK] = Data;
}
else {
Data = dj2d_mem[Addr & DJ2D_MEM_MASK];
}
return Data;
}