File:  [RetroPC.NET] / xmil / fdd / fdd_d88.c
Revision 1.1: download - view: text, annotated - select for diffs
Sun Aug 1 14:31:30 2004 JST (21 years, 3 months ago) by yui
Branches: MAIN
CVS tags: HEAD
initialize

#include	"compiler.h"
#include	"dosio.h"
#include	"pccore.h"
#include	"x1_io.h"
#include	"x1_fdc.h"
#include	"fdd_mtr.h"
#include	"fdd_d88.h"
#include	"fddfile.h"


static	D88_HEADER	d88head[4];
static	D88_SECTOR	cursec;
static	short		curdrv = -1;
static	WORD		curtrk = -1;
static	BYTE		curtype = 0;
static	WORD		cursct = -1;
static	long		curfp = 0;
static	DWORD		cursize = 0;
static	BYTE		curwrite = 0;
static	BYTE		curtrkerr = 0;
static	BYTE		hole = 0;
static	BYTE		*curdata;
static	WORD		crcnum = 0;
static	BYTE		crcerror = FALSE;

extern	BYTE		WRITEPT[];
extern	BYTE		DISKNUM[];

extern	WORD		readdiag;

#define		TAO_MODE_GAP	0x4e
#define		TAO_MODE_SYNC	0x00
#define		TAO_MODE_AM		0xf5
#define		TAO_MODE_IM		0xf6
#define		TAO_MODE_ID		0xfe
#define		TAO_MODE_DATA	0xfb
#define		TAO_ENDOFDATA	0xf7

#define		TAO_CMD_GAP		0x4e
#define		TAO_CMD_SYNC	0x00
#define		TAO_CMD_IM_IN	0xf6
#define		TAO_CMD_IM		0xfc
#define		TAO_CMD_AM_IN	0xf5
#define		TAO_CMD_IAM		0xfe
#define		TAO_CMD_DAM		0xfb
#define		TAO_CMD_DDAM	0xf8
#define		TAO_CMD_CRC		0xf7

typedef struct {
	BYTE	mode;
	BYTE	flag;
	WORD	cnt;
	WORD	size;
	WORD	ptr;
	WORD	top;
	WORD	gap;
	BYTE	sector;
	WORD	lostdatacnt;
	BYTE	maxsector;
	WORD	maxsize;
} WID_PARA;

#define LOSTDATA_COUNT	256

static	WID_PARA WID_2D	= {TAO_ENDOFDATA, 3, 0, 0, 0, 0, 0, 0, 0, 33, 0x1f80};
static	WID_PARA WID_2HD= {TAO_ENDOFDATA, 3, 0, 0, 0, 0, 0, 0, 0, 55, 0x2f80};
static	WID_PARA WID_ERR= {TAO_ENDOFDATA, 4, 0, 0, 0, 0, 0, 0, 0,  0, 0x0000};
static	WID_PARA tao	= {TAO_ENDOFDATA, 4, 0, 0, 0, 0, 0, 0, 0,  0, 0x0000};

static	BYTE		D88_BUF[0x4000];
static	BYTE		TAO_BUF[0x3000];


//----------------------------------------------------------------------

DWORD nexttrackp(D88_HEADER *head, DWORD fptr, DWORD last) {

	int		t;
	DWORD	ret;
	DWORD	*trkp;

	ret = last;
	trkp = (DWORD *)head->trackp;
	for (t=0; t<164; t++, trkp++) {
		if ((*trkp > fptr) && (*trkp < ret)) {
			ret = *trkp;
		}
	}
	return(ret);
}


int curdataflush(void) {

	FDDFILE	fdd;
	FILEH	fh;
	int		ret = 0;

	if ((!curfp) || (!cursize)) {
		return(-1);
	}
	if (!curwrite) {
		return(0);
	}
	curwrite = 0;
	fdd = fddfile + curdrv;
	fh = file_open(fdd->fname);
	if (fh == FILEH_INVALID) {
		return(-1);
	}
	if ((file_seek(fh, curfp, FSEEK_SET) != curfp) ||
		(file_write(fh, D88_BUF, cursize) != cursize)) {
		ret = -1;
	}
	if (file_close(fh)) {
		ret = -1;
	}
	return(ret);
}


DWORD read_d88track(short drv, WORD track, BYTE type) {

	FDDFILE	fdd;
	FILEH	hdr;

	curdataflush();
	curdrv = drv;
	curtrk = track;
	curtype = type;
	cursct = -1;
	curwrite = 0;
	curtrkerr = 0;
	crcnum = 0;
	crcerror = 0;

	if ((drv < 0) || (drv > 3) || (track > 163) ||
		((type == 0) && (d88head[drv].fd_type == 0x20)) ||
		((type == 1) && (d88head[drv].fd_type != 0x20)) ||
		((curfp = d88head[drv].trackp[track]) == 0) ||
		((cursize = nexttrackp(&d88head[drv], curfp,
								d88head[drv].fd_size) - curfp) > 0x4000)) {
		goto readd88_err;
	}

	fdd = fddfile + drv;
	if ((hdr = file_open(fdd->fname)) == FILEH_INVALID) {
		goto readd88_err;
	}
	if (file_seek(hdr, curfp, FSEEK_SET) != curfp) {
		file_close(hdr);
		goto readd88_err;
	}
	if (file_read(hdr, D88_BUF, (WORD)cursize) != (WORD)cursize) {
		file_close(hdr);
		goto readd88_err;
	}
	if (file_close(hdr)) {
		goto readd88_err;
	}
	return(TRUE);

readd88_err:
	curfp = 0;
	cursize = 0;
	curtrkerr = 1;
	return(FALSE);
}




int seeksector(short drv, WORD track, WORD sector) {

static	int		lastflag = FALSE;

	BYTE 		*p;
	WORD		sec;

	if ((curdrv != drv) || (curtrk != track) || (curtype != FDC.media)) {
		read_d88track(drv, track, FDC.media);
	}
	if (curtrkerr) {
		cursct = sector;
		goto seekerror;
	}
	if (cursct != sector) {
		cursct = sector;
		p = D88_BUF;
		for (sec=0; sec<40;) {
			if ((WORD)((D88_SECTOR *)p)->r == sector) {
				memcpy(&cursec, p, sizeof(D88_SECTOR));
				curdata = p + sizeof(D88_SECTOR);
				lastflag = TRUE;
				break;
			}
			if (++sec >= ((D88_SECTOR *)p)->sectors) {
				goto seekerror;
			}
			p += ((D88_SECTOR *)p)->size;
			p += sizeof(D88_SECTOR);
		}
		if (sec >= 40) {
			goto seekerror;
		}
	}
	return(lastflag);

seekerror:;
	ZeroMemory(&cursec, sizeof(D88_SECTOR));
	curdata = &D88_BUF[16];
	lastflag = FALSE;
	return(FALSE);
}


void drvflush(short drv) {

	if (curdrv == drv) {
		curdataflush();
		curdrv = -1;
		curtrk = -1;
		cursct = -1;
	}
}


//**********************************************************************

BRESULT fdd_eject_d88(REG8 drv) {

	FDDFILE	fdd;

	drvflush(drv);
	fdd = fddfile + drv;
	ZeroMemory(&d88head[drv], sizeof(D88_HEADER));
	fdd->fname[0] = '\0';
	DISKNUM[drv] = 0;
	return(0);
}

BRESULT fdd_set_d88(REG8 drv, const OEMCHAR *fname) {

	FDDFILE	fdd;
	WORD	attr;
	FILEH	hdr;
	short	rsize;

	fdd_eject_d88(drv);
	fdd = fddfile + drv;
	if ((drv < 0 || drv > 3) ||
		((attr = file_attr(fname)) & 0x18)) {	// エラー・ディレクトリ・ラベル
		return(1);
	}
	if ((hdr = file_open(fname)) == FILEH_INVALID) {
		return(1);
	}
	rsize = file_read(hdr, &d88head[drv], sizeof(D88_HEADER));
	file_close(hdr);
	if (rsize != sizeof(D88_HEADER)) {
		fdd_eject_d88(drv);
		return(1);
	}
	if (attr & 1) {
		d88head[drv].protect |= (WORD)0x10;
	}
	milstr_ncpy(fdd->fname, fname, NELEMENTS(fdd->fname));
	DISKNUM[drv] = 1;
	return(0);
}


//**********************************************************************

short fdd_crc_d88(void) {

	WORD		track;
	BYTE		*p;
	WORD		sec;

	ZeroMemory(FDC.crc_dat, 6);
	if ((track = (WORD)(FDC.c << 1) + (WORD)FDC.h) > 163) {
		goto crcerror_d88;
	}
	seeksector(FDC.drv, track, FDC.r);
	if (curtrkerr) {
		goto crcerror_d88;
	}
	p = D88_BUF;
	for (sec=0; sec<crcnum;) {
		if (++sec >= ((D88_SECTOR *)p)->sectors) {
			goto crcerror_d88;
		}
		p += ((D88_SECTOR *)p)->size;
		p += sizeof(D88_SECTOR);
	}
	*(long *)FDC.crc_dat = *(long *)p;
	FDC.rreg = ((D88_SECTOR *)p)->c;				// ??? メルヘンヴェール
	crcnum++;
	if (((D88_SECTOR *)p)->stat) {
		crcerror = TRUE;
	}
	else {
		crcerror = FALSE;
	}
	return(0);

crcerror_d88:;
	crcerror = TRUE;
	return(1);
}


BYTE fdd_stat_d88(void) {

	BYTE		type, cmnd;
	BYTE		ans = 0;
	int			seekable;
	WORD		trk;

	if (DISKNUM[FDC.drv] == DRV_EMPTY) {
		return(0x80);						// NOT READY
	}
	type = FDC.type;
	cmnd = (BYTE)(FDC.cmnd >> 4);
	trk = (FDC.c << 1) + (WORD)FDC.h;
	seekable = seeksector(FDC.drv, trk, FDC.r);
	if (!FDC.r) {
		seekable = TRUE;
	}

	if (type == 0 || type == 1 || type == 4 ||
		cmnd == 0x0a || cmnd == 0x0b || cmnd == 0x0f) {
		if (d88head[FDC.drv].protect & 0x10) {	// WRITE PROTECT
			ans |= 0x40;
		}
	}
	if (type == 2 || cmnd == 0x0f) {
		if (FDC.r && cursec.del_flg) {
			ans |= 0x20;					// RECODE TYPE / WRITE FAULT
		}
	}
	if (type == 1 || type == 2) {
		if ((trk > 163) || (!seekable)) {
			ans |= 0x10;					// SEEK ERROR / RECORD NOT FOUND
		}
		if ((!(ans & 0xf0)) && FDC.r && (cursec.stat)) {
			ans |= 0x08;					// CRC ERROR
		}
	}
	if (cmnd == 0x0c) {
		if (curtrkerr) {
			ans |= 0x10;
		}
		if (crcerror) {
			ans |= 0x08;					// CRC ERROR
		}
	}
	if (type == 1 || type == 4) {
		if (type == 1) {					// ver0.25
			ans |= 0x20;					// HEAD ENGAGED (X1 デハ ツネニ 1)
			if (!FDC.c) {					// TRACK00
				ans |= 0x04;
			}
		}
		if (++hole < 8) {					// ver0.25
			ans |= 0x02;					// INDEX
		}
	}
	else if (!(ans & 0xf0)) {
		if ((type != 4) && (FDDMTR_BUSY)) {
			ans |= 0x01;
		}
		if ((type == 2) && ((WORD)FDC.off < cursec.size)) {
			ans |= 0x03; 					// DATA REQUEST / BUSY
		}
		else if ((cmnd == 0x0e) && (readdiag < 0x1a00)) {
			ans |= 0x03;
		}
		else if ((cmnd == 0x0c) && (FDC.crc_off < 6)) {		// ver0.25
			ans |= 0x03;
		}
		else if (cmnd == 0x0f) {
			if (tao.flag == 3) {
				if (++tao.lostdatacnt > LOSTDATA_COUNT) {
					tao.flag = 4;
				}
			}
			ans |= tao.flag;
		}
	}
	return(ans);
}

//**********************************************************************

void fdd_read_d88(void) {
						// POCO:読めなかったらレジスタを変更させない
	if ((fdd_stat_d88() & 0xf3) == 3) {
		FDC.data = curdata[FDC.off];
#if 0 //def TRACE
{
	char	buf[256];
	wsprintf(buf, "%3d %2d %02x -> %04x/%04x",
						(FDC.c << 1) + FDC.h, FDC.r, FDC.off, R.HL.W,
							dma.CNT_B.w);
	TRACE_(buf, FDC.data);
}
#endif
	}
}


void fdd_write_d88(void) {

	if ((fdd_stat_d88() & 0xf3) == 3) {
		curdata[FDC.off] = FDC.data;
		curwrite = 1;
	}
}


BYTE fdd_incoff_d88(void) {

	BYTE	cmnd;
	WORD	trk;

	cmnd = (BYTE)(FDC.cmnd >> 4);
	trk = (FDC.c << 1) + (WORD)FDC.h;
	seeksector(FDC.drv, trk, FDC.r);
	if ((WORD)(++FDC.off) < cursec.size) {
		return(0);
	}
	FDC.off = cursec.size;
	if (cmnd == 0x09 || cmnd == 0x0b) {
		FDC.rreg = FDC.r + 1;						// ver0.25
		if (seeksector(FDC.drv, trk, FDC.rreg)) {
			FDC.r++;
			FDC.off = 0;
			return(0);
		}
	}
	return(1);
}

// ---------------------------------------------------------------------------

void init_tao_d88(void) {

	if ((FDC.media == 0) && (d88head[FDC.drv].fd_type != 0x20)) {
		tao = WID_2D;
	}
	else if ((FDC.media == 1) && (d88head[FDC.drv].fd_type == 0x20)) {
		tao = WID_2HD;
	}
	else {
		tao = WID_ERR;
	}
}


int fileappend(FILEH hdr, D88_HEADER *head,
									long ptr, long last, long apsize) {

	long	length;
	WORD	size;
	WORD	rsize;
	int		t;
	long	*trkp;

	if ((length = last - ptr) <= 0) {			// 書き換える必要なし
		return(0);
	}
	while(length) {
		if (length >= 0x4000) {
			size = 0x4000;
		}
		else {
			size = (WORD)length;
		}
		length -= (long)size;
		file_seek(hdr, ptr+length, 0);
		rsize = file_read(hdr, D88_BUF, size);
		file_seek(hdr, ptr+length+apsize, 0);
		file_write(hdr, D88_BUF, rsize);
	}

	trkp = head->trackp;
	for (t=0; t<164; t++, trkp++) {
		if ((*trkp) && (*trkp >= ptr)) {
			(*trkp) += apsize;
		}
	}
	return(0);
}



void endoftrack(void) {

	FDDFILE		fdd;
	FILEH		hdr;
	int			i;
	WORD		trk;
	D88_HEADER	*head;
	long		fpointer;
	long		endpointer;
	long		lastpointer;
	long		trksize;
	int			ptr;
	long		apsize;

	if (!tao.sector) {
		tao.flag = 4;
		return;
	}
	tao.flag = 0;

	curdataflush();						// write cache flush &
	curdrv = -1;						// use D88_BUF[] for temp

	head = &d88head[FDC.drv];
	trk = (FDC.c << 1) + (WORD)FDC.h;

	ptr = 0;
	for (i=0; i<(int)tao.sector; i++) {
		((D88_SECTOR *)&TAO_BUF[ptr])->sectors = tao.sector;
		ptr += ((D88_SECTOR *)&TAO_BUF[ptr])->size + 16;
	}

	fdd = fddfile + FDC.drv;
	if ((hdr = file_open(fdd->fname)) == FILEH_INVALID) {
		return;
	}
	lastpointer = file_seek(hdr, 0, 2);
	if ((fpointer = head->trackp[trk]) == 0) {
		fpointer = 0;								// 新規トラック
		for (i=trk; i>=0; i--) {
			if (head->trackp[i]) {
				fpointer = head->trackp[i];
				break;
			}
		}
		if (fpointer) {								// ヒットした
			fpointer = nexttrackp(head, fpointer, lastpointer);
		}
		else {
			fpointer = sizeof(D88_HEADER);
		}
		endpointer = fpointer;
	}
	else {										// トラックデータは既にある
		endpointer = nexttrackp(head, fpointer, lastpointer);
	}
	trksize = endpointer - fpointer;
	if ((apsize = (long)tao.size - trksize) > 0) {
								// 書き込むデータのほーが大きい
		fileappend(hdr, head, endpointer, lastpointer, apsize);
		head->fd_size += apsize;
	}
	head->trackp[trk] = fpointer;
	file_seek(hdr, fpointer, 0);
	file_write(hdr, TAO_BUF, tao.size);
	file_seek(hdr, 0, 0);
	file_write(hdr, head, sizeof(D88_HEADER));
	file_close(hdr);
}


void fdd_wtao_d88(BYTE data) {

	if (tao.flag != 3) {
		return;
	}
	tao.lostdatacnt = 0;
	if (tao.cnt > tao.maxsize) {
		endoftrack();
		return;
	}
	tao.cnt++;
	switch(tao.mode) {
		case TAO_ENDOFDATA:
			if (data == TAO_MODE_GAP) {
				tao.mode = TAO_MODE_GAP;
				tao.gap = 0;
			}
			break;
		case TAO_MODE_GAP:
			if (data == TAO_MODE_GAP) {
				if (tao.gap++ > 256) {
					endoftrack();
				}
			}
			else if (data == TAO_CMD_SYNC) {
				tao.mode = TAO_MODE_SYNC;
			}
#if 1												// ver0.26 Zeliard
			else if (data == 0xf4) {
				endoftrack();
			}
#endif
			else {
				tao.flag = 4;
			}
			break;
		case TAO_MODE_SYNC:
//			tao.cnt--;								// ver0.26 Zeliard
			if (data == TAO_CMD_AM_IN) {
				tao.mode = TAO_MODE_AM;
			}
			else if (data == TAO_CMD_IM_IN) {
				tao.mode = TAO_MODE_IM;
			}
			else if (data) {
				tao.flag = 4;
			}
			break;
		case TAO_MODE_IM:
			if (data == TAO_CMD_IM) {
				tao.mode = TAO_ENDOFDATA;
			}
			else if (data != TAO_CMD_IM_IN) {
				tao.flag = 4;
			}
			break;
		case TAO_MODE_AM:
			if (data == TAO_CMD_IAM) {
				tao.mode = TAO_MODE_ID;
				tao.ptr = 0;
				tao.top = tao.size;
			}
			else if (data == TAO_CMD_DAM) {
				tao.mode = TAO_MODE_DATA;
				tao.ptr = 0;
			}
			else if (data == TAO_CMD_DDAM) {
				tao.mode = TAO_MODE_DATA;
				tao.ptr = 0;
				((D88_SECTOR *)&TAO_BUF[tao.top])->del_flg = 1;
			}
			break;
		case TAO_MODE_ID:
			if ((data == TAO_CMD_IAM) && (!tao.ptr)) {
				break;
			}
			else if (tao.ptr < 4) {
				TAO_BUF[tao.size++] = data;
				tao.ptr++;
			}
			else if (data == TAO_CMD_CRC) {
				tao.mode = TAO_ENDOFDATA;
				ZeroMemory(&TAO_BUF[tao.size], 12);
				tao.size += 12;
			}
			break;
		case TAO_MODE_DATA:						// DATA WRITE
			if ((!tao.ptr) &&
				((data == TAO_CMD_DAM) || (data == TAO_CMD_DDAM))) {
				break;
			}
			else if (data == TAO_CMD_CRC) {			// nで判定した方が無難か?
				tao.mode = TAO_ENDOFDATA;
				((D88_SECTOR *)&TAO_BUF[tao.top])->size = tao.ptr;
				if (tao.sector++ > tao.maxsector) {
					tao.flag = 4;
				}
			}
			else {
				TAO_BUF[tao.size++] = data;
				tao.ptr++;
			}
			break;
	}
}


RetroPC.NET-CVS <cvs@retropc.net>