Support Apple II J-Plus model (#773, PR #776)

. Added II-JPlus rom & video rom
. Added new apple2jp model
. Fixed support for AN3 for II/II+ models (nothing to do with J-Plus support)
This commit is contained in:
TomCh 2020-04-02 20:17:32 +01:00 committed by GitHub
parent 5177c093fb
commit dd2914a38e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 109 additions and 18 deletions

View File

@ -1091,6 +1091,14 @@
RelativePath=".\resource\Apple2_Plus.rom"
>
</File>
<File
RelativePath=".\resource\Apple2_JPlus.rom"
>
</File>
<File
RelativePath=".\resource\Apple2_JPlus_Video.rom"
>
</File>
<File
RelativePath=".\resource\Apple2e.rom"
>

BIN
resource/Apple2_JPlus.rom Normal file

Binary file not shown.

Binary file not shown.

View File

@ -325,6 +325,7 @@ IDR_TKCLOCK_FW FIRMWARE "TKClock.rom"
IDR_APPLE2_ROM ROM "Apple2.rom"
IDR_APPLE2_PLUS_ROM ROM "Apple2_Plus.rom"
IDR_APPLE2_JPLUS_ROM ROM "Apple2_JPlus.rom"
IDR_APPLE2E_ROM ROM "Apple2e.rom"
IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom"
IDR_PRAVETS_82_ROM ROM "Pravets82.rom"
@ -333,6 +334,13 @@ IDR_PRAVETS_8C_ROM ROM "Pravets8C.rom"
IDR_TK3000_2E_ROM ROM "TK3000e.rom"
IDR_FREEZES_F8_ROM ROM "FREEZES_NON-AUTOSTART_F8_ROM.rom"
/////////////////////////////////////////////////////////////////////////////
//
// VIDEO ROM
//
IDR_APPLE2_JPLUS_VIDEO_ROM ROM "Apple2_JPlus_Video.rom"
/////////////////////////////////////////////////////////////////////////////
//
// Menu

View File

@ -49,6 +49,8 @@
#define IDR_TKCLOCK_FW 148
#define IDR_DISK2_13SECTOR_FW 149
#define IDR_DISK2_16SECTOR_FW 150
#define IDR_APPLE2_JPLUS_ROM 151
#define IDR_APPLE2_JPLUS_VIDEO_ROM 152
#define IDC_KEYB_BUFFER_ENABLE 1005
#define IDC_SAVESTATE 1006
#define IDC_SAVESTATE_ON_EXIT 1007

View File

@ -1692,6 +1692,8 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
g_cmdLine.model = A2TYPE_APPLE2;
else if (strcmp(lpCmdLine, "apple2p") == 0)
g_cmdLine.model = A2TYPE_APPLE2PLUS;
else if (strcmp(lpCmdLine, "apple2jp") == 0)
g_cmdLine.model = A2TYPE_APPLE2JPLUS;
else if (strcmp(lpCmdLine, "apple2e") == 0)
g_cmdLine.model = A2TYPE_APPLE2E;
else if (strcmp(lpCmdLine, "apple2ee") == 0)

View File

@ -48,6 +48,7 @@ enum AppMode_e
// TODO: Move to StringTable.h
#define TITLE_APPLE_2 TEXT("Apple ][ Emulator")
#define TITLE_APPLE_2_PLUS TEXT("Apple ][+ Emulator")
#define TITLE_APPLE_2_JPLUS TEXT("Apple ][ J-Plus Emulator")
#define TITLE_APPLE_2E TEXT("Apple //e Emulator")
#define TITLE_APPLE_2E_ENHANCED TEXT("Enhanced Apple //e Emulator")
#define TITLE_APPLE_2C TEXT("Apple //e Emulator")
@ -168,6 +169,7 @@ enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE};
enum eApple2Type {
A2TYPE_APPLE2=0,
A2TYPE_APPLE2PLUS,
A2TYPE_APPLE2JPLUS,
A2TYPE_APPLE2E=APPLE2E_MASK,
A2TYPE_APPLE2EENHANCED,
A2TYPE_UNDEFINED,
@ -196,17 +198,22 @@ inline bool IsApple2Original(eApple2Type type) // Apple ][
return type == A2TYPE_APPLE2;
}
inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+
inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+,][J-Plus
{
return ((type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) && !(type & APPLECLONE_MASK);
}
inline bool IsApple2JPlus(eApple2Type type) // Apple ][J-Plus
{
return type == A2TYPE_APPLE2JPLUS;
}
inline bool IsClone(eApple2Type type)
{
return (type & APPLECLONE_MASK) != 0;
}
inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+ or clone ][,][+
inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+,][J-Plus or clone ][,][+
{
return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0;
}

View File

@ -34,10 +34,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
CPageConfig* CPageConfig::ms_this = 0; // reinit'd in ctor
enum APPLEIICHOICE {MENUITEM_IIORIGINAL, MENUITEM_IIPLUS, MENUITEM_IIE, MENUITEM_ENHANCEDIIE, MENUITEM_CLONE};
enum APPLEIICHOICE {MENUITEM_IIORIGINAL, MENUITEM_IIPLUS, MENUITEM_IIJPLUS, MENUITEM_IIE, MENUITEM_ENHANCEDIIE, MENUITEM_CLONE};
const TCHAR CPageConfig::m_ComputerChoices[] =
TEXT("Apple ][ (Original)\0")
TEXT("Apple ][+\0")
TEXT("Apple ][ J-Plus\0")
TEXT("Apple //e\0")
TEXT("Enhanced Apple //e\0")
TEXT("Clone\0");
@ -182,6 +183,7 @@ BOOL CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM
{
case A2TYPE_APPLE2: nCurrentChoice = MENUITEM_IIORIGINAL; break;
case A2TYPE_APPLE2PLUS: nCurrentChoice = MENUITEM_IIPLUS; break;
case A2TYPE_APPLE2JPLUS: nCurrentChoice = MENUITEM_IIJPLUS; break;
case A2TYPE_APPLE2E: nCurrentChoice = MENUITEM_IIE; break;
case A2TYPE_APPLE2EENHANCED:nCurrentChoice = MENUITEM_ENHANCEDIIE; break;
case A2TYPE_PRAVETS82: nCurrentChoice = MENUITEM_CLONE; break;
@ -380,6 +382,7 @@ eApple2Type CPageConfig::GetApple2Type(DWORD NewMenuItem)
{
case MENUITEM_IIORIGINAL: return A2TYPE_APPLE2;
case MENUITEM_IIPLUS: return A2TYPE_APPLE2PLUS;
case MENUITEM_IIJPLUS: return A2TYPE_APPLE2JPLUS;
case MENUITEM_IIE: return A2TYPE_APPLE2E;
case MENUITEM_ENHANCEDIIE: return A2TYPE_APPLE2EENHANCED;
case MENUITEM_CLONE: return A2TYPE_CLONE;

View File

@ -256,6 +256,7 @@ static void GetAppleWindowTitle()
default:
case A2TYPE_APPLE2: g_pAppTitle = TITLE_APPLE_2 ; break;
case A2TYPE_APPLE2PLUS: g_pAppTitle = TITLE_APPLE_2_PLUS ; break;
case A2TYPE_APPLE2JPLUS: g_pAppTitle = TITLE_APPLE_2_JPLUS ; break;
case A2TYPE_APPLE2E: g_pAppTitle = TITLE_APPLE_2E ; break;
case A2TYPE_APPLE2EENHANCED: g_pAppTitle = TITLE_APPLE_2E_ENHANCED; break;
case A2TYPE_PRAVETS82: g_pAppTitle = TITLE_PRAVETS_82 ; break;

View File

@ -485,8 +485,11 @@ static BYTE __stdcall IORead_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG
case 0xC: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xD: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xE: // fall through...
case 0xF: return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xF: if (IsApple2PlusOrClone(GetApple2Type()))
IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
else
return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
}
return 0;
@ -511,8 +514,11 @@ static BYTE __stdcall IOWrite_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON
case 0xC: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xD: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xE: // fall through...
case 0xF: return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xF: if (IsApple2PlusOrClone(GetApple2Type()))
IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
else
return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
}
return 0;
@ -690,6 +696,9 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT
JoyportControl(address & 0x3); // AN0 and AN1 control
}
if (address >= 0xC05C && address <= 0xC05D && IsApple2JPlus(GetApple2Type()))
NTSC_VideoInitAppleType(); // AN2 switches between Katakana & ASCII video rom chars (GH#773)
if (!write)
return MemReadFloatingBus(nExecutedCycles);
else
@ -1506,6 +1515,7 @@ void MemInitializeROM(void)
{
case A2TYPE_APPLE2: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_APPLE2PLUS: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_PLUS_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_APPLE2JPLUS: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_JPLUS_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_APPLE2E: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2E_ROM ), "ROM"); ROM_SIZE = Apple2eRomSize; break;
case A2TYPE_APPLE2EENHANCED:hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2E_ENHANCED_ROM), "ROM"); ROM_SIZE = Apple2eRomSize; break;
case A2TYPE_PRAVETS82: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_PRAVETS_82_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
@ -1521,6 +1531,7 @@ void MemInitializeROM(void)
{
case A2TYPE_APPLE2: _tcscpy(sRomFileName, TEXT("APPLE2.ROM" )); break;
case A2TYPE_APPLE2PLUS: _tcscpy(sRomFileName, TEXT("APPLE2_PLUS.ROM" )); break;
case A2TYPE_APPLE2JPLUS: _tcscpy(sRomFileName, TEXT("APPLE2_JPLUS.ROM" )); break;
case A2TYPE_APPLE2E: _tcscpy(sRomFileName, TEXT("APPLE2E.ROM" )); break;
case A2TYPE_APPLE2EENHANCED:_tcscpy(sRomFileName, TEXT("APPLE2E_ENHANCED.ROM")); break;
case A2TYPE_PRAVETS82: _tcscpy(sRomFileName, TEXT("PRAVETS82.ROM" )); break;

View File

@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Applewin.h"
#include "CPU.h" // CpuGetCyclesThisVideoFrame()
#include "Frame.h"
#include "Memory.h" // MemGetMainPtr() MemGetAuxPtr()
#include "Memory.h" // MemGetMainPtr(), MemGetAuxPtr(), MemGetAnnunciator()
#include "Video.h" // g_pFramebufferbits
#include "RGBMonitor.h"
@ -450,13 +450,14 @@ 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_APPLE2JPLUS: csbits = &csbits_a2j[MemGetAnnunciator(2) ? 1 : 0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2E: csbits = Get2e_csbits(); break;
case A2TYPE_APPLE2EENHANCED:csbits = Get2e_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
case A2TYPE_TK30002E: csbits = &csbits_enhanced2e[0]; break; // Enhanced Apple //e clone
default: csbits = &csbits_enhanced2e[0]; break;
default: _ASSERT(0); csbits = &csbits_enhanced2e[0]; break;
}
}

View File

@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "Applewin.h"
#include "../resource/resource.h"
#include "Video.h"
#include "NTSC_CharSet.h"
@ -29,6 +30,7 @@ unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
static unsigned char csbits_2e_pal[2][256][8]; // PAL Original or Enhanced //e (2764 8K video ROM - low 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_a2j[2][256][8]; // ][J-Plus
unsigned char csbits_pravets82[1][256][8]; // Pravets 82
unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C
@ -105,7 +107,7 @@ static void get_csbits(csbits_t csbits, const char* resourceName, const UINT cy0
// FLASH toggles every 16 VBLs, so alternates between selecting NORMAL control/special and INVERSE control/special
//
void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
static void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
{
int RA = 0; // rom address
int i = 0;
@ -154,7 +156,7 @@ void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
}
}
void userVideoRomForIIe(void)
static void userVideoRomForIIe(void)
{
const BYTE* pVideoRom;
UINT size = GetVideoRom(pVideoRom); // 2K or 4K or 8K
@ -177,20 +179,36 @@ void userVideoRomForIIe(void)
//-------------------------------------
void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom)
{
int RA = 0; // rom address
static void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom, const int AN2=0);
for (int i=0; i<256; i++, RA+=8)
static void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom, const int AN2/*=0*/)
{
const bool isApple2JPlus = IsApple2JPlus(GetApple2Type()); // GH#773
for (int i=0; i<256; i++)
{
int RA = i*8; // rom address
if (isApple2JPlus)
{
// AN2=0: $00-3F, $00-3F; $80-BF, $80-BF => KKAA (Repeat Katakana)
// AN2=1: $40-7F, $40-7F; $C0-FF, $C0-FF => AAAA (Repeat ASCII)
RA &= ~(1<<(6+3));
RA |= (AN2<<(6+3)); // AN2 controls A9 (UTAII 8-12, Fig 8.7)
}
for (int y=0; y<8; y++)
{
BYTE n = pVideoRom[RA+y];
// UTAII:8-30 "Bit 7 of your EPROM fonts will control flashing in the lower 1024 bytes of the EPROM"
// UTAII:8-31 "If you leave O7 (EPROM Output7) reset in these patterns, the resulting characters will be inversions..."
if (!(n & 0x80) && RA < 1024)
n = n ^ 0x7f;
// Apple II J-Plus: simplest logic is just invert if reading low 1K of video ROM
if (RA < 1024)
{
if (!(n & 0x80) || isApple2JPlus)
n = n ^ 0x7f;
}
// UTAII:8-30 "TEXT ROM pattern is ... reversed"
BYTE d = 0;
@ -202,7 +220,7 @@ void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom)
}
}
void userVideoRomForIIPlus(void)
static void userVideoRomForIIPlus(void)
{
const BYTE* pVideoRom;
UINT size = GetVideoRom(pVideoRom); // 2K or 4K or 8K
@ -214,6 +232,30 @@ void userVideoRomForIIPlus(void)
//-------------------------------------
static void VideoRomForIIJPlus(void)
{
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_JPLUS_VIDEO_ROM), "ROM");
if (hResInfo == NULL)
return;
DWORD dwResSize = SizeofResource(NULL, hResInfo);
if(dwResSize != kVideoRomSize2K)
return;
HGLOBAL hResData = LoadResource(NULL, hResInfo);
if(hResData == NULL)
return;
BYTE* pVideoRom = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource
if (pVideoRom == NULL)
return;
userVideoRom2K(&csbits_a2j[0], pVideoRom, 0);
userVideoRom2K(&csbits_a2j[1], pVideoRom, 1);
}
//-------------------------------------
void make_csbits(void)
{
get_csbits(&csbits_enhanced2e[0], TEXT("CHARSET40"), 0); // Enhanced //e: Alt char set off
@ -228,6 +270,8 @@ void make_csbits(void)
memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e));
memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8);
VideoRomForIIJPlus();
// Try to use any user-provided video ROM for Original/Enhanced //e
userVideoRomForIIe();

View File

@ -4,6 +4,7 @@ typedef unsigned char (*csbits_t)[256][8];
extern unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
extern unsigned char csbits_a2[1][256][8]; // ][ and ][+
extern unsigned char csbits_a2j[2][256][8]; // ][J-Plus
extern unsigned char csbits_pravets82[1][256][8]; // Pravets 82
extern unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
extern unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C

View File

@ -138,6 +138,7 @@ static std::string GetSnapshotUnitSlotsName(void)
#define SS_YAML_VALUE_APPLE2 "Apple]["
#define SS_YAML_VALUE_APPLE2PLUS "Apple][+"
#define SS_YAML_VALUE_APPLE2JPLUS "Apple][ J-Plus"
#define SS_YAML_VALUE_APPLE2E "Apple//e"
#define SS_YAML_VALUE_APPLE2EENHANCED "Enhanced Apple//e"
#define SS_YAML_VALUE_APPLE2C "Apple2c"
@ -150,6 +151,7 @@ static eApple2Type ParseApple2Type(std::string type)
{
if (type == SS_YAML_VALUE_APPLE2) return A2TYPE_APPLE2;
else if (type == SS_YAML_VALUE_APPLE2PLUS) return A2TYPE_APPLE2PLUS;
else if (type == SS_YAML_VALUE_APPLE2JPLUS) return A2TYPE_APPLE2JPLUS;
else if (type == SS_YAML_VALUE_APPLE2E) return A2TYPE_APPLE2E;
else if (type == SS_YAML_VALUE_APPLE2EENHANCED) return A2TYPE_APPLE2EENHANCED;
else if (type == SS_YAML_VALUE_APPLE2C) return A2TYPE_APPLE2C;
@ -167,6 +169,7 @@ static std::string GetApple2TypeAsString(void)
{
case A2TYPE_APPLE2: return SS_YAML_VALUE_APPLE2;
case A2TYPE_APPLE2PLUS: return SS_YAML_VALUE_APPLE2PLUS;
case A2TYPE_APPLE2JPLUS: return SS_YAML_VALUE_APPLE2JPLUS;
case A2TYPE_APPLE2E: return SS_YAML_VALUE_APPLE2E;
case A2TYPE_APPLE2EENHANCED:return SS_YAML_VALUE_APPLE2EENHANCED;
case A2TYPE_APPLE2C: return SS_YAML_VALUE_APPLE2C;