Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Andrea Odetti 2018-10-14 15:22:10 +01:00
commit b697be894d
7 changed files with 117 additions and 33 deletions

View file

@ -8,6 +8,12 @@ https://github.com/AppleWin/AppleWin/issues/new
Tom Charlesworth
1.27.9.0 - 2 Oct 2018
---------------------
. [Bug #582] Support for partial disk II latch reads when accesses are very close.
- Fixes Curse of the Azure Bonds & Pool of Radiance (saving characters and creating disks).
1.27.8.0 - 9 Sep 2018
---------------------
. [Bug #555] Fix for showing 559th DHGR/DGR/TEXT80 vertical column (retaining 560-pixel display width).

View file

@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,27,8,0
PRODUCTVERSION 1,27,8,0
FILEVERSION 1,27,9,0
PRODUCTVERSION 1,27,9,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, 8, 0"
VALUE "FileVersion", "1, 27, 9, 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, 8, 0"
VALUE "ProductVersion", "1, 27, 9, 0"
END
END
BLOCK "VarFileInfo"

View file

@ -129,13 +129,16 @@ void LogFileTimeUntilFirstKeyReadReset(void)
}
// Log the time from emulation restart/reboot until the first key read: BIT $C000
// . NB. AZTEC.DSK does prior LDY $C000 reads, but the BIT $C000 is at the "Press any key" message
// . AZTEC.DSK (DOS 3.3) does prior LDY $C000 reads, but the BIT $C000 is at the "Press any key" message
// . Phasor1.dsk / ProDOS 1.1.1: PC=E797: B1 50: LDA ($50),Y / "Select an Option:" message
void LogFileTimeUntilFirstKeyRead(void)
{
if (!g_fh || bLogKeyReadDone)
return;
if (mem[regs.pc-3] != 0x2C) // bit $c000
if ( (mem[regs.pc-3] != 0x2C) // AZTEC: bit $c000
&& !((regs.pc-2) == 0xE797 && mem[regs.pc-2] == 0xB1 && mem[regs.pc-1] == 0x50) // Phasor1: lda ($50),y
)
return;
DWORD dwTime = GetTickCount() - dwLogKeyReadTickStart;

View file

@ -1493,7 +1493,7 @@ int GetDisassemblyLine ( WORD nBaseAddress, DisasmLine_t & line_ )
if (! (bDisasmFormatFlags & DISASM_FORMAT_SYMBOL))
{
pTarget = FormatAddress( nTarget, nOpbyte );
pTarget = FormatAddress( nTarget, (iOpmode != AM_R) ? nOpbyte : 3 ); // GH#587: For Bcc opcodes, pretend it's a 3-byte opcode to print a 16-bit target addr
}
// sprintf( sTarget, g_aOpmodes[ iOpmode ]._sFormat, pTarget );

View file

@ -86,6 +86,7 @@ static WORD phases = 0; // state bits for stepper magnet phases 0 - 3
static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry
static UINT g_uSlot = 0;
static unsigned __int64 g_uDiskLastCycle = 0;
static unsigned __int64 g_uDiskLastReadLatchCycle = 0;
static FormatTrack g_formatTrack;
static bool IsDriveValid( const int iDrive );
@ -895,7 +896,23 @@ static void __stdcall DiskReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULO
// but Sherwood Forest sets shift mode and reads with the drive off, so don't check for now
if (!floppywritemode)
{
const ULONG nReadCycleDiff = (ULONG) (g_nCumulativeCycles - g_uDiskLastReadLatchCycle);
// Support partial nibble read if disk reads are very close: (GH#582)
// . 6 cycles (1st->2nd read) for DOS 3.3 / $BD34: "read with delays to see if disk is spinning." (Beneath Apple DOS)
// . 6 cycles (1st->2nd read) for Curse of the Azure Bonds (loop to see if disk is spinning)
// . 31 cycles is the max for a partial 8-bit nibble
const ULONG kReadAccessThreshold = enhancedisk ? 6 : 31;
if (nReadCycleDiff <= kReadAccessThreshold)
{
UINT invalidBits = 8 - (nReadCycleDiff / 4); // 4 cycles per bit-cell
floppylatch = *(pFloppy->trackimage + pFloppy->byte) >> invalidBits;
return; // Early return so don't update: g_uDiskLastReadLatchCycle & pFloppy->byte
}
floppylatch = *(pFloppy->trackimage + pFloppy->byte);
g_uDiskLastReadLatchCycle = g_nCumulativeCycles;
#if LOG_DISK_NIBBLES_READ
#if LOG_DISK_NIBBLES_USE_RUNTIME_VAR
@ -959,6 +976,10 @@ void DiskReset(const bool bIsPowerCycle/*=false*/)
if (bIsPowerCycle) // GH#460
{
// NB. This doesn't affect the drive head (ie. drive's track position)
// . The initial machine start-up state is track=0, but after a power-cycle the track could be any value.
// . (For DiskII firmware, this results in a subtle extra latch read in this latter case, for the track!=0 case)
g_aFloppyDrive[DRIVE_1].spinning = 0;
g_aFloppyDrive[DRIVE_1].writelight = 0;
g_aFloppyDrive[DRIVE_2].spinning = 0;
@ -1363,7 +1384,8 @@ int DiskSetSnapshot_v1(const SS_CARD_DISK2* const pSS)
// Unit version history:
// 2: Added: Format Track state & DiskLastCycle
static const UINT kUNIT_VERSION = 2;
// 3: Added: DiskLastReadLatchCycle
static const UINT kUNIT_VERSION = 3;
#define SS_YAML_VALUE_CARD_DISK2 "Disk]["
@ -1375,6 +1397,7 @@ static const UINT kUNIT_VERSION = 2;
#define SS_YAML_KEY_FLOPPY_MOTOR_ON "Floppy Motor On"
#define SS_YAML_KEY_FLOPPY_WRITE_MODE "Floppy Write Mode"
#define SS_YAML_KEY_LAST_CYCLE "Last Cycle"
#define SS_YAML_KEY_LAST_READ_LATCH_CYCLE "Last Read Latch Cycle"
#define SS_YAML_KEY_DISK2UNIT "Unit"
#define SS_YAML_KEY_FILENAME "Filename"
@ -1429,6 +1452,7 @@ void DiskSaveSnapshot(class YamlSaveHelper& yamlSaveHelper)
yamlSaveHelper.SaveBool(SS_YAML_KEY_FLOPPY_MOTOR_ON, floppymotoron == TRUE);
yamlSaveHelper.SaveBool(SS_YAML_KEY_FLOPPY_WRITE_MODE, floppywritemode == TRUE);
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_LAST_CYCLE, g_uDiskLastCycle); // v2
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_LAST_READ_LATCH_CYCLE, g_uDiskLastReadLatchCycle); // v3
g_formatTrack.SaveSnapshot(yamlSaveHelper); // v2
DiskSaveSnapshotDisk2Unit(yamlSaveHelper, DRIVE_1);
@ -1534,6 +1558,11 @@ bool DiskLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT vers
g_formatTrack.LoadSnapshot(yamlLoadHelper);
}
if (version >= 3)
{
g_uDiskLastReadLatchCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_LAST_READ_LATCH_CYCLE);
}
// Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1
for(UINT i=0; i<NUM_DRIVES; i++)
{

View file

@ -79,7 +79,7 @@ MEMORY MANAGEMENT SOFT SWITCHES
$C000 W 80STOREOFF Allow page2 to switch video page1 page2
$C001 W 80STOREON Allow page2 to switch main & aux video memory
$C002 W RAMRDOFF Read enable main memory from $0200-$BFFF
$C003 W RAMDRON Read enable aux memory from $0200-$BFFF
$C003 W RAMRDON Read enable aux memory from $0200-$BFFF
$C004 W RAMWRTOFF Write enable main memory from $0200-$BFFF
$C005 W RAMWRTON Write enable aux memory from $0200-$BFFF
$C006 W INTCXROMOFF Enable slot ROM from $C100-$C7FF (but $C800-$CFFF depends on INTC8ROM)
@ -129,29 +129,44 @@ SOFT SWITCH STATUS FLAGS
// Notes
// -----
//
// mem
// - a copy of the memimage ptr
//
// memimage
// - 64KB
//
// mem
// (a pointer to memimage 64KB)
// - a 64KB r/w memory cache
// - reflects the current readable memory in the 6502's 64K address space
// . excludes $Cxxx I/O memory
// . could be a mix of RAM/ROM, main/aux, etc
// - may also reflect the current writeable memory (on a 256-page granularity) if the write page addr == read page addr
// . for this case, the memdirty flag(s) are valid
// . when writes instead occur to backing-store, then memdirty flag(s) can be ignored
//
// memmain, memaux
// - physical contiguous 64KB RAM for main & aux respectively
// - physical contiguous 64KB "backing-store" for main & aux respectively
// - NB. 4K bank1 BSR is at $C000-$CFFF
//
// memwrite
// - 1 ptr entry per 256-byte page
// - 1 pointer entry per 256-byte page
// - used to write to a page
// - if RD & WR point to the same 256-byte RAM page, then memwrite will point to the page in 'mem'
// . ie. when SW_AUXREAD==SW_AUXWRITE, or 4K-BSR is r/w, or 8K BSR is r/w, or SW_80STORE=1
// . So 'mem' remains correct for both r&w operations, but the physical 64K mem block becomes stale
// - if RD & WR point to different 256-byte pages, then memwrite will point to the page in the physical 64K mem block
// . writes will still set the dirty flag (but can be ignored)
// . UpdatePaging() ignores this, as it only copies back to the physical 64K mem block when memshadow changes (for that 256-byte page)
//
// memdirty
// - 1 byte entry per 256-byte page
// - set when a write occurs to a 256-byte page
// - indicates that 'mem' (ie. the cache) is out-of-sync with the "physical" 64K backing-store memory
// - NB. a page's dirty flag is only useful(valid) when 'mem' is used for both read & write for the corresponding page
// When they differ, then writes go directly to the backing-store.
// . In this case, the dirty flag will just force a memcpy() to the same address in backing-store.
//
// memshadow
// - 1 ptr entry per 256-byte page
// - reflects how 'mem' is setup
// - 1 pointer entry per 256-byte page
// - reflects how 'mem' is setup for read operations (at a 256-byte granularity)
// . EG: if ALTZP=1, then:
// . mem will have copies of memaux's ZP & stack
// . memshadow[0] = &memaux[0x0000]
@ -817,19 +832,6 @@ static bool IsCardInSlot(const UINT uSlot)
//===========================================================================
static void BackMainImage(void)
{
for (UINT loop = 0; loop < 256; loop++)
{
if (memshadow[loop] && ((*(memdirty+loop) & 1) || (loop <= 1)))
CopyMemory(memshadow[loop], memimage+(loop << 8), 256);
*(memdirty+loop) &= ~1;
}
}
//===========================================================================
DWORD GetMemMode(void)
{
return memmode;
@ -925,7 +927,7 @@ static void UpdatePaging(BOOL initialize)
for (loop = 0xC0; loop < 0xC8; loop++)
{
memdirty[loop] = 0; // ROM can't be dirty
memdirty[loop] = 0; // mem(cache) can't be dirty for ROM (but STA $Csnn will set the dirty flag)
const UINT uSlotOffset = (loop & 0x0f) * 0x100;
if (loop == 0xC3)
memshadow[loop] = (SW_SLOTC3ROM && !SW_INTCXROM) ? pCxRomPeripheral+uSlotOffset // C300..C3FF - Slot 3 ROM (all 0x00's)
@ -937,7 +939,7 @@ static void UpdatePaging(BOOL initialize)
for (loop = 0xC8; loop < 0xD0; loop++)
{
memdirty[loop] = 0; // ROM can't be dirty (but STA $CFFF will set the dirty flag)
memdirty[loop] = 0; // mem(cache) can't be dirty for ROM (but STA $Cnnn will set the dirty flag)
const UINT uRomOffset = (loop & 0x0f) * 0x100;
memshadow[loop] = (!SW_INTCXROM && !INTC8ROM) ? pCxRomPeripheral+uRomOffset // C800..CFFF - Peripheral ROM (GH#486)
: pCxRomInternal+uRomOffset; // C800..CFFF - Internal ROM
@ -1070,6 +1072,19 @@ bool MemCheckINTCXROM()
//===========================================================================
static void BackMainImage(void)
{
for (UINT loop = 0; loop < 256; loop++)
{
if (memshadow[loop] && ((*(memdirty+loop) & 1) || (loop <= 1)))
CopyMemory(memshadow[loop], mem+(loop << 8), 256);
*(memdirty+loop) &= ~1;
}
}
//===========================================================================
static LPBYTE MemGetPtrBANK1(const WORD offset, const LPBYTE pMemBase)
{
if ((offset & 0xF000) != 0xC000) // Requesting RAM at physical addr $Cxxx (ie. 4K RAM BANK1)
@ -1114,6 +1129,34 @@ LPBYTE MemGetAuxPtr(const WORD offset)
//-------------------------------------
// if memshadow == memmain
// so RD memmain
// case: RD == WR
// so RD(mem),WR(mem)
// so 64K memmain could be incorrect
// *therefore mem is correct
// case: RD != WR
// so RD(mem),WR(memaux)
// doesn't matter since RD != WR, then it's guaranteed that memaux is correct
// *therefore either mem or memmain is correct
// else ; memshadow != memmain
// so RD memaux (or ROM)
// case: RD == WR
// so RD(mem),WR(mem)
// so 64K memaux could be incorrect
// *therefore memmain is correct
// case: RD != WR
// so RD(mem),WR(memmain)
// doesn't matter since RD != WR, then it's guaranteed that memmain is correct
// *therefore memmain is correct
//
// *OR*
//
// Is the mem(cache) setup to read (via memshadow) from memmain?
// . if yes, then return the mem(cache) address as writes (via memwrite) may've made the mem(cache) dirty.
// . if no, then return memmain, as the mem(cache) isn't involved in memmain (any writes will go directly to this backing-store).
//
LPBYTE MemGetMainPtr(const WORD offset)
{
LPBYTE lpMem = MemGetPtrBANK1(offset, memmain);
@ -1127,6 +1170,9 @@ LPBYTE MemGetMainPtr(const WORD offset)
//===========================================================================
// Used by:
// . Savestate: MemSaveSnapshotMemory(), MemLoadSnapshotAux()
// . Debugger : CmdMemorySave(), CmdMemoryLoad()
LPBYTE MemGetBankPtr(const UINT nBank)
{
BackMainImage(); // Flush any dirty pages to back-buffer
@ -1784,7 +1830,7 @@ _done_saturn:
// IT DOES SO.
//
// NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour.
// - although any date-race is probably a bug in the 6502 code too.
// - although any data-race is probably a bug in the 6502 code too.
if ((address >= 4) && (address <= 5) &&
((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) {
modechanging = 1;

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() MemGetBankPtr()
#include "Memory.h" // MemGetMainPtr() MemGetAuxPtr()
#include "Video.h" // g_pFramebufferbits
#include "NTSC.h"