Add support for PAL/European or custom 8K video ROMs (#596)

Added new cmd-line switch: -videorom <file> to replace the video ROM for the Enhanced //e.
- Support video ROM sizes of 4K, 8K and 16K (top 8K only).
- NB. The rocker switch is set to European video ROM.
F10 (for //e or Enhanced //e models) emulates the PAL //e's rocker switch (under the keyboard) to toggle between European or US video ROM.

Other:
- Fixed debugger's view of the AltCharSet soft-switch (it was showing the opposite state).
This commit is contained in:
TomCh 2018-11-17 16:29:17 +00:00 committed by GitHub
parent 14e0bb7b71
commit aa59c71847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 208 additions and 20 deletions

View File

@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,27,10,0
PRODUCTVERSION 1,27,10,0
FILEVERSION 1,27,11,0
PRODUCTVERSION 1,27,11,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -271,12 +271,12 @@ BEGIN
VALUE "Comments", "https://github.com/AppleWin"
VALUE "CompanyName", "AppleWin"
VALUE "FileDescription", "Apple //e Emulator for Windows"
VALUE "FileVersion", "1, 27, 10, 0"
VALUE "FileVersion", "1, 27, 11, 0"
VALUE "InternalName", "APPLEWIN"
VALUE "LegalCopyright", " 1994-2018 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis"
VALUE "OriginalFilename", "APPLEWIN.EXE"
VALUE "ProductName", "Apple //e Emulator"
VALUE "ProductVersion", "1, 27, 10, 0"
VALUE "ProductVersion", "1, 27, 11, 0"
END
END
BLOCK "VarFileInfo"

View File

@ -1289,6 +1289,22 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800))
g_bCustomRomF8Failed = true;
}
else if (strcmp(lpCmdLine, "-videorom") == 0) // Use 4K,8K or 16K video ROM for Enhanced //e
{
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
if (!ReadVideoRomFile(lpCmdLine))
{
std::string msg = "Failed to load video rom (not found or not exactly 4/8/16KiB)";
LogFileOutput("%s", msg.c_str());
MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK);
}
else
{
SetVideoRomRockerSwitch(true); // Use PAL char set
}
}
else if (strcmp(lpCmdLine, "-printscreen") == 0) // Turn on display of the last filename print screen was saved to
{
g_bDisplayPrintScreenFileName = true;
@ -1553,7 +1569,9 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
if (g_bCustomRomF8Failed)
{
MessageBox(g_hFrameWindow, "Failed to load custom F8 rom (not found or not exactly 2KB)", TEXT("AppleWin Error"), MB_OK);
std::string msg = "Failed to load custom F8 rom (not found or not exactly 2KiB)";
LogFileOutput("%s", msg.c_str());
MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK);
bShutdown = true;
}

View File

@ -3089,7 +3089,7 @@ void DrawSoftSwitches( int iSoftSwitch )
_DrawSoftSwitch( rect, 0xC00C, bSet, "Col", "40", "80", NULL, bgMemory );
// C00E = off, C00F = on
bSet = VideoGetSWAltCharSet();
bSet = !VideoGetSWAltCharSet();
_DrawSoftSwitch( rect, 0xC00E, bSet, NULL, "ASC", "MOUS", NULL, bgMemory ); // ASCII/MouseText
#if SOFTSWITCH_LANGCARD

View File

@ -1316,14 +1316,19 @@ LRESULT CALLBACK FrameWndProc (
}
else if (wparam == VK_F10)
{
if (g_Apple2Type == A2TYPE_PRAVETS8A && !KeybGetCtrlStatus())
{
KeybToggleP8ACapsLock (); // F10: Toggles P8 Capslock
}
else
if (KeybGetCtrlStatus())
{
SetUsingCursor(FALSE); // Ctrl+F10
}
else if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED)
{
SetVideoRomRockerSwitch( !GetVideoRomRockerSwitch() ); // F10: toggle rocker switch
NTSC_VideoInitAppleType();
}
else if (g_Apple2Type == A2TYPE_PRAVETS8A)
{
KeybToggleP8ACapsLock (); // F10: Toggles Pravets8A Capslock
}
}
else if (wparam == VK_F11 && !KeybGetCtrlStatus()) // Save state (F11)
{
@ -1758,7 +1763,6 @@ LRESULT CALLBACK FrameWndProc (
KeybUpdateCtrlShiftStatus();
// http://msdn.microsoft.com/en-us/library/windows/desktop/gg153546(v=vs.85).aspx
// v1.25.0: Alt-Return Alt-Enter toggle fullscreen
if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
return 0; // NOP -- eat key
@ -1772,7 +1776,10 @@ LRESULT CALLBACK FrameWndProc (
case WM_SYSKEYUP:
KeybUpdateCtrlShiftStatus();
// v1.25.0: Alt-Return Alt-Enter toggle fullscreen
// F10: no WM_KEYUP handler for VK_F10. Don't allow WM_KEYUP to pass to default handler which will show the app window's "menu" (and lose focus)
if (wparam == VK_F10)
return 0;
if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
ScreenWindowResize(false);
else

View File

@ -471,7 +471,7 @@ static void set_csbits()
case A2TYPE_APPLE2: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2PLUS: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2E: csbits = &csbits_2e[0]; break;
case A2TYPE_APPLE2EENHANCED:csbits = &csbits_enhanced2e[0]; break;
case A2TYPE_APPLE2EENHANCED:csbits = GetEnhanced2e_csbits(); break;
case A2TYPE_PRAVETS82: csbits = &csbits_pravets82[0]; g_nVideoCharSet = 0; break; // Apple ][ clone
case A2TYPE_PRAVETS8M: csbits = &csbits_pravets8M[0]; g_nVideoCharSet = 0; break; // Apple ][ clone
case A2TYPE_PRAVETS8A: csbits = &csbits_pravets8C[0]; break; // Apple //e clone

View File

@ -21,10 +21,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "Applewin.h"
#include "Video.h"
#include "NTSC_CharSet.h"
unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e
unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
static unsigned char csbits_enhanced2e_pal[2][256][8]; // PAL Enhanced //e (2764 8K video ROM - top 4K) via rocker switch under keyboard
unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext)
unsigned char csbits_a2[1][256][8]; // ][ and ][+
unsigned char csbits_pravets82[1][256][8]; // Pravets 82
@ -86,6 +88,91 @@ static void get_csbits(csbits_t csbits, const char* resourceName, const UINT cy0
delete [] pBuffer;
}
//-------------------------------------
// ROM address (RA):
// -----------------
// . RA10,..,RA3;SEGC,SEGB,SEGA => [2^8][2^3] => 256 chars of 8 lines (total = 2KiB)
// . VID7,..,VID0 is the 8-bit video character (eg. from TEXT/$400 memory)
//
// UTAIIe:8-13, Table 8.2:
//
// ALTCHRSET | RA10 | RA9
//------------------------------------------
// 0 | VID7 + VID6.FLASH | VID6.VID7
// 1 | VID7 | VID6
//
// FLASH toggles every 16 VBLs, so alternates between selecting NORMAL control/special and INVERSE control/special
//
void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
{
int RA = 0; // rom address
int i = 0;
// regular char set
for (; i<64; i++, RA+=8) // [00..3F] INVERSE / [40..7F] FLASH
{
for (int y=0; y<8; y++)
{
csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
csbits[0][i+64][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-14 (Table 8.3) we use FLASH=0, so RA=00ccccccsss
}
}
RA = (1<<10 | 0<<9); // UTAIIe:8-14 (Table 8.3)
for (i=128; i<256; i++, RA+=8) // [80..BF] NORMAL
{
for (int y=0; y<8; y++)
{
csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
}
}
RA = (1<<10 | 1<<9); // UTAIIe:8-14 (Table 8.3)
for (i=192; i<256; i++, RA+=8) // [C0..FF] NORMAL
{
for (int y=0; y<8; y++)
{
csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
}
}
// alt char set
RA = 0;
for (i=0; i<256; i++, RA+=8) // [00..7F] INVERSE / [80..FF] NORMAL
{
for (int y=0; y<8; y++)
{
csbits[1][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
}
}
}
void userVideoRom(void)
{
const BYTE* pVideoRom;
UINT size = GetVideoRom(pVideoRom); // 4K or 8K
if (!size)
return;
if (size == kVideoRomSize4K)
{
userVideoRom4K(&csbits_enhanced2e[0], pVideoRom);
return;
}
userVideoRom4K(&csbits_enhanced2e_pal[0], pVideoRom);
userVideoRom4K(&csbits_enhanced2e[0], &pVideoRom[4*1024]);
}
//-------------------------------------
void make_csbits(void)
{
get_csbits(&csbits_enhanced2e[0], TEXT("CHARSET40"), 0); // Enhanced //e: Alt char set off
@ -99,4 +186,15 @@ void make_csbits(void)
// Original //e is just Enhanced //e with the 32 mousetext chars [0x40..0x5F] replaced by the non-alt charset chars [0x40..0x5F]
memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e));
memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8);
// Try to use any user-provided video ROM for Enhanced //e
userVideoRom();
}
csbits_t GetEnhanced2e_csbits(void)
{
if (IsVideoRom4K())
return csbits_enhanced2e;
return GetVideoRomRockerSwitch() == false ? csbits_enhanced2e : csbits_enhanced2e_pal;
}

View File

@ -2,7 +2,7 @@
typedef unsigned char (*csbits_t)[256][8];
extern unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e
extern unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
extern unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext)
extern unsigned char csbits_a2[1][256][8]; // ][ and ][+
extern unsigned char csbits_pravets82[1][256][8]; // Pravets 82
@ -10,3 +10,4 @@ extern unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
extern unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C
void make_csbits(void);
csbits_t GetEnhanced2e_csbits(void);

View File

@ -647,7 +647,7 @@ void VideoResetState ()
//===========================================================================
BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
BYTE VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
{
address &= 0xFF;
@ -1141,6 +1141,65 @@ static void Video_SaveScreenShot( const char *pScreenShotFileName, const VideoSc
}
}
//===========================================================================
static const UINT kVideoRomSize8K = kVideoRomSize4K*2;
static const UINT kVideoRomSize16K = kVideoRomSize8K*2;
static const UINT kVideoRomSizeMax = kVideoRomSize16K;
static BYTE g_videoRom[kVideoRomSizeMax];
static UINT g_videoRomSize = 0;
static bool g_videoRomRockerSwitch = false;
bool ReadVideoRomFile(const char* pRomFile)
{
g_videoRomSize = 0;
HANDLE h = CreateFile(pRomFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (h == INVALID_HANDLE_VALUE)
return false;
const ULONG size = GetFileSize(h, NULL);
if (size == kVideoRomSize4K || size == kVideoRomSize8K || size == kVideoRomSize16K)
{
DWORD bytesRead;
if (ReadFile(h, g_videoRom, size, &bytesRead, NULL) && bytesRead == size)
g_videoRomSize = size;
}
if (g_videoRomSize == kVideoRomSize16K)
{
// Use top 8K (assume bottom 8K is all 0xFF's)
memcpy(&g_videoRom[0], &g_videoRom[kVideoRomSize8K], kVideoRomSize8K);
g_videoRomSize = kVideoRomSize8K;
}
CloseHandle(h);
return g_videoRomSize != 0;
}
UINT GetVideoRom(const BYTE*& pVideoRom)
{
pVideoRom = &g_videoRom[0];
return g_videoRomSize;
}
bool GetVideoRomRockerSwitch(void)
{
return g_videoRomRockerSwitch;
}
void SetVideoRomRockerSwitch(bool state)
{
g_videoRomRockerSwitch = state;
}
bool IsVideoRom4K(void)
{
return g_videoRomSize == 0 || g_videoRomSize == kVideoRomSize4K;
}
//===========================================================================
void Config_Load_Video()
@ -1160,8 +1219,6 @@ void Config_Save_Video()
REGSAVE(TEXT(REGVALUE_VIDEO_MONO_COLOR ),g_nMonochromeRGB);
}
// ____________________________________________________________________
//===========================================================================
static void videoCreateDIBSection()
{

View File

@ -198,7 +198,14 @@ enum VideoScreenShot_e
void Video_TakeScreenShot( VideoScreenShot_e iScreenShotType );
void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel );
BYTE VideoSetMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
BYTE VideoSetMode(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
const UINT kVideoRomSize4K = 4*1024;
bool ReadVideoRomFile(const char* pRomFile);
UINT GetVideoRom(const BYTE*& pVideoRom);
bool GetVideoRomRockerSwitch(void);
void SetVideoRomRockerSwitch(bool state);
bool IsVideoRom4K(void);
void Config_Load_Video(void);
void Config_Save_Video(void);