Skip to content

Commit

Permalink
VidHD: Support SHR for Apple II/II+ models (AppleWin#997, PR AppleWin…
Browse files Browse the repository at this point in the history
…#1013)

. Support aux writes for II/II+ (6502 emulation, not 65C02)
. Extend VidHD save-state for II/II+ aux memory
  • Loading branch information
tomcw committed Dec 19, 2021
1 parent ff65a9f commit 577ffcc
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 45 deletions.
2 changes: 2 additions & 0 deletions help/CommandLine.html
Expand Up @@ -48,6 +48,8 @@ <h2 style="COLOR: rgb(0,128,0)">Command line</h2>
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>
Expand Down
9 changes: 8 additions & 1 deletion help/cfg-config.html
Expand Up @@ -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>
Expand Down Expand Up @@ -64,6 +64,13 @@ <h2 style="COLOR: rgb(0,128,0)">Configuration Settings</h2>
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>
Expand Down
4 changes: 2 additions & 2 deletions help/cfg-input.html
Expand Up @@ -42,15 +42,15 @@ <h2 style="color: rgb(0, 128, 0);">Input Settings</h2>
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>

<strong>SNES MAX card:</strong><br>
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>
Expand Down
Binary file modified help/img/config.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions help/savestate.html
Expand Up @@ -34,6 +34,7 @@ <h2 style="COLOR: rgb(0,128,0)">Save-state Files</h2>
<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>
Expand Down
5 changes: 4 additions & 1 deletion source/CPU/cpu_general.inl
Expand Up @@ -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);\
} \
Expand Down
18 changes: 15 additions & 3 deletions source/Memory.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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()))
{
Expand Down
3 changes: 3 additions & 0 deletions source/Memory.h
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
85 changes: 69 additions & 16 deletions source/VidHD.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"
Expand All @@ -165,26 +189,55 @@ 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)
{
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;
}
6 changes: 5 additions & 1 deletion source/VidHD.h
Expand Up @@ -9,6 +9,7 @@ class VidHDCard : public Card
VidHDCard(UINT slot) :
Card(CT_VidHD, slot)
{
m_memMode = 0;
m_SCREENCOLOR = 0;
m_NEWVIDEO = 0;
m_BORDERCOLOR = 0;
Expand All @@ -27,8 +28,9 @@ class VidHDCard : public Card

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);

Expand All @@ -37,6 +39,8 @@ class VidHDCard : public Card
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;
Expand Down

0 comments on commit 577ffcc

Please sign in to comment.