From dd2914a38edacef53d6a58b9c6e9b5c0f9d485e8 Mon Sep 17 00:00:00 2001 From: TomCh Date: Thu, 2 Apr 2020 20:17:32 +0100 Subject: [PATCH] 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) --- AppleWinExpress2008.vcproj | 8 ++++ resource/Apple2_JPlus.rom | Bin 0 -> 12288 bytes resource/Apple2_JPlus_Video.rom | Bin 0 -> 2048 bytes resource/Applewin.rc | 8 ++++ resource/resource.h | 2 + source/Applewin.cpp | 2 + source/Common.h | 11 ++++- source/Configuration/PageConfig.cpp | 5 ++- source/Frame.cpp | 1 + source/Memory.cpp | 19 +++++++-- source/NTSC.cpp | 5 ++- source/NTSC_CharSet.cpp | 62 ++++++++++++++++++++++++---- source/NTSC_CharSet.h | 1 + source/SaveState.cpp | 3 ++ 14 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 resource/Apple2_JPlus.rom create mode 100644 resource/Apple2_JPlus_Video.rom diff --git a/AppleWinExpress2008.vcproj b/AppleWinExpress2008.vcproj index 0fdb2a79..28abd76a 100644 --- a/AppleWinExpress2008.vcproj +++ b/AppleWinExpress2008.vcproj @@ -1091,6 +1091,14 @@ RelativePath=".\resource\Apple2_Plus.rom" > + + + + diff --git a/resource/Apple2_JPlus.rom b/resource/Apple2_JPlus.rom new file mode 100644 index 0000000000000000000000000000000000000000..8db7de21e439bdeecb23c67d74c40969d4fc6c0d GIT binary patch literal 12288 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

P^b;#fQxdXbon9~HHD ziZ~umWhdW5FWeJi>thGDk5m^+x48(V+is}1z&1%+%`|GpG=3r_02^p|pmD3Lf-*Ze zkjAFo^VA#eqR$54K|XNEcO?+8_XNI|gHk9^DjgtC7#rC|gFwa4nwRp6<|TukCF5i+ z@V+z}J{a)a6B@BX8m zy7O?nsl4a2!sCoklI%bDsQnI?X6RN(_jpKdal!fEVHS`%O>@aJo%4cop!N(W{1%k$2dyxDJa;L&3UvEKA4F<|2Wo>ex!>&v@ z=YVP3qW!QT%GRRzd!(*Cb5F216-azdu>Kx=#65@P;{a}`(*Zi8HU!+WZ!t#^>eL29p zp5mIHly|jA;{yAoZ}8(}ZppL3XMyT;&h=z{Sb-nsoQkjKmd!6)*rK`3)y^rIkG{HR zr=`R5({M$jkgjqzIp*s* zWwTo}cQ|1lc$2W@394ChooT{E2v}+9*MdyurX+QXDL0$`qisU=LVT2f#)1 z!fR$T(89q#`p5RGK;8rQglSGDeU71O4*Kana7TEEw_gz^Lq%TV)WoCX_oTZVV(#<2 zw1zs;aWDnXgp!a565+c8iSRVKd~fp{{Y+>F08iOvs5i}&N5G-zr$O-uB@goV>E0L& zMDJeYTAa*by>*dgaV(GF3p^uy#rt1YkJ>oVi+_by4WjSDXm{B1q%gi%7i#}L46OM! z?0S-YGwf7R9~qxCH)&prrk^}6MSnf7?3uFkkbGT=hA?cdbzVKA^c#I}k#*Eu9JuTI zffMf=>Mw>3egZsp9+^*=d7-f{q^nS9tdHcS=w+Ej3=-{Vcj358l YBU=mq@cq~K#*e?L8c;32`|RES1D%ZNLI3~& literal 0 HcmV?d00001 diff --git a/resource/Apple2_JPlus_Video.rom b/resource/Apple2_JPlus_Video.rom new file mode 100644 index 0000000000000000000000000000000000000000..cd419afe634492a1bc686939f45508089e544e1a GIT binary patch literal 2048 zcmeHGO^e$w5EaHOqJ-ju52ctOL$P84|^&(6yrlMA%wCAW5f~`9fX;_ zH(6TRztBvKH4!rJx_%ba^o~jgUIRB;$a;Vh=)GSqJ6p!^@xu#NqCi4E`p+=MFGR;D^H;f;VdDv z6Y=GeVA}6I&)C6lp06T61A<83_g(jcxWlnOp#K14{V?b}2l6pK zj{@&WUxUsiAPsBhR{P0$zUo{lzHt73@qPp706d8azz65>qYtIQA1Aq>@0I#$w-})- zX@d%7kF6x=JRTGEdwZLX$m@lm-88TcS{)Pb4XUU^!Y5AuCZ&y1%y;$D;v@CV8k zP37yaU)<8z()-4Hv-h44;?6l=(TD9#>D|SW}jz2FkL*uQYbKsXpwj+3wJH{a}jCrXWvZ z(E#QEVE~c=+St0XRgIjrpspo&E%@>W3^+!48qB$_cbLv>&L?3N}vnR7X@|W!+n|M-^hsFZ#!_Q1{8n~O|Vi8#897up2dE@e^ra}Ly!CY N-@kwUAO4f?{}&l1TlD|{ literal 0 HcmV?d00001 diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 8c3c0e25..8422331a 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -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 diff --git a/resource/resource.h b/resource/resource.h index ce0bec36..932ac25d 100644 --- a/resource/resource.h +++ b/resource/resource.h @@ -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 diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 9863081e..74598476 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -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) diff --git a/source/Common.h b/source/Common.h index dc6947e9..6a9b5cc6 100644 --- a/source/Common.h +++ b/source/Common.h @@ -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; } diff --git a/source/Configuration/PageConfig.cpp b/source/Configuration/PageConfig.cpp index ffe3846e..ddba9ce3 100644 --- a/source/Configuration/PageConfig.cpp +++ b/source/Configuration/PageConfig.cpp @@ -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; diff --git a/source/Frame.cpp b/source/Frame.cpp index b8e9caf6..40fdd55c 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -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; diff --git a/source/Memory.cpp b/source/Memory.cpp index 49b545b7..b65dd0e8 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -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; diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 4c49426d..fb5e077a 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -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; } } diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index 628f0596..ac3051be 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -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(); diff --git a/source/NTSC_CharSet.h b/source/NTSC_CharSet.h index 6a5c86cc..e3d1d7fd 100644 --- a/source/NTSC_CharSet.h +++ b/source/NTSC_CharSet.h @@ -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 diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 33c57d2c..7d1de8a2 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -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;