diff --git a/FD502/fd502.cpp b/FD502/fd502.cpp index dd7f529a..539a194d 100644 --- a/FD502/fd502.cpp +++ b/FD502/fd502.cpp @@ -50,7 +50,7 @@ constexpr auto EXTROMSIZE = 16384u; using namespace std; -extern DiskInfo Drive[5]; +extern DiskInfo gVirtualDrive[5]; static unsigned char ExternalRom[EXTROMSIZE]; static unsigned char DiskRom[EXTROMSIZE]; static unsigned char RGBDiskRom[EXTROMSIZE]; @@ -81,7 +81,7 @@ static HWND g_hConfDlg = nullptr; static HINSTANCE gModuleInstance; static unsigned long RealDisks=0; long CreateDisk (unsigned char); -static char TempFileName[MAX_PATH]=""; +static char gSelectedDiskFile[MAX_PATH]=""; unsigned char LoadExtRom( unsigned char, const char *); int BeckerEnabled=0; @@ -147,9 +147,9 @@ extern "C" becker_enable(0); #endif CloseCartDialog(g_hConfDlg); - for (unsigned char Drive = 0; Drive <= 3; Drive++) + for (unsigned char dnum = 0; dnum <= 3; dnum++) { - unmount_disk_image(Drive); + unmount_disk_image(dnum); } } @@ -267,7 +267,7 @@ LRESULT CALLBACK Config(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam* { static unsigned char temp=0,temp2=0; long ChipChoice[3]={IDC_EXTROM,IDC_TRSDOS,IDC_RGB}; - long VirtualDrive[2]={IDC_DISKA,IDC_DISKB}; + long gVirtualDrive[2]={IDC_DISKA,IDC_DISKB}; char VirtualNames[5][16]={"None","Drive 0","Drive 1","Drive 2","Drive 3"}; switch (message) @@ -297,7 +297,7 @@ LRESULT CALLBACK Config(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam* SendDlgItemMessage(hDlg,ChipChoice[temp],BM_SETCHECK,(temp==TempSelectRom),0); for (temp=0;temp<2;temp++) for (temp2=0;temp2<5;temp2++) - SendDlgItemMessage (hDlg,VirtualDrive[temp], CB_ADDSTRING, 0, (LPARAM) VirtualNames[temp2]); + SendDlgItemMessage (hDlg,gVirtualDrive[temp], CB_ADDSTRING, 0, (LPARAM) VirtualNames[temp2]); SendDlgItemMessage (hDlg, IDC_DISKA,CB_SETCURSEL,(WPARAM)PhysicalDriveA,(LPARAM)0); SendDlgItemMessage (hDlg, IDC_DISKB,CB_SETCURSEL,(WPARAM)PhysicalDriveB,(LPARAM)0); @@ -413,10 +413,10 @@ void Load_Disk(unsigned char disk) if (dlg.show(0,h_own)) { CreateFlag = 1; HANDLE hr = nullptr; - dlg.getpath(TempFileName,MAX_PATH); + dlg.getpath(gSelectedDiskFile,MAX_PATH); // Verify file exists hr = CreateFile - (TempFileName,0,FILE_SHARE_READ,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); + (gSelectedDiskFile,0,FILE_SHARE_READ,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); // Create new disk file if it does not if (hr == INVALID_HANDLE_VALUE) { NewDiskNumber = disk; @@ -427,7 +427,7 @@ void Load_Disk(unsigned char disk) } // Attempt mount if file existed or file create was not canceled if (CreateFlag==1) { - if (mount_disk_image(TempFileName,disk)==0) { + if (mount_disk_image(gSelectedDiskFile,disk)==0) { MessageBox(g_hConfDlg,"Can't open file","Error",0); } else { dlg.getdir(FloppyPath); @@ -447,7 +447,7 @@ unsigned char SetChip(unsigned char Tmp) void BuildCartridgeMenu() { - char TempMsg[64]=""; + char TempMsg[MAX_PATH]=""; char TempBuf[MAX_PATH]=""; if (CartMenuCallback ==nullptr) MessageBox(g_hConfDlg,"No good","Ok",0); @@ -457,34 +457,34 @@ void BuildCartridgeMenu() CartMenuCallback(gCallbackContext, "FD-502 Drive 0",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(10),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[0].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[0].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(11),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Drive 1",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(12),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[1].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[1].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(13),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Drive 2",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(14),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[2].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[2].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(15),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Drive 3",MID_ENTRY,MIT_Head); CartMenuCallback(gCallbackContext, "Insert",ControlId(17),MIT_Slave); - strcpy(TempMsg,"Eject: "); - strcpy(TempBuf,Drive[3].ImageName); + strncpy(TempMsg,"Eject: ",MAX_PATH); + strncpy(TempBuf,gVirtualDrive[3].ImageName,MAX_PATH); PathStripPath(TempBuf); - strcat(TempMsg,TempBuf); + strncat(TempMsg,TempBuf,MAX_PATH); CartMenuCallback(gCallbackContext, TempMsg,ControlId(18),MIT_Slave); CartMenuCallback(gCallbackContext, "FD-502 Config",ControlId(16),MIT_StandAlone); @@ -519,7 +519,7 @@ LRESULT CALLBACK NewDisk(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam for (temp=0;temp<=2;temp++) SendDlgItemMessage(hDlg,DiskTracks[temp],BM_SETCHECK,(temp==NewDiskTracks),0); SendDlgItemMessage(hDlg,IDC_DBLSIDE,BM_SETCHECK,DblSided,0); - strcpy(Dummy,TempFileName); + strcpy(Dummy,gSelectedDiskFile); PathStripPath(Dummy); SendDlgItemMessage(hDlg,IDC_TEXT1,WM_SETTEXT,0,(LPARAM)(LPCSTR)Dummy); return TRUE; @@ -561,17 +561,17 @@ LRESULT CALLBACK NewDisk(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam case IDOK: { EndDialog(hDlg, LOWORD(wParam)); - const char *ext = TempFileName + strlen(TempFileName) - 4; - if (ext < TempFileName) ext = TempFileName; + const char *ext = gSelectedDiskFile + strlen(gSelectedDiskFile) - 4; + if (ext < gSelectedDiskFile) ext = gSelectedDiskFile; // if it doesn't end with .dsk, append it if (_stricmp(ext, ".dsk") != 0) { - PathRemoveExtension(TempFileName); - strcat(TempFileName, ".dsk"); + PathRemoveExtension(gSelectedDiskFile); + strcat(gSelectedDiskFile, ".dsk"); } - if (CreateDiskHeader(TempFileName, NewDiskType, NewDiskTracks, DblSided)) + if (CreateDiskHeader(gSelectedDiskFile, NewDiskType, NewDiskTracks, DblSided)) { - strcpy(TempFileName, ""); + strcpy(gSelectedDiskFile, ""); MessageBox(g_hConfDlg, "Can't create File", "Error", 0); } return TRUE; @@ -732,7 +732,7 @@ void SaveConfig() for (Index=0;Index<4;Index++) { sprintf(Temp,"Disk#%i",Index); - WritePrivateProfileString(ModName,Temp,Drive[Index].ImageName,IniFile); + WritePrivateProfileString(ModName,Temp,gVirtualDrive[Index].ImageName,IniFile); } WritePrivateProfileInt(ModName,"ClkEnable",ClockEnabled ,IniFile); WritePrivateProfileInt(ModName, "TurboDisk", SetTurboDisk(QUERY), IniFile); diff --git a/FD502/wd1793.cpp b/FD502/wd1793.cpp index 24a1e00e..90cf5082 100644 --- a/FD502/wd1793.cpp +++ b/FD502/wd1793.cpp @@ -28,6 +28,7 @@ This file is part of VCC (Virtual Color Computer). * Last change date 06/27/2006 seek time more closely emulated * * Last change date 05/16/2007 Better DMK support. Diecom protection works now * * Last change date 05/21/2007 Added fdrawcmd support for real disk access/ * +* Last change date 02/07/2026 EJJ Sanitize variable names * * * ********************************************************************************/ //#define USE_LOGGING @@ -75,7 +76,7 @@ bool CmdFormat (HANDLE , PFD_FORMAT_PARAMS , ULONG ); static unsigned char StepTimesMS[4]={6,12,20,30}; static unsigned short BytesperSector[4]={128,256,512,1024}; static unsigned char TransferBuffer[16384]=""; -DiskInfo Drive[5]; +DiskInfo gVirtualDrive[5]; static unsigned char StatusReg=READY; static unsigned char DataReg=0; static unsigned char TrackReg=0; @@ -220,8 +221,8 @@ void DecodeControlReg(unsigned char Tmp) if (Tmp & CTRL_MOTOR_EN) { MotorOn=1; - if ( Drive[CurrentDisk].ImageType == RAW) - DeviceIoControl(Drive[CurrentDisk].FileHandle, IOCTL_FD_MOTOR_ON, nullptr, 0, nullptr, 0, &dwRet, nullptr); + if ( gVirtualDrive[CurrentDisk].ImageType == RAW) + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle, IOCTL_FD_MOTOR_ON, nullptr, 0, nullptr, 0, &dwRet, nullptr); } if ( (Side==1) & (CurrentDisk==NONE) ) @@ -253,11 +254,11 @@ int mount_disk_image(const char *filename,unsigned char drive) void unmount_disk_image(unsigned char drive) { - if (Drive[drive].FileHandle !=nullptr) - CloseHandle(Drive[drive].FileHandle); - Drive[drive].FileHandle=nullptr; - Drive[drive].ImageType=0; - strcpy(Drive[drive].ImageName,""); + if (gVirtualDrive[drive].FileHandle !=nullptr) + CloseHandle(gVirtualDrive[drive].FileHandle); + gVirtualDrive[drive].FileHandle=nullptr; + gVirtualDrive[drive].ImageType=0; + strcpy(gVirtualDrive[drive].ImageName,""); DirtyDisk=true; if (drive==(PhysicalDriveA-1)) PhysicalDriveA=0; @@ -269,7 +270,7 @@ void unmount_disk_image(unsigned char drive) void DiskStatus(char* text_buffer, size_t buffer_size) { if (MotorOn==1) - sprintf(text_buffer,"FD-502:Drv:%1.1i %s Trk:%2.2i Sec:%2.2i Hd:%1.1i",CurrentDisk,ImageFormat[Drive[CurrentDisk].ImageType],Drive[CurrentDisk].HeadPosition,SectorReg,Side); + sprintf(text_buffer,"FD-502:Drv:%1.1i %s Trk:%2.2i Sec:%2.2i Hd:%1.1i",CurrentDisk,ImageFormat[gVirtualDrive[CurrentDisk].ImageType],gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,Side); else sprintf(text_buffer,"FD-502:Idle"); } @@ -281,49 +282,49 @@ unsigned char MountDisk(const char *FileName,unsigned char disk) long TotalSectors=0; unsigned char TmpSides=0,TmpSectors=0,TmpMod=0; - if (Drive[disk].FileHandle !=nullptr) + if (gVirtualDrive[disk].FileHandle !=nullptr) unmount_disk_image(disk); //Image Geometry Defaults - Drive[disk].FirstSector=1; - Drive[disk].Sides=1; - Drive[disk].Sectors=18; - Drive[disk].SectorSize=1; - Drive[disk].WriteProtect=0; - Drive[disk].RawDrive=0; + gVirtualDrive[disk].FirstSector=1; + gVirtualDrive[disk].Sides=1; + gVirtualDrive[disk].Sectors=18; + gVirtualDrive[disk].SectorSize=1; + gVirtualDrive[disk].WriteProtect=0; + gVirtualDrive[disk].RawDrive=0; if (!strcmp(FileName,"*Floppy A:")) - Drive[disk].RawDrive=1; + gVirtualDrive[disk].RawDrive=1; if (!strcmp(FileName,"*Floppy B:")) - Drive[disk].RawDrive=2; + gVirtualDrive[disk].RawDrive=2; - if (Drive[disk].RawDrive==0) + if (gVirtualDrive[disk].RawDrive==0) { - Drive[disk].FileHandle = CreateFile( FileName,GENERIC_READ | GENERIC_WRITE,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); - if (Drive[disk].FileHandle==INVALID_HANDLE_VALUE) + gVirtualDrive[disk].FileHandle = CreateFile( FileName,GENERIC_READ | GENERIC_WRITE,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); + if (gVirtualDrive[disk].FileHandle==INVALID_HANDLE_VALUE) { //Can't open read/write might be read only - Drive[disk].FileHandle = CreateFile(FileName,GENERIC_READ,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); - Drive[disk].WriteProtect=0xFF; + gVirtualDrive[disk].FileHandle = CreateFile(FileName,GENERIC_READ,0,nullptr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,nullptr); + gVirtualDrive[disk].WriteProtect=0xFF; } - if (Drive[disk].FileHandle==INVALID_HANDLE_VALUE) + if (gVirtualDrive[disk].FileHandle==INVALID_HANDLE_VALUE) return 1; //Give up cant mount it - strcpy(Drive[disk].ImageName,FileName); - Drive[disk].FileSize= GetFileSize(Drive[disk].FileHandle,nullptr); - Drive[disk].HeaderSize = Drive[disk].FileSize % 256; - SetFilePointer(Drive[disk].FileHandle,0,nullptr,FILE_BEGIN); - ReadFile(Drive[disk].FileHandle,HeaderBlock,HEADERBUFFERSIZE,&BytesRead,nullptr); + strcpy(gVirtualDrive[disk].ImageName,FileName); + gVirtualDrive[disk].FileSize= GetFileSize(gVirtualDrive[disk].FileHandle,nullptr); + gVirtualDrive[disk].HeaderSize = gVirtualDrive[disk].FileSize % 256; + SetFilePointer(gVirtualDrive[disk].FileHandle,0,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[disk].FileHandle,HeaderBlock,HEADERBUFFERSIZE,&BytesRead,nullptr); } else - Drive[disk].HeaderSize=0xFF; + gVirtualDrive[disk].HeaderSize=0xFF; - switch (Drive[disk].HeaderSize) + switch (gVirtualDrive[disk].HeaderSize) { case 4: - Drive[disk].FirstSector=HeaderBlock[3]; + gVirtualDrive[disk].FirstSector=HeaderBlock[3]; case 3: - Drive[disk].SectorSize=HeaderBlock[2]; + gVirtualDrive[disk].SectorSize=HeaderBlock[2]; case 2: - Drive[disk].Sectors = HeaderBlock[0]; - Drive[disk].Sides = HeaderBlock[1]; + gVirtualDrive[disk].Sectors = HeaderBlock[0]; + gVirtualDrive[disk].Sides = HeaderBlock[1]; case 0: //OS9 Image checks @@ -333,53 +334,53 @@ unsigned char MountDisk(const char *FileName,unsigned char disk) TmpMod=1; if ( (TmpSides*TmpSectors)!=0) TmpMod = TotalSectors%(TmpSides*TmpSectors); - if ((TmpSectors ==18) & (TmpMod==0) & (Drive[disk].HeaderSize ==0)) //Sanity Check + if ((TmpSectors ==18) & (TmpMod==0) & (gVirtualDrive[disk].HeaderSize ==0)) //Sanity Check { - Drive[disk].ImageType=OS9; - Drive[disk].Sides = TmpSides; - Drive[disk].Sectors = TmpSectors; + gVirtualDrive[disk].ImageType=OS9; + gVirtualDrive[disk].Sides = TmpSides; + gVirtualDrive[disk].Sectors = TmpSectors; } else - Drive[disk].ImageType=JVC; - Drive[disk].TrackSize = Drive[disk].Sectors * BytesperSector[Drive[disk].SectorSize]; + gVirtualDrive[disk].ImageType=JVC; + gVirtualDrive[disk].TrackSize = gVirtualDrive[disk].Sectors * BytesperSector[gVirtualDrive[disk].SectorSize]; break; case 12: - Drive[disk].ImageType=VDK; //VDK - Drive[disk].Sides = HeaderBlock[9]; - Drive[disk].TrackSize = Drive[disk].Sectors * BytesperSector[Drive[disk].SectorSize]; + gVirtualDrive[disk].ImageType=VDK; //VDK + gVirtualDrive[disk].Sides = HeaderBlock[9]; + gVirtualDrive[disk].TrackSize = gVirtualDrive[disk].Sectors * BytesperSector[gVirtualDrive[disk].SectorSize]; break; case 16: - Drive[disk].ImageType=DMK; //DMK - if (Drive[disk].WriteProtect != 0xFF) - Drive[disk].WriteProtect = HeaderBlock[0]; - Drive[disk].TrackSize = (HeaderBlock[3]<<8 | HeaderBlock[2]); - Drive[disk].Sides = 2-((HeaderBlock[4] & 16 )>>4); + gVirtualDrive[disk].ImageType=DMK; //DMK + if (gVirtualDrive[disk].WriteProtect != 0xFF) + gVirtualDrive[disk].WriteProtect = HeaderBlock[0]; + gVirtualDrive[disk].TrackSize = (HeaderBlock[3]<<8 | HeaderBlock[2]); + gVirtualDrive[disk].Sides = 2-((HeaderBlock[4] & 16 )>>4); break; case 0xFF: - if (Drive[disk].RawDrive) + if (gVirtualDrive[disk].RawDrive) { - if (Drive[disk].FileHandle !=nullptr) + if (gVirtualDrive[disk].FileHandle !=nullptr) unmount_disk_image(disk); - Drive[disk].ImageType=RAW; - Drive[disk].Sides=2; + gVirtualDrive[disk].ImageType=RAW; + gVirtualDrive[disk].Sides=2; - Drive[disk].FileHandle = OpenFloppy(Drive[disk].RawDrive-1); - if (Drive[disk].FileHandle == nullptr) + gVirtualDrive[disk].FileHandle = OpenFloppy(gVirtualDrive[disk].RawDrive-1); + if (gVirtualDrive[disk].FileHandle == nullptr) return 1; - strcpy(Drive[disk].ImageName,FileName); - if (Drive[disk].RawDrive==1) + strcpy(gVirtualDrive[disk].ImageName,FileName); + if (gVirtualDrive[disk].RawDrive==1) PhysicalDriveA=disk+1; - if (Drive[disk].RawDrive==2) + if (gVirtualDrive[disk].RawDrive==2) PhysicalDriveB=disk+1; } break; default: return 1; } - strncpy(Drive[disk].ImageTypeName,ImageFormat[Drive[disk].ImageType],4); + strncpy(gVirtualDrive[disk].ImageTypeName,ImageFormat[gVirtualDrive[disk].ImageType],4); return 0; //Return 0 on success } @@ -403,43 +404,43 @@ long ReadSector (unsigned char Side, //0 or 1 const unsigned char *pva=nullptr; //************************ - if (Drive[CurrentDisk].FileHandle==nullptr) + if (gVirtualDrive[CurrentDisk].FileHandle==nullptr) return 0; - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - if (((Side+1) > Drive[CurrentDisk].Sides) | (TrackReg != Drive[CurrentDisk].HeadPosition)) + if (((Side+1) > gVirtualDrive[CurrentDisk].Sides) | (TrackReg != gVirtualDrive[CurrentDisk].HeadPosition)) return 0; - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize) + (BytesperSector[Drive[CurrentDisk].SectorSize] * (Sector - Drive[CurrentDisk].FirstSector) ) ) ; + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize) + (BytesperSector[gVirtualDrive[CurrentDisk].SectorSize] * (Sector - gVirtualDrive[CurrentDisk].FirstSector) ) ) ; DLOG_C("FDC S%d trk:%d side:%d sect:%d hsiz:%d nside:%d tsiz:%d ssiz:%d fsec:%d\n", FileOffset, Track, Side, Sector, - Drive[CurrentDisk].HeaderSize, - Drive[CurrentDisk].Sides, - Drive[CurrentDisk].TrackSize, - BytesperSector[Drive[CurrentDisk].SectorSize], - Drive[CurrentDisk].FirstSector); - - SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - ReadFile(Drive[CurrentDisk].FileHandle,ReturnBuffer,BytesperSector[Drive[CurrentDisk].SectorSize],&BytesRead,nullptr); - if (BytesRead != BytesperSector[Drive[CurrentDisk].SectorSize]) //Fake the read for short images + gVirtualDrive[CurrentDisk].HeaderSize, + gVirtualDrive[CurrentDisk].Sides, + gVirtualDrive[CurrentDisk].TrackSize, + BytesperSector[gVirtualDrive[CurrentDisk].SectorSize], + gVirtualDrive[CurrentDisk].FirstSector); + + SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,ReturnBuffer,BytesperSector[gVirtualDrive[CurrentDisk].SectorSize],&BytesRead,nullptr); + if (BytesRead != BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]) //Fake the read for short images { - memset(ReturnBuffer,0xFF,BytesperSector[Drive[CurrentDisk].SectorSize]); - BytesRead=BytesperSector[Drive[CurrentDisk].SectorSize]; + memset(ReturnBuffer,0xFF,BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]); + BytesRead=BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]; } - return(BytesperSector[Drive[CurrentDisk].SectorSize]); + return(BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]); case DMK: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); //Need to read the entire track due to the emulation of interleave on these images - ReadFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesRead,nullptr); - if (BytesRead!=Drive[CurrentDisk].TrackSize) //DMK can't be short the image is corupt + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesRead,nullptr); + if (BytesRead!=gVirtualDrive[CurrentDisk].TrackSize) //DMK can't be short the image is corupt return 0; CurrentSector.Sector=Sector; if (GetSectorInfo (&CurrentSector,TempBuffer)==0) @@ -449,14 +450,14 @@ long ReadSector (unsigned char Side, //0 or 1 case RAW: pva=(unsigned char *)RawReadBuf; - if (TrackReg != Drive[CurrentDisk].HeadPosition) + if (TrackReg != gVirtualDrive[CurrentDisk].HeadPosition) return 0; //Read the entire track and cache it. Speeds up disk reads - if (DirtyDisk | (rwp.phead != Side) | (rwp.cyl != Drive[CurrentDisk].HeadPosition ) ) + if (DirtyDisk | (rwp.phead != Side) | (rwp.cyl != gVirtualDrive[CurrentDisk].HeadPosition ) ) { rwp.flags = FD_OPTION_MFM; rwp.phead = Side; - rwp.cyl = Drive[CurrentDisk].HeadPosition; + rwp.cyl = gVirtualDrive[CurrentDisk].HeadPosition; rwp.head = Side; rwp.sector = 1; rwp.size = 1; //256 Byte Secotors @@ -467,8 +468,8 @@ long ReadSector (unsigned char Side, //0 or 1 sp.cyl = Track; sp.head = Side; // seek to cyl - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &sp, sizeof(sp), nullptr, 0, &dwRet, nullptr); - Ret=DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_READ_DATA, &rwp, sizeof(rwp), RawReadBuf,4608, &dwRet, nullptr); + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &sp, sizeof(sp), nullptr, 0, &dwRet, nullptr); + Ret=DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_READ_DATA, &rwp, sizeof(rwp), RawReadBuf,4608, &dwRet, nullptr); if (dwRet != 4608) return 0; DirtyDisk=false; @@ -496,25 +497,25 @@ long WriteSector ( unsigned char Side, //0 or 1 unsigned char Ret=0; const unsigned char *pva=nullptr; SectorInfo CurrentSector; - if ( (Drive[CurrentDisk].FileHandle==nullptr) | ((Side+1) > Drive[CurrentDisk].Sides) ) + if ( (gVirtualDrive[CurrentDisk].FileHandle==nullptr) | ((Side+1) > gVirtualDrive[CurrentDisk].Sides) ) return 0; - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize) + (BytesperSector[Drive[CurrentDisk].SectorSize] * (Sector - Drive[CurrentDisk].FirstSector) ) ) ; - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - WriteFile(Drive[CurrentDisk].FileHandle,WriteBuffer,BytesperSector[Drive[CurrentDisk].SectorSize],&BytesWritten,nullptr); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize) + (BytesperSector[gVirtualDrive[CurrentDisk].SectorSize] * (Sector - gVirtualDrive[CurrentDisk].FirstSector) ) ) ; + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + WriteFile(gVirtualDrive[CurrentDisk].FileHandle,WriteBuffer,BytesperSector[gVirtualDrive[CurrentDisk].SectorSize],&BytesWritten,nullptr); return BytesWritten; case DMK: //DMK - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); //Need to read the entire track due to the emulation of interleave on these images - ReadFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesRead,nullptr); - if (BytesRead!=Drive[CurrentDisk].TrackSize) + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesRead,nullptr); + if (BytesRead!=gVirtualDrive[CurrentDisk].TrackSize) return 0; CurrentSector.Sector=Sector; @@ -525,9 +526,9 @@ long WriteSector ( unsigned char Side, //0 or 1 Crc=ccitt_crc16(0xE295,&TempBuffer[CurrentSector.DAM] , CurrentSector.Lenth); //0xcdb4 TempBuffer[CurrentSector.DAM + CurrentSector.Lenth ] =Crc>>8; TempBuffer[CurrentSector.DAM + CurrentSector.Lenth +1 ] =(Crc & 0xFF); - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - WriteFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesWritten,nullptr); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + WriteFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesWritten,nullptr); return(CurrentSector.Lenth); case RAW: @@ -535,7 +536,7 @@ long WriteSector ( unsigned char Side, //0 or 1 pva=(unsigned char *) RawReadBuf; rwp.flags = FD_OPTION_MFM; rwp.phead = Side; - rwp.cyl = Drive[CurrentDisk].HeadPosition; + rwp.cyl = gVirtualDrive[CurrentDisk].HeadPosition; rwp.head = Side; rwp.sector = Sector; rwp.size = 1; //256 Byte Secotors @@ -546,9 +547,9 @@ long WriteSector ( unsigned char Side, //0 or 1 sp.cyl = Track; sp.head = Side; // seek to cyl - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &Track, sizeof(Track), nullptr, 0, &dwRet, nullptr); + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &Track, sizeof(Track), nullptr, 0, &dwRet, nullptr); memcpy(RawReadBuf,WriteBuffer,256); - Ret=DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_WRITE_DATA, &rwp, sizeof(rwp), RawReadBuf,18*(128< Drive[CurrentDisk].Sides) + if ((Side+1) > gVirtualDrive[CurrentDisk].Sides) return 0; //STUB Write Me return 0; case DMK: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Track * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)+128); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - ReadFile(Drive[CurrentDisk].FileHandle,WriteBuffer,(Drive[CurrentDisk].TrackSize-128),&BytesRead,nullptr); - if (BytesRead != ((unsigned)Drive[CurrentDisk].TrackSize-128) ) + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (Track * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)+128); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,WriteBuffer,(gVirtualDrive[CurrentDisk].TrackSize-128),&BytesRead,nullptr); + if (BytesRead != ((unsigned)gVirtualDrive[CurrentDisk].TrackSize-128) ) return 0; break; } @@ -703,7 +704,7 @@ void PingFdc() wobble/=4; } - if ( ((CurrentCommand<=7) | (CurrentCommand==IDLE)) & (Drive[CurrentDisk].FileHandle!=nullptr) ) + if ( ((CurrentCommand<=7) | (CurrentCommand==IDLE)) & (gVirtualDrive[CurrentDisk].FileHandle!=nullptr) ) { if (IndexPulse ) StatusReg|=INDEXPULSE; @@ -722,56 +723,56 @@ void PingFdc() switch (CurrentCommand) { case RESTORE: - if (Drive[CurrentDisk].HeadPosition!=0) + if (gVirtualDrive[CurrentDisk].HeadPosition!=0) { - Drive[CurrentDisk].HeadPosition-=1; + gVirtualDrive[CurrentDisk].HeadPosition-=1; ExecTimeWaiter=(CyclesperStep * StepTimeMS); - if (Drive[CurrentDisk].ImageType==RAW) - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, nullptr, 1, nullptr, 0, &dwRet, nullptr); + if (gVirtualDrive[CurrentDisk].ImageType==RAW) + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, nullptr, 1, nullptr, 0, &dwRet, nullptr); } else { TrackReg=0; StatusReg=READY; StatusReg|=TRACK_ZERO; - Drive[CurrentDisk].HeadPosition=0; - if (Drive[CurrentDisk].WriteProtect) + gVirtualDrive[CurrentDisk].HeadPosition=0; + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; CommandDone(); } break; case SEEK: - if (Drive[CurrentDisk].HeadPosition!=DataReg) + if (gVirtualDrive[CurrentDisk].HeadPosition!=DataReg) { if (StepDirection==1) - Drive[CurrentDisk].HeadPosition+=1; + gVirtualDrive[CurrentDisk].HeadPosition+=1; else - Drive[CurrentDisk].HeadPosition-=1; + gVirtualDrive[CurrentDisk].HeadPosition-=1; ExecTimeWaiter=(CyclesperStep * StepTimeMS); } else { - Drive[CurrentDisk].HeadPosition=TrackReg; + gVirtualDrive[CurrentDisk].HeadPosition=TrackReg; StatusReg=READY; - if (Drive[CurrentDisk].HeadPosition==0) + if (gVirtualDrive[CurrentDisk].HeadPosition==0) StatusReg|=TRACK_ZERO; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; CommandDone(); } - if (Drive[CurrentDisk].ImageType==RAW) - DeviceIoControl(Drive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &TrackReg, sizeof(TrackReg), nullptr, 0, &dwRet, nullptr); + if (gVirtualDrive[CurrentDisk].ImageType==RAW) + DeviceIoControl(gVirtualDrive[CurrentDisk].FileHandle , IOCTL_FDCMD_SEEK, &TrackReg, sizeof(TrackReg), nullptr, 0, &dwRet, nullptr); break; case STEP: case STEPUPD: if (StepDirection==1) - Drive[CurrentDisk].HeadPosition+=1; + gVirtualDrive[CurrentDisk].HeadPosition+=1; else { - if (Drive[CurrentDisk].HeadPosition >0) - Drive[CurrentDisk].HeadPosition-=1; + if (gVirtualDrive[CurrentDisk].HeadPosition >0) + gVirtualDrive[CurrentDisk].HeadPosition-=1; } if (CurrentCommand & 1) @@ -781,9 +782,9 @@ void PingFdc() else TrackReg-=1; } - if ( Drive[CurrentDisk].HeadPosition == 0) + if ( gVirtualDrive[CurrentDisk].HeadPosition == 0) StatusReg=TRACK_ZERO; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; StatusReg=READY; CommandDone(); @@ -792,10 +793,10 @@ void PingFdc() case STEPIN: case STEPINUPD: StepDirection=1; - Drive[CurrentDisk].HeadPosition+=1; + gVirtualDrive[CurrentDisk].HeadPosition+=1; if (CurrentCommand & 1) TrackReg+=1; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; StatusReg=READY; CommandDone(); @@ -804,13 +805,13 @@ void PingFdc() case STEPOUT: case STEPOUTUPD: StepDirection=0; - if ( Drive[CurrentDisk].HeadPosition > 0 ) - Drive[CurrentDisk].HeadPosition-=1; + if ( gVirtualDrive[CurrentDisk].HeadPosition > 0 ) + gVirtualDrive[CurrentDisk].HeadPosition-=1; if (CurrentCommand & 1) TrackReg-=1; - if ( Drive[CurrentDisk].HeadPosition == 0) + if ( gVirtualDrive[CurrentDisk].HeadPosition == 0) StatusReg=TRACK_ZERO; - if (Drive[CurrentDisk].WriteProtect) + if (gVirtualDrive[CurrentDisk].WriteProtect) StatusReg|=WRITEPROTECT; StatusReg=READY; CommandDone(); @@ -890,7 +891,7 @@ void DispatchCommand(unsigned char Tmp) ExecTimeWaiter= CyclestoSettle + (CyclesperStep * StepTimeMS); TrackReg=DataReg; StatusReg= BUSY; - if ( Drive[CurrentDisk].HeadPosition > DataReg) + if ( gVirtualDrive[CurrentDisk].HeadPosition > DataReg) StepDirection=0; else StepDirection=1; @@ -997,11 +998,11 @@ unsigned char GetBytefromSector () if (TransferBufferSize == 0) { - TransferBufferSize = ReadSector(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); + TransferBufferSize = ReadSector(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); // WriteLog("BEGIN Readsector",0); } - if (TransferBufferSize==0)// IRON| (TrackReg != Drive[CurrentDrive].HeadPosition) ) //| (SectorReg > Drive[CurrentDrive].Sectors) + if (TransferBufferSize==0)// IRON| (TrackReg != gVirtualDrive[CurrentDrive].HeadPosition) ) //| (SectorReg > gVirtualDrive[CurrentDrive].Sectors) { CommandDone(); StatusReg=RECNOTFOUND; @@ -1037,25 +1038,25 @@ unsigned char GetBytefromAddress () if (TransferBufferSize == 0) { - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - TransferBuffer[0]= Drive[CurrentDisk].HeadPosition; - TransferBuffer[1]= Drive[CurrentDisk].Sides; + TransferBuffer[0]= gVirtualDrive[CurrentDisk].HeadPosition; + TransferBuffer[1]= gVirtualDrive[CurrentDisk].Sides; TransferBuffer[2]= IndexCounter/176; - TransferBuffer[3]= Drive[CurrentDisk].SectorSize; + TransferBuffer[3]= gVirtualDrive[CurrentDisk].SectorSize; TransferBuffer[4]= (Crc >> 8); TransferBuffer[5]= (Crc & 0xFF); TransferBufferSize=6; break; case DMK: - TransferBuffer[0]= Drive[CurrentDisk].HeadPosition; //CurrentSector.Track; not right need to get from image - TransferBuffer[1]= Drive[CurrentDisk].Sides; + TransferBuffer[0]= gVirtualDrive[CurrentDisk].HeadPosition; //CurrentSector.Track; not right need to get from image + TransferBuffer[1]= gVirtualDrive[CurrentDisk].Sides; TransferBuffer[2]= IndexCounter/176; - TransferBuffer[3]= IndexCounter/176; //Drive[CurrentDrive].SectorSize; + TransferBuffer[3]= IndexCounter/176; //gVirtualDrive[CurrentDrive].SectorSize; Crc = 0;//CurrentSector.CRC; TransferBuffer[4]= (Crc >> 8); TransferBuffer[5]= (Crc & 0xFF); @@ -1064,7 +1065,7 @@ unsigned char GetBytefromAddress () } //END Switch } - if ( Drive[CurrentDisk].FileHandle==nullptr ) + if ( gVirtualDrive[CurrentDisk].FileHandle==nullptr ) { StatusReg=RECNOTFOUND; CommandDone(); @@ -1096,11 +1097,11 @@ unsigned char GetBytefromTrack () if (TransferBufferSize == 0) { - TransferBufferSize = ReadTrack(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); + TransferBufferSize = ReadTrack(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); // WriteLog("BEGIN READTRACK",0); } - if (TransferBufferSize==0)//iron | (TrackReg != Drive[CurrentDrive].HeadPosition) ) //| (SectorReg > Drive[CurrentDrive].Sectors) + if (TransferBufferSize==0)//iron | (TrackReg != gVirtualDrive[CurrentDrive].HeadPosition) ) //| (SectorReg > gVirtualDrive[CurrentDrive].Sectors) { CommandDone(); StatusReg=RECNOTFOUND; @@ -1138,13 +1139,13 @@ unsigned char WriteBytetoSector (unsigned char Tmp) if (TransferBufferSize==0) { // WriteLog("Begining WriteSector data collection Command",0); - switch (Drive[CurrentDisk].ImageType) + switch (gVirtualDrive[CurrentDisk].ImageType) { case JVC: case VDK: case OS9: - TransferBufferSize=BytesperSector[Drive[CurrentDisk].SectorSize]; - if ((TransferBufferSize==0) | (TrackReg != Drive[CurrentDisk].HeadPosition) | (SectorReg > Drive[CurrentDisk].Sectors) ) + TransferBufferSize=BytesperSector[gVirtualDrive[CurrentDisk].SectorSize]; + if ((TransferBufferSize==0) | (TrackReg != gVirtualDrive[CurrentDisk].HeadPosition) | (SectorReg > gVirtualDrive[CurrentDisk].Sectors) ) { StatusReg=RECNOTFOUND; CommandDone(); @@ -1153,12 +1154,12 @@ unsigned char WriteBytetoSector (unsigned char Tmp) break; case DMK: - FileOffset= Drive[CurrentDisk].HeaderSize + ( (Drive[CurrentDisk].HeadPosition * Drive[CurrentDisk].Sides * Drive[CurrentDisk].TrackSize)+ (Side * Drive[CurrentDisk].TrackSize)); - Result=SetFilePointer(Drive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); - ReadFile(Drive[CurrentDisk].FileHandle,TempBuffer,Drive[CurrentDisk].TrackSize,&BytesRead,nullptr); + FileOffset= gVirtualDrive[CurrentDisk].HeaderSize + ( (gVirtualDrive[CurrentDisk].HeadPosition * gVirtualDrive[CurrentDisk].Sides * gVirtualDrive[CurrentDisk].TrackSize)+ (Side * gVirtualDrive[CurrentDisk].TrackSize)); + Result=SetFilePointer(gVirtualDrive[CurrentDisk].FileHandle,FileOffset,nullptr,FILE_BEGIN); + ReadFile(gVirtualDrive[CurrentDisk].FileHandle,TempBuffer,gVirtualDrive[CurrentDisk].TrackSize,&BytesRead,nullptr); CurrentSector.Sector=SectorReg; GetSectorInfo(&CurrentSector,TempBuffer); - if ( (CurrentSector.DAM == 0) | (BytesRead != Drive[CurrentDisk].TrackSize) ) + if ( (CurrentSector.DAM == 0) | (BytesRead != gVirtualDrive[CurrentDisk].TrackSize) ) { StatusReg=RECNOTFOUND; CommandDone(); @@ -1175,11 +1176,11 @@ unsigned char WriteBytetoSector (unsigned char Tmp) if (TransferBufferIndex>=TransferBufferSize) { - RetVal=WriteSector(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer,TransferBufferSize); + RetVal=WriteSector(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer,TransferBufferSize); StatusReg=READY; if (( RetVal==0) | (LostDataFlag==1) ) StatusReg=LOSTDATA; - if (Drive[CurrentDisk].WriteProtect != 0) + if (gVirtualDrive[CurrentDisk].WriteProtect != 0) StatusReg=WRITEPROTECT | RECNOTFOUND; CommandDone(); LostDataFlag=0; @@ -1202,12 +1203,12 @@ unsigned char WriteBytetoTrack (unsigned char Tmp) if (TransferBufferIndex>=TransferBufferSize) { - RetVal=WriteTrack(Side,Drive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); + RetVal=WriteTrack(Side,gVirtualDrive[CurrentDisk].HeadPosition,SectorReg,TransferBuffer); StatusReg=READY; if (( RetVal==0) | (LostDataFlag==1) ) StatusReg=LOSTDATA; - if (Drive[CurrentDisk].WriteProtect != 0) + if (gVirtualDrive[CurrentDisk].WriteProtect != 0) StatusReg=WRITEPROTECT | RECNOTFOUND; CommandDone(); LostDataFlag=0; @@ -1275,7 +1276,7 @@ long GetSectorInfo (SectorInfo *Sector,const unsigned char *TempBuffer) { Temp1= (TempBuffer[IdamIndex+1]<<8) | TempBuffer[IdamIndex]; //Reverse Bytes and Get the pointer Density= Temp1>>15; //Density flag - Temp1= (0x3FFF & Temp1) % Drive[CurrentDisk].TrackSize; //Mask and keep from overflowing + Temp1= (0x3FFF & Temp1) % gVirtualDrive[CurrentDisk].TrackSize; //Mask and keep from overflowing IdamIndex+=2; } while ( (IdamIndex<128) & (Temp1 !=0) & (Sector->Sector != TempBuffer[Temp1+3]) ); diff --git a/config.cpp b/config.cpp index fadb1c0b..24b61038 100644 --- a/config.cpp +++ b/config.cpp @@ -120,7 +120,7 @@ struct STRConfig char PathtoExe[MAX_PATH] = { 0 }; char FloppyPath[MAX_PATH] = { 0 }; char CassPath[MAX_PATH] = { 0 }; - unsigned char ShowMousePointer = 0; + unsigned char ShowMousePointer = 0; unsigned char UseExtCocoRom = 0; char ExtRomFile[MAX_PATH] = { 0 }; unsigned char EnableOverclock = 0; @@ -218,11 +218,14 @@ void LoadConfig(SystemState *LCState) } else { ini = appData + "/Vcc.ini"; } + Util::copy_to_char(ini, gcIniFilePath, MAX_PATH); // Establish application path char AppName[MAX_LOADSTRING]=""; LoadString(nullptr, IDS_APP_TITLE,AppName, MAX_LOADSTRING); + + // Write release to ini file Setting().write("Version","Release",AppName); // Load settings @@ -236,18 +239,11 @@ void LoadConfig(SystemState *LCState) } //--------------------------------------------------------------- -// Fatal if this is called before valid gcIniFilePath is established +// This must not be called before valid gcIniFilePath is established //--------------------------------------------------------------- VCC::Util::settings& Setting() { if (!gpSettings) { - // Fatal if ini file can not be opened - if (!Util::ValidateRWFile(gcIniFilePath)) { - std::string s = "Can't open settings " - + std::string(gcIniFilePath); - MessageBox(EmuState.WindowHandle,s.c_str(),"Fatal",0); - exit(0); - } gpSettings = new Util::settings(gcIniFilePath); } return *gpSettings; diff --git a/libcommon/include/vcc/bus/basic_cartridge.h b/libcommon/include/vcc/bus/basic_cartridge.h index 89cd296a..e6d90932 100644 --- a/libcommon/include/vcc/bus/basic_cartridge.h +++ b/libcommon/include/vcc/bus/basic_cartridge.h @@ -18,7 +18,6 @@ #pragma once #include -//TODO: Stomp this bad boy out. It has no purpose namespace VCC::Core { diff --git a/libcommon/include/vcc/bus/cartridge.h b/libcommon/include/vcc/bus/cartridge.h index df9fa829..da92f934 100644 --- a/libcommon/include/vcc/bus/cartridge.h +++ b/libcommon/include/vcc/bus/cartridge.h @@ -19,21 +19,19 @@ #include // defines LIBCOMMON_EXPORT if libcommon is a DLL #include - namespace VCC::Core { struct LIBCOMMON_EXPORT cartridge { public: - + // In Chet's workd strings get a typedef because that keeps things opaque using name_type = std::string; using catalog_id_type = std::string; using description_type = std::string; - public: - + // lock cartridge objects down by deleting move constructers cartridge() = default; cartridge(const cartridge&) = delete; cartridge(cartridge&&) = delete; @@ -46,7 +44,6 @@ namespace VCC::Core virtual void start() = 0; virtual void stop() = 0; - virtual void reset() = 0; virtual void process_horizontal_sync() = 0; virtual void write_port(unsigned char port_id, unsigned char value) = 0; diff --git a/libcommon/include/vcc/bus/cartridge_loader.h b/libcommon/include/vcc/bus/cartridge_loader.h index 89515a2e..e7ce02ae 100644 --- a/libcommon/include/vcc/bus/cartridge_loader.h +++ b/libcommon/include/vcc/bus/cartridge_loader.h @@ -61,7 +61,6 @@ namespace VCC::Core LIBCOMMON_EXPORT cartridge_file_type determine_cartridge_type(const std::string& filename); - // TODO: Eliminate the redundant overloads of loader result LIBCOMMON_EXPORT cartridge_loader_result load_rom_cartridge( const std::string& filename, std::unique_ptr cartridge_context); @@ -69,18 +68,18 @@ namespace VCC::Core LIBCOMMON_EXPORT cartridge_loader_result load_cpak_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const host_context, + void* const pakContainer, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks); LIBCOMMON_EXPORT cartridge_loader_result load_cartridge( const std::string& filename, // Cartridge filename - std::unique_ptr cartridge_context, // Yet another cartridge context - void* const host_context, // Even more context + std::unique_ptr cartridge_context, // Loader context + void* const pakContainer, // Pak container object const std::string& iniPath, // Path of ini file - HWND hVccWnd, // handle to main VCC window proc - const cpak_callbacks& cpak_callbacks); // Callbacks AKA context + HWND hVccWnd, // handle to main window + const cpak_callbacks& cpak_callbacks); // Callbacks // Return load error string per cartridge load status LIBCOMMON_EXPORT std::string cartridge_load_error_string( diff --git a/libcommon/include/vcc/bus/cpak_cartridge.h b/libcommon/include/vcc/bus/cpak_cartridge.h index 1244787c..24ce1205 100644 --- a/libcommon/include/vcc/bus/cpak_cartridge.h +++ b/libcommon/include/vcc/bus/cpak_cartridge.h @@ -35,11 +35,11 @@ namespace VCC::Core public: LIBCOMMON_EXPORT cpak_cartridge( - HMODULE module_handle, // Cartridge filename - void* const host_context, // Yet another cartridge context - path_type configuration_path, // Path of ini file - HWND hVccWnd, // Handle to main VCC window proc - const cpak_callbacks& cpak_callbacks); // Callbacks AKA context + HMODULE module_handle, // Cartridge filename + void* const pakContainer, // pointer to container object + path_type configuration_path, // Path of ini file + HWND hVccWnd, // Handle to main VCC window proc + const cpak_callbacks& cpak_callbacks); // Callbacks LIBCOMMON_EXPORT name_type name() const override; LIBCOMMON_EXPORT catalog_id_type catalog_id() const override; @@ -61,7 +61,7 @@ namespace VCC::Core private: const HMODULE handle_; - void* const host_context_; + void* const pakContainer_; const HWND hVccWnd_; const path_type configuration_path_; const cpak_callbacks cpak_callbacks_; diff --git a/libcommon/include/vcc/util/DialogOps.h b/libcommon/include/vcc/util/DialogOps.h index fe8ca942..1b2b4eee 100644 --- a/libcommon/include/vcc/util/DialogOps.h +++ b/libcommon/include/vcc/util/DialogOps.h @@ -17,6 +17,8 @@ //////////////////////////////////////////////////////////////////////////////// #pragma once #include // defines LIBCOMMON_EXPORT if libcommon is a DLL +#include +#include #include //------------------------------------------------------------------------------------------- @@ -33,22 +35,6 @@ LIBCOMMON_EXPORT void CenterDialog(HWND hDlg); // otherwise the open dialog is shown. If "Owner" is NULL GetActiveWindow() is used. // The selected filename is placed in "Path" // -// setpath() sets "Path" before calling show(). -// -// setDefExt(), setInitialDir(), setFilter(), setFlags(), and setTitle() set the -// elements in the OPENFILENAME structure that is used by get save/open file() -// -// path() returns a pointer to Path. -// getpath gets a copy of "Path". -// getdir() returns a copy of the directory portion of "Path" -// getupath() gets a copy of "Path" with all '\' chars replaced by '/' -// -// upath_ is a copy of path_ with backslashes converted to slashes -// -// There is an effort to standardize VCC using slashes as directory seperators -// but GetSaveFileName(&ofn_) and GetOpenFileName are older windows functions -// that do not play well with slashes so there is a bit of converting in and out; -// //------------------------------------------------------------------------------------------- #include #include @@ -57,31 +43,123 @@ class LIBCOMMON_EXPORT FileDialog { public: - FileDialog(); + FileDialog() { + ZeroMemory(&ofn_, sizeof(ofn_)); + ofn_.lStructSize = sizeof(ofn_); + flags_ = OFN_HIDEREADONLY; + } + + void init() { + ZeroMemory(&ofn_, sizeof(ofn_)); + ofn_.lStructSize = sizeof(ofn_); + flags_ = OFN_HIDEREADONLY; + } bool show(BOOL Save = FALSE, HWND Owner = nullptr); - void setpath(const char * Path); - void setDefExt(const char * DefExt); - void setInitialDir(const char * InitialDir); - void setFilter(const char * Filter); - void setFlags(unsigned int Flags); - void setTitle(const char * Title); - void getdir(char * Dir, int maxsize = MAX_PATH) const; - void getpath(char * Path, int maxsize = MAX_PATH) const; - void getupath(char * Path, int maxsize = MAX_PATH) const; - void gettype(char * Type, int maxsize = 4) const; - std::string getdir(); - std::string gettype(); - std::string getpath(); - - const char *path() const; - const char *upath() const; + + void setDefExt(const char * DefExt) + { + sDefext_.assign(DefExt ? DefExt : ""); + } + + void setInitialDir(const char * InitialDir) + { + sInitDir_.assign(InitialDir ? InitialDir : ""); + } + + //Set null terminated Filter items + void setFilter(const char* Filter) + { + sFilter_.clear(); + if (!Filter) return; + const char* p = Filter; + while (*p) p += std::strlen(p) + 1; + sFilter_.assign(Filter, p + 1 - Filter); + } + + void setFlags(unsigned int Flags) + { + flags_ = Flags | OFN_HIDEREADONLY; + } + + void setTitle(const char * Title) + { + sTitle_.assign(Title ? Title : ""); + } + + void setpath(const char * File) + { + sFile_.assign(File ? File : ""); + } + + // Return selected file + std::string getpath() const + { + return sFile_; + } + + // Return selected directory + std::string getdir() const + { + return VCC::Util::GetDirectoryPart(sFile_); + } + + // Return selected filetype + std::string gettype() const + { + std::string s = VCC::Util::GetFileNamePart(sFile_); + size_t pos = s.rfind('.'); + if (pos == std::string::npos || pos == s.size()-1) return {}; + return s.substr(pos+1); + } + + // Get a copy of the selected file path + void getpath(char * PathCopy, int maxsize=MAX_PATH) const + { + if (PathCopy == nullptr) return; + strncpy(PathCopy,sFile_.c_str(),maxsize); + } + + // Copy of the selected file path + void getupath(char * PathCopy, int maxsize=MAX_PATH) const + { + if (PathCopy == nullptr) return; + strncpy(PathCopy,sFile_.c_str(),maxsize); + } + + // copy the directory to c string + void getdir(char * Dir, int maxsize=MAX_PATH) const + { + if (Dir == nullptr) return; + VCC::Util::copy_to_char(getdir(),Dir,maxsize); + } + + // copy the file type to c string + void gettype(char * Type, int maxsize=16) const + { + if (Type == nullptr) return; + VCC::Util::copy_to_char(gettype(),Type,maxsize); + } + + // Get a pointer to the selected file path + const char *path() const + { + return sFile_.c_str(); + } + + const char *upath() const + { + return sFile_.c_str(); + } private: OPENFILENAME ofn_; - char path_[MAX_PATH] = {}; - char upath_[MAX_PATH] = {}; - char initialdir_[MAX_PATH] = {}; + std::string sFile_ {}; + std::string sInitDir_ {}; + std::string sTitle_ {}; + std::string sFilter_ {}; + std::string sDefext_ {}; + DWORD flags_; }; diff --git a/libcommon/include/vcc/util/fileutil.h b/libcommon/include/vcc/util/fileutil.h index 5ae1c1fc..c4bb74f4 100644 --- a/libcommon/include/vcc/util/fileutil.h +++ b/libcommon/include/vcc/util/fileutil.h @@ -161,23 +161,29 @@ namespace VCC::Util { // TODO: In line functions that should go elsewhere //------------------------------------------------------------------------ - // Return string with case conversion + // Return string with case conversion + inline std::string to_lower(std::string s) { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::tolower(c); }); - return s; - } + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { + return static_cast(std::tolower(c)); + }); + return s; + } inline std::string to_upper(std::string s) { std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::toupper(c); }); + [](unsigned char c) { + return static_cast(std::toupper(c)); + }); return s; } - // Convert case of string inplace inline void make_lower(std::string& s) { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::tolower(c); }); + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { + return static_cast(std::tolower(c)); + }); } inline void make_lower(char* s) { @@ -187,8 +193,10 @@ namespace VCC::Util { } inline void make_upper(std::string& s) { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c){ return std::toupper(c); }); + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { + return static_cast(std::toupper(c)); + }); } inline void make_upper(char* s) { diff --git a/libcommon/include/vcc/util/settings.h b/libcommon/include/vcc/util/settings.h index 70b977e7..ab1ae5e4 100644 --- a/libcommon/include/vcc/util/settings.h +++ b/libcommon/include/vcc/util/settings.h @@ -31,25 +31,25 @@ namespace VCC::Util LIBCOMMON_EXPORT explicit settings(path_type path); // write string value - LIBCOMMON_EXPORT void write + LIBCOMMON_EXPORT bool write (const std::string& section, const std::string& key, const std::string& value) const; // write int value - LIBCOMMON_EXPORT void write + LIBCOMMON_EXPORT bool write (const std::string& section, const std::string& key, int value) const; // write bool value - LIBCOMMON_EXPORT void write_bool + LIBCOMMON_EXPORT bool write_bool (const std::string& section, const std::string& key, bool value) const; // get char * value - LIBCOMMON_EXPORT void read + LIBCOMMON_EXPORT bool read (const std::string& section, const std::string& key, const std::string& default_value, @@ -69,22 +69,28 @@ namespace VCC::Util int default_value) const; // delete key - LIBCOMMON_EXPORT void delete_key + LIBCOMMON_EXPORT bool delete_key (const std::string& section, const std::string& key) const - { ::WritePrivateProfileString - (section.c_str(), key.c_str(), NULL, path_.c_str());} + { + return ::WritePrivateProfileString + (section.c_str(), key.c_str(), NULL, path_.c_str()); + } - // delete section - LIBCOMMON_EXPORT void delete_section + // delete section + LIBCOMMON_EXPORT bool delete_section (const std::string& section) const - { ::WritePrivateProfileString - (section.c_str(), NULL, NULL, path_.c_str());} + { + return ::WritePrivateProfileString + (section.c_str(), NULL, NULL, path_.c_str()); + } - // flush cache - LIBCOMMON_EXPORT void flush () const - { ::WritePrivateProfileString - (NULL, NULL, NULL, path_.c_str());} + // flush cache + LIBCOMMON_EXPORT bool flush () const + { + return ::WritePrivateProfileString + (NULL, NULL, NULL, path_.c_str()); + } private: const path_type path_; diff --git a/libcommon/src/bus/CartridgeInterface.txt b/libcommon/src/bus/CartridgeInterface.txt new file mode 100644 index 00000000..168da28a --- /dev/null +++ b/libcommon/src/bus/CartridgeInterface.txt @@ -0,0 +1,280 @@ + +This attempts to describe the cartridge interface design for VCC + +--- + +# VCC Cartridge Types + +VCC emulates the physical cartridges that could be plugged into the side expansion slot of a CoCo 3 +or into a MultiPak Interface. VCC supports three main categories of cartridges: + +--- + +## 1. ROM Cartridges + +ROM cartridges contain only read-only memory and the minimal hardware needed to expose that memory +to the CoCo 3. + +**Key characteristics:** + +- Typically contain 6809 or 6309 executable code. +- The CoCo reads data directly from mapped ROM addresses. +- Some cartridges support bank switching by writing to I/O ports. +- In VCC, all ROM banking logic is implemented inside the emulator itself. + +**Implications for VCC:** + +- ROM cartridges require no host-side code. +- They are stored as simple binary files. +- Some ROM files include headers or signatures to indicate special mapping or banking behavior. +- Most common ROM cartridges were 16 KB or smaller and mapped at `0xC000` in ROM mode. + +--- + +## 2. Hardware Cartridges + +Hardware cartridges contain actual devices, such as: + +- Disk controllers +- Sound synthesizers +- RS-232 interfaces +- Additional microprocessors +- Often, onboard ROM + +These cartridges require host-side x86 code to emulate their hardware behavior. + +**In VCC:** + +- Hardware cartridges are implemented as **Windows DLLs**. +- VCC identifies them by checking for the `MZ` signature at the start of the file. +- Hardware DLL's must export the initCart call to be valid +- ROM data for these cartridges is usually stored separately, though this is not required. +- Some hardware cartridges can load multiple ROMs and switch between them under program control. +- The DLL is responsible for loading and managing these ROMs. +- The CoCo communicates with the emulated hardware by reading and writing specific I/O ports. +- Hardware cartridges may generate interrupts or output audio through a dedicated sound channel. +- Hardware cartridges cannot load other hardware cartridges. + +--- + +## 3. MultiPak Cartridge (MPI) + +MultiPak it not a true cartridge, it is a bus expansion that acts as hosts for other hardware +cartridges. + +**Capabilities:** + +- MultiPak Cartridge DLL must export the init MPI call to be valid +- Provide multiple cartridge slots. +- Contains no ROM of it's own +- Allow slot selection through UI controls or programmatically. + +**VCC support:** + +- VCC currently emulates the original Radio Shack MultiPak Interface. +- Multipak can only be inserted Coco slide slot, not into another multipak. +- Third-party MultiPak-style devices also exist, including: + - Two-slot versions + - Hobbyist designs supporting up to eight slots + +--- + +# Cartridge Loader: Cartridge Type Identification Logic + +The cartridge loader determines the cartridge type using the following sequence: + +1. **Check if the file can be read** + - If it cannot be read, the cartridge is **not loadable**. + +2. **Check if the file is a DLL** + - If it is *not* a DLL, the cartridge is a **ROM Cartridge**. + +3. **Check if the DLL exports `InitCart`** + - If it does *not*, the cartridge is **not loadable**. + +4. **Check if the DLL exports PakGetCapabilities** + - If it does not, the cartridge is CART_TYPE_GENERIC + +5. Continue with loading and initialization + + +--- + +Cartridge Exports + +DLL's can export any of the following calls + + Get cart type and capabilities (required) + Const cart_capabilities* PakGetCapabilities (void); + + Initiate pack (required) + PakInitialize (slot_context, settings_path, hVccWnd_, &callbacks); + + Terminate pack, prepare for DLL unload + PakTerminate () + + Get pack name + PakGetName (name, buf_size) + + Get pack ID + PakGetCatalogId (catalogId, buf_size) + + Get pack description + PakGetDescription (Description, buf_size) + + Reset the pack + PakReset () + + Horizontal sync occurred + PakProcessHorizontalSync () + + Get pack status line text + PakGetStatus (Status, buf_size) + + Write I/O port + PakWritePort (Port, data) + + Read I/O port + unsigned char PakReadPort (Port) + + Read ROM byten + unsigned char PakReadMemoryByte (Address) + + Sample audio line + unsigned short PakSampleAudio () + + A hardware pack menu item was clicked + PakMenuItemClicked (menu_item_id) + +--- + +Callbacks + + void assert_cartridge_line(slot_context, bool line_state) = 0; + void assert_interrupt(slot_context, Interrupt interrupt, InterruptSource interrupt_source) = 0; + void write_memory_byte(slot_context, unsigned char value, unsigned short address) = 0; + unsigned char read_memory_byte(slot_context, unsigned short address) = 0; + void add_menu_item(slot_context, const char* menu_name, int menu_id, MenuItemType menu_type) = 0; + +It has recently been recognized that there are two classes of callbacks: + +- Fast callbacks initiated by events in the CPU loop like asserting interrupts, cart +lines, or reading and writing memory to handle DMA requests. These must be syncronous +and return quickly to not affect emulator timing. Fast callbacks must use the already +in place callback mechanisms. Fast callbacks are determined by Coco's physical bus and +are not likely to change. + +- Slow callbacks initiated by UI like adding menu items or inserting cartridges in slots. +These can be asyncronous and can rely on exports to recieve replies. A perfect mechanism +for slow callbacks already exists for free - the main window message loop. A cartridge +can send a message to the main window and let VCC main dispatch it. Enhancements to +cartridge UI that require future changes or additions should use these callbacks. + +In the current codebase the messaging mechanism is already being used for a callback. When +the MPI needs to initiate a hard VCC reset is does so by sending a message to WinMain. + +The add_menu_item callback is not tied to the CPU loop and qualifies as a slow callback. +This callback will be replaced by a Windows message. + +--- + +The dynamic cartridge menu system. + +When cartridges are loaded or unloaded the Cartridge menu must be changed to show items for +controlling the cartridges. Traditionally the Pakinterface generated the first menu item which +gives users control over which cartridge is plugged into the side of the coco. If that +cartridge is the MPI additional menu items are added, the first such item brings up a MPI +configuration dialog. That dialog shows the user what carts are in MPI slots, which cart +is selected at boot (CTS), a description of the cart in that slot, and controls allowing users +to modify these settings. After the MPI config menu item additional menu items are added +for cartridges currently in MPI slots. These menu items are added by carts as they are +initialized. Each cartridge, starting with the MPI, then carts in slots 4 through 1, are +intialized. When a cart is initialized to generates AddMenuitem callbacks for it's menu item. + +Using the cartridge initialization export to initiate the addition of menu items causes an +issue if a cart is removed or added after VCC has started up, specifically carts should not +be initialized a second time after loading. So add menu item messages are saved in a list and +the cart menu is cleared then the list is traversed to retore the menuitems after each change. + +--- + +New Design Philosophy For The MPI (Not yet implemented) + +VCC and forks of VCC use run-time loading and unloading of dynamic libraries to simulate +the inserting and removing of Cartridges. + +A special "cartridge" is the Multipak MPI. On a physical Coco the MPI it is not actually +a cartridge. It is more accurately an extension of the bus. + +The pakinterface loads and unloads cartridges. So does the MPI. If both MPI and pakinterface +call cartridge DLLs directly there are now two modules, VCC and MPI, that need to know about +cartridge lifetimes, handles, exports, and inports. All loading and unloading of carts belongs +in one place and that place is the PakInterface part of VCC main. + +When slot management is moved to the Pakinterface the logic that controls the CTS and SCS and +the management of saved slot content settings must move too. The pakinterface must share this +information with the MPI DLL which becomes purely a user interface. + +Moving cartridge and slot management from the MPI to the Pakinterface would seem to require +extensive changes to the interface. This document attemps to explain how such a move can be +done with minimal risk. + +--- + +To wrap up the pakinterface slot management concept: + +- The pakinterface maintains a list indexed by slot number of loaded cartridges. + +- Slots are numbered 0-4. Slot 0 is the Boot slot. Slots 1-4 only loaded if MPI is in the Boot slot. + +- The pakinterface maintains the cartridge menu and dynamic menu items + +- The pakInterface routes I/O to slots per CTS/SCS using existing capability / callcacks + +- The pakinterface saves slot content to settings. + +- Any change to current CTS triggers a reset. This is detected and effected by the pakinterface + +- Reset stops the CPU, unloads all cartridges, reloads the basic rom, reloads cartridges + per settings, and then restarts the CPU. + +- pakInterface sends MPI changes to CTS/SCS via a new MPI export + +- The opaque slot_context is renamed to slot_context and is made transparent. Some carts don't + work right if they are not a specific slot. They can use slot_number to verify the slot they + are in is valid. + +- on request pakInterface sends MPI active cart description via a new MPI export + +- on request pakInterface sends MPI slot contents + +- Then MPI should never call a cartridge DLL directly. It should always request actions through + messages to the pakInterface using the WinMain message loop. + +- The MPI saves the startup slot setting. Changing this causes no changes to running CPI + +- The MPI requests cartridge loads / unloads by sending messages to WinMain. + +- The MPI requests slot and cartridge information by sending messages to WinMain. + +- The MPI has new exports to recieve results from slot changes and cartridge information requests. + +- The MPI "Reset VCC" button sends a reset message to VCC main. + +- With the exception of add_menu_item() all other exports and callbacks remain the same. + +--- + +Implementation Plan + +1. Solidify methods for sending and interpreting messages from DLL's to WinMain message loop. + Use the VCC Reset message from MPI Config to prove the methods. + +2. Replace the AddCartMenu callback with a message and modify pakinterface to maintain the cartridge + dynamic menus. + +3. Move slot maintenance, cartridge loading, and cartidge calls from MPI to pakinterface. + +4. Cartridges can use slot_id from transparent slot_context, if desired. + + diff --git a/libcommon/src/bus/cartridge_loader.cpp b/libcommon/src/bus/cartridge_loader.cpp index 6370dedc..07e5e01d 100644 --- a/libcommon/src/bus/cartridge_loader.cpp +++ b/libcommon/src/bus/cartridge_loader.cpp @@ -117,7 +117,7 @@ namespace VCC::Core cartridge_loader_result load_cpak_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const host_context, + void* const pakContainer, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks) @@ -142,7 +142,7 @@ namespace VCC::Core { details.cartridge = std::make_unique( details.handle.get(), - host_context, + pakContainer, iniPath, hVccWnd, cpak_callbacks); @@ -156,7 +156,7 @@ namespace VCC::Core // Load a cartridge; either a ROM image or a pak dll. Load cartridge is called // by both mpi/multipak_cartridge.cpp and pakinterface.cpp. cartridge_context is defined - // in libcommon/include/vcc/bus/cartridge_context.h. host_context is a generic + // in libcommon/include/vcc/bus/cartridge_context.h. pakContainer is a generic // pointer explicitly cast to multipak_cartridge in mpi/multipak_cartridge.cpp. // mutlipak_cartridge refers specifically to a cart loaded by the multipak. // cpak_callbacks is used by all hardware paks and is defined in @@ -165,7 +165,7 @@ namespace VCC::Core cartridge_loader_result load_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const host_context, + void* const pakContainer, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks) @@ -184,10 +184,10 @@ namespace VCC::Core return VCC::Core::load_cpak_cartridge( filename, move(cartridge_context), - host_context, + pakContainer, iniPath, hVccWnd, - cpak_callbacks); // Callbacks hidden in here + cpak_callbacks); // Callbacks in here } } diff --git a/libcommon/src/bus/cpak_cartridge.cpp b/libcommon/src/bus/cpak_cartridge.cpp index cb23a0aa..12f04327 100644 --- a/libcommon/src/bus/cpak_cartridge.cpp +++ b/libcommon/src/bus/cpak_cartridge.cpp @@ -80,13 +80,13 @@ namespace VCC::Core cpak_cartridge::cpak_cartridge( HMODULE module_handle, - void* const host_context, + void* const pakContainer, path_type configuration_path, const HWND hVccWnd, const cpak_callbacks& cpak_callbacks) : handle_(module_handle), - host_context_(host_context), + pakContainer_(pakContainer), configuration_path_(move(configuration_path)), hVccWnd_(hVccWnd), cpak_callbacks_(cpak_callbacks), @@ -127,7 +127,7 @@ namespace VCC::Core void cpak_cartridge::start() { - initialize_(host_context_, configuration_path_.c_str(), hVccWnd_, &cpak_callbacks_); + initialize_(pakContainer_, configuration_path_.c_str(), hVccWnd_, &cpak_callbacks_); } void cpak_cartridge::stop() diff --git a/libcommon/src/util/DialogOps.cpp b/libcommon/src/util/DialogOps.cpp index 9649591a..96510885 100644 --- a/libcommon/src/util/DialogOps.cpp +++ b/libcommon/src/util/DialogOps.cpp @@ -20,7 +20,6 @@ #include #include #include -//#include //------------------------------------------------------------------------------------------- // FileDialog class shows a dialog for user to select a file for open or save. @@ -30,19 +29,23 @@ // do not play well with slashes so there is a bit of converting in and out; // // "path" refers to reverse slash path -// "upath" refers to forward slash path // //------------------------------------------------------------------------------------------- -// FileDialog constructor initializes open file name structure. -FileDialog::FileDialog() { - ZeroMemory(&ofn_, sizeof(ofn_)); - ofn_.lStructSize = sizeof(ofn_); - ofn_.Flags = OFN_HIDEREADONLY; -} - // FileDialog::show calls GetOpenFileName() or GetSaveFileName() bool FileDialog::show(BOOL Save, HWND Owner) { + + char file[MAX_PATH]; + ::VCC::Util::copy_to_char(sFile_,file,sizeof(file)); + ::VCC::Util::RevDirSlashes(file); + ofn_.nMaxFile = sizeof(file); + ofn_.lpstrFile = file; + + char idir[MAX_PATH]; + ::VCC::Util::copy_to_char(sInitDir_,idir,sizeof(idir)); + ::VCC::Util::RevDirSlashes(idir); + ofn_.lpstrInitialDir = idir; + // instance is that of the current module ofn_.hInstance = GetModuleHandle(nullptr); @@ -53,8 +56,10 @@ bool FileDialog::show(BOOL Save, HWND Owner) { ofn_.hwndOwner = GetActiveWindow(); } - ofn_.nMaxFile = sizeof(path_); - ofn_.lpstrFile = path_; + ofn_.lpstrDefExt = sDefext_.c_str(); + ofn_.lpstrFilter = sFilter_.c_str(); + ofn_.lpstrTitle = sTitle_.c_str(); + ofn_.Flags |= flags_; // Call Save or Open per boolean int rc; @@ -64,101 +69,14 @@ bool FileDialog::show(BOOL Save, HWND Owner) { rc = GetOpenFileName(&ofn_) ; } - // upath_ is the forward slash version - if (rc == 1) { - strncpy (upath_,path_,MAX_PATH); - VCC::Util::FixDirSlashes(upath_); - } - - return ((rc == 1) && (*path_ != '\0')); -} - -void FileDialog::setDefExt(const char * DefExt) { - ofn_.lpstrDefExt = DefExt; -} - -void FileDialog::setInitialDir(const char * InitialDir) { - if (InitialDir == nullptr) return; - strncpy(initialdir_,InitialDir,MAX_PATH); - VCC::Util::RevDirSlashes(initialdir_); - ofn_.lpstrInitialDir = initialdir_; -} - -void FileDialog::setFilter(const char * Filter) { - ofn_.lpstrFilter = Filter; -} - -void FileDialog::setFlags(unsigned int Flags) { - ofn_.Flags |= Flags; -} - -void FileDialog::setTitle(const char * Title) { - ofn_.lpstrTitle = Title; -} - -// Overwrite what is currently in path_ -void FileDialog::setpath(const char * NewPath) { - if (NewPath == nullptr) return; - strncpy(path_,NewPath,MAX_PATH); - VCC::Util::RevDirSlashes(path_); - strncpy(upath_,NewPath,MAX_PATH); - VCC::Util::FixDirSlashes(upath_); -} - -// Get a copy of the selected file path -void FileDialog::getpath(char * PathCopy, int maxsize) const { - if (PathCopy == nullptr) return; - strncpy(PathCopy,path_,maxsize); -} - -// Get a copy of the selected file path with slash delimiters -void FileDialog::getupath(char * PathCopy, int maxsize) const { - if (PathCopy == nullptr) return; - strncpy(PathCopy,upath_,maxsize); -} - -// Get a pointer to the selected file path -const char *FileDialog::path() const -{ - return path_; -} -const char *FileDialog::upath() const -{ - return upath_; -} - -// FileDialog::getdir() returns the directory portion of the file path -void FileDialog::getdir(char * Dir, int maxsize) const { - if (Dir == nullptr) return; - std::string s = VCC::Util::GetDirectoryPart(path_); - VCC::Util::copy_to_char(s,Dir,maxsize); -} + // Copy file selected back + if ((rc == 1) && (*file != '\0')) { + sFile_.assign(file ? file : ""); + VCC::Util::FixDirSlashes(sFile_); + return true; + }; -// FileDialog::gettype() returns the file type -void FileDialog::gettype(char * Type, int maxsize) const { - if (Type == nullptr) return; - if (maxsize < 1) return; - *Type = '\0'; - std::string s = VCC::Util::GetFileNamePart(path_); - size_t pos = s.rfind('.'); - if (pos == std::string::npos || pos == s.size()-1) return; - VCC::Util::copy_to_char(s.substr(pos+1),Type,maxsize); -} - -// String overloads for path_ and path_ components -std::string FileDialog::getpath() { - return path_; -} -std::string FileDialog::getdir() { - if (path_ == nullptr) return ""; - std::filesystem::path p(path_); - return p.parent_path().string(); - -} -std::string FileDialog::gettype() { - if (path_ == nullptr) return ""; - std::filesystem::path p(path_); - return p.extension().string(); + return false; } //------------------------------------------------------------ diff --git a/libcommon/src/util/FileOps.cpp b/libcommon/src/util/FileOps.cpp index ebc95b29..dd5e21df 100644 --- a/libcommon/src/util/FileOps.cpp +++ b/libcommon/src/util/FileOps.cpp @@ -72,7 +72,7 @@ void PathStripPath ( char *TextBuffer) return; for (; Index >= 0; Index--) - if (TextBuffer[Index] == '\\') + if (TextBuffer[Index] == '\\' || TextBuffer[Index] == '/') break; if (Index < 0) //delimiter not found diff --git a/libcommon/src/util/settings.cpp b/libcommon/src/util/settings.cpp index 95c643c8..bc2b6671 100644 --- a/libcommon/src/util/settings.cpp +++ b/libcommon/src/util/settings.cpp @@ -28,12 +28,12 @@ namespace VCC::Util {} // save string value - void settings::write( + bool settings::write( const std::string& section, const std::string& key, const std::string& value) const { - ::WritePrivateProfileString( + return ::WritePrivateProfileString( section.c_str(), key.c_str(), value.c_str(), @@ -41,12 +41,12 @@ namespace VCC::Util } // save int value - void settings::write + bool settings::write (const std::string& section, const std::string& key, int value) const { - ::WritePrivateProfileString( + return ::WritePrivateProfileString( section.c_str(), key.c_str(), std::to_string(value).c_str(), @@ -54,24 +54,24 @@ namespace VCC::Util } // save bool value - void settings::write_bool + bool settings::write_bool (const std::string& section, const std::string& key, bool value) const { int ival = value ? 1 : 0; - write(section, key, ival); + return write(section, key, ival); } // get char * value - void settings::read + bool settings::read (const std::string& section, const std::string& key, const std::string& default_value, char* buffer, size_t buffer_size) const { - ::GetPrivateProfileStringA( + return ::GetPrivateProfileStringA( section.c_str(), key.c_str(), default_value.c_str(), diff --git a/mpi/multipak_cartridge.cpp b/mpi/multipak_cartridge.cpp index 84294dc3..aa2a309d 100644 --- a/mpi/multipak_cartridge.cpp +++ b/mpi/multipak_cartridge.cpp @@ -26,31 +26,22 @@ namespace { - // Callback trampolines - // host_context is the opaque callback_context provided for this cartridge instance. - // In multipak this is always a multipak_cartridge*, allowing the trampoline to - // bounce the operation to the correct slot without exposing host internals. template - void assert_cartridge_line_on_slot(void* host_context, bool line_state) + void assert_cartridge_line_on_slot(void* pakContainer, bool line_state) { - static_cast(host_context)->assert_cartridge_line( + static_cast(pakContainer)->assert_cartridge_line( SlotIndex_, line_state); } template - void append_menu_item_on_slot(void* host_context, const char* text, int id, MenuItemType type) + void append_menu_item_on_slot(void* pakContainer, const char* text, int id, MenuItemType type) { - static_cast(host_context)->append_menu_item( + static_cast(pakContainer)->append_menu_item( SlotIndex_, { text, static_cast(id), type }); } // Per-slot callback table. - // Each entry provides the host-side trampoline functions for that slot, - // allowing cartridges to call back into multipak using a uniform API - // while the trampolines route the request to the correct slot. - // Multipak uses two slot specific callbacks, the rest are just passed from vcc. - // TODO: This could have been done with just a slot number! struct cartridge_slot_callbacks { PakAssertCartridgeLineHostCallback set_cartridge_line; @@ -164,8 +155,8 @@ void multipak_cartridge::write_port(unsigned char port_id, unsigned char value) // slot_select_port_id is 0x7f if (port_id == slot_select_port_id) { - // Bits 1-0 SCS slot (FDC) - // Bits 5-4 CTS slot (ROM) + // Bits 1-0 SCS slot + // Bits 5-4 CTS slot cached_scs_slot_ = value & 3; cached_cts_slot_ = (value >> 4) & 3; slot_register_ = value; @@ -322,6 +313,7 @@ void multipak_cartridge::eject_cartridge(slot_id_type slot) SendMessage(gVccWnd,WM_COMMAND,(WPARAM) ID_FILE_RESET,(LPARAM) 0); } +// create cartridge object and load cart DLL multipak_cartridge::mount_status_type multipak_cartridge::mount_cartridge( slot_id_type slot, const path_type& filename) { @@ -334,23 +326,25 @@ multipak_cartridge::mount_status_type multipak_cartridge::mount_cartridge( }; DLOG_C("%3d %p %p %p %p %p\n",slot,callbacks); - auto* multipakHost = this; + // pakContainer is a pointer to the multipak object. It is passed + // to cartridge DLL's and returned with callbacks to route them + // to the correct slot without exposing host internals. + // TODO: This could have been done with just a slot number! + + auto* pakContainer = this; - // callback_context is a host-owned opaque per-cartridge state. Passed to cartridges - // at initialization and returned on every callback so the host can route and manage a - // specific cartridge instance. MPI currently uses it to know what slot a cart is in. + // ctx is passed to the loader but not to cartridge DLL's auto ctx = std::make_unique( slot, *context_, - *multipakHost); - + *pakContainer); DLOG_C("load cart %d %s\n",slot,filename); auto loadedCartridge = VCC::Core::load_cartridge( filename, std::move(ctx), - multipakHost, + pakContainer, context_->configuration_path(), gVccWnd, callbacks); diff --git a/pakinterface.cpp b/pakinterface.cpp index 2c0500a2..6dc08a14 100644 --- a/pakinterface.cpp +++ b/pakinterface.cpp @@ -287,14 +287,7 @@ cartridge_loader_status PakLoadCartridge(const char* filename) // Insert Module returns 0 on success static cartridge_loader_status load_any_cartridge(const char *filename, const char* iniPath) { - // callback_context is a host-owned opaque per-cartridge state. Passed to the cartridge - // at initialization and returned on every callback so the host can route and manage a - // specific cartridge instance. Currently for pakinterface it is empty, but MPI uses it. - - // TODO:: Consider using a slot number instead. slot0 for this, slot1-slot4 for MMI - // That way all loaded cart context can reside in a simple vector with no reliance - // on cart trampolines to maintain context. With slot_num in the callbacks MPI will - // not have intercept to adjust menu_id's and forwarding the callback to main. + // vccContext is passed to the loader but not to the cart DLL auto vccContext=std::make_unique(); cpak_callbacks callbacks { @@ -308,7 +301,7 @@ static cartridge_loader_status load_any_cartridge(const char *filename, const ch auto loadedCartridge = VCC::Core::load_cartridge( filename, std::move(vccContext), - nullptr, // No host context for the main app + nullptr, // pakContainer goes here iniPath, EmuState.WindowHandle, callbacks); @@ -318,6 +311,7 @@ static cartridge_loader_status load_any_cartridge(const char *filename, const ch return loadedCartridge.load_result; } + // unload active cartridge UnloadDll(); VCC::Util::section_locker lock(gPakMutex); @@ -326,6 +320,8 @@ static cartridge_loader_status load_any_cartridge(const char *filename, const ch gActiveCartrige = move(loadedCartridge.cartridge); gActiveModule = move(loadedCartridge.handle); BeginCartMenu(); + + // initialize the cartridge gActiveCartrige->start(); // Reset if enabled. TODO: Send DoHardReset message instead