ここら辺を参考に、P31フォーマットとかSD-6031関連の機能を実装します。
http://tulip-house.ddo.jp/digital/SD6031/spec.html
お目当てはSD6031イメージファイル選択プログラム。
http://blogs.dion.ne.jp/sbeach/archives/2013-0710.html
(2013/8/3 追記)とりあえず、P31フォーマットをD88フォーマットに変換するよう実装しました。
system.cpp
/* NEC PC-6001 Emulator 'yaPC-6001' Skelton for retropc emulator Author : tanam Date : 2013.07.15- [ system port ] */ #include <stdio.h> #include <windows.h> #include <shlwapi.h> #include <tchar.h> #include "../i8255.h" #include "../upd765a.h" #include "system.h" char DISK_LOG[1024]; char disk_path1[1024]; char disk_path2[1024]; char disk_path3[1024]; DSK60 *dsk; // イベントID // --- mini FDD --- #define EID_INIT1 (1) // 00h イニシャライズ(ドライブ1) #define EID_INIT2 (2) // 00h イニシャライズ(ドライブ2) #define EID_WRDATEX (21) // 01h ライト データ実行 #define EID_RDDATEX (22) // 02h リード データ実行 #define EID_GETPAR (30) // パラメータ受信 //************* Wait (us) ************* // --- mini FDD --- // この辺 よく分からなので超てけとー #define WFDD_INIT (500000) // 00h イニシャライズ #define WFDD_WRDAT (100) // 01h ライト データ #define WFDD_RDDAT (100) // 02h リード データ #define WFDD_SDDAT (100) // 03h センド データ #define WFDD_COPY (100) // 04h コピー #define WFDD_FORMAT (100) // 05h フォーマット #define WFDD_SDRES (100) // 06h センド リザルト ステータス #define WFDD_SDDRV (100) // 07h センド ドライブ ステータス #define WFDD_TRN (100) // 11h トランスミット #define WFDD_RCV (100) // 12h レシーブ #define WFDD_LOAD (100) // 14h ロード #define WFDD_SAVE (100) // 15h セーブ #define WFDD_GETPAR (100) // パラメータ受信 #define WFDD_SEEK (13000) // とりあえずSRT=13 // create d88 from pp31 void p31_d88(FILE *fp_p31, FILE *fp_d88, char *name); char *StrToUpper(char *s) { char *p; for (p = s; *p; p++) *p = toupper(*p); return s; } void conv(LPCTSTR name) { if (!name || !name[0]) return; FILE *fp_p31, *fp_d88; TCHAR path[MAX_PATH], d88name[MAX_PATH]; if (StrCmp(StrToUpper(PathFindExtension(name)), TEXT(".P31")) != 0) { MessageBox(NULL, TEXT("Drop .P31 file."), TEXT("P31_D88"), MB_OK); return; } if (fopen_s(&fp_p31, (char *)name, "rb")) { /// MessageBox(NULL, TEXT("Can't open the P31 file."), TEXT("P31_D88"), MB_OK); return; } lstrcpy(path, name); PathRemoveExtension(path); lstrcpy(d88name, path); PathAddExtension(path, TEXT(".D88")); if (!fopen_s(&fp_d88, (char *)path, "rb")) { fclose(fp_d88); fclose(fp_p31); return; } if (fopen_s(&fp_d88, (char *)path, "wb")) { /// MessageBox(NULL, TEXT("Can't create D88 file."), TEXT("P31_D88"), MB_OK); fclose(fp_p31); return; } p31_d88(fp_p31, fp_d88, d88name); /// MessageBox(NULL, TEXT("the D88 image created."), TEXT("P31_D88"), MB_OK); fclose(fp_d88); fclose(fp_p31); } // create d88 file from p31 void p31_d88(FILE *fp_p31, FILE *fp_d88, char *name) { int trk, sec, i; unsigned long dsize; // d88 header for (i=0; i<16; i++) fputc(0, fp_d88); fputc(0, fp_d88); for (i=0; i<9; i++) fputc(0, fp_d88); // reserved fputc(0x00, fp_d88); // write protect no fputc(0x00, fp_d88); // disk type = 2D dsize = 32+4*164+(16+256)*16*80; // disk size fputc(dsize&0xff, fp_d88); fputc((dsize>>8)&0xff, fp_d88); fputc((dsize>>16)&0xff, fp_d88); fputc((dsize>>24)&0xff, fp_d88); // pointers to tracks // 0 - 79 track for (trk=0; trk<80; trk++) { unsigned long val = 32+4*164+(16+256)*16*trk; fputc(val&0xff, fp_d88); fputc((val>>8)&0xff, fp_d88); fputc((val>>16)&0xff, fp_d88); fputc((val>>24)&0xff, fp_d88); } // 80 - 163 track for (trk=80; trk<164; trk++) { fputc(0, fp_d88); fputc(0, fp_d88); fputc(0, fp_d88); fputc(0, fp_d88); } // track data for (trk=0; trk<80; trk++) { for (sec=1; sec<17; sec++) { // sector header fputc(trk>>1, fp_d88); // C (cylinder) fputc(trk&1, fp_d88); // H (side) fputc(sec, fp_d88); // R (sector) fputc(1, fp_d88); // N (256 bytes/sector) fputc(16, fp_d88); // 16 sectors/track fputc(0, fp_d88); fputc(0, fp_d88); // double density fputc(0, fp_d88); // deleted mark fputc(0, fp_d88); // status for (i=0; i<5; i++) fputc(0, fp_d88); // reserved fputc(0, fp_d88); fputc(1, fp_d88); // data size of sector part { unsigned char buff[256]; fread(buff, 1, 256, fp_p31); fwrite(buff, 1, 256, fp_d88); fread(buff, 1, 256, fp_p31); } } } } //////////////////////////////////////////////////////////////// // ディスク 基底クラス //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// // コンストラクタ //////////////////////////////////////////////////////////////// DSK6::DSK6() : DrvNum(0) { for( int i=0; i<MAXDRV; i++ ){ ZeroMemory( FilePath[i], PATH_MAX ); Dimg[i] = NULL; Sys[i] = false; } } //////////////////////////////////////////////////////////////// // デストラクタ //////////////////////////////////////////////////////////////// DSK6::~DSK6( void ) { for( int i=0; i<DrvNum; i++ ) if( Dimg[i] ) Unmount( i ); } //////////////////////////////////////////////////////////////// // イベントコールバック関数 // // 引数: id イベントID // clock クロック // 返値: なし //////////////////////////////////////////////////////////////// void DSK6::EventCallback( int id, int clock ){} //////////////////////////////////////////////////////////////// // ウェイトカウンタリセット //////////////////////////////////////////////////////////////// void DSK6::ResetWait( void ) { waitcnt = 0; } //////////////////////////////////////////////////////////////// // ウェイトカウンタ加算 //////////////////////////////////////////////////////////////// void DSK6::AddWait( int w ) { waitcnt += w; } //////////////////////////////////////////////////////////////// // ウェイト設定 //////////////////////////////////////////////////////////////// bool DSK6::SetWait( int eid ) { PRINTD( DISK_LOG, "[DISK][SetWait] %dus ->", waitcnt ); if( waitcnt ) { /// && vm->evsc->Add( this, eid, waitcnt, EV_US ) ){ waitcnt = 0; PRINTD( DISK_LOG, "OK\n" ); return true; }else{ waitcnt = 0; PRINTD( DISK_LOG, "FALSE\n" ); return false; } } //////////////////////////////////////////////////////////////// // DISK マウント //////////////////////////////////////////////////////////////// bool DSK6::Mount( int drvno, char *filename ) { PRINTD( DISK_LOG, "[DISK][Mount] Drive : %d\n", drvno ); if( drvno >= DrvNum ) return false; // もしマウント済みであればアンマウントする if( Dimg[drvno] ) Unmount( drvno ); // ディスクイメージオブジェクトを確保 try{ Dimg[drvno] = new cD88; if( !Dimg[drvno]->Init( filename ) ) return false; /// throw Error::DiskMountFailed; } /// catch( std::bad_alloc ){ // new に失敗した場合 /// Error::SetError( Error::MemAllocFailed ); /// return false; /// } catch(...){ // 例外発生 /// catch( Error::Errno i ){ // 例外発生 /// Error::SetError( i ); Unmount( drvno ); return false; } // ファイルパス保存 strncpy( FilePath[drvno], filename, PATH_MAX ); // システムディスクチェック Dimg[drvno]->Seek( 0 ); if( Dimg[drvno]->Get8() == 'S' && Dimg[drvno]->Get8() == 'Y' && Dimg[drvno]->Get8() == 'S' ) Sys[drvno] = true; else Sys[drvno] = false; Dimg[drvno]->Seek( 0 ); // 念のため return true; } //////////////////////////////////////////////////////////////// // DISK アンマウント //////////////////////////////////////////////////////////////// void DSK6::Unmount( int drvno ) { PRINTD( DISK_LOG, "[DISK][Unmount] Drive : %d\n", drvno ); if( drvno >= DrvNum ) return; if( Dimg[drvno] ){ // ディスクイメージオブジェクトを開放 delete Dimg[drvno]; Dimg[drvno] = NULL; *FilePath[drvno] = '\0'; Sys[drvno] = false; } } //////////////////////////////////////////////////////////////// // ドライブ数取得 //////////////////////////////////////////////////////////////// int DSK6::GetDrives( void ) { return DrvNum; } //////////////////////////////////////////////////////////////// // マウント済み? //////////////////////////////////////////////////////////////// bool DSK6::IsMount( int drvno ) { if( drvno < DrvNum ) return Dimg[drvno] ? true : false; else return false; } //////////////////////////////////////////////////////////////// // システムディスク? //////////////////////////////////////////////////////////////// bool DSK6::IsSystem( int drvno ) { return Sys[drvno]; } //////////////////////////////////////////////////////////////// // プロテクト? //////////////////////////////////////////////////////////////// bool DSK6::IsProtect( int drvno ) { if( !IsMount( drvno ) ) return false; return Dimg[drvno]->IsProtect(); } //////////////////////////////////////////////////////////////// // ファイルパス取得 //////////////////////////////////////////////////////////////// const char *DSK6::GetFile( int drvno ) { return FilePath[drvno]; } //////////////////////////////////////////////////////////////// // DISK名取得 //////////////////////////////////////////////////////////////// const char *DSK6::GetName( int drvno ) { if( !IsMount( drvno ) ) return ""; return Dimg[drvno]->GetDiskImgName(); } //////////////////////////////////////////////////////////////// // ミニフロッピーディスククラス //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// // コンストラクタ //////////////////////////////////////////////////////////////// DSK60::DSK60() : io_D1H(0), io_D2H(0x08) { INITARRAY( RBuf, 0 ); INITARRAY( WBuf, 0 ); } //////////////////////////////////////////////////////////////// // デストラクタ //////////////////////////////////////////////////////////////// DSK60::~DSK60( void ){} //////////////////////////////////////////////////////////////// // イベントコールバック関数 // // 引数: id イベントID // clock クロック // 返値: なし //////////////////////////////////////////////////////////////// void DSK60::EventCallback( int id, int clock ) { switch( id ){ case EID_INIT1: // 00h イニシャライズ(ドライブ1) PRINTD( DISK_LOG, "<< [DISK][EventCallback] EID_INIT1 >>\n" ); if( DrvNum > 1 ){ mdisk.busy = 2; // ウェイト加算 DSK6::ResetWait(); DSK6::AddWait( WFDD_INIT ); DSK6::SetWait( EID_INIT2 ); break; } case EID_INIT2: // 00h イニシャライズ(ドライブ2) PRINTD( DISK_LOG, "<< [DISK][EventCallback] EID_INIT2 >>\n" ); if( !(io_D2H&0x10) ){ // DAVが立っていなければ待ち DSK6::ResetWait(); DSK6::AddWait( WFDD_INIT ); DSK6::SetWait( EID_INIT2 ); }else{ mdisk.busy = 0; mdisk.RFD = 1; mdisk.DAC = 1; } break; case EID_WRDATEX: // 01h ライト データ実行 PRINTD( DISK_LOG, "<< [DISK][EventCallback] EID_WRDATEX >>\n" ); mdisk.busy = 0; mdisk.RFD = 1; mdisk.DAC = 1; break; case EID_RDDATEX: // 02h リード データ実行 PRINTD( DISK_LOG, "<< [DISK][EventCallback] EID_RDDATEX >>\n" ); mdisk.busy = 0; mdisk.RFD = 1; mdisk.DAC = 1; break; case EID_GETPAR: // パラメータ受信 PRINTD( DISK_LOG, "<< [DISK][EventCallback] EID_GETPAR >>\n" ); mdisk.RFD = 1; mdisk.DAC = 1; break; default:; } } //////////////////////////////////////////////////////////////// // DISK処理 初期化 //////////////////////////////////////////////////////////////// bool DSK60::Init( int num ) { PRINTD( DISK_LOG, "[DISK][Init]\n" ); DrvNum = max( min( num, MAXDRV ) , 0 ); Reset(); return true; } //////////////////////////////////////////////////////////////// // リセット //////////////////////////////////////////////////////////////// void DSK60::Reset( void ) { ZeroMemory( &mdisk, sizeof( DISK60 ) ); mdisk.command = IDLE; // 受け取ったコマンド mdisk.retdat = 0xff; // port D0H から返す値 io_D1H = 0; io_D2H = 0x08; } //////////////////////////////////////////////////////////////// // アクセス中? //////////////////////////////////////////////////////////////// bool DSK60::InAccess( int drvno ) { return ( mdisk.busy == ( drvno + 1 ) ) ? true : false; } //////////////////////////////////////////////////////////////// // DISKユニットからのデータ入力 (port D0H) //////////////////////////////////////////////////////////////// BYTE DSK60::FddIn( void ) { PRINTD( DISK_LOG, "[DISK][FddIn] <- " ); if( mdisk.DAV && mdisk.step != 0 ){ // コマンド処理中でデータが有効な場合 switch( mdisk.command ){ case SEND_DATA: // 03h センド データ PRINTD( DISK_LOG, "SEND_DATA" ); // バッファから読む mdisk.retdat = RBuf[mdisk.ridx++]; if( mdisk.ridx >= mdisk.rsize ){ mdisk.rsize = 0; mdisk.ridx = 0; mdisk.command = IDLE; mdisk.step = 0; } break; case SEND_RESULT_STATUS: // 06h センド リザルト ステータス PRINTD( DISK_LOG, "SEND_RESULT_STATUS" ); // Bit7:I/O動作終了フラグ // Bit6:読込みバッファにデータ 有:1 無:0 // Bit5-1:- // Bit0:エラー有:1 無:0 mdisk.retdat = mdisk.rsize ? 0x40 : 0; break; case SEND_DRIVE_STATUS: // 07h センド ドライブ ステータス PRINTD( DISK_LOG, "SEND_DRIVE_STATUS" ); mdisk.retdat = 0xf0; for( int i=DrvNum; i>0; i-- ) mdisk.retdat |= 1<<(4+i); break; case 253: // fdh ファイル一覧 PRINTD( DISK_LOG, "LIST_FILE" ); // バッファから読む mdisk.retdat = RBuf[mdisk.ridx++]; if( mdisk.ridx >= mdisk.rsize ){ mdisk.rsize = 0; mdisk.ridx = 0; mdisk.command = IDLE; mdisk.step = 0; } break; default: mdisk.retdat = 0xff; } PRINTD( DISK_LOG, "%02X\n", mdisk.retdat ); return mdisk.retdat; } else{ // データが無効な場合 PRINTD( DISK_LOG, "FF\n" ); return 0xff; } } //////////////////////////////////////////////////////////////// // DISKユニットへのコマンド,データ出力 (port D1H) //////////////////////////////////////////////////////////////// void DSK60::FddOut( BYTE dat ) { PRINTD( DISK_LOG, "[DISK][FddOut] -> %02X ", dat ); int eid = EID_GETPAR; io_D1H = dat; mdisk.RFD = 0; DSK6::ResetWait(); DSK6::AddWait( WFDD_GETPAR ); if( mdisk.command == IDLE ){ // コマンドの場合 mdisk.command = dat; switch( mdisk.command ){ case INIT: // 00h イニシャライズ PRINTD( DISK_LOG, "INIT" ); eid = EID_INIT1; DSK6::AddWait( WFDD_INIT ); mdisk.busy = 1; break; case WRITE_DATA: // 01h ライト データ PRINTD( DISK_LOG, "WRITE_DATA" ); mdisk.step = 1; mdisk.wsize = 0; break; case READ_DATA: // 02h リード データ PRINTD( DISK_LOG, "READ_DATA" ); mdisk.step = 1; mdisk.rsize = 0; mdisk.ridx = 0; break; case SEND_DATA: // 03h センド データ PRINTD( DISK_LOG, "SEND_DATA" ); mdisk.step = 1; break; case COPY: // 04h コピー PRINTD( DISK_LOG, "COPY" ); break; case FORMAT: // 05h フォーマット PRINTD( DISK_LOG, "FORMAT" ); break; case SEND_RESULT_STATUS: // 06h センド リザルト ステータス PRINTD( DISK_LOG, "SEND_RESULT_STATUS" ); mdisk.step = 1; break; case SEND_DRIVE_STATUS: // 07h センド ドライブ ステータス PRINTD( DISK_LOG, "SEND_DRIVE_STATUS" ); mdisk.step = 1; break; case TRANSMIT: // 11h トランスミット PRINTD( DISK_LOG, "TRANSMIT" ); break; case RECEIVE: // 12h レシーブ PRINTD( DISK_LOG, "RECEIVE" ); break; case LOAD: // 14h ロード PRINTD( DISK_LOG, "LOAD" ); break; case SAVE: // 15h セーブ PRINTD( DISK_LOG, "SAVE" ); break; case 253: // fdh ファイル一覧 PRINTD( DISK_LOG, "LIST_FILE" ); mdisk.step = 1; break; case 254: // feh ファイル選択 PRINTD( DISK_LOG, "SELECT_FILE" ); mdisk.step = 1; break; default: eid = 0; } }else{ // データの場合 switch( mdisk.command ){ case WRITE_DATA: // 01h ライト データ switch( mdisk.step ){ case 1: // 01h:転送ブロック数 mdisk.blk = max( dat, 16 ); mdisk.size = mdisk.blk*256; mdisk.step++; break; case 2: // 02h:ドライブ番号-1 mdisk.drv = dat; mdisk.step++; break; case 3: // 03h:トラック番号 mdisk.trk = dat; mdisk.step++; break; case 4: // 04h:セクタ番号 mdisk.sct = dat; mdisk.step++; break; case 5: // 05h:データ書き込み eid = EID_WRDATEX; mdisk.busy = mdisk.drv + 1; WBuf[mdisk.wsize++] = dat; if( mdisk.wsize >= mdisk.size ){ if( Dimg[mdisk.drv] ){ // トラックNoを2倍(1D->2D) DSK6::AddWait( abs( Dimg[mdisk.drv]->Track() - mdisk.trk*2 ) / 2 ); Dimg[mdisk.drv]->Seek( mdisk.trk*2 ); Dimg[mdisk.drv]->SearchSector( mdisk.trk, 0, mdisk.sct, 1 ); // バッファから書込む for( int i=0; i < mdisk.wsize; i++ ) Dimg[mdisk.drv]->Put8( WBuf[i] ); /// DSK6::AddWait( mdisk.blk * WAIT_SECTOR(1) ); } mdisk.step = 0; } break; } break; case READ_DATA: // 02h リード データ switch( mdisk.step ){ case 1: // 01h:転送ブロック数 mdisk.blk = max( dat, 16 ); mdisk.size = mdisk.blk*256; mdisk.step++; break; case 2: // 02h:ドライブ番号-1 mdisk.drv = dat; mdisk.step++; break; case 3: // 03h:トラック番号 mdisk.trk = dat; mdisk.step++; break; case 4: // 04h:セクタ番号 mdisk.sct = dat; eid = EID_RDDATEX; mdisk.busy = mdisk.drv + 1; if( Dimg[mdisk.drv] ){ // トラックNoを2倍(1D->2D) DSK6::AddWait( abs( Dimg[mdisk.drv]->Track() - mdisk.trk*2 ) / 2 ); Dimg[mdisk.drv]->Seek( mdisk.trk*2 ); Dimg[mdisk.drv]->SearchSector( mdisk.trk, 0, mdisk.sct, 1 ); // バッファに読込む for( mdisk.rsize = 0; mdisk.rsize < mdisk.size; mdisk.rsize++ ) RBuf[mdisk.rsize] = Dimg[mdisk.drv]->Get8(); /// DSK6::AddWait( mdisk.blk * WAIT_SECTOR(1) ); mdisk.ridx = 0; } mdisk.step = 0; break; } break; case 253: // fdh ファイル一覧 if( mdisk.step==1 ){ // 01h:ドライブ番号-1 char file_path[256]; mdisk.drv = dat; mdisk.blk = 16; mdisk.size = 0; sprintf(file_path, disk_path1, mdisk.drv + 1); WIN32_FIND_DATA ffd; HANDLE h = FindFirstFile(file_path, &ffd); if ( h != INVALID_HANDLE_VALUE ) { do { RBuf[mdisk.size]=1; strncpy((char *)RBuf+mdisk.size+1, ffd.cFileName, 8); *(RBuf+mdisk.size+9)='.'; char *dot=strchr((char *)RBuf+mdisk.size+1, '.'); *dot=0; *(dot+1)=0; *(dot+2)=0; *(dot+3)=0; *(dot+4)=0; *(dot+5)=0; *(dot+6)=0; *(dot+7)=0; *(dot+8)=0; *(dot+9)=0; mdisk.size+=9; } while ( FindNextFile(h, &ffd) ); FindClose(h); } eid = EID_RDDATEX; mdisk.busy = mdisk.drv + 1; mdisk.rsize = ++mdisk.size; mdisk.ridx = 0; } break; case 254: // feh ファイル選択 switch( mdisk.step ){ case 1: // 01h:ドライブ番号-1 mdisk.drv = dat; mdisk.wsize = 0; mdisk.step++; break; case 2: // 02h:ファイル名 WBuf[mdisk.wsize++] = dat; if( mdisk.wsize == 8 ){ char file_path[256]; sprintf(file_path, disk_path2, mdisk.drv + 1, WBuf); conv(file_path); sprintf(file_path, disk_path3, mdisk.drv + 1, WBuf); dsk->Mount( mdisk.drv, file_path ); mdisk.step = 0; } } break; } } PRINTD( DISK_LOG, "\n" ); // ウェイト設定 if( eid ) { EventCallback( eid , 0); /// DSK6::SetWait( eid ); } } //////////////////////////////////////////////////////////////// // DISKユニットからの制御信号入力 (port D2H) //////////////////////////////////////////////////////////////// BYTE DSK60::FddCntIn( void ) { PRINTD( DISK_LOG, "[DISK][FddCntIn] <- %02X %s %s %s\n", (io_D2H&0xf0) | 0x08 | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV, mdisk.DAC ? "DAC" : "", mdisk.RFD ? "RFD" : "", mdisk.DAV ? "DAV" : "" ); io_D2H = (io_D2H&0xf0) | 0x08 | (mdisk.DAC<<2) | (mdisk.RFD<<1) | mdisk.DAV; return io_D2H; } //////////////////////////////////////////////////////////////// // DISKユニットへの制御信号出力 (port D3H) //////////////////////////////////////////////////////////////// void DSK60::FddCntOut( BYTE dat ) { PRINTD( DISK_LOG, "[DISK][FddCntOut] -> %02X ", dat ); if( dat&0x80 ){ // 最上位bitチェック // 1の場合は8255のモード設定なので無視(必ずモード0と仮定する) PRINTD( DISK_LOG, "8255 mode set\n" ); return; } switch( (dat>>1)&0x07 ){ case 7: // bit7 ATN PRINTD( DISK_LOG, "ATN:%d", dat&1 ); if( (dat&1) && !(io_D2H&0x80) ){ mdisk.RFD = 1; mdisk.command = IDLE; } break; case 6: // bit6 DAC PRINTD( DISK_LOG, "DAC:%d", dat&1 ); if( (dat&1) && !(io_D2H&0x40) ) mdisk.DAV = 0; break; case 5: // bit5 RFD PRINTD( DISK_LOG, "RFD:%d", dat&1 ); if( (dat&1) && !(io_D2H&0x20) ) mdisk.DAV = 1; break; case 4: // bit4 DAV PRINTD( DISK_LOG, "DAV:%d", dat&1 ); if( !(dat&1) ) mdisk.DAC = 0; break; } if( dat&1 ) io_D2H |= 1<<((dat>>1)&0x07); else io_D2H &= ~(1<<((dat>>1)&0x07)); PRINTD( DISK_LOG, "\n" ); } //////////////////////////////////////////////////////////////// // I/Oアクセス関数 //////////////////////////////////////////////////////////////// void DSK60::OutD1H( int, BYTE data ){ FddOut( data ); } void DSK60::OutD2H( int, BYTE data ){ io_D2H = (data&0xf0) | (io_D2H&0x0f); } void DSK60::OutD3H( int, BYTE data ){ FddCntOut( data ); } BYTE DSK60::InD0H( int ){ return FddIn(); } BYTE DSK60::InD1H( int ){ return io_D1H; } BYTE DSK60::InD2H( int ){ return FddCntIn(); } void SYSTEM::initialize() { dsk = new DSK60(); dsk->Init(MAXDRV); strcpy(disk_path1, emu->bios_path(_T("D%d/*.P31"))); strcpy(disk_path2, emu->bios_path(_T("D%d/%s.P31"))); strcpy(disk_path3, emu->bios_path(_T("D%d/%s.D88"))); } void SYSTEM::write_io8(uint32 addr, uint32 data) { if ((addr & 0xff)==0xD1) { dsk->OutD1H(0xD1, data); /// disk_out(0xD1, data); } if ((addr & 0xff)==0xD3) { dsk->OutD3H(0xD3, data); /// disk_out(0xD3, data); } return; } uint32 SYSTEM::read_io8(uint32 addr) { byte Value=0xff; switch(addr & 0xff) { case 0xD1: Value= dsk->InD1H(0xD1); /// Value= disk_inp(0xD1); break; case 0xD2: Value= dsk->InD2H(0xD2); /// Value= disk_inp(0xD2); break; case 0xD0: Value= dsk->InD0H(0xD0); /// Value= disk_inp(0xD0); break; } if (0x09d2==addr) { Value=0x0f; } return(Value); } void SYSTEM::open_disk(int drv, _TCHAR* file_path, int offset) { dsk->Mount( drv, file_path ); } void SYSTEM::close_disk(int drv) { dsk->Unmount(drv); }
system.h
/* NEC PC-6001 Emulator 'yaPC-6001' Skelton for retropc emulator Author : tanam Date : 2013.07.15- [ system port ] */ #ifndef _SYSTEM_H_ #define _SYSTEM_H_ #include "../vm.h" #include "../../emu.h" #include "../device.h" #include "../../fileio.h" #include "d88.h" // 最大ドライブ接続数 #define MAXDRV 4 // コマンド // 実際には PC-80S31 のコマンドだけど大体同じ? enum FddCommand { INIT = 0x00, WRITE_DATA = 0x01, READ_DATA = 0x02, SEND_DATA = 0x03, COPY = 0x04, FORMAT = 0x05, SEND_RESULT_STATUS = 0x06, SEND_DRIVE_STATUS = 0x07, TRANSMIT = 0x11, RECEIVE = 0x12, LOAD = 0x14, SAVE = 0x15, IDLE = 0xff, // 処理待ちの状態 EndofFdcCmd }; enum FdcPhase { IDLEP = 0, C_PHASE, E_PHASE, R_PHASE }; enum FdcSeek{ SK_STOP = 0, // シークなし SK_SEEK, // シーク中 SK_END // シーク完了 }; struct PD765 { BYTE command; // コマンド FdcPhase phase; // Phase (C/E/R) int step; // Phase内の処理手順 BYTE SRT; // Step Rate Time BYTE HUT; // Head Unloaded Time BYTE HLT; // Head Load Time bool ND; // Non DMA Mode true:Non DMA false:DMA FdcSeek SeekSta[4]; // シーク状態 BYTE NCN[4]; // New Cylinder Number BYTE PCN[4]; // Present Cylinder Number BYTE MT; // Multi-track BYTE MF; // MFM/FM Mode BYTE SK; // Skip BYTE HD; // Head BYTE US; // Unit Select BYTE C; // Cylinder Number BYTE H; // Head Address BYTE R; // Record BYTE N; // Number BYTE EOT; // End of Track BYTE GPL; // Gap Length BYTE DTL; // Data length BYTE D; // Format Data BYTE SC; // Sector BYTE st0; // ST0 BYTE st1; // ST1 BYTE st2; // ST2 BYTE st3; // ST3 BYTE status; // Status bool intr; // FDC割込み発生フラグ PD765() : command(0), phase(R_PHASE), step(0), SRT(32), HUT(0), HLT(0), ND(false), MT(0), MF(0), SK(0), HD(0), US(0), C(0), H(0), R(0), N(0), EOT(0), GPL(0), DTL(0), st0(0), st1(0), st2(0), st3(0), status(0) { INITARRAY( SeekSta, SK_STOP ); INITARRAY( NCN, 0 ); INITARRAY( PCN, 0 ); } }; // ミニフロッピーディスク 各種情報 struct DISK60 { int DAC; // Data Accepted :データ受信完 int RFD; // Ready For Data :データ受信準備完 int DAV; // Data Valid :データ送信完 int command; // 受け取ったコマンド int step; // パラメータ入力待ちステータス int blk; // 転送ブロック数 int drv; // ドライブ番号-1 int trk; // トラック番号 int sct; // セクタ番号 int rsize; // 読込みバッファのデータ数 int wsize; // 書込みバッファのデータ数 int ridx; int size; // 処理するバイト数 BYTE retdat; // port D0H から返す値 BYTE busy; // ドライブBUSY 1:ドライブ1 2:ドライブ2 DISK60() : DAC(0), RFD(0), DAV(0), command(IDLE), step(0), blk(0), drv(0), trk(0), sct(0), size(0), retdat(0xff), busy(0) {} }; //////////////////////////////////////////////////////////////// // クラス定義 //////////////////////////////////////////////////////////////// class DSK6 { /// : public P6DEVICE, public IDoko { protected: int DrvNum; // ドライブ数 char FilePath[MAXDRV][PATH_MAX]; // ファイルパス cD88 *Dimg[MAXDRV]; // ディスクイメージオブジェクトへのポインタ bool Sys[MAXDRV]; // システムディスクフラグ int waitcnt; // ウェイトカウンタ void ResetWait(); // ウェイトカウンタリセット void AddWait( int ); // ウェイトカウンタ加算 bool SetWait( int ); // ウェイト設定 public: DSK6(); /// VM6 *, const P6ID& ); // コンストラクタ virtual ~DSK6(); // デストラクタ virtual void EventCallback( int, int ); // イベントコールバック関数 virtual bool Init( int ) = 0; // 初期化 virtual void Reset() = 0; // リセット bool Mount( int, char * ); // DISK マウント void Unmount( int ); // DISK アンマウント int GetDrives(); // ドライブ数取得 bool IsMount( int ); // マウント済み? bool IsSystem( int ); // システムディスク? bool IsProtect( int ); // プロテクト? virtual bool InAccess( int ) = 0; // アクセス中? const char *GetFile( int ); // ファイルパス取得 const char *GetName( int ); // DISK名取得 }; class DSK60 : public DSK6 { /// , public Device { private: DISK60 mdisk; // ミニフロッピーディスク各種情報 BYTE RBuf[4096]; // 読込みバッファ BYTE WBuf[4096]; // 書込みバッファ BYTE io_D1H; BYTE io_D2H; BYTE FddIn(); // DISKユニットからのデータ入力 (port D0H) void FddOut( BYTE ); // DISKユニットへのコマンド,データ出力 (port D1H) BYTE FddCntIn(); // DISKユニットからの制御信号入力 (port D2H) void FddCntOut( BYTE ); // DISKユニットへの制御信号出力 (port D3H) public: // I/Oアクセス関数 void OutD1H( int, BYTE ); void OutD2H( int, BYTE ); void OutD3H( int, BYTE ); BYTE InD0H( int ); BYTE InD1H( int ); BYTE InD2H( int ); DSK60(); // コンストラクタ ~DSK60(); // デストラクタ void EventCallback( int, int ); // イベントコールバック関数 bool Init( int ); // 初期化 void Reset(); // リセット bool InAccess( int ); // アクセス中? // デバイスID enum IDOut{ outD1H=0, outD2H, outD3H }; enum IDIn { inD0H=0, inD1H, inD2H }; }; class SYSTEM : public DEVICE { private: DEVICE *d_pio, *d_fdc; public: SYSTEM(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {} ~SYSTEM() {} // common functions void initialize(); void write_io8(uint32 addr, uint32 data); uint32 read_io8(uint32 addr); void open_disk(int drv, _TCHAR* file_path, int offset); void close_disk(int drv); // unique functions void set_context_pio(DEVICE* device) { d_pio = device; } void set_context_fdc(DEVICE* device) { d_fdc = device; } }; #endif