VidHD: Support SHR for Apple II/II+ models (#997, PR #1013)

. Support aux writes for II/II+ (6502 emulation, not 65C02)
. Extend VidHD save-state for II/II+ aux memory
This commit is contained in:
TomCh 2021-12-19 14:17:51 +00:00 committed by GitHub
parent ff65a9f6bf
commit 577ffccf8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 131 additions and 45 deletions

View File

@ -48,6 +48,8 @@
Remove the SSC card from slot 2.<br><br>
-s3 empty<br>
Remove the Uthernet card from slot 3.<br><br>
-s3 vidhd<br>
Insert a VidHD card into slot 3.<br><br>
-s5 diskii<br>
Insert a 2nd Disk II controller card into slot 5.<br><br>
-s6 empty<br>

View File

@ -8,7 +8,7 @@
link="#008000" vlink="#008000">
<h2 style="COLOR: rgb(0,128,0)">Configuration Settings</h2>
<hr size="4">
<img style="FLOAT: right; WIDTH: 354px; HEIGHT: 460px" src="img/config.png" alt="Configuration settings"
<img style="FLOAT: right; WIDTH: 354px; HEIGHT: 497px" src="img/config.png" alt="Configuration settings"
hspace="5" vspace="5">
<strong>Model:</strong><br>
@ -64,6 +64,13 @@
When in full-screen mode, show floppy (activity and track) and harddisk status (activity); keyboard caps-lock status and if emulation is paused.<br>
<br>
<strong>VidHD in slot 3</strong><br>
Insert a VidHD card into slot 3 (which can co-exist with an 80-column card in the Apple //e's AUX slot).<br>
Allows all Apple II models to support the IIgs' Super Hi-Res (SHR) video modes and is supported by eg. <a href="https://archive.org/details/TotalReplay">Total Replay</a>.<br>
<br>
<hr>
<strong>Serial Port:</strong><br>
This option will remap the emulated Apple's serial port to your PC's serial port (or TCP port 1977).<br>
See <a href="card-ssc.html">Super Serial Card</a> for more details.<br>

View File

@ -42,7 +42,7 @@ then you should leave these values at 0.</li>
On real hardware this card allows up to 4 Atari 9-pin joysticks to be connected.<br>
Under emulation, the first 2 Windows-detected controllers will be used, and then for joysticks 3 and 4, use keys: ESDF+ZX and IJKL+NM. Note these keys will also be readable from the keyboard.<br>
<li>The card can be configured in slots 3, 4 or 5.
<li>Since it only uses the slot's DEVICE SELECT space ($C0Bx for slot 3) then it can co-exist with 80-column cards in the Apple //e's AUX slot. NB. For a real PAL Apple //e, then a slot riser card is required for it to fit.<br>
<li>Since it only uses the slot's DEVICE SELECT space ($C0Bx for slot 3) then it can co-exist with an 80-column card in the Apple //e's AUX slot. NB. For a real PAL Apple //e, then a slot riser card is required for it to fit.<br>
See Lukazi's <a href="https://lukazi.blogspot.com/2016/04/apple-ii-4play-joystick-card.html">4Play card</a> and <a href="https://lukazi.blogspot.com/2017/08/apple-ii-4play-joystick-card-software.html">4Play card software</a> blogs for more information.<br>
<br>
@ -50,7 +50,7 @@ See Lukazi's <a href="https://lukazi.blogspot.com/2016/04/apple-ii-4play-joystic
On real hardware this card allows up to 2 SNES controllers to be connected and all 12 buttons can be read.<br>
Under emulation, the first 2 Windows-detected controllers will be used, ideally with 12 (or more) buttons eg. Logitech F310, PlayStation Dualshock 4, DualSense. Note that for some controllers (eg. 8BitDo NES30 Pro) the buttons need remapping, so use the command line switches -snes-max-alt-joy1 or -snes-max-alt-joy2 to remap.<br>
<li>The card can be configured in slots 3, 4 or 5.
<li>Since it only uses the slot's DEVICE SELECT space ($C0Bx for slot 3) then it can co-exist with 80-column cards in the Apple //e's AUX slot. NB. This card is small, so no slot riser card is required.<br>
<li>Since it only uses the slot's DEVICE SELECT space ($C0Bx for slot 3) then it can co-exist with an 80-column card in the Apple //e's AUX slot. NB. This card is small, so no slot riser card is required.<br>
See Lukazi's <a href="https://lukazi.blogspot.com/2021/06/game-controller-snes-max-snes.html">SNES MAX</a> blog for more information.<br>
<br>
<br>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -34,6 +34,7 @@
<li>No-Slot clock</li>
<li>Uthernet card</li>
<li>4Play & SNES MAX joystick cards</li>
<li>VidHD card</li>
</ul>
The following are not yet persisted to the file:
<ul>

View File

@ -87,8 +87,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
else { \
memdirty[addr >> 8] = 0xFF; \
LPBYTE page = memwrite[addr >> 8]; \
if (page) \
if (page) { \
*(page+(addr & 0xFF)) = (BYTE)(a); \
if (memVidHD) /* GH#997 */\
*(memVidHD + addr) = (BYTE)(a); \
} \
else if ((addr & 0xF000) == 0xC000) \
IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles);\
} \

View File

@ -56,6 +56,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Tape.h"
#include "Tfe/tfe.h"
#include "RGBMonitor.h"
#include "VidHD.h"
#include "z80emu.h"
#include "Z80VICE/z80.h"
@ -142,7 +143,7 @@ SOFT SWITCH STATUS FLAGS
$C011 R7 BSRBANK2 1=bank2 available 0=bank1 available
$C012 R7 BSRREADRAM 1=BSR active for read 0=$D000-$FFFF active (BSR = Bank Switch RAM)
$C013 R7 RAMRD 0=main $0200-$BFFF active reads 1=aux active
$C014 R7 RAMWRT 0=main $0200-$BFFF active writes 1=aux writes
$C014 R7 RAMWRT 0=main $0200-$BFFF active writes 1=aux active
$C015 R7 INTCXROM 1=main $C100-$CFFF ROM active 0=slot active
$C016 R7 ALTZP 1=aux $0000-$1FF+auxBSR 0=main available
$C017 R7 SLOTC3ROM 1=slot $C3 ROM active 0=main $C3 ROM active
@ -238,6 +239,8 @@ static BOOL modechanging = 0; // An Optimisation: means delay calling Upda
static UINT memrompages = 1;
LPBYTE memVidHD = NULL; // For Apple II/II+ writes to aux mem (on VidHD card). memVidHD = memaux or NULL (depends on //e soft-switches)
static CNoSlotClock* g_NoSlotClock = new CNoSlotClock;
#ifdef RAMWORKS
@ -1494,7 +1497,7 @@ bool MemIsAddrCodeMemory(const USHORT addr)
void MemInitialize()
{
// ALLOCATE MEMORY FOR THE APPLE MEMORY IMAGE AND ASSOCIATED DATA STRUCTURES
memaux = ALIGNED_ALLOC(_6502_MEM_LEN);
memaux = ALIGNED_ALLOC(_6502_MEM_LEN); // NB. alloc even if model is Apple II/II+, since it's used by VidHD card
memmain = ALIGNED_ALLOC(_6502_MEM_LEN);
memimage = ALIGNED_ALLOC(_6502_MEM_LEN);
@ -1973,7 +1976,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
#endif
// DETERMINE THE NEW MEMORY PAGING MODE.
if (!IS_APPLE2)
if (IsAppleIIeOrAbove(GetApple2Type()))
{
switch (address)
{
@ -2006,6 +2009,15 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
#endif
}
}
else // Apple ][,][+,][J-Plus or clone ][,][+
{
if (GetCardMgr().QuerySlot(SLOT3) == CT_VidHD)
{
VidHDCard* vidHD = dynamic_cast<VidHDCard*>(GetCardMgr().GetObj(SLOT3));
vidHD->VideoIOWrite(programcounter, address, write, value, nExecutedCycles);
memVidHD = vidHD->IsWriteAux() ? memaux : NULL;
}
}
if (IsCopamBase64A(GetApple2Type()))
{

View File

@ -25,6 +25,8 @@
enum
{
// Note: All are in bytes!
TEXT_PAGE1_BEGIN = 0x0400,
APPLE_SLOT_SIZE = 0x0100, // 1 page = $Cx00 .. $CxFF (slot 1 .. 7)
APPLE_IO_BEGIN = 0xC000,
APPLE_SLOT_BEGIN = 0xC100, // each slot has 1 page reserved for it
@ -57,6 +59,7 @@ extern iofunction IOWrite[256];
extern LPBYTE memwrite[0x100];
extern LPBYTE mem;
extern LPBYTE memdirty;
extern LPBYTE memVidHD;
#ifdef RAMWORKS
const UINT kMaxExMemoryBanks = 127; // 127 * aux mem(64K) + main mem(64K) = 8MB

View File

@ -22,15 +22,33 @@
*/
/*
Emulate a VidHD card (Blue Shift Inc)
* Partial support only *
Allows any Apple II to support the IIgs' 320x200 and 640x200 256-colour Super High-Res video modes.
Currently only a //e with 64K aux memory supports SHR mode.
NB. The extended text modes 80x45, 120x67, 240x135 (and setting FG/BG colours) are not supported yet.
NB. Not supported yet:
. Apple II/II+ support for //e video modes (TEXT80, DGR, DHGR).
. IIgs SCREEN & BORDER COLOR.
. IIgs B&W DHGR.
. The VidHD extended text modes 80x45, 120x67, 240x135 (and setting FG/BG colours).
. Enable/disable VidHD soft-switch.
Implementation notes:
. II/II+
. Mirrors the 80STORE/PAGE2/AUXREAD/AUXWRITE switches to VidHD.
. Reuses 'memaux' that's for the //e models.
. AUXWRITE=1: writes occur to both main & memaux.
. 80STORE=1 && PAGE2=1: same as AUXWRITE=1 (but should be changed to *only* allow writes to aux's TEXT1 & HGR2 areas).
. Only 6502 (not 65C02) emulation supports this dual write to main & memaux (via the 'memVidHD' pointer):
- So a II/II+ with a 65C02 won't correctly support VidHD cards.
- And a //e with a 6502 will incur a slight overhead to test 'memVidHD' pointer (which is always NULL for //e's).
. VidHD card's save-state includes VidHD's aux mem ($400-$9FFF).
. //e with 1KiB 80-Col card: AppleWin doesn't support this - so currently out of scope.
*/
#include "StdAfx.h"
#include "Core.h"
#include "Memory.h"
#include "NTSC.h"
#include "Video.h"
@ -65,23 +83,28 @@ void VidHDCard::VideoIOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG
{
switch (addr & 0xff)
{
case 0x22: // SCREENCOLOR
m_SCREENCOLOR = value;
break;
case 0x29: // NEWVIDEO
m_NEWVIDEO = value;
break;
case 0x34: // BORDERCOLOR
m_BORDERCOLOR = value;
break;
case 0x35: // SHADOW
m_SHADOW = value;
break;
default:
_ASSERT(0);
case 0x00: m_memMode &= ~MF_80STORE; break;
case 0x01: m_memMode |= MF_80STORE; break;
case 0x02: m_memMode &= ~MF_AUXREAD; break;
case 0x03: m_memMode |= MF_AUXREAD; break;
case 0x04: m_memMode &= ~MF_AUXWRITE; break;
case 0x05: m_memMode |= MF_AUXWRITE; break;
case 0x54: m_memMode &= ~MF_PAGE2; break;
case 0x55: m_memMode |= MF_PAGE2; break;
// IIgs registers
case 0x22: m_SCREENCOLOR = value; break;
case 0x29: m_NEWVIDEO = value; break;
case 0x34: m_BORDERCOLOR = value; break;
case 0x35: m_SHADOW = value; break;
}
}
bool VidHDCard::IsWriteAux(void)
{
return (m_memMode & MF_AUXWRITE) || // Write to aux: $200-$BFFF
((m_memMode & MF_80STORE) && (m_memMode & MF_PAGE2)); // Write to aux: $400-$7FF and $2000-$3FFF
}
//===========================================================================
#pragma pack(push)
@ -154,6 +177,7 @@ void VidHDCard::UpdateSHRCell(bool is640Mode, bool isColorFillMode, uint16_t add
static const UINT kUNIT_VERSION = 1;
#define SS_YAML_KEY_MEMORYMODE "Memory Mode"
#define SS_YAML_KEY_SCREEN_COLOR "Screen Color"
#define SS_YAML_KEY_NEW_VIDEO "New Video"
#define SS_YAML_KEY_BORDER_COLOR "Border Color"
@ -165,15 +189,31 @@ std::string VidHDCard::GetSnapshotCardName(void)
return name;
}
static std::string MemGetSnapshotAuxMemStructName(void)
{
static const std::string name("Auxiliary Memory Bank");
return name;
}
void VidHDCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, m_memMode);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SCREEN_COLOR, m_SCREENCOLOR);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_NEW_VIDEO, m_NEWVIDEO);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_BORDER_COLOR, m_BORDERCOLOR);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SHADOW, m_SHADOW);
if (IsApple2PlusOrClone(GetApple2Type())) // Save aux mem for II/II+
{
// Save [$400-$9FFF]
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotAuxMemStructName().c_str());
LPBYTE pMemBase = MemGetBankPtr(1);
yamlSaveHelper.SaveMemory(pMemBase, (SHR_MEMORY_END + 1) - TEXT_PAGE1_BEGIN, TEXT_PAGE1_BEGIN);
}
}
bool VidHDCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
@ -181,10 +221,23 @@ bool VidHDCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
if (version < 1 || version > kUNIT_VERSION)
throw std::runtime_error("Card: wrong version");
m_memMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE);
m_SCREENCOLOR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SCREEN_COLOR);
m_NEWVIDEO = yamlLoadHelper.LoadUint(SS_YAML_KEY_NEW_VIDEO);
m_BORDERCOLOR = yamlLoadHelper.LoadUint(SS_YAML_KEY_BORDER_COLOR);
m_SHADOW = yamlLoadHelper.LoadUint(SS_YAML_KEY_SHADOW);
if (IsApple2PlusOrClone(GetApple2Type())) // Load aux mem for II/II+
{
// Load [$400-$9FFF]
if (!yamlLoadHelper.GetSubMap(MemGetSnapshotAuxMemStructName()))
throw std::runtime_error("Memory: Missing map name: " + MemGetSnapshotAuxMemStructName());
LPBYTE pMemBase = MemGetBankPtr(1);
yamlLoadHelper.LoadMemory(pMemBase, (SHR_MEMORY_END + 1) - TEXT_PAGE1_BEGIN, TEXT_PAGE1_BEGIN);
yamlLoadHelper.PopMap();
}
return true;
}

View File

@ -9,6 +9,7 @@ public:
VidHDCard(UINT slot) :
Card(CT_VidHD, slot)
{
m_memMode = 0;
m_SCREENCOLOR = 0;
m_NEWVIDEO = 0;
m_BORDERCOLOR = 0;
@ -27,8 +28,9 @@ public:
void VideoIOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
bool IsSHR(void) { return (m_NEWVIDEO & 0xC0) == 0xC0; } // 11000001 = Enable SHR(b7) | Linearize SHR video memory(b6)
bool IsSHR(void) { return (m_NEWVIDEO & 0xC0) == 0xC0; } // 11000000 = Enable SHR(b7) | Linearize SHR video memory(b6)
bool IsDHGRBlackAndWhite(void) { return (m_NEWVIDEO & (1 << 5)) ? true : false; }
bool IsWriteAux(void);
static void UpdateSHRCell(bool is640Mode, bool isColorFillMode, uint16_t addrPalette, bgra_t* pVideoAddress, uint32_t a);
@ -37,6 +39,8 @@ public:
virtual bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version);
private:
const UINT SHR_MEMORY_END = 0x9FFF;
UINT m_memMode; // Only used by II/II+
BYTE m_SCREENCOLOR;
BYTE m_NEWVIDEO;
BYTE m_BORDERCOLOR;

View File

@ -198,7 +198,7 @@ std::string YamlHelper::GetMapValue(MapYaml& mapYaml, const std::string& key, bo
return value;
}
bool YamlHelper::GetSubMap(MapYaml** mapYaml, const std::string& key, const bool canBeNull = false)
bool YamlHelper::GetSubMap(MapYaml** mapYaml, const std::string& key, const bool canBeNull/*=false*/)
{
MapYaml::const_iterator iter = (*mapYaml)->find(key);
if (iter == (*mapYaml)->end() || (!canBeNull && iter->second.subMap == NULL))
@ -247,7 +247,7 @@ void YamlHelper::MakeAsciiToHexTable(void)
m_AsciiToHex[i] = i - 'a' + 0xA;
}
UINT YamlHelper::LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize)
UINT YamlHelper::LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize, const UINT offset)
{
UINT bytes = 0;
@ -255,11 +255,11 @@ UINT YamlHelper::LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_
{
const char* pKey = it->first.c_str();
UINT addr = strtoul(pKey, NULL, 16);
if (addr >= kAddrSpaceSize)
if (addr >= (kAddrSpaceSize + offset))
throw std::runtime_error("Memory: line address too big: " + it->first);
LPBYTE pDst = (LPBYTE) (pMemBase + addr);
const LPBYTE pDstEnd = (LPBYTE) (pMemBase + kAddrSpaceSize);
const LPBYTE pDstEnd = (LPBYTE) (pMemBase + kAddrSpaceSize + offset);
if (it->second.subMap)
throw std::runtime_error("Memory: unexpected sub-map");
@ -385,15 +385,15 @@ double YamlLoadHelper::LoadDouble(const std::string& key)
return strtod(value.c_str(), NULL);
}
void YamlLoadHelper::LoadMemory(const LPBYTE pMemBase, const size_t size)
void YamlLoadHelper::LoadMemory(const LPBYTE pMemBase, const size_t size, const UINT offset/*=0*/)
{
m_yamlHelper.LoadMemory(*m_pMapYaml, pMemBase, size);
m_yamlHelper.LoadMemory(*m_pMapYaml, pMemBase, size, offset);
}
void YamlLoadHelper::LoadMemory(std::vector<BYTE>& memory, const size_t size)
void YamlLoadHelper::LoadMemory(std::vector<BYTE>& memory, const size_t size, const UINT offset/*=0*/)
{
memory.reserve(size); // expand (but don't shrink) vector's capacity (NB. vector's size doesn't change)
const UINT bytes = m_yamlHelper.LoadMemory(*m_pMapYaml, &memory[0], size);
const UINT bytes = m_yamlHelper.LoadMemory(*m_pMapYaml, &memory[0], size, offset);
memory.resize(bytes); // resize so that vector contains /bytes/ elements - so that size() gives correct value.
}
@ -519,7 +519,7 @@ void YamlSaveHelper::SaveDouble(const char* key, double value)
}
// Pre: uMemSize must be multiple of 8
void YamlSaveHelper::SaveMemory(const LPBYTE pMemBase, const UINT uMemSize)
void YamlSaveHelper::SaveMemory(const LPBYTE pMemBase, const UINT uMemSize, const UINT offset/*=0*/)
{
if (uMemSize & 7)
throw std::runtime_error("Memory: size must be multiple of 8");
@ -532,23 +532,23 @@ void YamlSaveHelper::SaveMemory(const LPBYTE pMemBase, const UINT uMemSize)
size_t lineSize = kIndent+6+2*kStride+2; // "AAAA: 00010203...3F\n\00" = 6+ 2*64 +2
char* const pLine = new char [lineSize];
for(DWORD dwOffset = 0x0000; dwOffset < uMemSize; dwOffset+=kStride)
for (DWORD addr = offset; addr < (uMemSize + offset); addr += kStride)
{
char* pDst = pLine;
for (UINT i=0; i<kIndent; i++)
*pDst++ = ' ';
*pDst++ = szHex[ (dwOffset>>12)&0xf ];
*pDst++ = szHex[ (dwOffset>>8)&0xf ];
*pDst++ = szHex[ (dwOffset>>4)&0xf ];
*pDst++ = szHex[ dwOffset&0xf ];
*pDst++ = szHex[ (addr>>12)&0xf ];
*pDst++ = szHex[ (addr>>8)&0xf ];
*pDst++ = szHex[ (addr>>4)&0xf ];
*pDst++ = szHex[ addr&0xf ];
*pDst++ = ':';
*pDst++ = ' ';
LPBYTE pMem = pMemBase + dwOffset;
LPBYTE pMem = pMemBase + addr;
for (UINT i=0; i<kStride; i+=8)
{
if (dwOffset + i >= uMemSize) // Support short final line (still multiple of 8 bytes)
if (addr + i >= (uMemSize + offset)) // Support short final line (still multiple of 8 bytes)
{
lineSize = lineSize - 2*kStride + 2*i;
break;

View File

@ -49,8 +49,8 @@ private:
void GetNextEvent(void);
int ParseMap(MapYaml& mapYaml);
std::string GetMapValue(MapYaml& mapYaml, const std::string &key, bool& bFound);
UINT LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize);
bool GetSubMap(MapYaml** mapYaml, const std::string &key, const bool canBeNull /*= false*/);
UINT LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize, const UINT offset);
bool GetSubMap(MapYaml** mapYaml, const std::string &key, const bool canBeNull=false);
void GetMapRemainder(std::string& mapName, MapYaml& mapYaml);
void MakeAsciiToHexTable(void);
@ -100,8 +100,8 @@ public:
std::string LoadString(const std::string& key);
float LoadFloat(const std::string & key);
double LoadDouble(const std::string & key);
void LoadMemory(const LPBYTE pMemBase, const size_t size);
void LoadMemory(std::vector<BYTE>& memory, const size_t size);
void LoadMemory(const LPBYTE pMemBase, const size_t size, const UINT offset=0);
void LoadMemory(std::vector<BYTE>& memory, const size_t size, const UINT offset=0);
bool GetSubMap(const std::string & key, const bool canBeNull=false)
{
@ -228,7 +228,7 @@ public:
void SaveString(const char* key, const std::string & value);
void SaveFloat(const char* key, float value);
void SaveDouble(const char* key, double value);
void SaveMemory(const LPBYTE pMemBase, const UINT uMemSize);
void SaveMemory(const LPBYTE pMemBase, const UINT uMemSize, const UINT offset=0);
class Label
{

View File

@ -14,6 +14,7 @@ SynchronousEventManager g_SynchronousEventMgr;
LPBYTE memwrite[0x100]; // TODO: Init
LPBYTE mem = NULL; // TODO: Init
LPBYTE memdirty = NULL; // TODO: Init
LPBYTE memVidHD = NULL; // TODO: Init
iofunction IORead[256] = {0}; // TODO: Init
iofunction IOWrite[256] = {0}; // TODO: Init