diff --git a/FD502/fd502.cpp b/FD502/fd502.cpp index 539a194d..818dd195 100644 --- a/FD502/fd502.cpp +++ b/FD502/fd502.cpp @@ -57,8 +57,7 @@ static unsigned char RGBDiskRom[EXTROMSIZE]; static char FloppyPath[MAX_PATH]; static char RomFileName[MAX_PATH]=""; static char TempRomFileName[MAX_PATH]=""; -static void* gCallbackContextPtr = nullptr; -void* const& gCallbackContext(gCallbackContextPtr); +slot_id_type gSlotId {}; PakAssertInteruptHostCallback AssertInt = nullptr; static PakAppendCartridgeMenuHostCallback CartMenuCallback = nullptr; unsigned char PhysicalDriveA=0,PhysicalDriveB=0,OldPhysicalDriveA=0,OldPhysicalDriveB=0; @@ -120,13 +119,13 @@ extern "C" } __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) { DLOG_C("FDC %p %p %p %p %p\n",*callbacks); - gCallbackContextPtr = callback_context; + gSlotId = SlotId; CartMenuCallback = callbacks->add_menu_item; AssertInt = callbacks->assert_interrupt; strcpy(IniFile, configuration_path); @@ -452,43 +451,43 @@ void BuildCartridgeMenu() if (CartMenuCallback ==nullptr) MessageBox(g_hConfDlg,"No good","Ok",0); - CartMenuCallback(gCallbackContext, "", MID_BEGIN, MIT_Head); - CartMenuCallback(gCallbackContext, "", MID_ENTRY, MIT_Seperator); + CartMenuCallback(gSlotId, "", MID_BEGIN, MIT_Head); + CartMenuCallback(gSlotId, "", MID_ENTRY, MIT_Seperator); - CartMenuCallback(gCallbackContext, "FD-502 Drive 0",MID_ENTRY,MIT_Head); - CartMenuCallback(gCallbackContext, "Insert",ControlId(10),MIT_Slave); + CartMenuCallback(gSlotId, "FD-502 Drive 0",MID_ENTRY,MIT_Head); + CartMenuCallback(gSlotId, "Insert",ControlId(10),MIT_Slave); strncpy(TempMsg,"Eject: ",MAX_PATH); strncpy(TempBuf,gVirtualDrive[0].ImageName,MAX_PATH); PathStripPath(TempBuf); strncat(TempMsg,TempBuf,MAX_PATH); - CartMenuCallback(gCallbackContext, TempMsg,ControlId(11),MIT_Slave); + CartMenuCallback(gSlotId, TempMsg,ControlId(11),MIT_Slave); - CartMenuCallback(gCallbackContext, "FD-502 Drive 1",MID_ENTRY,MIT_Head); - CartMenuCallback(gCallbackContext, "Insert",ControlId(12),MIT_Slave); + CartMenuCallback(gSlotId, "FD-502 Drive 1",MID_ENTRY,MIT_Head); + CartMenuCallback(gSlotId, "Insert",ControlId(12),MIT_Slave); strncpy(TempMsg,"Eject: ",MAX_PATH); strncpy(TempBuf,gVirtualDrive[1].ImageName,MAX_PATH); PathStripPath(TempBuf); strncat(TempMsg,TempBuf,MAX_PATH); - CartMenuCallback(gCallbackContext, TempMsg,ControlId(13),MIT_Slave); + CartMenuCallback(gSlotId, TempMsg,ControlId(13),MIT_Slave); - CartMenuCallback(gCallbackContext, "FD-502 Drive 2",MID_ENTRY,MIT_Head); - CartMenuCallback(gCallbackContext, "Insert",ControlId(14),MIT_Slave); + CartMenuCallback(gSlotId, "FD-502 Drive 2",MID_ENTRY,MIT_Head); + CartMenuCallback(gSlotId, "Insert",ControlId(14),MIT_Slave); strncpy(TempMsg,"Eject: ",MAX_PATH); strncpy(TempBuf,gVirtualDrive[2].ImageName,MAX_PATH); PathStripPath(TempBuf); strncat(TempMsg,TempBuf,MAX_PATH); - CartMenuCallback(gCallbackContext, TempMsg,ControlId(15),MIT_Slave); + CartMenuCallback(gSlotId, TempMsg,ControlId(15),MIT_Slave); - CartMenuCallback(gCallbackContext, "FD-502 Drive 3",MID_ENTRY,MIT_Head); - CartMenuCallback(gCallbackContext, "Insert",ControlId(17),MIT_Slave); + CartMenuCallback(gSlotId, "FD-502 Drive 3",MID_ENTRY,MIT_Head); + CartMenuCallback(gSlotId, "Insert",ControlId(17),MIT_Slave); strncpy(TempMsg,"Eject: ",MAX_PATH); strncpy(TempBuf,gVirtualDrive[3].ImageName,MAX_PATH); PathStripPath(TempBuf); strncat(TempMsg,TempBuf,MAX_PATH); - CartMenuCallback(gCallbackContext, TempMsg,ControlId(18),MIT_Slave); + CartMenuCallback(gSlotId, TempMsg,ControlId(18),MIT_Slave); - CartMenuCallback(gCallbackContext, "FD-502 Config",ControlId(16),MIT_StandAlone); - CartMenuCallback(gCallbackContext,"", MID_FINISH, MIT_Head); + CartMenuCallback(gSlotId, "FD-502 Config",ControlId(16),MIT_StandAlone); + CartMenuCallback(gSlotId,"", MID_FINISH, MIT_Head); } long CreateDisk (unsigned char Disk) diff --git a/FD502/fd502.h b/FD502/fd502.h index 943b4d44..17cd9b61 100644 --- a/FD502/fd502.h +++ b/FD502/fd502.h @@ -19,7 +19,7 @@ This file is part of VCC (Virtual Color Computer). */ #include -extern void*const& gCallbackContext; +extern slot_id_type gSlotId; extern PakAssertInteruptHostCallback AssertInt; void BuildCartridgeMenu(); diff --git a/FD502/wd1793.cpp b/FD502/wd1793.cpp index 90cf5082..506e6c05 100644 --- a/FD502/wd1793.cpp +++ b/FD502/wd1793.cpp @@ -964,7 +964,7 @@ void DispatchCommand(unsigned char Tmp) StatusReg=READY; ExecTimeWaiter=1; if ((Tmp & 15) != 0) - AssertInt(gCallbackContext, INT_NMI,IS_NMI); + AssertInt(gSlotId, INT_NMI,IS_NMI); // WriteLog("FORCEINTERUPT",0); break; @@ -1309,7 +1309,7 @@ long GetSectorInfo (SectorInfo *Sector,const unsigned char *TempBuffer) void CommandDone() { if (InteruptEnable) - AssertInt(gCallbackContext, INT_NMI,IS_NMI); + AssertInt(gSlotId, INT_NMI,IS_NMI); TransferBufferSize=0; CurrentCommand=IDLE; } diff --git a/GMC/Cartridge.cpp b/GMC/Cartridge.cpp index 1771a20d..f92d73b3 100644 --- a/GMC/Cartridge.cpp +++ b/GMC/Cartridge.cpp @@ -21,8 +21,8 @@ namespace detail { - void NullAssetCartridgeLine(void*, bool) {} - void NullAddMenuItem(void*, const char *, int, MenuItemType) {} + void NullAssetCartridgeLine(slot_id_type, bool) {} + void NullAddMenuItem(slot_id_type, const char *, int, MenuItemType) {} } @@ -47,8 +47,6 @@ Cartridge::~Cartridge() } - - void Cartridge::LoadConfiguration(const std::string& /*filename*/) { } @@ -59,10 +57,9 @@ void Cartridge::LoadMenuItems() } - -void Cartridge::SetCallbackContext(void* key) +void Cartridge::SetSlotId(slot_id_type SlotId) { - m_CallbackContext = key; + m_SlotId = SlotId; } diff --git a/GMC/Cartridge.h b/GMC/Cartridge.h index 38f1f454..1bab6b66 100644 --- a/GMC/Cartridge.h +++ b/GMC/Cartridge.h @@ -4,8 +4,8 @@ namespace detail { - void NullAssetCartridgeLine(void*, bool); - void NullAddMenuItem(void*, const char*, int, MenuItemType); + void NullAssetCartridgeLine(slot_id_type, bool); + void NullAddMenuItem(slot_id_type, const char*, int, MenuItemType); } class Cartridge @@ -20,7 +20,7 @@ class Cartridge virtual ~Cartridge(); - virtual void SetCallbackContext(void* key); + virtual void SetSlotId(slot_id_type SlotId); virtual void SetCartLineAssertCallback(PakAssertCartridgeLineHostCallback callback); virtual void SetMenuBuilderCallback(PakAppendCartridgeMenuHostCallback addMenuCallback); virtual void SetConfigurationPath(std::string path); @@ -39,12 +39,12 @@ class Cartridge void AssetCartridgeLine(bool state) const { - AssetCartridgeLinePtr(m_CallbackContext, state); + AssetCartridgeLinePtr(m_SlotId, state); } void AddMenuItem(const char * name, int id, MenuItemType type) { - AddMenuItemPtr(m_CallbackContext, name, id, type); + AddMenuItemPtr(m_SlotId, name, id, type); } virtual void LoadConfiguration(const std::string& filename); @@ -55,7 +55,7 @@ class Cartridge friend const char* PakGetName(); friend const char* PakGetCatalogId(); friend void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks); @@ -71,7 +71,7 @@ class Cartridge static Cartridge* m_Singleton; - void* m_CallbackContext = nullptr; + slot_id_type m_SlotId {}; std::string m_Name; std::string m_CatalogId; std::string m_ConfigurationPath; diff --git a/GMC/CartridgeTrampolines.cpp b/GMC/CartridgeTrampolines.cpp index b26cb2ea..7dceab99 100644 --- a/GMC/CartridgeTrampolines.cpp +++ b/GMC/CartridgeTrampolines.cpp @@ -35,7 +35,7 @@ GMC_EXPORT const char* PakGetDescription() GMC_EXPORT void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) @@ -47,7 +47,7 @@ GMC_EXPORT void PakInitialize( callbacks->read_memory_byte, callbacks->add_menu_item); - Cartridge::m_Singleton->SetCallbackContext(callback_context); + Cartridge::m_Singleton->SetSlotId(SlotId); Cartridge::m_Singleton->SetMenuBuilderCallback(callbacks->add_menu_item); Cartridge::m_Singleton->SetCartLineAssertCallback(callbacks->assert_cartridge_line); Cartridge::m_Singleton->SetConfigurationPath(configuration_path); diff --git a/GMC/CartridgeTrampolines.h b/GMC/CartridgeTrampolines.h index 3a4f4118..4fdb5961 100644 --- a/GMC/CartridgeTrampolines.h +++ b/GMC/CartridgeTrampolines.h @@ -4,7 +4,7 @@ GMC_EXPORT const char* PakGetName(); GMC_EXPORT const char* PakGetCatalogId(); GMC_EXPORT void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks); diff --git a/HardDisk/harddisk.cpp b/HardDisk/harddisk.cpp index c4b751ce..511dcd64 100644 --- a/HardDisk/harddisk.cpp +++ b/HardDisk/harddisk.cpp @@ -41,7 +41,7 @@ static char IniFile[MAX_PATH] { 0 }; static char HardDiskPath[MAX_PATH]; static ::VCC::Device::rtc::cloud9 cloud9_rtc; -static void* gCallbackContext = nullptr; +static slot_id_type gSlotId {}; static PakReadMemoryByteHostCallback MemRead8 = nullptr; static PakWriteMemoryByteHostCallback MemWrite8 = nullptr; static PakAppendCartridgeMenuHostCallback CartMenuCallback = nullptr; @@ -64,12 +64,12 @@ using namespace std; void MemWrite(unsigned char Data, unsigned short Address) { - MemWrite8(gCallbackContext, Data, Address); + MemWrite8(gSlotId, Data, Address); } unsigned char MemRead(unsigned short Address) { - return MemRead8(gCallbackContext, Address); + return MemRead8(gSlotId, Address); } @@ -104,12 +104,12 @@ extern "C" } __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) { - gCallbackContext = callback_context; + gSlotId = SlotId; CartMenuCallback = callbacks->add_menu_item; MemRead8 = callbacks->read_memory_byte; MemWrite8 = callbacks->write_memory_byte; @@ -378,27 +378,27 @@ void BuildCartridgeMenu() char TempMsg[512] = ""; char TempBuf[MAX_PATH] = ""; - CartMenuCallback(gCallbackContext, "", MID_BEGIN, MIT_Head); - CartMenuCallback(gCallbackContext, "", MID_ENTRY, MIT_Seperator); + CartMenuCallback(gSlotId, "", MID_BEGIN, MIT_Head); + CartMenuCallback(gSlotId, "", MID_ENTRY, MIT_Seperator); - CartMenuCallback(gCallbackContext, "HD Drive 0", MID_ENTRY, MIT_Head); - CartMenuCallback(gCallbackContext, "Insert", ControlId(10), MIT_Slave); + CartMenuCallback(gSlotId, "HD Drive 0", MID_ENTRY, MIT_Head); + CartMenuCallback(gSlotId, "Insert", ControlId(10), MIT_Slave); strcpy(TempMsg, "Eject: "); strcpy(TempBuf, VHDfile0); PathStripPath(TempBuf); strcat(TempMsg, TempBuf); - CartMenuCallback(gCallbackContext, TempMsg, ControlId(11), MIT_Slave); + CartMenuCallback(gSlotId, TempMsg, ControlId(11), MIT_Slave); - CartMenuCallback(gCallbackContext, "HD Drive 1", MID_ENTRY, MIT_Head); - CartMenuCallback(gCallbackContext, "Insert", ControlId(12), MIT_Slave); + CartMenuCallback(gSlotId, "HD Drive 1", MID_ENTRY, MIT_Head); + CartMenuCallback(gSlotId, "Insert", ControlId(12), MIT_Slave); strcpy(TempMsg, "Eject: "); strcpy(TempBuf, VHDfile1); PathStripPath(TempBuf); strcat(TempMsg, TempBuf); - CartMenuCallback(gCallbackContext, TempMsg, ControlId(13), MIT_Slave); + CartMenuCallback(gSlotId, TempMsg, ControlId(13), MIT_Slave); - CartMenuCallback(gCallbackContext, "HD Config", ControlId(14), MIT_StandAlone); - CartMenuCallback(gCallbackContext, "", MID_FINISH, MIT_Head); + CartMenuCallback(gSlotId, "HD Config", ControlId(14), MIT_StandAlone); + CartMenuCallback(gSlotId, "", MID_FINISH, MIT_Head); } // Dialog for creating a new hard disk diff --git a/SuperIDE/SuperIDE.cpp b/SuperIDE/SuperIDE.cpp index 3c6a0619..9341479f 100644 --- a/SuperIDE/SuperIDE.cpp +++ b/SuperIDE/SuperIDE.cpp @@ -50,8 +50,7 @@ static bool ClockReadOnly = true; static unsigned char DataLatch=0; static HINSTANCE gModuleInstance; static HWND hConfDlg = nullptr; -static void* gCallbackContextPtr = nullptr; -static void* const& gCallbackContext(gCallbackContextPtr); +static slot_id_type gSlotId {}; using namespace std; @@ -87,12 +86,12 @@ extern "C" } __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) { - gCallbackContextPtr = callback_context; + gSlotId = SlotId; CartMenuCallback = callbacks->add_menu_item; strcpy(IniFile, configuration_path); @@ -221,24 +220,24 @@ void BuildCartridgeMenu() { char TempMsg[512]=""; char TempBuf[MAX_PATH]=""; - CartMenuCallback(gCallbackContext, "", MID_BEGIN, MIT_Head); - CartMenuCallback(gCallbackContext, "", MID_ENTRY, MIT_Seperator); - CartMenuCallback(gCallbackContext, "IDE Master",MID_ENTRY,MIT_Head); - CartMenuCallback(gCallbackContext, "Insert",ControlId(10),MIT_Slave); + CartMenuCallback(gSlotId, "", MID_BEGIN, MIT_Head); + CartMenuCallback(gSlotId, "", MID_ENTRY, MIT_Seperator); + CartMenuCallback(gSlotId, "IDE Master",MID_ENTRY,MIT_Head); + CartMenuCallback(gSlotId, "Insert",ControlId(10),MIT_Slave); QueryDisk(MASTER,TempBuf); strcpy(TempMsg,"Eject: "); PathStripPath (TempBuf); strcat(TempMsg,TempBuf); - CartMenuCallback(gCallbackContext, TempMsg,ControlId(11),MIT_Slave); - CartMenuCallback(gCallbackContext, "IDE Slave",MID_ENTRY,MIT_Head); - CartMenuCallback(gCallbackContext, "Insert",ControlId(12),MIT_Slave); + CartMenuCallback(gSlotId, TempMsg,ControlId(11),MIT_Slave); + CartMenuCallback(gSlotId, "IDE Slave",MID_ENTRY,MIT_Head); + CartMenuCallback(gSlotId, "Insert",ControlId(12),MIT_Slave); QueryDisk(SLAVE,TempBuf); strcpy(TempMsg,"Eject: "); PathStripPath (TempBuf); strcat(TempMsg,TempBuf); - CartMenuCallback(gCallbackContext, TempMsg,ControlId(13),MIT_Slave); - CartMenuCallback(gCallbackContext, "IDE Config",ControlId(14),MIT_StandAlone); - CartMenuCallback(gCallbackContext, "", MID_FINISH, MIT_Head); + CartMenuCallback(gSlotId, TempMsg,ControlId(13),MIT_Slave); + CartMenuCallback(gSlotId, "IDE Config",ControlId(14),MIT_StandAlone); + CartMenuCallback(gSlotId, "", MID_FINISH, MIT_Head); } LRESULT CALLBACK IDE_Config(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) diff --git a/acia/acia.cpp b/acia/acia.cpp index 0b728d23..28ab5a22 100644 --- a/acia/acia.cpp +++ b/acia/acia.cpp @@ -40,8 +40,8 @@ void SaveConfig(); //------------------------------------------------------------------------ // Pak host //------------------------------------------------------------------------ -static void* gCallbackContextPtr = nullptr; -void* const& gCallbackContext(gCallbackContextPtr); +slot_id_type gSlotId; + static PakAppendCartridgeMenuHostCallback CartMenuCallback = nullptr; PakAssertInteruptHostCallback AssertInt = nullptr; @@ -119,12 +119,12 @@ extern "C" } __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) { - gCallbackContextPtr = callback_context; + gSlotId = SlotId; CartMenuCallback = callbacks->add_menu_item; AssertInt = callbacks->assert_interrupt; strcpy(IniFile, configuration_path); @@ -140,7 +140,6 @@ extern "C" sc6551_close(); AciaStat[0]='\0'; } - } @@ -243,10 +242,10 @@ __declspec(dllexport) void PakMenuItemClicked(unsigned char /*MenuID*/) //---------------------------------------------------------------------- void BuildCartridgeMenu() { - CartMenuCallback(gCallbackContext, "", MID_BEGIN, MIT_Head); - CartMenuCallback(gCallbackContext, "", MID_ENTRY, MIT_Seperator); - CartMenuCallback(gCallbackContext, "ACIA Config", ControlId(16), MIT_StandAlone); - CartMenuCallback(gCallbackContext, "", MID_FINISH, MIT_Head); + CartMenuCallback(gSlotId, "", MID_BEGIN, MIT_Head); + CartMenuCallback(gSlotId, "", MID_ENTRY, MIT_Seperator); + CartMenuCallback(gSlotId, "ACIA Config", ControlId(16), MIT_StandAlone); + CartMenuCallback(gSlotId, "", MID_FINISH, MIT_Head); } //----------------------------------------------------------------------- diff --git a/acia/acia.h b/acia/acia.h index 23df1e5f..4dc16be5 100644 --- a/acia/acia.h +++ b/acia/acia.h @@ -69,7 +69,7 @@ extern char AciaFileRdPath[MAX_PATH]; // Path for file reads extern char AciaFileWrPath[MAX_PATH]; // Path for file writes extern PakAssertInteruptHostCallback AssertInt; -extern void* const& gCallbackContext; +extern slot_id_type gSlotId; // Device extern void sc6551_init(); diff --git a/acia/sc6551.cpp b/acia/sc6551.cpp index bbff168d..fcadebdc 100644 --- a/acia/sc6551.cpp +++ b/acia/sc6551.cpp @@ -250,7 +250,7 @@ void sc6551_heartbeat() StatReg |= StatRxF; // Assert CART if interrupts not disabled or already asserted. if (!((CmdReg & CmdRxI) || (StatReg & StatIRQ))) { - AssertInt(gCallbackContext, INT_CART, IS_NMI); + AssertInt(gSlotId, INT_CART, IS_NMI); StatReg |= StatIRQ; } } diff --git a/becker/becker.cpp b/becker/becker.cpp index 6998f6bd..25dbb4fb 100644 --- a/becker/becker.cpp +++ b/becker/becker.cpp @@ -18,7 +18,7 @@ static SOCKET dwSocket = 0; // vcc stuff static HINSTANCE gModuleInstance; -static void* gCallbackContext = nullptr; +slot_id_type gSlotId {}; static PakAppendCartridgeMenuHostCallback CartMenuCallback = nullptr; static PakAssertCartridgeLineHostCallback PakSetCart = nullptr; LRESULT CALLBACK Config(HWND, UINT, WPARAM, LPARAM); @@ -415,12 +415,12 @@ extern "C" } __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) { - gCallbackContext = callback_context; + gSlotId = SlotId; CartMenuCallback = callbacks->add_menu_item; PakSetCart = callbacks->assert_cartridge_line; strcpy(IniFile, configuration_path); @@ -536,10 +536,10 @@ extern "C" __declspec(dllexport) void PakGetStatus(char* text_buffer, size_t buf void BuildCartridgeMenu() { - CartMenuCallback(gCallbackContext, "", MID_BEGIN, MIT_Head); - CartMenuCallback(gCallbackContext, "", MID_ENTRY, MIT_Seperator); - CartMenuCallback(gCallbackContext, "DriveWire Server..", ControlId(16), MIT_StandAlone); - CartMenuCallback(gCallbackContext, "", MID_FINISH, MIT_Head); + CartMenuCallback(gSlotId, "", MID_BEGIN, MIT_Head); + CartMenuCallback(gSlotId, "", MID_ENTRY, MIT_Seperator); + CartMenuCallback(gSlotId, "DriveWire Server..", ControlId(16), MIT_StandAlone); + CartMenuCallback(gSlotId, "", MID_FINISH, MIT_Head); } extern "C" __declspec(dllexport) void PakMenuItemClicked(unsigned char MenuID) diff --git a/libcommon/include/vcc/bus/cartridge_loader.h b/libcommon/include/vcc/bus/cartridge_loader.h index e7ce02ae..e5d61729 100644 --- a/libcommon/include/vcc/bus/cartridge_loader.h +++ b/libcommon/include/vcc/bus/cartridge_loader.h @@ -68,7 +68,8 @@ namespace VCC::Core LIBCOMMON_EXPORT cartridge_loader_result load_cpak_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const pakContainer, +// void* const pakContainer, + slot_id_type SlotId, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks); @@ -76,7 +77,8 @@ namespace VCC::Core LIBCOMMON_EXPORT cartridge_loader_result load_cartridge( const std::string& filename, // Cartridge filename std::unique_ptr cartridge_context, // Loader context - void* const pakContainer, // Pak container object +// void* const pakContainer, // Pak container object + slot_id_type SlotId, const std::string& iniPath, // Path of ini file HWND hVccWnd, // handle to main window const cpak_callbacks& cpak_callbacks); // Callbacks diff --git a/libcommon/include/vcc/bus/cpak_cartridge.h b/libcommon/include/vcc/bus/cpak_cartridge.h index 24ce1205..666fe870 100644 --- a/libcommon/include/vcc/bus/cpak_cartridge.h +++ b/libcommon/include/vcc/bus/cpak_cartridge.h @@ -31,12 +31,11 @@ namespace VCC::Core using path_type = std::string; - public: LIBCOMMON_EXPORT cpak_cartridge( HMODULE module_handle, // Cartridge filename - void* const pakContainer, // pointer to container object + slot_id_type const SlotId, // Slot id path_type configuration_path, // Path of ini file HWND hVccWnd, // Handle to main VCC window proc const cpak_callbacks& cpak_callbacks); // Callbacks @@ -61,7 +60,7 @@ namespace VCC::Core private: const HMODULE handle_; - void* const pakContainer_; + slot_id_type SlotId_; const HWND hVccWnd_; const path_type configuration_path_; const cpak_callbacks cpak_callbacks_; diff --git a/libcommon/include/vcc/bus/cpak_cartridge_definitions.h b/libcommon/include/vcc/bus/cpak_cartridge_definitions.h index a72ae4f8..ead0739a 100644 --- a/libcommon/include/vcc/bus/cpak_cartridge_definitions.h +++ b/libcommon/include/vcc/bus/cpak_cartridge_definitions.h @@ -15,53 +15,64 @@ // You should have received a copy of the GNU General Public License along with // VCC (Virtual Color Computer). If not, see . //////////////////////////////////////////////////////////////////////////////// + + //=========================================================// + // This defines the binary interface used by all pak DLLs. // + //=========================================================// + #pragma once #include +#include // for std::size_t #include -// This defines the hardware cartridge interface, it is included by all hardware packs. +//---------------------------------------------------------------- +// ABI identity is based on SlotId; 0 = Boot Slot, 1-4 = MPI slots +//---------------------------------------------------------------- +using slot_id_type = std::size_t; + extern "C" { enum MenuItemType; using PakWriteMemoryByteHostCallback = void (*) - (void* callback_context, unsigned char value, unsigned short address); + (slot_id_type SlotId, unsigned char value, unsigned short address); using PakReadMemoryByteHostCallback = unsigned char (*) - (void* callback_context, unsigned short address); + (slot_id_type SlotId, unsigned short address); using PakAssertCartridgeLineHostCallback = void (*) - (void* callback_context, bool lineState); + (slot_id_type SlotId, bool lineState); using PakAssertInteruptHostCallback = void (*) - (void* callback_context, Interrupt interrupt, InterruptSource interrupt_source); + (slot_id_type SlotId, Interrupt interrupt, InterruptSource interrupt_source); using PakAppendCartridgeMenuHostCallback = void (*) - (void* callback_context, const char* menu_name, int menu_id, MenuItemType menu_type); + (slot_id_type SlotId, const char* menu_name, int menu_id, MenuItemType menu_type); // Cartridge Callbacks struct cpak_callbacks { - const PakAssertInteruptHostCallback assert_interrupt; + const PakAssertInteruptHostCallback assert_interrupt; const PakAssertCartridgeLineHostCallback assert_cartridge_line; - const PakWriteMemoryByteHostCallback write_memory_byte; - const PakReadMemoryByteHostCallback read_memory_byte; + const PakWriteMemoryByteHostCallback write_memory_byte; + const PakReadMemoryByteHostCallback read_memory_byte; const PakAppendCartridgeMenuHostCallback add_menu_item; }; // Cartridge exports. At least PakInitilizeModuleFunction must be implimented using PakInitializeModuleFunction = void (*)( - void* callback_context, // Host or MPI - const char* const configuration_path, // Path of ini file - HWND hVccWnd, // VCC Main window HWND - const cpak_callbacks* const context); // Callbacks - using PakTerminateModuleFunction = void (*)(); - using PakGetNameModuleFunction = const char* (*)(); - using PakGetCatalogIdModuleFunction = const char* (*)(); - using PakGetDescriptionModuleFunction = const char* (*)(); - using PakResetModuleFunction = void (*)(); - using PakHeartBeatModuleFunction = void (*)(); - using PakGetStatusModuleFunction = void (*)(char* text_buffer, size_t buffer_size); - using PakWritePortModuleFunction = void (*)(unsigned char port, unsigned char value); - using PakReadMemoryByteModuleFunction = unsigned char (*)(unsigned short address); - using PakReadPortModuleFunction = unsigned char (*)(unsigned char port); - using PakSampleAudioModuleFunction = unsigned short (*)(); + slot_id_type SlotId, // SlotId + const char* const configuration_path, // Path of ini file + HWND hVccWnd, // VCC Main window HWND + const cpak_callbacks* const context); // Callback + + using PakTerminateModuleFunction = void (*)(); + using PakGetNameModuleFunction = const char* (*)(); + using PakGetCatalogIdModuleFunction = const char* (*)(); + using PakGetDescriptionModuleFunction = const char* (*)(); + using PakResetModuleFunction = void (*)(); + using PakHeartBeatModuleFunction = void (*)(); + using PakGetStatusModuleFunction = void (*)(char* text_buffer, size_t buffer_size); + using PakWritePortModuleFunction = void (*)(unsigned char port, unsigned char value); + using PakReadMemoryByteModuleFunction = unsigned char (*)(unsigned short address); + using PakReadPortModuleFunction = unsigned char (*)(unsigned char port); + using PakSampleAudioModuleFunction = unsigned short (*)(); using PakMenuItemClickedModuleFunction = void (*)(unsigned char itemId); } diff --git a/libcommon/src/bus/CartridgeInterface.txt b/libcommon/src/bus/CartridgeInterface.txt index 168da28a..c8a265dc 100644 --- a/libcommon/src/bus/CartridgeInterface.txt +++ b/libcommon/src/bus/CartridgeInterface.txt @@ -1,29 +1,26 @@ -This attempts to describe the cartridge interface design for VCC +This describes 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: +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. +ROM cartridges contain only read-only memory and the minimal hardware needed to expose that +memory to the CoCo 3. -**Key characteristics:** +**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. @@ -47,7 +44,7 @@ These cartridges require host-side x86 code to emulate their hardware behavior. - 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 +- Hardware DLL's must export the PakInitialize 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. @@ -59,8 +56,8 @@ These cartridges require host-side x86 code to emulate their hardware behavior. ## 3. MultiPak Cartridge (MPI) -MultiPak it not a true cartridge, it is a bus expansion that acts as hosts for other hardware -cartridges. +MultiPak is a special type of hardware cartridge, not really a true cartridge, it is a +bus expansion that acts as hosts for other hardware cartridges. **Capabilities:** @@ -97,18 +94,20 @@ The cartridge loader determines the cartridge type using the following sequence: 5. Continue with loading and initialization - --- -Cartridge Exports +#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 (SLotId, settings_path, hVccWnd, &callbacks); - Initiate pack (required) - PakInitialize (slot_context, settings_path, hVccWnd_, &callbacks); + Retrieve cart menu (NEW) + PakGetMenuItems(menu_items, count); + + Get cart capabilities (PROPOSED) + PakGetCapabilities (void); Terminate pack, prepare for DLL unload PakTerminate () @@ -137,7 +136,7 @@ DLL's can export any of the following calls Read I/O port unsigned char PakReadPort (Port) - Read ROM byten + Read ROM byte unsigned char PakReadMemoryByte (Address) Sample audio line @@ -148,57 +147,43 @@ DLL's can export any of the following calls --- -Callbacks +#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; +Callbacks are used by cartridge DLL's to initiate host (or MPI) actions. The +following callbacks currently exist: -It has recently been recognized that there are two classes of callbacks: + assert_cartridge_line (SlotId, line_state) -- 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. + assert_interrupt (SlotId, interrupt, interrupt_source) -- 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. + write_memory_byte (SlotId, value, address) -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. + read_memory_byte (SlotId, unsigned short address) -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. + add_menu_item (SlotId, menu_name, menu_id, menu_type) **depreciated** ---- +SlotId is used by the MPI to filter assert_cartridge_line and to bias menu items. + +There are two type of callbacks: -The dynamic cartridge menu system. +- Fast callbacks initiated by 6x09 code running inside the CPU loop such as asserting +interrupts, cart lines, or reading and writing memory to handle DMA requests. These +are syncronous and must return quickly to not affect emulator timing. Fast callbacks +are determined by Coco3's physical bus and are not likely to change. -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. +- Notifications initiated by cartridge UI events like adding menu items or inserting +cartridges in slots. These are asyncronous and can rely on DLL exports for details. +A good mechanism for these is Vcc's main window message loop. The main window handle +(hVccWnd) has been added to PakInitialize() and a message to it is used by the MPI to +initiate a VCC reset. -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. +The add_menu_item callback is not tied to the CPU loop and qualifies as a slow callback. +This callback is being replaced by windows menu item change message and a new export. +See **CartridgeMenuSystem.txt** for a description of this change. --- -New Design Philosophy For The MPI (Not yet implemented) +#A New Design Philosophy For The MPI (In progress) VCC and forks of VCC use run-time loading and unloading of dynamic libraries to simulate the inserting and removing of Cartridges. @@ -211,17 +196,11 @@ call cartridge DLLs directly there are now two modules, VCC and MPI, that need t 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 +If 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 slot management concept: - The pakinterface maintains a list indexed by slot number of loaded cartridges. @@ -240,18 +219,18 @@ To wrap up the pakinterface slot management concept: - 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. +- The opaque slot_context is renamed to SlotId (0-4) and is made transparent. Some carts + don't work right if they are not a specific slot. They can use SlotId to verify the slot + they are in is right for them. (This has been completed) -- on request pakInterface sends MPI active cart description via a new MPI export +- On request pakInterface sends MPI active cart description via a new MPI export -- on request pakInterface sends MPI slot contents +- 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 saves the startup slot setting. Changing this causes no changes to running CPU - The MPI requests cartridge loads / unloads by sending messages to WinMain. @@ -267,14 +246,11 @@ To wrap up the pakinterface slot management concept: 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. +1. Replace opaque slot_context pointer in init export with transparent SlotId. Cartridges can + use SlotId or simply return it in callbacks. (This is complete) -2. Replace the AddCartMenu callback with a message and modify pakinterface to maintain the cartridge - dynamic menus. +2. Replace the AddCartMenu callback with a message and modify pakinterface to maintain the + cartridge dynamic menus. See **CartridgeMenuSystem.txt** for more description. 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/CartridgeMenuSystem.txt b/libcommon/src/bus/CartridgeMenuSystem.txt new file mode 100644 index 00000000..c2fa2326 --- /dev/null +++ b/libcommon/src/bus/CartridgeMenuSystem.txt @@ -0,0 +1,80 @@ + +# **VCC Cartridge Export Based Menu System** + +This replaces per‑item callbacks with a single export‑based model for exchanging menu +items between cartridge DLLs, Multipak (MPI), and the PakInterface host. + +Concept: + +- Each cartridge DLL maintains its own internal list of menu items. +- Each DLL exposes **one export** that returns its entire menu list on demand. +- MPI aggregates child cartridge menus, applies slot‑based ID biasing, and returns a + unified list to the host. +- The host rebuilds the UI menu from the aggregated list. +- DLLs notify the host of menu changes using a single Windows message. + +Benefits: + +- Menu state is always derived from a **single export call**, not a sequence of callbacks. +- DLLs do not depend on host internals, callback tables, or routing logic. +- Clear separation of responsibilities: + - DLLs own their menu state. + - MPI aggregates and biases. + - Host renders. +- The export signature and struct layout remain stable even if internal implementations change. + +--- + +## **Component Details** + +### **Cartridge DLL** + +A cartridge DLL: + +- Maintains a **static internal list** of its menu items. +- Updates this list whenever its internal state changes. +- Sends **WM_VCC_MENU_CHANGED** to the host after updating its list. +- Implements a single GetMenuItemList export that: + - Accepts a pointer to a buffer of menu items (or `nullptr` for size query). + - Accepts a pointer to a count value. + - Interprets the count as: + - **Input:** maximum number of items the host can accept. + - **Output:** total number of items the DLL has (or number copied). +- Never copies more items than the host indicates. +- Returns failure if not all items could be copied. +- Protects the list from export access while it is being updated. + +If the buffer pointer is `nullptr`, the DLL sets count to the number of items it has. +If the buffer pointer is not `nullptr`, the DLL copies up to the specified count. + +--- + +### **Multipak (MPI)** + +MPI acts as an **aggregator** and applies deterministic slot‑based menu ID biasing. +The MPI is only permitted to be installed in the boot slot. (Coco side slot) + +MPI: + +- Maintains references to each child cartridge’s menu export. +- When its export is called: + - Generates MPI’s own menu items. + - Calls each child cartridge’s export to retrieve their items. + - Applies **slot‑based menu ID biasing**: + - Each slot receives a unique bias range. + - Biasing is applied only by MPI. + - DLLs remain unaware of slot numbers or bias rules. + - Merges all items into a single unified list. +- Returns the unified list to the host using the same export pattern as cartridges. + +--- + +### **PakInterface Host** + +The host: + +- Listens for **WM_VCC_MENU_CHANGED** from any DLL including the MPI. +- On receiving the message, calls the boot slot's export and rebuilds the menu. + +The host only sees a flat, final list of menu items. + diff --git a/libcommon/src/bus/cartridge_loader.cpp b/libcommon/src/bus/cartridge_loader.cpp index 07e5e01d..9216b706 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 pakContainer, + slot_id_type SlotId, 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(), - pakContainer, + SlotId, iniPath, hVccWnd, cpak_callbacks); @@ -154,18 +154,18 @@ namespace VCC::Core return { nullptr, nullptr, cartridge_loader_status::not_expansion }; } - // 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. 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. + // 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_loader_result is defined in libcommon/include/vcc/bus/cartridge_loader.h + // cartridge_context is defined in libcommon/include/vcc/bus/cartridge_context.h + // SlotId is size_t 0-4, 0 = boot slot (side slot), 1-4 = MPI slots. SlotId is + // passed to cpak cart DLLs and is returned as first argment of callbacks // cpak_callbacks is used by all hardware paks and is defined in - // libcommon/include/vcc/bus/cpak_cartridge_definitions.h. cartridge_loader_result - // is defined in libcommon/include/vcc/bus/cartridge_loader.h + // libcommon/include/vcc/bus/cpak_cartridge_definitions.h. cartridge_loader_result load_cartridge( const std::string& filename, std::unique_ptr cartridge_context, - void* const pakContainer, + slot_id_type SlotId, const std::string& iniPath, HWND hVccWnd, const cpak_callbacks& cpak_callbacks) @@ -184,9 +184,9 @@ namespace VCC::Core return VCC::Core::load_cpak_cartridge( filename, move(cartridge_context), - pakContainer, - iniPath, - hVccWnd, + SlotId, // Where cart is inserted + iniPath, // Path to vcc ini file + hVccWnd, // MainVcc window handle cpak_callbacks); // Callbacks in here } } diff --git a/libcommon/src/bus/cpak_cartridge.cpp b/libcommon/src/bus/cpak_cartridge.cpp index 12f04327..4c590f3c 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 pakContainer, + slot_id_type SlotId, path_type configuration_path, const HWND hVccWnd, const cpak_callbacks& cpak_callbacks) : handle_(module_handle), - pakContainer_(pakContainer), + SlotId_(SlotId), configuration_path_(move(configuration_path)), hVccWnd_(hVccWnd), cpak_callbacks_(cpak_callbacks), @@ -127,7 +127,7 @@ namespace VCC::Core void cpak_cartridge::start() { - initialize_(pakContainer_, configuration_path_.c_str(), hVccWnd_, &cpak_callbacks_); + initialize_(SlotId_, configuration_path_.c_str(), hVccWnd_, &cpak_callbacks_); } void cpak_cartridge::stop() diff --git a/mpi/host_cartridge_context.h b/mpi/host_cartridge_context.h index a66f59ff..9f831214 100644 --- a/mpi/host_cartridge_context.h +++ b/mpi/host_cartridge_context.h @@ -21,7 +21,7 @@ // Define the CPAK interface in yet another place but call it something else. extern "C" __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks); @@ -37,9 +37,9 @@ class host_cartridge_context : public ::VCC::Core::cartridge_context public: - explicit host_cartridge_context(void* callback_context, const path_type& configuration_filename) + explicit host_cartridge_context(slot_id_type SlotId, const path_type& configuration_filename) : - callback_context_(callback_context), + SlotId_(SlotId), configuration_filename_(configuration_filename) {} @@ -55,33 +55,33 @@ class host_cartridge_context : public ::VCC::Core::cartridge_context void write_memory_byte(unsigned char value, unsigned short address) override { - write_memory_byte_(callback_context_, value, address); + write_memory_byte_(SlotId_, value, address); } unsigned char read_memory_byte(unsigned short address) override { - return read_memory_byte_(callback_context_, address); + return read_memory_byte_(SlotId_, address); } void assert_cartridge_line(bool line_state) override { - assert_cartridge_line_(callback_context_, line_state); + assert_cartridge_line_(SlotId_, line_state); } void assert_interrupt(Interrupt interrupt, InterruptSource interrupt_source) override { - assert_interrupt_(callback_context_, interrupt, interrupt_source); + assert_interrupt_(SlotId_, interrupt, interrupt_source); } void add_menu_item(const char* menu_name, int menu_id, MenuItemType menu_type) override { - add_menu_item_(callback_context_, menu_name, menu_id, menu_type); + add_menu_item_(SlotId_, menu_name, menu_id, menu_type); } private: friend void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks); @@ -90,11 +90,11 @@ class host_cartridge_context : public ::VCC::Core::cartridge_context private: - void* const callback_context_; + slot_id_type SlotId_; const path_type& configuration_filename_; - PakWriteMemoryByteHostCallback write_memory_byte_ = [](void*, unsigned char, unsigned short) {}; - PakReadMemoryByteHostCallback read_memory_byte_ = [](void*, unsigned short) -> unsigned char { return 0; }; - PakAssertCartridgeLineHostCallback assert_cartridge_line_ = [](void*, bool) {}; - PakAssertInteruptHostCallback assert_interrupt_ = [](void*, Interrupt, InterruptSource) {}; - PakAppendCartridgeMenuHostCallback add_menu_item_ = [](void*, const char*, int, MenuItemType) {}; + PakWriteMemoryByteHostCallback write_memory_byte_ = [](slot_id_type, unsigned char, unsigned short) {}; + PakReadMemoryByteHostCallback read_memory_byte_ = [](slot_id_type, unsigned short) -> unsigned char { return 0; }; + PakAssertCartridgeLineHostCallback assert_cartridge_line_ = [](slot_id_type, bool) {}; + PakAssertInteruptHostCallback assert_interrupt_ = [](slot_id_type, Interrupt, InterruptSource) {}; + PakAppendCartridgeMenuHostCallback add_menu_item_ = [](slot_id_type, const char*, int, MenuItemType) {}; }; diff --git a/mpi/mpi.cpp b/mpi/mpi.cpp index b2b1e0fe..9389ae6d 100644 --- a/mpi/mpi.cpp +++ b/mpi/mpi.cpp @@ -28,8 +28,9 @@ HINSTANCE gModuleInstance = nullptr; static std::string gConfigurationFilename; HWND gVccWnd; +slot_id_type SlotId = 0; const std::shared_ptr - gHostCallbacks(std::make_shared(nullptr, gConfigurationFilename)); + gHostCallbacks(std::make_shared(SlotId, gConfigurationFilename)); // mpi configuration object multipak_configuration gMultiPakConfiguration("MPI"); @@ -59,7 +60,7 @@ extern "C" //Initialize MPI - capture callback addresses and build menus. __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, // allways zero const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) diff --git a/mpi/multipak_cartridge.cpp b/mpi/multipak_cartridge.cpp index aa2a309d..301df45a 100644 --- a/mpi/multipak_cartridge.cpp +++ b/mpi/multipak_cartridge.cpp @@ -26,33 +26,11 @@ namespace { - template - void assert_cartridge_line_on_slot(void* pakContainer, bool line_state) - { - static_cast(pakContainer)->assert_cartridge_line( - SlotIndex_, - line_state); - } - template - void append_menu_item_on_slot(void* pakContainer, const char* text, int id, MenuItemType type) - { - static_cast(pakContainer)->append_menu_item( - SlotIndex_, - { text, static_cast(id), type }); - } - // Per-slot callback table. - struct cartridge_slot_callbacks - { - PakAssertCartridgeLineHostCallback set_cartridge_line; - PakAppendCartridgeMenuHostCallback append_menu_item; - }; - const std::array gSlotCallbacks = { { - { assert_cartridge_line_on_slot<0>, append_menu_item_on_slot<0> }, - { assert_cartridge_line_on_slot<1>, append_menu_item_on_slot<1> }, - { assert_cartridge_line_on_slot<2>, append_menu_item_on_slot<2> }, - { assert_cartridge_line_on_slot<3>, append_menu_item_on_slot<3> } - } }; +// SlotId is an unsigned int 0-4 used to indicate to a cartridge which slot +// it is in. SlotId 0 is the boot slot, SlotId's 1-4 are multipak slots +// mpi_slot indexes used elsewhere in this source differ, they represent only +// multipak mpi_slots and are numbered 0-3, (SlotId = mpi_slot+1) // Is a port a disk port? constexpr std::pair disk_controller_io_port_range = { 0x40, 0x5f }; @@ -95,14 +73,15 @@ void multipak_cartridge::start() cached_scs_slot_ = switch_slot_; // Mount them - for (auto slot(0u); slot < slots_.size(); slot++) + for (auto mpi_slot(0u); mpi_slot < slots_.size(); mpi_slot++) { - const auto path(VCC::Util::find_pak_module_path(configuration_.slot_cartridge_path(slot))); + const auto path(VCC::Util::find_pak_module_path( + configuration_.slot_cartridge_path(mpi_slot))); if (!path.empty()) { - if (mount_cartridge(slot, path) != VCC::Core::cartridge_loader_status::success) { - DLOG_C("Clearing configured slot path %d\n",slot); - configuration_.slot_cartridge_path(slot,""); + if (mount_cartridge(mpi_slot, path) != VCC::Core::cartridge_loader_status::success) { + DLOG_C("Clearing configured slot path %d\n",mpi_slot); + configuration_.slot_cartridge_path(mpi_slot,""); } } } @@ -116,9 +95,9 @@ void multipak_cartridge::stop() { gConfigurationDialog.close(); - for (auto slot(0u); slot < slots_.size(); slot++) + for (auto mpi_slot(0u); mpi_slot < slots_.size(); mpi_slot++) { - eject_cartridge(slot); + eject_cartridge(mpi_slot); } } @@ -126,9 +105,9 @@ void multipak_cartridge::reset() { VCC::Util::section_locker lock(mutex_); - unsigned char slot = switch_slot_ & 3; - switch_slot_ = cached_cts_slot_ = cached_scs_slot_ = slot; - slot_register_ = 0b11001100 | slot | (slot << 4); + unsigned char mpi_slot = switch_slot_ & 3; + switch_slot_ = cached_cts_slot_ = cached_scs_slot_ = mpi_slot; + slot_register_ = 0b11001100 | mpi_slot | (mpi_slot << 4); for (const auto& cartridge_slot : slots_) { @@ -282,80 +261,105 @@ void multipak_cartridge::menu_item_clicked(unsigned char menu_item_id) } -multipak_cartridge::label_type multipak_cartridge::slot_label(slot_id_type slot) const +multipak_cartridge::label_type multipak_cartridge::slot_label(slot_id_type mpi_slot) const { VCC::Util::section_locker lock(mutex_); - return slots_[slot].label(); + return slots_[mpi_slot].label(); } -multipak_cartridge::description_type multipak_cartridge::slot_description(slot_id_type slot) const +multipak_cartridge::description_type multipak_cartridge::slot_description(slot_id_type mpi_slot) const { VCC::Util::section_locker lock(mutex_); - return slots_[slot].description(); + return slots_[mpi_slot].description(); } -bool multipak_cartridge::empty(slot_id_type slot) const +bool multipak_cartridge::empty(slot_id_type mpi_slot) const { VCC::Util::section_locker lock(mutex_); - return slots_[slot].empty(); + return slots_[mpi_slot].empty(); } -void multipak_cartridge::eject_cartridge(slot_id_type slot) +void multipak_cartridge::eject_cartridge(slot_id_type mpi_slot) { VCC::Util::section_locker lock(mutex_); - slots_[slot].stop(); - slots_[slot] = {}; - if (slot == cached_cts_slot_ || slot == switch_slot_) + slots_[mpi_slot].stop(); + slots_[mpi_slot] = {}; + if (mpi_slot == cached_cts_slot_ || mpi_slot == switch_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) + slot_id_type mpi_slot, const path_type& filename) { + // Capture pointer to multipak_cartridge + static multipak_cartridge* self = nullptr; + self = this; + + // Create thunks for slot sensitive callbacks + static auto assert_cartridge_line_thunk = + +[](slot_id_type SlotId, + bool line_state) + { + self->assert_cartridge_line(SlotId, line_state); + }; + + static auto append_menu_item_thunk = + +[](slot_id_type SlotId, + const char* menu_name, + int menu_id, + MenuItemType menu_type) + { + menu_item_type item {menu_name, (unsigned int)menu_id, menu_type}; + self->append_menu_item(SlotId, item); + }; + + // Build callback table for carts loaded on MPI cpak_callbacks callbacks { gHostCallbacks->assert_interrupt_, - gSlotCallbacks[slot].set_cartridge_line, + assert_cartridge_line_thunk, gHostCallbacks->write_memory_byte_, gHostCallbacks->read_memory_byte_, - gSlotCallbacks[slot].append_menu_item + append_menu_item_thunk }; - DLOG_C("%3d %p %p %p %p %p\n",slot,callbacks); + + DLOG_C("%3d %p %p %p %p %p\n",mpi_slot,callbacks); - // 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; + std::size_t SlotId = mpi_slot + 1; // ctx is passed to the loader but not to cartridge DLL's + auto* pakContainer = this; auto ctx = std::make_unique( - slot, + mpi_slot, *context_, - *pakContainer); + *pakContainer); // Why does the loader need this? - DLOG_C("load cart %d %s\n",slot,filename); + DLOG_C("load cart %d %s\n",mpi_slot,filename); auto loadedCartridge = VCC::Core::load_cartridge( filename, std::move(ctx), - pakContainer, - context_->configuration_path(), + SlotId, + context_->configuration_path(), // ini file name gVccWnd, callbacks); - if (loadedCartridge.load_result != mount_status_type::success) - { + if (loadedCartridge.load_result != mount_status_type::success) { // Tell user why load failed - auto error_string(VCC::Core::cartridge_load_error_string(loadedCartridge.load_result)); + auto error_string( + VCC::Core::cartridge_load_error_string( + loadedCartridge.load_result) + ); error_string += "\n\n"; error_string += filename; - MessageBox(GetForegroundWindow(), error_string.c_str(), "Load Error", MB_OK | MB_ICONERROR); + MessageBox(GetForegroundWindow(), + error_string.c_str(), + "Load Error", + MB_OK | MB_ICONERROR); return loadedCartridge.load_result; } @@ -363,22 +367,22 @@ multipak_cartridge::mount_status_type multipak_cartridge::mount_cartridge( VCC::Util::section_locker lock(mutex_); - slots_[slot] = { + slots_[mpi_slot] = { filename, move(loadedCartridge.handle), move(loadedCartridge.cartridge) }; - slots_[slot].start(); - slots_[slot].reset(); + slots_[mpi_slot].start(); + slots_[mpi_slot].reset(); return loadedCartridge.load_result; } // The following has no effect until VCC is reset -void multipak_cartridge::switch_to_slot(slot_id_type slot) +void multipak_cartridge::switch_to_slot(slot_id_type mpi_slot) { - switch_slot_ = slot; + switch_slot_ = mpi_slot; } multipak_cartridge::slot_id_type multipak_cartridge::selected_switch_slot() const @@ -392,28 +396,30 @@ multipak_cartridge::slot_id_type multipak_cartridge::selected_scs_slot() const } // Save cart Menu items into containers per slot -void multipak_cartridge::append_menu_item(slot_id_type slot, menu_item_type item) +void multipak_cartridge::append_menu_item(slot_id_type SlotId, menu_item_type item) { + DLOG_C("menu_item %d %d \n",SlotId,item.menu_id); + + auto mpi_slot = SlotId - 1; + switch (item.menu_id) { case MID_BEGIN: { VCC::Util::section_locker lock(mutex_); - slots_[slot].reset_menu(); + slots_[mpi_slot].reset_menu(); break; } - case MID_FINISH: build_menu(); break; - default: { - // Add 50 times the slot number to control id's + // Add 50 times the slot_id to menu_ids so WinMain knows who is calling if (item.menu_id >= MID_CONTROL) { - item.menu_id += (slot + 1) * 50; + item.menu_id += SlotId * 50; } VCC::Util::section_locker lock(mutex_); - slots_[slot].append_menu_item(item); + slots_[mpi_slot].append_menu_item(item); break; } } @@ -422,27 +428,28 @@ void multipak_cartridge::append_menu_item(slot_id_type slot, menu_item_type item // This gets called any time a cartridge menu is changed. It draws the entire menu. void multipak_cartridge::build_menu() { + // do we really need this here? menu draw should be async VCC::Util::section_locker lock(mutex_); // Init the menu, establish MPI config control, build slot menus, then draw it. context_->add_menu_item("", MID_BEGIN, MIT_Head); context_->add_menu_item("", MID_ENTRY, MIT_Seperator); context_->add_menu_item("MPI Config", ControlId(19), MIT_StandAlone); - for (int slot = 3; slot >= 0; slot--) + for (int mpi_slot = 3; mpi_slot >= 0; mpi_slot--) { - slots_[slot].enumerate_menu_items(*context_); + slots_[mpi_slot].enumerate_menu_items(*context_); } context_->add_menu_item("", MID_FINISH, MIT_Head); // Finish draws the entire menu } - -void multipak_cartridge::assert_cartridge_line(slot_id_type slot, bool line_state) +void multipak_cartridge::assert_cartridge_line(slot_id_type SlotId, bool line_state) { - VCC::Util::section_locker lock(mutex_); + DLOG_C("cart line %d %d \n",SlotId,line_state); - slots_[slot].line_state(line_state); - if (selected_scs_slot() == slot) - { - context_->assert_cartridge_line(slots_[slot].line_state()); + VCC::Util::section_locker lock(mutex_); + auto mpi_slot = SlotId - 1; + slots_[mpi_slot].line_state(line_state); + if (selected_scs_slot() == mpi_slot) { + context_->assert_cartridge_line(slots_[mpi_slot].line_state()); } } diff --git a/mpi/multipak_cartridge_context.h b/mpi/multipak_cartridge_context.h index 00ea1e44..34fdf247 100644 --- a/mpi/multipak_cartridge_context.h +++ b/mpi/multipak_cartridge_context.h @@ -23,7 +23,8 @@ class multipak_cartridge_context : public ::VCC::Core::cartridge_context { public: - multipak_cartridge_context(size_t slot_id, ::VCC::Core::cartridge_context& parent_context, multipak_cartridge& multipak) + multipak_cartridge_context + (size_t slot_id, ::VCC::Core::cartridge_context& parent_context, multipak_cartridge& multipak) : slot_id_(slot_id), parent_context_(parent_context), diff --git a/orch90/orch90.cpp b/orch90/orch90.cpp index 7d2eaf07..38fb9452 100644 --- a/orch90/orch90.cpp +++ b/orch90/orch90.cpp @@ -30,7 +30,7 @@ This file is part of VCC (Virtual Color Computer). #include static HINSTANCE gModuleInstance; -static void* gCallbackContext = nullptr; +static slot_id_type gSlotId {}; static PakAssertCartridgeLineHostCallback PakSetCart = nullptr; static unsigned char LeftChannel=0,RightChannel=0; static unsigned char Rom[8192]; @@ -67,13 +67,13 @@ extern "C" } __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const /*configuration_path*/, HWND hVccWnd, const cpak_callbacks* const callbacks) { DLOG_C("orch90 init\n"); - gCallbackContext = callback_context; + gSlotId = SlotId; PakSetCart = callbacks->assert_cartridge_line; } @@ -100,7 +100,7 @@ extern "C" __declspec(dllexport) void PakReset() { DLOG_C("orch90 reset\n"); - if (LoadRom()) PakSetCart(gCallbackContext, 1); + if (LoadRom()) PakSetCart(gSlotId, 1); } __declspec(dllexport) unsigned char PakReadMemoryByte(unsigned short Address) diff --git a/pakinterface.cpp b/pakinterface.cpp index 6dc08a14..0509a8be 100644 --- a/pakinterface.cpp +++ b/pakinterface.cpp @@ -99,27 +99,27 @@ struct vcc_cartridge_context : public ::VCC::Core::cartridge_context } }; -static void PakAssertCartrigeLine(void* /*callback_context*/, bool line_state) +static void PakAssertCartrigeLine(slot_id_type /*SlotId*/, bool line_state) { SetCart(line_state); } -static void PakWriteMemoryByte(void* /*callback_context*/, unsigned char data, unsigned short address) +static void PakWriteMemoryByte(slot_id_type /*SlotId*/, unsigned char data, unsigned short address) { MemWrite8(data, address); } -static unsigned char PakReadMemoryByte(void* /*callback_context*/, unsigned short address) +static unsigned char PakReadMemoryByte(slot_id_type /*SlotId*/, unsigned short address) { return MemRead8(address); } -static void PakAssertInterupt(void* /*callback_context*/, Interrupt interrupt, InterruptSource source) +static void PakAssertInterupt(slot_id_type /*SlotId*/, Interrupt interrupt, InterruptSource source) { PakAssertInterupt(interrupt, source); } -static void PakAddMenuItem(void* /*callback_context*/, const char* name, int menu_id, MenuItemType type) +static void PakAddMenuItem(slot_id_type /*SlotId*/, const char* name, int menu_id, MenuItemType type) { CartMenuCallBack(name, menu_id, type); } @@ -298,10 +298,12 @@ static cartridge_loader_status load_any_cartridge(const char *filename, const ch PakAddMenuItem }; + slot_id_type SlotId = 0; + auto loadedCartridge = VCC::Core::load_cartridge( filename, std::move(vccContext), - nullptr, // pakContainer goes here + SlotId, iniPath, EmuState.WindowHandle, callbacks); diff --git a/sdc/sdc.cpp b/sdc/sdc.cpp index 2454090b..33e0f7c2 100644 --- a/sdc/sdc.cpp +++ b/sdc/sdc.cpp @@ -164,8 +164,9 @@ namespace util = ::VCC::Util; static HINSTANCE gModuleInstance; // Dll handle static int idle_ctr = 0; // Idle Status counter +static slot_id_type gSlotId {}; + // Callback pointers -static void* gCallbackContext = nullptr; static PakAssertInteruptHostCallback AssertIntCallback = nullptr; static PakAppendCartridgeMenuHostCallback CartMenuCallback = nullptr; @@ -301,14 +302,14 @@ extern "C" { // PakInitialize gets called first, sets up dynamic menues and captures callbacks __declspec(dllexport) void PakInitialize( - void* const callback_context, + slot_id_type SlotId, const char* const configuration_path, HWND hVccWnd, const cpak_callbacks* const callbacks) { gVccWindow = hVccWnd; DLOG_C("SDC %p %p %p %p %p\n",*callbacks); - gCallbackContext = callback_context; + gSlotId = SlotId; CartMenuCallback = callbacks->add_menu_item; AssertIntCallback = callbacks->assert_interrupt; strcpy(IniFile, configuration_path); @@ -435,9 +436,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID rsvd) //------------------------------------------------------------- void BuildCartridgeMenu() { - CartMenuCallback(gCallbackContext, "", MID_BEGIN, MIT_Head); - CartMenuCallback(gCallbackContext, "", MID_ENTRY, MIT_Seperator); - CartMenuCallback(gCallbackContext, "SDC Drive 0",MID_ENTRY,MIT_Head); + CartMenuCallback(gSlotId, "", MID_BEGIN, MIT_Head); + CartMenuCallback(gSlotId, "", MID_ENTRY, MIT_Seperator); + CartMenuCallback(gSlotId, "SDC Drive 0",MID_ENTRY,MIT_Head); char tmp[64]={}; if (strcmp(gCocoDisk[0].name,"") == 0) { strcpy(tmp,"empty"); @@ -449,9 +450,9 @@ void BuildCartridgeMenu() strcat(tmp," (no next)"); } } - CartMenuCallback(gCallbackContext, tmp, ControlId(11),MIT_Slave); - CartMenuCallback(gCallbackContext, "SDC Config", ControlId(10), MIT_StandAlone); - CartMenuCallback(gCallbackContext, "", MID_FINISH, MIT_Head); + CartMenuCallback(gSlotId, tmp, ControlId(11),MIT_Slave); + CartMenuCallback(gSlotId, "SDC Config", ControlId(10), MIT_StandAlone); + CartMenuCallback(gSlotId, "", MID_FINISH, MIT_Head); } //------------------------------------------------------------ @@ -1275,7 +1276,7 @@ void SDCFloppyRestore() FlopStatus = FLP_NORMAL; FlopWrCnt = 0; FlopRdCnt = 0; - AssertIntCallback(gCallbackContext, INT_NMI, IS_NMI); + AssertIntCallback(gSlotId, INT_NMI, IS_NMI); } //---------------------------------------------------------------------- @@ -1368,7 +1369,7 @@ void SDCFloppyWriteData(unsigned char data) } else { FlopStatus = FLP_NORMAL; if ((FlopStatus &= FLP_DATAREQ) != 0) - AssertIntCallback(gCallbackContext, INT_NMI, IS_NMI); + AssertIntCallback(gSlotId, INT_NMI, IS_NMI); } FlopData = data; } @@ -1393,7 +1394,7 @@ unsigned char SDCFloppyReadData() FlopRdCnt--; } else { if ((FlopStatus &= FLP_DATAREQ) != 0) - AssertIntCallback(gCallbackContext, INT_NMI, IS_NMI); + AssertIntCallback(gSlotId, INT_NMI, IS_NMI); FlopStatus = FLP_NORMAL; rpy = 0; }