mirror of
https://github.com/libretro/NP2kai.git
synced 2024-10-07 14:53:33 +00:00
1141 lines
26 KiB
C
Executable File
1141 lines
26 KiB
C
Executable File
//
|
|
// FDC μPD765A
|
|
//
|
|
|
|
#include "compiler.h"
|
|
#include "cpucore.h"
|
|
#include "pccore.h"
|
|
#include "iocore.h"
|
|
#include "diskimage/fddfile.h"
|
|
#if defined(SUPPORT_SWSEEKSND)
|
|
#include "sound/pcmmix.h"
|
|
#include "fdd_mtr.res"
|
|
#endif
|
|
#include "soundmng.h"
|
|
|
|
#if 1
|
|
#undef TRACEOUT
|
|
#define TRACEOUT(s) (void)(s)
|
|
#endif /* 0 */
|
|
|
|
extern void fddmtrsnd_play(UINT num, BOOL play);
|
|
|
|
enum {
|
|
FDC_DMACH2HD = 2,
|
|
FDC_DMACH2DD = 3
|
|
};
|
|
|
|
static const UINT8 FDCCMD_TABLE[32] = {
|
|
0, 0, 8, 2, 1, 8, 8, 1, 0, 8, 1, 0, 8, 5, 0, 2,
|
|
0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0};
|
|
|
|
|
|
#define FDC_FORCEREADY (1)
|
|
#define FDC_DELAYERROR7
|
|
|
|
#define FDC_INT_DELAY 5 /*!< Delay 100ms */
|
|
|
|
void fdc_intwait(NEVENTITEM item) {
|
|
|
|
if (item->flag & NEVENT_SETEVENT) {
|
|
fdc.intreq = TRUE;
|
|
if (fdc.chgreg & 1) {
|
|
pic_setirq(0x0b);
|
|
}
|
|
else {
|
|
pic_setirq(0x0a);
|
|
}
|
|
}
|
|
}
|
|
|
|
void fdc_interrupt(void) {
|
|
|
|
nevent_set(NEVENT_FDCINT, 512, fdc_intwait, NEVENT_ABSOLUTE);
|
|
}
|
|
|
|
static void fdc_interruptreset(void) {
|
|
|
|
fdc.intreq = FALSE;
|
|
}
|
|
|
|
static BOOL fdc_isfdcinterrupt(void) {
|
|
|
|
return(fdc.intreq);
|
|
}
|
|
|
|
REG8 DMACCALL fdc_dmafunc(REG8 func) {
|
|
|
|
// TRACEOUT(("fdc_dmafunc = %d", func));
|
|
switch(func) {
|
|
case DMAEXT_START:
|
|
return(1);
|
|
|
|
case DMAEXT_END: // TC
|
|
fdc.tc = 1;
|
|
break;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
static void fdc_dmaready(REG8 enable) {
|
|
|
|
if (fdc.chgreg & 1) {
|
|
dmac.dmach[FDC_DMACH2HD].ready = enable;
|
|
}
|
|
else {
|
|
dmac.dmach[FDC_DMACH2DD].ready = enable;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void fdcsend_error7(void) {
|
|
|
|
fdc.tc = 0;
|
|
fdc.event = FDCEVENT_BUFSEND;
|
|
fdc.bufp = 0;
|
|
fdc.bufcnt = 7;
|
|
fdc.buf[0] = (UINT8)(fdc.stat[fdc.us] >> 0);
|
|
fdc.buf[1] = (UINT8)(fdc.stat[fdc.us] >> 8);
|
|
fdc.buf[2] = (UINT8)(fdc.stat[fdc.us] >> 16);
|
|
fdc.buf[3] = fdc.C;
|
|
fdc.buf[4] = fdc.H;
|
|
fdc.buf[5] = fdc.R;
|
|
fdc.buf[6] = fdc.N;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB | FDCSTAT_DIO;
|
|
fdc.stat[fdc.us] = 0; // ver0.29
|
|
fdc_dmaready(0);
|
|
dmac_check();
|
|
fdc_interrupt();
|
|
}
|
|
|
|
void fdcsend_success7(void) {
|
|
|
|
fdc.tc = 0;
|
|
fdc.event = FDCEVENT_BUFSEND;
|
|
fdc.bufp = 0;
|
|
fdc.bufcnt = 7;
|
|
#ifdef SUPPORT_KAI_IMAGES
|
|
if (fdd_fdcresult() == FALSE) {
|
|
fdc.buf[0] = (fdc.hd << 2) | fdc.us;
|
|
fdc.buf[1] = 0;
|
|
fdc.buf[2] = 0;
|
|
}
|
|
else {
|
|
// FDイメージファイルがFDCリザルトコードを持っている場合は
|
|
// (fdc.statに設定しているはずなので)そちらを設定
|
|
fdc.buf[0] = (fdc.hd << 2) | fdc.us | (UINT8)(fdc.stat[fdc.us] >> 0);
|
|
fdc.buf[1] = (UINT8)(fdc.stat[fdc.us] >> 8);
|
|
fdc.buf[2] = (UINT8)(fdc.stat[fdc.us] >> 16);
|
|
}
|
|
#else
|
|
fdc.buf[0] = (fdc.hd << 2) | fdc.us;
|
|
fdc.buf[1] = 0;
|
|
fdc.buf[2] = 0;
|
|
#endif
|
|
fdc.buf[3] = fdc.C;
|
|
fdc.buf[4] = fdc.H;
|
|
fdc.buf[5] = fdc.R;
|
|
fdc.buf[6] = fdc.N;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB | FDCSTAT_DIO;
|
|
fdc.stat[fdc.us] = 0; // ver0.29
|
|
fdc_dmaready(0);
|
|
dmac_check();
|
|
fdc_interrupt();
|
|
}
|
|
|
|
#if 0
|
|
// FDCのタイムアウト まぁ本当はこんなんじゃダメだけど… ver0.29
|
|
void fdctimeoutproc(NEVENTITEM item) {
|
|
|
|
if (item->flag & NEVENT_SETEVENT) {
|
|
fdc.stat[fdc.us] = FDCRLT_IC0 | FDCRLT_EN | (fdc.hd << 2) | fdc.us;
|
|
fdcsend_error7();
|
|
}
|
|
}
|
|
|
|
static void fdc_timeoutset(void) {
|
|
|
|
nevent_setbyms(NEVENT_FDCTIMEOUT, 166, fdctimeoutproc, NEVENT_ABSOLUTE);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
static BOOL FDC_DriveCheck(BOOL protectcheck) {
|
|
|
|
// if (!fddfile[fdc.us].fname[0]) {
|
|
if (!fdd_diskready(fdc.us)) {
|
|
fdc.stat[fdc.us] = FDCRLT_IC0 | FDCRLT_NR | (fdc.hd << 2) | fdc.us;
|
|
fdcsend_error7();
|
|
return(FALSE);
|
|
}
|
|
// else if ((protectcheck) && (fddfile[fdc.us].protect)) {
|
|
else if ((protectcheck) && fdd_diskprotect(fdc.us)) {
|
|
fdc.stat[fdc.us] = FDCRLT_IC0 | FDCRLT_NW | (fdc.hd << 2) | fdc.us;
|
|
fdcsend_error7();
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
static void get_mtmfsk(void) {
|
|
|
|
fdc.mt = (fdc.cmd >> 7) & 1;
|
|
fdc.mf = fdc.cmd & 0x40; // ver0.29
|
|
fdc.sk = (fdc.cmd >> 5) & 1;
|
|
}
|
|
|
|
static void get_hdus(void) {
|
|
|
|
fdc.hd = (fdc.cmds[0] >> 2) & 1;
|
|
fdc.us = fdc.cmds[0] & 3;
|
|
}
|
|
|
|
static void get_chrn(void) {
|
|
|
|
fdc.C = fdc.cmds[1];
|
|
fdc.H = fdc.cmds[2];
|
|
fdc.R = fdc.cmds[3];
|
|
fdc.N = fdc.cmds[4];
|
|
}
|
|
|
|
static void get_eotgsldtl(void) {
|
|
|
|
fdc.eot = fdc.cmds[5];
|
|
fdc.gpl = fdc.cmds[6];
|
|
fdc.dtl = fdc.cmds[7];
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
static void FDC_Invalid(void) { // cmd: xx
|
|
|
|
fdc.event = FDCEVENT_BUFSEND;
|
|
fdc.bufcnt = 1;
|
|
fdc.bufp = 0;
|
|
fdc.buf[0] = 0x80;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB | FDCSTAT_DIO;
|
|
}
|
|
|
|
#ifdef SUPPORT_KAI_IMAGES
|
|
static void FDC_ReadDiagnostic(void) { // cmd: 02
|
|
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
get_hdus();
|
|
get_chrn();
|
|
get_eotgsldtl();
|
|
fdc.stat[fdc.us] = (fdc.hd << 2) | fdc.us;
|
|
|
|
if (FDC_DriveCheck(FALSE)) {
|
|
fdc.event = FDCEVENT_BUFSEND;
|
|
// fdc.bufcnt = makedianosedata();
|
|
fdc.bufp = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void FDC_Specify(void) { // cmd: 03
|
|
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
fdc.srt = fdc.cmds[0] >> 4;
|
|
fdc.hut = fdc.cmds[0] & 0x0f;
|
|
fdc.hlt = fdc.cmds[1] >> 1;
|
|
fdc.nd = fdc.cmds[1] & 1;
|
|
fdc.stat[fdc.us] = (fdc.hd << 2) | fdc.us;
|
|
break;
|
|
}
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= FDCSTAT_RQM;
|
|
}
|
|
|
|
static void FDC_SenseDeviceStatus(void) { // cmd: 04
|
|
|
|
switch (fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
get_hdus();
|
|
fdc.buf[0] = (fdc.hd << 2) | fdc.us;
|
|
fdc.stat[fdc.us] = (fdc.hd << 2) | fdc.us;
|
|
if (fdc.equip & (1 << fdc.us)) {
|
|
fdc.buf[0] |= 0x08;
|
|
if (!fdc.treg[fdc.us]) {
|
|
fdc.buf[0] |= 0x10;
|
|
}
|
|
if (fdd_diskready(fdc.us) || (fdc.ctrlreg & 0x40)) {/* 170107 念のため */
|
|
fdc.buf[0] |= 0x20;
|
|
}
|
|
if (fddfile[fdc.us].protect) {
|
|
fdc.buf[0] |= 0x40;
|
|
}
|
|
}
|
|
else {
|
|
fdc.buf[0] |= 0x80;
|
|
}
|
|
// TRACEOUT(("FDC_SenseDeviceStatus %.2x", fdc.buf[0]));
|
|
fdc.event = FDCEVENT_BUFSEND;
|
|
fdc.bufcnt = 1;
|
|
fdc.bufp = 0;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB | FDCSTAT_DIO;
|
|
break;
|
|
|
|
default:
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= FDCSTAT_RQM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static BRESULT writesector(void) {
|
|
|
|
fdc.stat[fdc.us] = (fdc.hd << 2) | fdc.us;
|
|
if (!FDC_DriveCheck(TRUE)) {
|
|
return(FAILURE);
|
|
}
|
|
if (fdd_write()) {
|
|
fdc.stat[fdc.us] = fdc.us | (fdc.hd << 2) | FDCRLT_IC0 | FDCRLT_ND;
|
|
fdcsend_error7();
|
|
return(FAILURE);
|
|
}
|
|
fdc.event = FDCEVENT_BUFRECV;
|
|
fdc.bufcnt = 128 << fdc.N;
|
|
fdc.bufp = 0;
|
|
// fdc.status = FDCSTAT_RQM | FDCSTAT_NDM | FDCSTAT_CB;
|
|
#if defined(SUPPORT_SWSEEKSND)
|
|
if(np2cfg.MOTOR) fddmtrsnd_play(1, TRUE);
|
|
#else
|
|
if(np2cfg.MOTOR) soundmng_pcmplay(SOUND_PCMSEEK, FALSE);
|
|
#endif
|
|
fdc_dmaready(1);
|
|
dmac_check();
|
|
return(SUCCESS);
|
|
}
|
|
|
|
static void FDC_WriteData(void) { // cmd: 05
|
|
// cmd: 09
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
get_hdus();
|
|
get_chrn();
|
|
get_eotgsldtl();
|
|
fdc.stat[fdc.us] = (fdc.hd << 2) | fdc.us;
|
|
fdc.treg[fdc.us] = fdc.C; /* 170101 ST modified to work on Windows 9x/2000 */
|
|
if (FDC_DriveCheck(TRUE)) {
|
|
fdc.event = FDCEVENT_BUFRECV;
|
|
fdc.bufcnt = 128 << fdc.N;
|
|
fdc.bufp = 0;
|
|
#if 1 // ver0.27 ??
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB;
|
|
if (fdc.nd) {
|
|
fdc.status |= FDCSTAT_NDM;
|
|
}
|
|
#else
|
|
fdc.status = FDCSTAT_RQM | FDCSTAT_NDM | FDCSTAT_CB;
|
|
#endif
|
|
fdc_dmaready(1);
|
|
dmac_check();
|
|
}
|
|
break;
|
|
|
|
case FDCEVENT_BUFRECV:
|
|
if (writesector()) {
|
|
return;
|
|
}
|
|
/* 170101 ST modified to work on Windows 9x/2000 form ... */
|
|
//if (fdc.tc) {
|
|
// fdcsend_success7();
|
|
// return;
|
|
//}
|
|
if ((fdc.tc) || (fdc.R++ == fdc.eot)) {
|
|
fdc.R = 1;
|
|
if (fdc.mt) {
|
|
fdc.hd ^= 1;
|
|
fdc.stat[fdc.us] = (fdc.hd << 2) | fdc.us;
|
|
fdc.H ^= 1;
|
|
if (fdc.tc || !fdc.H) {
|
|
fdc.C++;
|
|
fdcsend_success7();
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
fdc.C++;
|
|
fdcsend_success7();
|
|
}
|
|
//fdc.stat[fdc.us] = fdc.us | (fdc.hd << 2) |
|
|
// FDCRLT_IC0 | FDCRLT_EN;
|
|
//fdcsend_error7();
|
|
break;
|
|
}
|
|
/* 170101 ST modified to work on Windows 9x/2000 ... to */
|
|
break;
|
|
|
|
default:
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= FDCSTAT_RQM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void readsector(void) {
|
|
|
|
fdc.stat[fdc.us] = (fdc.hd << 2) | fdc.us;
|
|
if (!FDC_DriveCheck(FALSE)) {
|
|
return;
|
|
}
|
|
if (fdd_read()) {
|
|
fdc.stat[fdc.us] = fdc.us | (fdc.hd << 2) | FDCRLT_IC0 | FDCRLT_ND;
|
|
fdcsend_error7();
|
|
return;
|
|
}
|
|
#if defined(SUPPORT_SWSEEKSND)
|
|
if(np2cfg.MOTOR) fddmtrsnd_play(1, TRUE);
|
|
#else
|
|
if(np2cfg.MOTOR) soundmng_pcmplay(SOUND_PCMSEEK, FALSE);
|
|
#endif
|
|
|
|
fdc.event = FDCEVENT_BUFSEND2;
|
|
fdc.bufp = 0;
|
|
#if 0 // ver0.27 ??
|
|
fdc.status = FDCSTAT_NDM | FDCSTAT_CB;
|
|
if (!(fdc.ctrlreg & 0x10)) {
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_DIO;
|
|
}
|
|
#else
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_DIO | FDCSTAT_CB;
|
|
if (fdc.nd) {
|
|
fdc.status |= FDCSTAT_NDM;
|
|
}
|
|
#endif
|
|
fdc_dmaready(1);
|
|
dmac_check();
|
|
}
|
|
|
|
static void FDC_ReadData(void) { // cmd: 06
|
|
// cmd: 0c
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
get_hdus();
|
|
get_chrn();
|
|
get_eotgsldtl();
|
|
fdc.treg[fdc.us] = fdc.C; /* 170101 ST modified to work on Windows 9x/2000 */
|
|
readsector();
|
|
break;
|
|
|
|
case FDCEVENT_NEXTDATA:
|
|
fdc.bufcnt = 0;
|
|
if (fdc.R++ == fdc.eot) {
|
|
/* 170101 ST modified to work on Windows 9x/2000 form ... */
|
|
fdc.R = 1;
|
|
if (fdc.mt) {
|
|
fdc.hd ^= 1;
|
|
fdc.H ^= 1;
|
|
if (fdc.H) {
|
|
readsector();
|
|
break;
|
|
}
|
|
}
|
|
fdc.C++;
|
|
fdcsend_success7();
|
|
//fdc.stat[fdc.us] = fdc.us | (fdc.hd << 2) |
|
|
// FDCRLT_IC0 | FDCRLT_EN;
|
|
//fdcsend_error7();
|
|
break;
|
|
/* 170101 ST modified to work on Windows 9x/2000 ... to */
|
|
}
|
|
readsector();
|
|
break;
|
|
|
|
#ifdef FDC_DELAYERROR7
|
|
case FDCEVENT_BUSY:
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= FDCSTAT_RQM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void FDC_Recalibrate(void) { // cmd: 07
|
|
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
get_hdus();
|
|
// fdc.ncn = 0;
|
|
// fdc.R = 1; /* 170107 for Windows95 */
|
|
// fdc.crcn = fdc.R; /* 170107 for Windows95 */
|
|
fdc.int_stat[fdc.us] = /* (fdc.hd << 2) | */ fdc.us;
|
|
fdc.int_stat[fdc.us] |= FDCRLT_SE;
|
|
if (!(fdc.equip & (1 << fdc.us))) {
|
|
fdc.int_stat[fdc.us] |= FDCRLT_IC0;
|
|
if (!(fdc.ctrlreg & 0x40)) {
|
|
// 強制ReadyでなければNR
|
|
fdc.int_stat[fdc.us] |= FDCRLT_NR;
|
|
}
|
|
else {
|
|
// 強制ReadyならばNRは立たないがECが立つ(sector0が見つからないので)
|
|
fdc.int_stat[fdc.us] |= FDCRLT_EC;
|
|
}
|
|
}
|
|
else if (!fdd_diskready(fdc.us)) {
|
|
// Win95, 98用
|
|
fdc.ncn = 0;
|
|
fdc.R = 1; /* 170107 for Windows95 */
|
|
fdc.crcn = fdc.R; /* 170107 for Windows95 */
|
|
if (fdc.ctrlreg & 0x40) {
|
|
fdc.treg[fdc.us] = fdc.ncn;
|
|
}else{
|
|
fdc.int_stat[fdc.us] |= FDCRLT_NR;
|
|
}
|
|
}
|
|
else {
|
|
fdc.ncn = 0;
|
|
fdc.treg[fdc.us] = fdc.ncn;
|
|
fdc.R = 1; /* 170107 for Windows95 */
|
|
fdc.crcn = fdc.R; /* 170107 for Windows95 */
|
|
/* 170107 for Windows95 form ... */
|
|
// if (fdd_seek()) {
|
|
// fdc.stat[fdc.us] |= FDCRLT_IC0;
|
|
if (fdd_diskready(fdc.us)) {
|
|
#if defined(SUPPORT_SWSEEKSND)
|
|
if(np2cfg.MOTOR) fddmtrsnd_play(1, TRUE);
|
|
#else
|
|
if(np2cfg.MOTOR) soundmng_pcmplay(SOUND_PCMSEEK1, FALSE);
|
|
#endif
|
|
}
|
|
// }
|
|
/* 170107 for Windows95 ... to */
|
|
}
|
|
fdc.int_timer[fdc.us] = FDC_INT_DELAY;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
|
|
// fdc_interrupt();
|
|
break;
|
|
// default:
|
|
// fdc_interrupt();
|
|
// break;
|
|
}
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status |= FDCSTAT_RQM;
|
|
fdc.status &= ~FDCSTAT_CB;
|
|
}
|
|
|
|
static void FDC_SenceintStatus(void) { // cmd: 08
|
|
|
|
int i;
|
|
|
|
fdc.event = FDCEVENT_BUFSEND;
|
|
fdc.bufp = 0;
|
|
fdc.bufcnt = 0;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB | FDCSTAT_DIO;
|
|
|
|
|
|
// if (fdc_isfdcinterrupt()) {
|
|
// i = 0;
|
|
if (fdc.stat[fdc.us]) {
|
|
fdc.buf[0] = (UINT8)fdc.stat[fdc.us];
|
|
fdc.buf[1] = fdc.treg[fdc.us];
|
|
fdc.bufcnt = 2;
|
|
fdc.stat[fdc.us] = 0;
|
|
// TRACEOUT(("fdc stat - %d [%.2x]", fdc.us, fdc.buf[0]));
|
|
}
|
|
else {
|
|
for (i=0; i<4; i++) {
|
|
if (fdc.stat[i]) {
|
|
fdc.buf[0] = (UINT8)fdc.stat[i];
|
|
fdc.buf[1] = fdc.treg[i];
|
|
fdc.bufcnt = 2;
|
|
fdc.stat[i] = 0;
|
|
// TRACEOUT(("fdc stat - %d [%.2x]", i, fdc.buf[0]));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// for (; i<4; i++) {
|
|
// if (fdc.stat[i]) {
|
|
// break;
|
|
// }
|
|
// }
|
|
// if (i >= 4) {
|
|
// fdc_interruptreset();
|
|
// }
|
|
//
|
|
// }
|
|
if (!fdc.bufcnt) {
|
|
fdc.buf[0] = FDCRLT_IC1;
|
|
fdc.bufcnt = 1;
|
|
}
|
|
/* 170101 ST modified to work on Windows 9x/2000 form ... */
|
|
else if ((fdc.ctrlreg & 0x08) == 0) {
|
|
//fdc.buf[0] |= 0x08;
|
|
//fdc.bufcnt = 1;
|
|
fdc.ctrlreg |= 0x08; // アクセスされたらモータ回す・・・ np21w ver0.86 rev39
|
|
}
|
|
/* 170101 ST modified to work on Windows 9x/2000 ... to */
|
|
}
|
|
|
|
static void FDC_ReadID(void) { // cmd: 0a
|
|
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
fdc.mf = fdc.cmd & 0x40;
|
|
get_hdus();
|
|
if (fdd_readid() == SUCCESS) {
|
|
fdcsend_success7();
|
|
//fdc.status = 0x80; // TEST
|
|
#if defined(SUPPORT_SWSEEKSND)
|
|
if(np2cfg.MOTOR) fddmtrsnd_play(1, TRUE);
|
|
#else
|
|
if(np2cfg.MOTOR) soundmng_pcmplay(SOUND_PCMSEEK, FALSE);
|
|
#endif
|
|
}
|
|
else {
|
|
fdc.stat[fdc.us] = fdc.us | (fdc.hd << 2) |
|
|
// FDCRLT_IC0 | FDCRLT_MA;
|
|
FDCRLT_IC0 | FDCRLT_ND;
|
|
|
|
fdcsend_error7();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void FDC_WriteID(void) { // cmd: 0d
|
|
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
// TRACE_("FDC_WriteID FDCEVENT_CMDRECV", 0);
|
|
get_hdus();
|
|
fdc.N = fdc.cmds[1];
|
|
fdc.sc = fdc.cmds[2];
|
|
fdc.gpl = fdc.cmds[3];
|
|
fdc.d = fdc.cmds[4];
|
|
if (FDC_DriveCheck(TRUE)) {
|
|
// TRACE_("FDC_WriteID FDC_DriveCheck", 0);
|
|
if (fdd_formatinit()) {
|
|
// TRACE_("FDC_WriteID fdd_formatinit", 0);
|
|
fdcsend_error7();
|
|
break;
|
|
}
|
|
/* 170107 modified to work on Windows 9x/2000 form ... */
|
|
if (!fdd_isformating()) {
|
|
fdc.crcn = 1;
|
|
fdcsend_success7();
|
|
break;
|
|
}
|
|
/* 170107 modified to work on Windows 9x/2000 ... to */
|
|
// TRACE_("FDC_WriteID FDCEVENT_BUFRECV", 0);
|
|
fdc.event = FDCEVENT_BUFRECV;
|
|
fdc.bufcnt = 4;
|
|
fdc.bufp = 0;
|
|
#if 1 // ver0.27 ??
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB;
|
|
if (fdc.nd) {
|
|
fdc.status |= FDCSTAT_NDM;
|
|
}
|
|
#else
|
|
fdc.status = FDCSTAT_RQM | FDCSTAT_NDM | FDCSTAT_CB;
|
|
#endif
|
|
fdc_dmaready(1);
|
|
dmac_check();
|
|
}
|
|
break;
|
|
|
|
case FDCEVENT_BUFRECV:
|
|
if (fdd_formating(fdc.buf)) {
|
|
fdcsend_error7();
|
|
break;
|
|
}
|
|
if ((fdc.tc) || (!fdd_isformating())) {
|
|
fdcsend_success7();
|
|
return;
|
|
}
|
|
fdc.event = FDCEVENT_BUFRECV;
|
|
fdc.bufcnt = 4;
|
|
fdc.bufp = 0;
|
|
#if 1 // ver0.27 ??
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
fdc.status |= FDCSTAT_RQM | FDCSTAT_CB;
|
|
if (fdc.nd) {
|
|
fdc.status |= FDCSTAT_NDM;
|
|
}
|
|
#else
|
|
fdc.status = FDCSTAT_RQM | FDCSTAT_NDM | FDCSTAT_CB;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status = FDCSTAT_RQM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void FDC_Seek(void) { // cmd: 0f
|
|
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
get_hdus();
|
|
// fdc.ncn = fdc.cmds[1];
|
|
// fdc.treg[fdc.us] = fdc.ncn;
|
|
// fdc.R = 1;
|
|
// fdc.crcn = fdc.R; /* 170107 for Windows95 */
|
|
/* 170101 ST modified to work on Windows 9x/2000 */
|
|
fdc.int_stat[fdc.us] = /*(fdc.hd << 2) |*/ fdc.us;
|
|
fdc.int_stat[fdc.us] |= FDCRLT_SE;
|
|
if (!fdd_diskready(fdc.us)) {
|
|
fdc.int_stat[fdc.us] |= FDCRLT_IC0 | FDCRLT_NR;
|
|
}
|
|
else {
|
|
fdc.ncn = fdc.cmds[1];
|
|
fdc.treg[fdc.us] = fdc.ncn;
|
|
fdc.R = 1;
|
|
fdc.crcn = fdc.R; /* 170107 for Windows95 */
|
|
/* 170107 for Windows95 form ... */
|
|
//if (fdd_seek()) {
|
|
// fdc.stat[fdc.us] |= FDCRLT_IC0;
|
|
#if defined(SUPPORT_SWSEEKSND)
|
|
if(np2cfg.MOTOR) fddmtrsnd_play(1, TRUE);
|
|
#else
|
|
if(np2cfg.MOTOR) soundmng_pcmplay(SOUND_PCMSEEK1, FALSE);
|
|
#endif
|
|
//}
|
|
/* 170107 for Windows95 ... to */
|
|
}
|
|
fdc.int_timer[fdc.us] = FDC_INT_DELAY;
|
|
fdc.status &= 0x0f;
|
|
fdc.status |= (1 << fdc.us);
|
|
// fdc_interrupt();
|
|
break;
|
|
}
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status |= FDCSTAT_RQM;
|
|
fdc.status &= ~FDCSTAT_CB;
|
|
}
|
|
|
|
#ifdef SUPPORT_KAI_IMAGES
|
|
static void FDC_ScanEqual(void) { // cmd: 11, 19, 1d
|
|
|
|
switch(fdc.event) {
|
|
case FDCEVENT_CMDRECV:
|
|
get_hdus();
|
|
get_chrn();
|
|
fdc.eot = fdc.cmds[5];
|
|
fdc.gpl = fdc.cmds[6];
|
|
fdc.stp = fdc.cmds[7];
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
typedef void (*FDCOPE)(void);
|
|
|
|
static const FDCOPE FDC_Ope[0x20] = {
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
FDC_ReadData, // FDC_ReadDiagnostic,
|
|
FDC_Specify,
|
|
FDC_SenseDeviceStatus,
|
|
FDC_WriteData,
|
|
FDC_ReadData,
|
|
FDC_Recalibrate,
|
|
FDC_SenceintStatus,
|
|
FDC_WriteData,
|
|
FDC_ReadID,
|
|
FDC_Invalid,
|
|
FDC_ReadData,
|
|
FDC_WriteID,
|
|
FDC_Invalid,
|
|
FDC_Seek,
|
|
FDC_Invalid, // 10
|
|
#ifdef SUPPORT_KAI_IMAGES
|
|
FDC_ScanEqual,
|
|
#else
|
|
FDC_Invalid, // FDC_ScanEqual,
|
|
#endif
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
#ifdef SUPPORT_KAI_IMAGES
|
|
FDC_ScanEqual,
|
|
#else
|
|
FDC_Invalid, // FDC_ScanEqual,
|
|
#endif
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
FDC_Invalid,
|
|
#ifdef SUPPORT_KAI_IMAGES
|
|
FDC_ScanEqual,
|
|
#else
|
|
FDC_Invalid, // FDC_ScanEqual,
|
|
#endif
|
|
FDC_Invalid,
|
|
FDC_Invalid};
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
static void fdcstatusreset(void) {
|
|
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status = FDCSTAT_RQM;
|
|
}
|
|
|
|
void DMACCALL fdc_datawrite(REG8 data) {
|
|
|
|
// if ((fdc.status & (FDCSTAT_RQM | FDCSTAT_DIO)) == FDCSTAT_RQM) {
|
|
switch(fdc.event) {
|
|
case FDCEVENT_BUFRECV:
|
|
// TRACE_("write", fdc.bufp);
|
|
fdc.buf[fdc.bufp++] = data;
|
|
if ((!(--fdc.bufcnt)) || (fdc.tc)) {
|
|
fdc.status &= ~FDCSTAT_RQM;
|
|
FDC_Ope[fdc.cmd & 0x1f]();
|
|
}
|
|
break;
|
|
|
|
case FDCEVENT_CMDRECV:
|
|
fdc.cmds[fdc.cmdp++] = data;
|
|
if (!(--fdc.cmdcnt)) {
|
|
fdc.status &= ~FDCSTAT_RQM;
|
|
FDC_Ope[fdc.cmd & 0x1f]();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fdc.cmd = data;
|
|
get_mtmfsk();
|
|
fdc.status |= FDCSTAT_CB; // コマンド受けたらCBをセット
|
|
if (FDCCMD_TABLE[data & 0x1f]) {
|
|
fdc.event = FDCEVENT_CMDRECV;
|
|
fdc.cmdp = 0;
|
|
fdc.cmdcnt = FDCCMD_TABLE[data & 0x1f];
|
|
fdc.status |= FDCSTAT_RQM;
|
|
}
|
|
else {
|
|
fdc.status &= ~FDCSTAT_RQM;
|
|
FDC_Ope[fdc.cmd & 0x1f]();
|
|
}
|
|
break;
|
|
}
|
|
// }
|
|
}
|
|
|
|
REG8 DMACCALL fdc_dataread(void) {
|
|
|
|
int i;
|
|
|
|
// if ((fdc.status & (FDCSTAT_RQM | FDCSTAT_DIO))
|
|
// == (FDCSTAT_RQM | FDCSTAT_DIO)) {
|
|
switch(fdc.event) {
|
|
case FDCEVENT_BUFSEND:
|
|
fdc.lastdata = fdc.buf[fdc.bufp++];
|
|
if (!(--fdc.bufcnt)) {
|
|
fdc.event = FDCEVENT_NEUTRAL;
|
|
fdc.status &= ~(1 << fdc.us);
|
|
fdc.status &= ~(FDCSTAT_DIO | FDCSTAT_CB);
|
|
fdc.status |= FDCSTAT_RQM;
|
|
}
|
|
// 割り込みクリア処理
|
|
for (i = 0; i < 4; i++) {
|
|
if (fdc.stat[i]) {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= 4) {
|
|
fdc_interruptreset();
|
|
}
|
|
break;
|
|
|
|
case FDCEVENT_BUFSEND2:
|
|
if (fdc.bufcnt) {
|
|
fdc.lastdata = fdc.buf[fdc.bufp++];
|
|
fdc.bufcnt--;
|
|
}
|
|
if (fdc.tc) {
|
|
if (!fdc.bufcnt) { // ver0.26
|
|
fdc.R++;
|
|
if ((fdc.cmd & 0x80) && fdd_seeksector()) {
|
|
fdc.C += fdc.hd;
|
|
fdc.H = fdc.hd ^ 1;
|
|
fdc.R = 1;
|
|
}
|
|
}
|
|
/* 170101 ST modified to work on Windows 9x/2000 */
|
|
fdc.R = 1;
|
|
fdcsend_success7();
|
|
}
|
|
if (!fdc.bufcnt) {
|
|
fdc.event = FDCEVENT_NEXTDATA;
|
|
fdc.status &= ~(FDCSTAT_RQM | FDCSTAT_NDM);
|
|
FDC_Ope[fdc.cmd & 0x1f]();
|
|
}
|
|
break;
|
|
}
|
|
// }
|
|
return(fdc.lastdata);
|
|
}
|
|
|
|
/* SEEKとRECALIBRATEの割り込み通知処理 */
|
|
void fdc_intdelay(void) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (fdc.int_timer[i]) {
|
|
fdc.int_timer[i]--;
|
|
if (!fdc.int_timer[i]) {
|
|
fdc.stat[i] = fdc.int_stat[i];
|
|
fdc_interrupt();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---- I/O
|
|
|
|
static void IOOUTCALL fdc_o92(UINT port, REG8 dat) {
|
|
|
|
TRACEOUT(("fdc out %.2x %.2x [%.4x:%.4x]", port, dat, CPU_CS, CPU_IP));
|
|
|
|
if (((port >> 4) ^ fdc.chgreg) & 1) {
|
|
return;
|
|
}
|
|
// /* 170101 ST modified to work on Windows 9x/2000 form ... */
|
|
// if (fdc.status & FDCSTAT_DIO) {
|
|
// fdc.status &= ~FDCSTAT_DIO;
|
|
// fdc.status |= FDCSTAT_RQM;
|
|
// }
|
|
// /* 170101 ST modified to work on Windows 9x/2000 ... to */
|
|
|
|
if ((fdc.status & (FDCSTAT_RQM | FDCSTAT_DIO)) == FDCSTAT_RQM) {
|
|
fdc_datawrite(dat);
|
|
}
|
|
}
|
|
|
|
static void IOOUTCALL fdc_o94(UINT port, REG8 dat) {
|
|
|
|
UINT8 i;
|
|
|
|
TRACEOUT(("fdc out %.2x %.2x [%.4x:%.4x]", port, dat, CPU_CS, CPU_IP));
|
|
|
|
if (((port >> 4) ^ fdc.chgreg) & 1) {
|
|
return;
|
|
}
|
|
if ((fdc.ctrlreg ^ dat) & 0x10) {
|
|
fdcstatusreset();
|
|
fdc_dmaready(0);
|
|
dmac_check();
|
|
}
|
|
/* 170101 ST modified to work on Windows 9x/2000 form ... */
|
|
if ((fdc.ctrlreg ^ dat) & 0x80) {
|
|
if (dat & 0x80) {
|
|
fdcstatusreset();
|
|
|
|
if(dat & 0x08){ // XXX: Workaround for OSASK
|
|
// FDCリセット後 1,024ms以内にINTがアクティブになる
|
|
for (i = 0; i < 4; i++) {
|
|
fdc.int_stat[i] = fdc.stat[i];
|
|
fdc.int_timer[i] = FDC_INT_DELAY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (fdc.chgreg & 4) {
|
|
if ((fdc.ctrlreg ^ dat) & 0x08) {
|
|
if (dat & 0x08) {
|
|
for (i = 0; i < 4; i++) {
|
|
if (fdd_diskready(i)) {
|
|
fdc.int_stat[i] = FDCRLT_AI | i;
|
|
fdc.int_timer[i] = FDC_INT_DELAY;
|
|
fdc.status |= (1 << i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* 170101 ST modified to work on Windows 9x/2000 ... to */
|
|
fdc.ctrlreg = dat;
|
|
}
|
|
|
|
static REG8 IOINPCALL fdc_i90(UINT port) {
|
|
|
|
TRACEOUT(("fdc in %.2x %.2x [%.4x:%.4x]", port, fdc.status,
|
|
CPU_CS, CPU_IP));
|
|
|
|
if (((port >> 4) ^ fdc.chgreg) & 1) {
|
|
return(0xff);
|
|
}
|
|
return(fdc.status);
|
|
}
|
|
|
|
static REG8 IOINPCALL fdc_i92(UINT port) {
|
|
|
|
REG8 ret;
|
|
|
|
if (((port >> 4) ^ fdc.chgreg) & 1) {
|
|
return(0xff);
|
|
}
|
|
if ((fdc.status & (FDCSTAT_RQM | FDCSTAT_DIO))
|
|
== (FDCSTAT_RQM | FDCSTAT_DIO)) {
|
|
ret = fdc_dataread();
|
|
}
|
|
else {
|
|
ret = fdc.lastdata;
|
|
}
|
|
TRACEOUT(("fdc in %.2x %.2x [%.4x:%.4x]", port, ret, CPU_CS, CPU_IP));
|
|
return(ret);
|
|
}
|
|
|
|
static REG8 IOINPCALL fdc_i94(UINT port) {
|
|
|
|
REG8 ret;
|
|
|
|
if (((port >> 4) ^ fdc.chgreg) & 1) {
|
|
return(0xff);
|
|
}
|
|
|
|
ret = 0x40;
|
|
if (!(port & 0x10)) /* CC */
|
|
{
|
|
ret |= 0x20; /* DMA */
|
|
ret |= 0x10; /* readyを立てるるる */
|
|
}
|
|
|
|
if (pccore.dipsw[0] & 8)
|
|
{
|
|
ret |= 0x04; /* 内蔵優先 */
|
|
}
|
|
else
|
|
{
|
|
ret |= 0x08; /* 外付け優先 */
|
|
}
|
|
TRACEOUT(("fdc in %.2x %.2x [%.4x:%.4x]", port, ret,
|
|
CPU_CS, CPU_IP));
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void IOOUTCALL fdc_obe(UINT port, REG8 dat) {
|
|
|
|
TRACEOUT(("fdc out %.2x %.2x [%.4x:%.4x]", port, dat, CPU_CS, CPU_IP));
|
|
|
|
fdc.chgreg = dat;
|
|
if (fdc.chgreg & 2) {
|
|
CTRL_FDMEDIA = DISKTYPE_2HD;
|
|
}
|
|
else {
|
|
CTRL_FDMEDIA = DISKTYPE_2DD;
|
|
}
|
|
(void)port;
|
|
}
|
|
|
|
static REG8 IOINPCALL fdc_ibe(UINT port) {
|
|
|
|
(void)port;
|
|
TRACEOUT(("fdc in %.2x %.2x [%.4x:%.4x]", port, ((fdc.chgreg & 3) | 8),
|
|
CPU_CS, CPU_IP));
|
|
|
|
return((fdc.chgreg & 3) | 8 | 0xf0);
|
|
}
|
|
|
|
static void IOOUTCALL fdc_o4be(UINT port, REG8 dat) {
|
|
|
|
TRACEOUT(("fdc out %.2x %.2x [%.4x:%.4x]", port, dat, CPU_CS, CPU_IP));
|
|
|
|
fdc.reg144 = dat;
|
|
if (dat & 0x10) {
|
|
fdc.rpm[(dat >> 5) & 3] = dat & 1;
|
|
}
|
|
(void)port;
|
|
}
|
|
|
|
static REG8 IOINPCALL fdc_i4be(UINT port) {
|
|
|
|
(void)port;
|
|
TRACEOUT(("fdc in %.2x %.2x [%.4x:%.4x]", port, (fdc.rpm[(fdc.reg144 >> 5) & 3] | 0xf0),
|
|
CPU_CS, CPU_IP));
|
|
return(fdc.rpm[(fdc.reg144 >> 5) & 3] | 0xfe);
|
|
}
|
|
|
|
|
|
// ---- I/F
|
|
|
|
static const IOOUT fdco90[4] = {
|
|
NULL, fdc_o92, fdc_o94, NULL};
|
|
static const IOINP fdci90[4] = {
|
|
fdc_i90, fdc_i92, fdc_i94, NULL};
|
|
static const IOOUT fdcobe[1] = {fdc_obe};
|
|
static const IOINP fdcibe[1] = {fdc_ibe};
|
|
|
|
void fdc_reset(const NP2CFG *pConfig) {
|
|
|
|
ZeroMemory(&fdc, sizeof(fdc));
|
|
fdc.equip = pConfig->fddequip;
|
|
#if defined(SUPPORT_PC9821)
|
|
fdc.support144 = 1;
|
|
#else
|
|
fdc.support144 = pConfig->usefd144;
|
|
#endif
|
|
fdcstatusreset();
|
|
dmac_attach(DMADEV_2HD, FDC_DMACH2HD);
|
|
dmac_attach(DMADEV_2DD, FDC_DMACH2DD);
|
|
CTRL_FDMEDIA = DISKTYPE_2HD;
|
|
fdc.chgreg = 3;
|
|
}
|
|
|
|
void fdc_bind(void) {
|
|
|
|
iocore_attachcmnoutex(0x0090, 0x00f9, fdco90, 4);
|
|
iocore_attachcmninpex(0x0090, 0x00f9, fdci90, 4);
|
|
iocore_attachcmnoutex(0x00c8, 0x00f9, fdco90, 4);
|
|
iocore_attachcmninpex(0x00c8, 0x00f9, fdci90, 4);
|
|
|
|
if (fdc.support144) {
|
|
iocore_attachout(0x04be, fdc_o4be);
|
|
iocore_attachinp(0x04be, fdc_i4be);
|
|
}
|
|
iocore_attachsysoutex(0x00be, 0x0cff, fdcobe, 1);
|
|
iocore_attachsysinpex(0x00be, 0x0cff, fdcibe, 1);
|
|
}
|
|
|