Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0706697b13
20 changed files with 494 additions and 146 deletions
|
@ -121,11 +121,14 @@ C017 RDC3ROM
|
|||
C018 RD80STORE
|
||||
C019 RDVBLBAR
|
||||
C01A RDTEXT
|
||||
C01B RDMIXED
|
||||
C01C RDPAGE2
|
||||
C01D RDHIRES
|
||||
C01E ALTCHARSET
|
||||
C01F RD80COL
|
||||
C020 TAPEOUT
|
||||
C030 SPKR
|
||||
C040 STROBE
|
||||
C050 TXTCLR
|
||||
C051 TXTSET
|
||||
C052 MIXCLR
|
||||
|
@ -145,18 +148,48 @@ C05F CLRAN3
|
|||
C060 TAPEIN
|
||||
C061 BUTNO
|
||||
C062 BUTN1
|
||||
C063 BUTN2
|
||||
C064 PADDL0
|
||||
C065 PADDL1
|
||||
C066 PADDL2
|
||||
C067 PADDL3
|
||||
C070 PTRIG
|
||||
C080 STEPPER
|
||||
C081 ROMIN
|
||||
|
||||
; Slot-0: Language Card
|
||||
C080 LCRAMIN2
|
||||
C081 ROMIN2
|
||||
C082 LCROMIN2
|
||||
C083 LCBANK2
|
||||
C08A ENABLE1
|
||||
C08B LCBANK1/ENABLE2
|
||||
C08C DATASTROBE
|
||||
C08D LOADLATCH
|
||||
C08E SETREADMODE
|
||||
C08E WRITEPROT
|
||||
C08F SETWRITEMODE
|
||||
C084 LCRAMIN2_
|
||||
C085 ROMIN2_
|
||||
C086 LCROMIN2_
|
||||
C087 LCBANK2_
|
||||
C088 LCRAMIN1
|
||||
C089 ROMIN1
|
||||
C08A LCROMIN1
|
||||
C08B LCBANK1
|
||||
C08C LCRAMIN1_
|
||||
C08D ROMIN1_
|
||||
C08E LCROMIN1_
|
||||
C08F LCBANK1_
|
||||
|
||||
; Slot-6: DiskII interface
|
||||
C0E0 DRV_P0_OFF
|
||||
C0E1 DRV_P0_ON
|
||||
C0E2 DRV_P1_OFF
|
||||
C0E3 DRV_P1_ON
|
||||
C0E4 DRV_P2_OFF
|
||||
C0E5 DRV_P2_ON
|
||||
C0E6 DRV_P3_OFF
|
||||
C0E7 DRV_P3_ON
|
||||
C0E8 DRV_OFF
|
||||
C0E9 DRV_ON
|
||||
C0EA DRV_SEL1
|
||||
C0EB DRV_SEL2
|
||||
C0EC DRV_SHIFT
|
||||
C0ED DRV_LOAD
|
||||
C0EE DRV_READ
|
||||
C0EF DRV_WRITE
|
||||
|
||||
; Firmware
|
||||
; Renamed due to ROM name collision
|
||||
|
|
|
@ -9,6 +9,18 @@ https://github.com/AppleWin/AppleWin/issues/new
|
|||
Tom Charlesworth
|
||||
|
||||
|
||||
1.29.12.0 - 26 Apr 2020
|
||||
-----------------------
|
||||
. [PR #757] Allow use of an INI-file for configuration instead of the Registry (fixes #709).
|
||||
- new command line switch: -conf <INI-file>
|
||||
. [Change #773] Added Apple II J-Plus support.
|
||||
. [Bug #778] Fixed for when Joystick(s) are disabled.
|
||||
. [Bug #777] Fixed Phasor speech (SSI263) to match Mockingboard (when in Mockingboard mode).
|
||||
- fixes: #698 (Rescue Raiders), #753 (Bejeweled).
|
||||
- also improvements to Phasor card's native Phasor mode.
|
||||
. [PR #775] Debugger: Fixed so that hitting "=" in the debugger sets PC to the current cursor address.
|
||||
|
||||
|
||||
1.29.11.0 - 27 Mar 2020
|
||||
-----------------------
|
||||
. [Bug #771] Added new command line switch to load custom ROM: -rom <file>.
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
/*
|
||||
|
||||
|
||||
2.9.1.0 Added: Bookmarks now have their own indicator (a number with a box around it) and replace the ":" seperator. Updated Debug_Font.bmp
|
||||
|
||||
.18 Fixed: Resetting bookmarks wasn't setting the total bookmarks back to zero.
|
||||
.17 Fixed: If all bookmarks were used then setting a new one wouldn't update an existing one to the new address.
|
||||
.16 Fixed: Replacing an existing bookmark incorrectly increased the total bookmark count.
|
||||
.15 Cleanup: HELP CALC examples and See also.
|
||||
.14 Fixed: HELP JSR wasn't color-coding syntax.
|
||||
.13 Added: PROFILE LIST now shows how many clock cycles were executed.
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<p>The team would like to thank the following people for their contributions:</p>
|
||||
<p style="MARGIN-LEFT: 40px">Brian Broker: This HTML / CHM help file</p>
|
||||
<p style="MARGIN-LEFT: 40px">Thomas Stahl: TV emulation mode (up to v1.25.0.4)</p>
|
||||
<p style="MARGIN-LEFT: 40px">Chris Foxwell: SSI263 phoneme samples</p>
|
||||
<p style="MARGIN-LEFT: 40px">Greg Hedger: SSI263 phoneme samples</p>
|
||||
<p style="MARGIN-LEFT: 40px">Robert Hoem: Hard disk card (source module & f/w)</p>
|
||||
<p style="MARGIN-LEFT: 40px">VICE team: TFE, Z80, MC6821 PIA emulation modules (<a href="http://vice-emu.sourceforge.net/index.html#developers">http://vice-emu.sourceforge.net/index.html#developers</a>)<br>
|
||||
- In particular, Spiro Trikaliotis for TFE, whose code Glenn Jones adapted for Uthernet support</p>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 42 KiB |
|
@ -1,4 +1,4 @@
|
|||
#define APPLEWIN_VERSION 1,29,11,0
|
||||
#define APPLEWIN_VERSION 1,29,12,0
|
||||
|
||||
#define xstr(a) str(a)
|
||||
#define str(a) #a
|
||||
|
|
|
@ -123,11 +123,51 @@ CSpeech g_Speech;
|
|||
|
||||
//===========================================================================
|
||||
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
static UINT64 g_timeTotal = 0;
|
||||
UINT64 g_timeCpu = 0;
|
||||
UINT64 g_timeVideo = 0; // part of timeCpu
|
||||
UINT64 g_timeMB_Timer = 0; // part of timeCpu
|
||||
UINT64 g_timeMB_NoTimer = 0;
|
||||
UINT64 g_timeSpeaker = 0;
|
||||
static UINT64 g_timeVideoRefresh = 0;
|
||||
|
||||
void LogPerfTimings(void)
|
||||
{
|
||||
if (g_timeTotal)
|
||||
{
|
||||
UINT64 cpu = g_timeCpu - g_timeVideo - g_timeMB_Timer;
|
||||
UINT64 video = g_timeVideo + g_timeVideoRefresh;
|
||||
UINT64 spkr = g_timeSpeaker;
|
||||
UINT64 mb = g_timeMB_Timer + g_timeMB_NoTimer;
|
||||
UINT64 audio = spkr + mb;
|
||||
UINT64 other = g_timeTotal - g_timeCpu - g_timeSpeaker - g_timeMB_NoTimer - g_timeVideoRefresh;
|
||||
|
||||
LogOutput("Perf breakdown:\n");
|
||||
LogOutput(". CPU %% = %2f.2\n", (double)cpu / (double)g_timeTotal * 100.0);
|
||||
LogOutput(". Video %% = %2f.2\n", (double)video / (double)g_timeTotal * 100.0);
|
||||
LogOutput("... NTSC %% = %2f.2\n", (double)g_timeVideo / (double)g_timeTotal * 100.0);
|
||||
LogOutput("... refresh %% = %2f.2\n", (double)g_timeVideoRefresh / (double)g_timeTotal * 100.0);
|
||||
LogOutput(". Audio %% = %2f.2\n", (double)audio / (double)g_timeTotal * 100.0);
|
||||
LogOutput("... Speaker %% = %2f.2\n", (double)spkr / (double)g_timeTotal * 100.0);
|
||||
LogOutput("... MB %% = %2f.2\n", (double)mb / (double)g_timeTotal * 100.0);
|
||||
LogOutput(". Other %% = %2f.2\n", (double)other / (double)g_timeTotal * 100.0);
|
||||
LogOutput(". TOTAL %% = %2f.2\n", (double)(cpu+video+audio+other) / (double)g_timeTotal * 100.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
|
||||
static DWORD dwLogKeyReadTickStart;
|
||||
static bool bLogKeyReadDone = false;
|
||||
|
||||
void LogFileTimeUntilFirstKeyReadReset(void)
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
LogPerfTimings();
|
||||
#endif
|
||||
|
||||
if (!g_fh)
|
||||
return;
|
||||
|
||||
|
@ -234,6 +274,10 @@ static bool g_uModeStepping_LastGetKey_ScrollLock = false;
|
|||
|
||||
static void ContinueExecution(void)
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
PerfMarker* pPerfMarkerTotal = new PerfMarker(g_timeTotal);
|
||||
#endif
|
||||
|
||||
_ASSERT(g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING);
|
||||
|
||||
const double fUsecPerSec = 1.e6;
|
||||
|
@ -352,6 +396,9 @@ static void ContinueExecution(void)
|
|||
const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame();
|
||||
if (g_dwCyclesThisFrame >= dwClksPerFrame && !VideoGetVblBarEx(g_dwCyclesThisFrame))
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
PerfMarker perfMarkerVideoRefresh(g_timeVideoRefresh);
|
||||
#endif
|
||||
g_dwCyclesThisFrame -= dwClksPerFrame;
|
||||
|
||||
if (g_bFullSpeed)
|
||||
|
@ -360,6 +407,10 @@ static void ContinueExecution(void)
|
|||
VideoRefreshScreen(); // Just copy the output of our Apple framebuffer to the system Back Buffer
|
||||
}
|
||||
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
delete pPerfMarkerTotal; // Explicitly call dtor *before* SysClk_WaitTimer()
|
||||
#endif
|
||||
|
||||
if ((g_nAppMode == MODE_RUNNING && !g_bFullSpeed) || bModeStepping_WaitTimer)
|
||||
{
|
||||
SysClk_WaitTimer();
|
||||
|
|
|
@ -63,3 +63,27 @@ extern CSpeech g_Speech;
|
|||
#endif
|
||||
|
||||
extern __interface IPropertySheet& sg_PropertySheet;
|
||||
|
||||
//
|
||||
|
||||
//#define LOG_PERF_TIMINGS
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
class PerfMarker
|
||||
{
|
||||
public:
|
||||
PerfMarker(UINT64& globalCounter)
|
||||
: counter(globalCounter)
|
||||
{
|
||||
QueryPerformanceCounter(&timeStart);
|
||||
}
|
||||
~PerfMarker()
|
||||
{
|
||||
QueryPerformanceCounter(&timeEnd);
|
||||
counter += (UINT64)timeEnd.QuadPart - (UINT64)timeStart.QuadPart;
|
||||
}
|
||||
private:
|
||||
UINT64& counter;
|
||||
LARGE_INTEGER timeStart;
|
||||
LARGE_INTEGER timeEnd;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -98,6 +98,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#endif
|
||||
#include "Video.h"
|
||||
#include "NTSC.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "z80emu.h"
|
||||
#include "Z80VICE/z80.h"
|
||||
|
@ -105,6 +106,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
||||
#include "YamlHelper.h"
|
||||
|
||||
#define LOG_IRQ_TAKEN_AND_RTI 0
|
||||
|
||||
// 6502 Accumulator Bit Flags
|
||||
#define AF_SIGN 0x80
|
||||
#define AF_OVERFLOW 0x40
|
||||
|
@ -243,6 +246,10 @@ static __forceinline void DoIrqProfiling(DWORD uCycles)
|
|||
if(regs.ps & AF_INTERRUPT)
|
||||
return; // Still in Apple's ROM
|
||||
|
||||
#if LOG_IRQ_TAKEN_AND_RTI
|
||||
LogOutput("ISR-end\n\n");
|
||||
#endif
|
||||
|
||||
g_nCycleIrqEnd = g_nCumulativeCycles + uCycles;
|
||||
g_nCycleIrqTime = (UINT) (g_nCycleIrqEnd - g_nCycleIrqStart);
|
||||
|
||||
|
@ -442,6 +449,9 @@ static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn,
|
|||
regs.pc = * (WORD*) (mem+0xFFFE);
|
||||
UINT uExtraCycles = 0; // Needed for CYC(a) macro
|
||||
CYC(7)
|
||||
#if defined(_DEBUG) && LOG_IRQ_TAKEN_AND_RTI
|
||||
LogOutput("IRQ\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
g_irqOnLastOpcodeCycle = false;
|
||||
|
@ -554,6 +564,11 @@ ULONG CpuGetCyclesThisVideoFrame(const ULONG nExecutedCycles)
|
|||
|
||||
DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate)
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
extern UINT64 g_timeCpu;
|
||||
PerfMarker perfMarker(g_timeCpu);
|
||||
#endif
|
||||
|
||||
g_nCyclesExecuted = 0;
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
|
|
@ -50,7 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#define ALLOW_INPUT_LOWERCASE 1
|
||||
|
||||
// See /docs/Debugger_Changelog.txt for full details
|
||||
const int DEBUGGER_VERSION = MAKE_VERSION(2,9,0,15);
|
||||
const int DEBUGGER_VERSION = MAKE_VERSION(2,9,1,0);
|
||||
|
||||
|
||||
// Public _________________________________________________________________________________________
|
||||
|
@ -484,13 +484,17 @@ bool _Bookmark_Del( const WORD nAddress )
|
|||
{
|
||||
// g_aBookmarks.at( iBookmark ) = NO_6502_TARGET;
|
||||
g_aBookmarks[ iBookmark ].bSet = false;
|
||||
g_nBookmarks--;
|
||||
bDeleted = true;
|
||||
}
|
||||
}
|
||||
return bDeleted;
|
||||
}
|
||||
|
||||
bool Bookmark_Find( const WORD nAddress )
|
||||
// Returns:
|
||||
// 0 if address does not have a bookmark set
|
||||
// N+1 if there is an existing bookmark that has this address
|
||||
int Bookmark_Find( const WORD nAddress )
|
||||
{
|
||||
// Ugh, linear search
|
||||
// int nSize = g_aBookmarks.size();
|
||||
|
@ -500,10 +504,10 @@ bool Bookmark_Find( const WORD nAddress )
|
|||
if (g_aBookmarks[ iBookmark ].nAddress == nAddress)
|
||||
{
|
||||
if (g_aBookmarks[ iBookmark ].bSet)
|
||||
return true;
|
||||
return iBookmark + 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -534,6 +538,8 @@ void _Bookmark_Reset()
|
|||
{
|
||||
g_aBookmarks[ iBookmark ].bSet = false;
|
||||
}
|
||||
|
||||
g_nBookmarks = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -598,15 +604,26 @@ Update_t CmdBookmarkAdd (int nArgs )
|
|||
ConsoleDisplayPush( sText );
|
||||
return ConsoleUpdate();
|
||||
}
|
||||
|
||||
if ((iBookmark < MAX_BOOKMARKS) && (g_nBookmarks < MAX_BOOKMARKS))
|
||||
|
||||
// 2.9.0.16 Fixed: Replacing an existing bookmark incorrectly increased the total bookmark count.
|
||||
int nOldBookmark = Bookmark_Find( nAddress );
|
||||
if (nOldBookmark)
|
||||
{
|
||||
g_aBookmarks[iBookmark].bSet = true;
|
||||
g_aBookmarks[iBookmark].nAddress = nAddress;
|
||||
bAdded = true;
|
||||
g_nBookmarks++;
|
||||
iBookmark++;
|
||||
_Bookmark_Del( nAddress );
|
||||
}
|
||||
|
||||
// 2.9.0.17 Fixed: If all bookmarks were used then setting a new one wouldn't update an existing one to the new address.
|
||||
if (g_aBookmarks[ iBookmark ].bSet)
|
||||
{
|
||||
g_aBookmarks[ iBookmark ].nAddress = nAddress;
|
||||
bAdded = true;
|
||||
}
|
||||
else
|
||||
if (g_nBookmarks < MAX_BOOKMARKS)
|
||||
{
|
||||
bAdded = _Bookmark_Add( iBookmark, nAddress );
|
||||
iBookmark++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bAdded)
|
||||
|
@ -632,11 +649,7 @@ Update_t CmdBookmarkClear (int nArgs)
|
|||
{
|
||||
if (! _tcscmp(g_aArgs[nArgs].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName))
|
||||
{
|
||||
for (iBookmark = 0; iBookmark < MAX_BOOKMARKS; iBookmark++ )
|
||||
{
|
||||
if (g_aBookmarks[ iBookmark ].bSet)
|
||||
g_aBookmarks[ iBookmark ].bSet = false;
|
||||
}
|
||||
_Bookmark_Reset();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -6896,11 +6909,16 @@ Update_t CmdCyclesInfo(int nArgs)
|
|||
else
|
||||
{
|
||||
if (strcmp(g_aArgs[1].sArg, "abs") == 0)
|
||||
g_videoScannerDisplayInfo.isAbsCycle = true;
|
||||
g_videoScannerDisplayInfo.cycleMode = VideoScannerDisplayInfo::abs;
|
||||
else if (strcmp(g_aArgs[1].sArg, "rel") == 0)
|
||||
g_videoScannerDisplayInfo.isAbsCycle = false;
|
||||
g_videoScannerDisplayInfo.cycleMode = VideoScannerDisplayInfo::rel;
|
||||
else if (strcmp(g_aArgs[1].sArg, "part") == 0)
|
||||
g_videoScannerDisplayInfo.cycleMode = VideoScannerDisplayInfo::part;
|
||||
else
|
||||
return Help_Arg_1(CMD_CYCLES_INFO);
|
||||
|
||||
if (g_videoScannerDisplayInfo.cycleMode == VideoScannerDisplayInfo::part)
|
||||
CmdCyclesReset(0);
|
||||
}
|
||||
|
||||
TCHAR sText[CONSOLE_WIDTH];
|
||||
|
@ -6910,6 +6928,12 @@ Update_t CmdCyclesInfo(int nArgs)
|
|||
return UPDATE_ALL;
|
||||
}
|
||||
|
||||
Update_t CmdCyclesReset(int /*nArgs*/)
|
||||
{
|
||||
g_videoScannerDisplayInfo.savedCumulativeCycles = g_nCumulativeCycles;
|
||||
return UPDATE_ALL;
|
||||
}
|
||||
|
||||
// View ___________________________________________________________________________________________
|
||||
|
||||
// See: CmdWindowViewOutput (int nArgs)
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
// Prototypes _______________________________________________________________
|
||||
|
||||
// Bookmarks
|
||||
bool Bookmark_Find( const WORD nAddress );
|
||||
int Bookmark_Find( const WORD nAddress );
|
||||
|
||||
// Breakpoints
|
||||
int CheckBreakpointsIO ();
|
||||
|
|
|
@ -123,6 +123,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
{TEXT("PAGEDOWN4K" ) , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" }, // Ctrl
|
||||
// Cycles info
|
||||
{TEXT("CYCLES") , CmdCyclesInfo , CMD_CYCLES_INFO, "Cycles display configuration" },
|
||||
{TEXT("RCC") , CmdCyclesReset , CMD_CYCLES_RESET, "Reset cycles counter" },
|
||||
// Disassembler Data
|
||||
{TEXT("Z") , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" },
|
||||
{TEXT("X") , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" },
|
||||
|
|
|
@ -622,7 +622,7 @@ void DebuggerSetColorBG( COLORREF nRGB, bool bTransparent )
|
|||
|
||||
// @param glyph Specifies a native glyph from the 16x16 chars Apple Font Texture.
|
||||
//===========================================================================
|
||||
void PrintGlyph( const int x, const int y, const char glyph )
|
||||
void PrintGlyph( const int x, const int y, const int glyph )
|
||||
{
|
||||
HDC hDstDC = GetDebuggerMemDC();
|
||||
|
||||
|
@ -1935,7 +1935,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
|
|||
bool bBreakpointEnable;
|
||||
GetBreakpointInfo( nBaseAddress, bBreakpointActive, bBreakpointEnable );
|
||||
bool bAddressAtPC = (nBaseAddress == regs.pc);
|
||||
bool bAddressIsBookmark = Bookmark_Find( nBaseAddress );
|
||||
int bAddressIsBookmark = Bookmark_Find( nBaseAddress );
|
||||
|
||||
DebugColors_e iBackground = BG_DISASM_1;
|
||||
DebugColors_e iForeground = FG_DISASM_MNEMONIC; // FG_DISASM_TEXT;
|
||||
|
@ -2005,16 +2005,8 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
|
|||
}
|
||||
}
|
||||
|
||||
if (bAddressIsBookmark)
|
||||
{
|
||||
DebuggerSetColorBG( DebuggerGetColor( BG_DISASM_BOOKMARK ) );
|
||||
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_BOOKMARK ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
|
||||
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
|
||||
}
|
||||
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
|
||||
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
|
||||
|
||||
// Address
|
||||
if (! bCursorLine)
|
||||
|
@ -2030,18 +2022,31 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
|
|||
PrintTextCursorX( (LPCTSTR) line.sAddress, linerect );
|
||||
}
|
||||
|
||||
if (bAddressIsBookmark)
|
||||
{
|
||||
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
|
||||
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
|
||||
}
|
||||
|
||||
// Address Seperator
|
||||
if (! bCursorLine)
|
||||
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ) );
|
||||
|
||||
if (g_bConfigDisasmAddressColon)
|
||||
PrintTextCursorX( ":", linerect );
|
||||
{
|
||||
if (bAddressIsBookmark)
|
||||
{
|
||||
DebuggerSetColorBG( DebuggerGetColor( BG_DISASM_BOOKMARK ) );
|
||||
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_BOOKMARK ) );
|
||||
|
||||
// Can't use PrintTextCursorX() as that clamps chars > 0x7F to Mouse Text
|
||||
// char bookmark_text[2] = { 0x7F + bAddressIsBookmark, 0 };
|
||||
// PrintTextCursorX( bookmark_text, linerect );
|
||||
FillRect( GetDebuggerMemDC(), &linerect, g_hConsoleBrushBG );
|
||||
PrintGlyph( linerect.left, linerect.top, 0x7F + bAddressIsBookmark ); // Glyphs 0x80 .. 0x89 = Unicode U+24EA, U+2460 .. U+2468
|
||||
linerect.left += g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontWidthAvg;
|
||||
|
||||
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
|
||||
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
|
||||
}
|
||||
else
|
||||
PrintTextCursorX( ":", linerect );
|
||||
}
|
||||
else
|
||||
PrintTextCursorX( " ", linerect ); // bugfix, not showing "addr:" doesn't alternate color lines
|
||||
|
||||
|
@ -3784,8 +3789,15 @@ void DrawVideoScannerInfo (int line)
|
|||
PrintText("cycles:", rect);
|
||||
rect.left += nameWidth * nFontWidth;
|
||||
|
||||
UINT cycles = 0;
|
||||
if (g_videoScannerDisplayInfo.cycleMode == VideoScannerDisplayInfo::abs)
|
||||
cycles = (UINT)g_nCumulativeCycles;
|
||||
else if (g_videoScannerDisplayInfo.cycleMode == VideoScannerDisplayInfo::rel)
|
||||
cycles = g_videoScannerDisplayInfo.cycleDelta;
|
||||
else // "part"
|
||||
cycles = (UINT)g_videoScannerDisplayInfo.lastCumulativeCycles - (UINT)g_videoScannerDisplayInfo.savedCumulativeCycles;
|
||||
|
||||
char sValue[10];
|
||||
const UINT cycles = g_videoScannerDisplayInfo.isAbsCycle ? (UINT)g_nCumulativeCycles : g_videoScannerDisplayInfo.cycleDelta;
|
||||
sprintf_s(sValue, sizeof(sValue), "%08X", cycles);
|
||||
PrintText(sValue, rect);
|
||||
}
|
||||
|
|
|
@ -102,15 +102,17 @@
|
|||
class VideoScannerDisplayInfo
|
||||
{
|
||||
public:
|
||||
VideoScannerDisplayInfo(void) : isDecimal(false), isHorzReal(false), isAbsCycle(false),
|
||||
VideoScannerDisplayInfo(void) : isDecimal(false), isHorzReal(false), cycleMode(rel),
|
||||
lastCumulativeCycles(0), cycleDelta(0) {}
|
||||
void Reset(void) { lastCumulativeCycles = g_nCumulativeCycles; cycleDelta = 0; }
|
||||
void Reset(void) { lastCumulativeCycles = savedCumulativeCycles = g_nCumulativeCycles; cycleDelta = 0; }
|
||||
|
||||
bool isDecimal;
|
||||
bool isHorzReal;
|
||||
bool isAbsCycle;
|
||||
enum CYCLE_MODE {abs=0, rel, part};
|
||||
CYCLE_MODE cycleMode;
|
||||
|
||||
unsigned __int64 lastCumulativeCycles;
|
||||
unsigned __int64 savedCumulativeCycles;
|
||||
UINT cycleDelta;
|
||||
};
|
||||
|
||||
|
|
|
@ -1408,11 +1408,17 @@ Update_t CmdHelpSpecific (int nArgs)
|
|||
break;
|
||||
// Cycles
|
||||
case CMD_CYCLES_INFO:
|
||||
ConsoleColorizePrint(sText, " Usage: <abs|rel>");
|
||||
ConsoleColorizePrint(sText, " Usage: <abs|rel|part>");
|
||||
ConsoleBufferPush(" Where:");
|
||||
ConsoleBufferPush(" <abs|rel> changes cycle output to absolute/relative");
|
||||
ConsoleBufferPush(" abs = absolute number of cycles since power-on");
|
||||
ConsoleBufferPush(" rel = number of cycles since last step or breakpoint");
|
||||
ConsoleBufferPush(" part= number of cycles relative to current instruction");
|
||||
break;
|
||||
case CMD_CYCLES_RESET:
|
||||
ConsoleBufferPush(" Use in conjunctioned with 'cycles part' to reset to current instruction");
|
||||
break;
|
||||
// Video-Scanner
|
||||
|
||||
case CMD_VIDEO_SCANNER_INFO:
|
||||
ConsoleColorizePrint(sText, " Usage: <dec|hex|real|apple>");
|
||||
ConsoleBufferPush(" Where:");
|
||||
|
|
|
@ -377,6 +377,7 @@
|
|||
, CMD_CURSOR_PAGE_DOWN_4K // Down to nearest 4K boundary
|
||||
// Cycles info
|
||||
, CMD_CYCLES_INFO
|
||||
, CMD_CYCLES_RESET
|
||||
// Disassembler Data
|
||||
, CMD_DISASM_DATA
|
||||
, CMD_DISASM_CODE
|
||||
|
@ -666,7 +667,8 @@
|
|||
Update_t CmdCursorPageUp4K (int nArgs);
|
||||
|
||||
// Cycles info
|
||||
Update_t CmdCyclesInfo (int nArgs);
|
||||
Update_t CmdCyclesInfo (int nArgs);
|
||||
Update_t CmdCyclesReset (int nArgs);
|
||||
|
||||
// Disk
|
||||
Update_t CmdDisk (int nArgs);
|
||||
|
|
|
@ -650,6 +650,10 @@ BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, UL
|
|||
|
||||
BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL));
|
||||
|
||||
// If no joystick connected, then this is always active (GH#778)
|
||||
if (joyinfo[joytype[nJoyNum]] == DEVICE_NONE)
|
||||
nPdlCntrActive = TRUE;
|
||||
|
||||
return MemReadFloatingBus(nPdlCntrActive, nExecutedCycles);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
#include "SSI263Phonemes.h"
|
||||
|
||||
#define LOG_SSI263 0
|
||||
#define LOG_SSI263B 0 // Alternate SSI263 logging (use in conjunction with CPU.cpp's LOG_IRQ_TAKEN_AND_RTI)
|
||||
|
||||
|
||||
#define SY6522_DEVICE_A 0
|
||||
|
@ -187,7 +188,8 @@ static bool g_bMBAvailable = false;
|
|||
|
||||
static SS_CARDTYPE g_SoundcardType = CT_Empty; // Use CT_Empty to mean: no soundcard
|
||||
static bool g_bPhasorEnable = false;
|
||||
static BYTE g_nPhasorMode = 0; // 0=Mockingboard emulation, 1=Phasor native
|
||||
enum PHASOR_MODE {PH_Mockingboard=0, PH_UNDEF1, PH_UNDEF2, PH_UNDEF3, PH_UNDEF4, PH_Phasor/*=5*/, PH_UNDEF6, PH_EchoPlus/*=7*/};
|
||||
static PHASOR_MODE g_phasorMode = PH_Mockingboard;
|
||||
static UINT g_PhasorClockScaleFactor = 1; // for save-state only
|
||||
|
||||
//-------------------------------------
|
||||
|
@ -363,8 +365,7 @@ static void UpdateIFR(SY6522_AY8910* pMB, BYTE clr_ifr, BYTE set_ifr=0)
|
|||
// NB. Mockingboard generates IRQ on both 6522s:
|
||||
// . SSI263's IRQ (A/!R) is routed via the 2nd 6522 (at $Cx80) and must generate a 6502 IRQ (not NMI)
|
||||
// . SC-01's IRQ (A/!R) is also routed via a (2nd?) 6522
|
||||
// Phasor's SSI263 appears to be wired directly to the 6502's IRQ (ie. not via a 6522)
|
||||
// . I assume Phasor's 6522s just generate 6502 IRQs (not NMIs)
|
||||
// Phasor's SSI263 IRQ (A/!R) line is *also* wired directly to the 6502's IRQ (as well as the 6522's CA1)
|
||||
|
||||
if (bIRQ)
|
||||
CpuIrqAssert(IS_6522);
|
||||
|
@ -394,7 +395,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
|
|||
|
||||
if(g_bPhasorEnable)
|
||||
{
|
||||
int nAY_CS = (g_nPhasorMode & 1) ? (~(nValue >> 3) & 3) : 1;
|
||||
int nAY_CS = (g_phasorMode == PH_Phasor) ? (~(nValue >> 3) & 3) : 1;
|
||||
|
||||
if(nAY_CS & 1)
|
||||
AY8910_Write(nDevice, nReg, nValue, 0);
|
||||
|
@ -590,31 +591,68 @@ const BYTE CONTROL_MASK = 0x80;
|
|||
const BYTE ARTICULATION_MASK = 0x70;
|
||||
const BYTE AMPLITUDE_MASK = 0x0F;
|
||||
|
||||
static BYTE SSI263_Read(BYTE nDevice, BYTE nReg)
|
||||
#if LOG_SSI263B
|
||||
static int ssiRegs[5]={-1,-1,-1,-1,-1};
|
||||
|
||||
void SSI_Output(void)
|
||||
{
|
||||
LogOutput("SSI: ");
|
||||
for (int i=0; i<=4; i++)
|
||||
{
|
||||
char r[3]="--";
|
||||
if (ssiRegs[i]>=0) sprintf(r,"%02X",ssiRegs[i]);
|
||||
LogOutput("%s ", r);
|
||||
ssiRegs[i] = -1;
|
||||
}
|
||||
LogOutput("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static BYTE SSI263_Read(BYTE nDevice, ULONG nExecutedCycles)
|
||||
{
|
||||
SY6522_AY8910* pMB = &g_MB[nDevice];
|
||||
|
||||
// Regardless of register, just return inverted A/!R in bit7
|
||||
// . A/!R is low for IRQ
|
||||
|
||||
return pMB->SpeechChip.CurrentMode << 7;
|
||||
return MemReadFloatingBus(pMB->SpeechChip.CurrentMode & 1, nExecutedCycles);
|
||||
}
|
||||
|
||||
static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
|
||||
{
|
||||
SY6522_AY8910* pMB = &g_MB[nDevice];
|
||||
|
||||
#if LOG_SSI263B
|
||||
_ASSERT(nReg < 5);
|
||||
if (nReg>4) nReg=4;
|
||||
if (ssiRegs[nReg]>=0) SSI_Output(); // overwriting a reg
|
||||
ssiRegs[nReg] = nValue;
|
||||
#endif
|
||||
|
||||
switch(nReg)
|
||||
{
|
||||
case SSI_DURPHON:
|
||||
#if LOG_SSI263
|
||||
if(g_fh) fprintf(g_fh, "DUR = 0x%02X, PHON = 0x%02X\n\n", nValue>>6, nValue&PHONEME_MASK);
|
||||
LogOutput("DUR = %d, PHON = 0x%02X\n", nValue>>6, nValue&PHONEME_MASK);
|
||||
#endif
|
||||
#if LOG_SSI263B
|
||||
SSI_Output();
|
||||
#endif
|
||||
|
||||
// Datasheet is not clear, but a write to DURPHON must clear the IRQ
|
||||
if (pMB->sy6522.PCR == 0x0C)
|
||||
UpdateIFR(pMB, IxR_PERIPHERAL);
|
||||
else // Phasor's SSI263.IRQ line appears to be wired directly to IRQ (Bypassing the 6522)
|
||||
// Notes:
|
||||
// . Phasor's text-to-speech playback has no CTL H->L
|
||||
// - ISR just writes CTL=0 (and new ART+AMP values), and writes DUR=x (and new PHON)
|
||||
// - since no CTL H->L, then DUR value doesn't take affect (so continue using previous)
|
||||
// - so the write to DURPHON must clear the IRQ
|
||||
// . Does a write of CTL=0 clear IRQ? (ie. CTL 0->0)
|
||||
// . Does a write of CTL=1 clear IRQ? (ie. CTL 0->1)
|
||||
// - SSI263 datasheet says: "Setting the Control bit (CTL) to a logic one puts the device into Power Down mode..."
|
||||
// . Does phoneme output only happen when CTL=0? (Otherwise device is in PD mode)
|
||||
|
||||
// SSI263 datasheet is not clear, but a write to DURPHON must clear the IRQ.
|
||||
// NB. For Mockingboard, A/!R is ack'ed by 6522's PCR handshake.
|
||||
if (g_bPhasorEnable && g_phasorMode == PH_Phasor)
|
||||
CpuIrqDeassert(IS_SPEECH);
|
||||
|
||||
pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin
|
||||
|
@ -623,7 +661,6 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
|
|||
|
||||
g_nSSI263Device = nDevice;
|
||||
|
||||
// Phoneme output not dependent on CONTROL bit
|
||||
SSI263_Play(nValue & PHONEME_MASK);
|
||||
break;
|
||||
case SSI_INFLECT:
|
||||
|
@ -632,6 +669,7 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
|
|||
#endif
|
||||
pMB->SpeechChip.Inflection = nValue;
|
||||
break;
|
||||
|
||||
case SSI_RATEINF:
|
||||
#if LOG_SSI263
|
||||
if(g_fh) fprintf(g_fh, "RATE = 0x%02X, INF = 0x%02X\n", nValue>>4, nValue&0x0F);
|
||||
|
@ -641,19 +679,44 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
|
|||
case SSI_CTTRAMP:
|
||||
#if LOG_SSI263
|
||||
if(g_fh) fprintf(g_fh, "CTRL = %d, ART = 0x%02X, AMP=0x%02X\n", nValue>>7, (nValue&ARTICULATION_MASK)>>4, nValue&LITUDE_MASK);
|
||||
//
|
||||
{
|
||||
bool H2L = (pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK);
|
||||
char newMode[20];
|
||||
sprintf_s(newMode, sizeof(newMode), "(new mode=%d)", pMB->SpeechChip.DurationPhoneme>>6);
|
||||
LogOutput("CTRL = %d->%d, ART = 0x%02X, AMP=0x%02X %s\n", pMB->SpeechChip.CtrlArtAmp>>7, nValue>>7, (nValue&ARTICULATION_MASK)>>4, nValue&LITUDE_MASK, H2L?newMode:"");
|
||||
}
|
||||
#endif
|
||||
#if LOG_SSI263B
|
||||
if ( ((pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK)) || ((nValue&0xF) == 0x0) ) // H->L or amp=0
|
||||
SSI_Output();
|
||||
#endif
|
||||
if((pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK)) // H->L
|
||||
{
|
||||
pMB->SpeechChip.CurrentMode = pMB->SpeechChip.DurationPhoneme & DURATION_MODE_MASK;
|
||||
if (pMB->SpeechChip.CurrentMode == MODE_IRQ_DISABLED)
|
||||
{
|
||||
// "Disables A/!R output only; does not change previous A/!R response" (SSI263 datasheet)
|
||||
// CpuIrqDeassert(IS_SPEECH);
|
||||
}
|
||||
}
|
||||
|
||||
pMB->SpeechChip.CtrlArtAmp = nValue;
|
||||
|
||||
// "Setting the Control bit (CTL) to a logic one puts the device into Power Down mode..." (SSI263 datasheet)
|
||||
if (pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK)
|
||||
{
|
||||
// CpuIrqDeassert(IS_SPEECH);
|
||||
// pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin
|
||||
}
|
||||
break;
|
||||
case SSI_FILFREQ:
|
||||
case SSI_FILFREQ: // RegAddr.b2=1 (b1 & b0 are: don't care)
|
||||
default:
|
||||
#if LOG_SSI263
|
||||
if(g_fh) fprintf(g_fh, "FFREQ = 0x%02X\n", nValue);
|
||||
#endif
|
||||
pMB->SpeechChip.FilterFreq = nValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -751,7 +814,7 @@ static UINT64 g_uLastMBUpdateCycle = 0;
|
|||
// Called by:
|
||||
// . MB_UpdateCycles() - when g_nMBTimerDevice == {0,1,2,3}
|
||||
// . MB_PeriodicUpdate() - when g_nMBTimerDevice == kTIMERDEVICE_INVALID
|
||||
static void MB_Update(void)
|
||||
static void MB_UpdateInt(void)
|
||||
{
|
||||
if (!MockingboardVoice.bActive)
|
||||
return;
|
||||
|
@ -958,8 +1021,59 @@ static void MB_Update(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void MB_Update(void)
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
extern UINT64 g_timeMB_NoTimer;
|
||||
extern UINT64 g_timeMB_Timer;
|
||||
PerfMarker perfMarker(g_nMBTimerDevice == kTIMERDEVICE_INVALID ? g_timeMB_NoTimer : g_timeMB_Timer);
|
||||
#endif
|
||||
|
||||
MB_UpdateInt();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Called by SSI263Thread(), MB_LoadSnapshot & Phasor_LoadSnapshot
|
||||
// Pre: g_bVotraxPhoneme, g_bPhasorEnable, g_phasorMode
|
||||
static void SetSpeechIRQ(SY6522_AY8910* pMB)
|
||||
{
|
||||
if (!g_bVotraxPhoneme)
|
||||
{
|
||||
// Always set SSI263's D7 pin regardless of SSI263 mode (DR1:0), including MODE_IRQ_DISABLED
|
||||
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
|
||||
|
||||
if ((pMB->SpeechChip.CurrentMode & DURATION_MODE_MASK) != MODE_IRQ_DISABLED)
|
||||
{
|
||||
if (!g_bPhasorEnable || (g_bPhasorEnable && g_phasorMode == PH_Mockingboard))
|
||||
{
|
||||
if ((pMB->sy6522.PCR & 1) == 0) // CA1 Latch/Input = 0 (Negative active edge)
|
||||
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
|
||||
if (pMB->sy6522.PCR == 0x0C) // CA2 Control = b#110 (Low output)
|
||||
pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin (cleared by 6522's PCR CA1/CA2 handshake)
|
||||
|
||||
// NB. Don't set CTL=1, as Mockingboard(SMS) speech doesn't work (it sets MODE_IRQ_DISABLED mode during ISR)
|
||||
//pMB->SpeechChip.CtrlArtAmp |= CONTROL_MASK; // 6522's CA2 sets Power Down mode (pin 18), which sets Control bit
|
||||
}
|
||||
else if (g_bPhasorEnable && g_phasorMode == PH_Phasor) // Phasor's SSI263 IRQ (A/!R) line is *also* wired directly to the 6502's IRQ (as well as the 6522's CA1)
|
||||
{
|
||||
CpuIrqAssert(IS_SPEECH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if (g_bVotraxPhoneme && pMB->sy6522.PCR == 0xB0)
|
||||
{
|
||||
// !A/R: Time-out of old phoneme (signal goes from low to high)
|
||||
|
||||
UpdateIFR(pMB, 0, IxR_VOTRAX);
|
||||
|
||||
g_bVotraxPhoneme = false;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
|
||||
{
|
||||
while(1)
|
||||
|
@ -990,32 +1104,15 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
|
|||
//if(g_fh) fprintf(g_fh, "IRQ: Phoneme complete (0x%02X)\n\n", g_nCurrentActivePhoneme);
|
||||
#endif
|
||||
|
||||
if (g_nCurrentActivePhoneme < 0)
|
||||
continue; // On CTRL+RESET or power-cycle (during phoneme playback): ResetState() is called, which set g_nCurrentActivePhoneme=-1
|
||||
|
||||
SSI263Voice[g_nCurrentActivePhoneme].bActive = false;
|
||||
g_nCurrentActivePhoneme = -1;
|
||||
|
||||
// Phoneme complete, so generate IRQ if necessary
|
||||
SY6522_AY8910* pMB = &g_MB[g_nSSI263Device];
|
||||
|
||||
if (!g_bVotraxPhoneme && pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED)
|
||||
{
|
||||
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
|
||||
|
||||
if (pMB->sy6522.PCR == 0x0C)
|
||||
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
|
||||
else // Phasor's SSI263.IRQ line appears to be wired directly to IRQ (Bypassing the 6522)
|
||||
CpuIrqAssert(IS_SPEECH);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if (g_bVotraxPhoneme && pMB->sy6522.PCR == 0xB0)
|
||||
{
|
||||
// !A/R: Time-out of old phoneme (signal goes from low to high)
|
||||
|
||||
UpdateIFR(pMB, 0, IxR_VOTRAX);
|
||||
|
||||
g_bVotraxPhoneme = false;
|
||||
}
|
||||
SetSpeechIRQ(pMB);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1470,7 +1567,7 @@ static void ResetState()
|
|||
g_bMB_RegAccessedFlag = false;
|
||||
g_bMB_Active = false;
|
||||
|
||||
g_nPhasorMode = 0;
|
||||
g_phasorMode = PH_Mockingboard;
|
||||
g_PhasorClockScaleFactor = 1;
|
||||
|
||||
g_uLastMBUpdateCycle = 0;
|
||||
|
@ -1499,6 +1596,8 @@ void MB_Reset() // CTRL+RESET or power-cycle
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Echo+ mode - Phasor's 2nd 6522 is mapped to every 16-byte offset in $Cnxx (Echo+ has a single 6522 controlling two AY-3-8913's)
|
||||
|
||||
static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
|
||||
{
|
||||
if (g_bFullSpeed)
|
||||
|
@ -1526,11 +1625,13 @@ static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULO
|
|||
if(nMB != 0) // Slot4 only
|
||||
return MemReadFloatingBus(nExecutedCycles);
|
||||
|
||||
int CS;
|
||||
if(g_nPhasorMode & 1)
|
||||
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
|
||||
else // Mockingboard Mode
|
||||
int CS = 0;
|
||||
if (g_phasorMode == PH_Mockingboard)
|
||||
CS = ( ( nAddr & 0x80 ) >> 7 ) + 1; // 1 or 2
|
||||
else if (g_phasorMode == PH_Phasor)
|
||||
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
|
||||
else if (g_phasorMode == PH_EchoPlus)
|
||||
CS = 2;
|
||||
|
||||
BYTE nRes = 0;
|
||||
|
||||
|
@ -1542,23 +1643,21 @@ static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULO
|
|||
|
||||
bool bAccessedDevice = (CS & 3) ? true : false;
|
||||
|
||||
if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
|
||||
if ((g_phasorMode == PH_Phasor) && ((nAddr & 0xD0) == 0x40)) // $Cn4x and $Cn6x (Mockingboard mode: SSI263.bit7 not readable)
|
||||
{
|
||||
nRes |= SSI263_Read(nMB, nAddr&0xf);
|
||||
_ASSERT(!bAccessedDevice);
|
||||
nRes = SSI263_Read(nMB*2+1, nExecutedCycles); // SSI263 only drives bit7
|
||||
bAccessedDevice = true;
|
||||
}
|
||||
|
||||
return bAccessedDevice ? nRes : MemReadFloatingBus(nExecutedCycles);
|
||||
}
|
||||
|
||||
if(nOffset <= (SY6522A_Offset+0x0F))
|
||||
// NB. Mockingboard: SSI263.bit7 not readable (TODO: check this with real h/w)
|
||||
if (nOffset < SY6522B_Offset)
|
||||
return SY6522_Read(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_A, nAddr&0xf);
|
||||
else if((nOffset >= SY6522B_Offset) && (nOffset <= (SY6522B_Offset+0x0F)))
|
||||
return SY6522_Read(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf);
|
||||
else if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
|
||||
return SSI263_Read(nMB, nAddr&0xf);
|
||||
else
|
||||
return MemReadFloatingBus(nExecutedCycles);
|
||||
return SY6522_Read(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1592,10 +1691,12 @@ static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL
|
|||
|
||||
int CS;
|
||||
|
||||
if(g_nPhasorMode & 1)
|
||||
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
|
||||
else // Mockingboard Mode
|
||||
if (g_phasorMode == PH_Mockingboard)
|
||||
CS = ( ( nAddr & 0x80 ) >> 7 ) + 1; // 1 or 2
|
||||
else if (g_phasorMode == PH_Phasor)
|
||||
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
|
||||
else if (g_phasorMode == PH_EchoPlus)
|
||||
CS = 2;
|
||||
|
||||
if(CS & 1)
|
||||
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_A, nAddr&0xf, nValue);
|
||||
|
@ -1603,33 +1704,64 @@ static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL
|
|||
if(CS & 2)
|
||||
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf, nValue);
|
||||
|
||||
if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
|
||||
SSI263_Write(nMB*2+1, nAddr&0xf, nValue); // Second 6522 is used for speech chip
|
||||
int CS_SSI263 = (g_phasorMode == PH_Mockingboard) ? (nAddr & 0xE0) == 0x40 // Mockingboard: $Cn4x
|
||||
: (g_phasorMode == PH_Phasor) ? (nAddr & 0xC0) == 0x40 // Phasor: $Cn4x and $Cn6x
|
||||
: 0; // Echo+
|
||||
|
||||
if (CS_SSI263)
|
||||
{
|
||||
// NB. Mockingboard mode: writes to $Cn4x/SSI263 also get written to 1st 6522 (have confirmed on real Phasor h/w)
|
||||
_ASSERT( (g_phasorMode == PH_Mockingboard && (CS==0 || CS==1)) || (g_phasorMode == PH_Phasor && (CS==0)) );
|
||||
SSI263_Write(nMB*2+1, nAddr&0x7, nValue); // Second 6522 is used for speech chip
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(nOffset <= (SY6522A_Offset+0x0F))
|
||||
if (nOffset < SY6522B_Offset)
|
||||
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_A, nAddr&0xf, nValue);
|
||||
else if((nOffset >= SY6522B_Offset) && (nOffset <= (SY6522B_Offset+0x0F)))
|
||||
else
|
||||
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf, nValue);
|
||||
else if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
|
||||
SSI263_Write(nMB*2+1, nAddr&0xf, nValue); // Second 6522 is used for speech chip
|
||||
|
||||
if ((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x07)))
|
||||
SSI263_Write(nMB*2+1, nAddr&0x7, nValue); // Second 6522 is used for speech chip -- TODO confirm with real MB h/w that writes go to 1st 6522
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Phasor's DEVICE SELECT' logic:
|
||||
// . if addr.[b3]==1, then clear the card's mode bits b2:b0
|
||||
// . if any of addr.[b2:b0] are a logic 1, then set these bits in the card's mode
|
||||
//
|
||||
// Example DEVICE SELECT' accesses for Phasor in slot-4: (from empirical observations on real Phasor h/w)
|
||||
// 1)
|
||||
// . RESET -> Mockingboard mode (b#000)
|
||||
// . $C0C5 -> Phasor mode (b#101)
|
||||
// 2)
|
||||
// . RESET -> Mockingboard mode (b#000)
|
||||
// . $C0C1, then $C0C4 (or $C0C4, then $C0C1) -> Phasor mode (b#101)
|
||||
// . $C0C2 -> Echo+ mode (b#111)
|
||||
// . $C0C5 -> remaing in Echo+ mode (b#111)
|
||||
// So $C0C5 seemingly results in 2 different modes.
|
||||
//
|
||||
|
||||
static BYTE __stdcall PhasorIO(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
|
||||
{
|
||||
if(!g_bPhasorEnable)
|
||||
if (!g_bPhasorEnable)
|
||||
return MemReadFloatingBus(nExecutedCycles);
|
||||
|
||||
if(g_nPhasorMode < 2)
|
||||
g_nPhasorMode = nAddr & 1;
|
||||
UINT bits = (UINT) g_phasorMode;
|
||||
if (nAddr & 8)
|
||||
bits = 0;
|
||||
bits |= (nAddr & 7);
|
||||
g_phasorMode = (PHASOR_MODE) bits;
|
||||
|
||||
g_PhasorClockScaleFactor = (nAddr & 4) ? 2 : 1;
|
||||
if (g_phasorMode == PH_Mockingboard || g_phasorMode == PH_EchoPlus)
|
||||
g_PhasorClockScaleFactor = 1;
|
||||
else if (g_phasorMode == PH_Phasor)
|
||||
g_PhasorClockScaleFactor = 2;
|
||||
|
||||
AY8910_InitClock((int)(Get6502BaseClock() * g_PhasorClockScaleFactor));
|
||||
|
||||
|
@ -1972,7 +2104,10 @@ void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot)
|
|||
// 3: Added: Unit state - GH#320
|
||||
// 4: Added: 6522 timerIrqDelay - GH#652
|
||||
// 5: Added: Unit state-B (Phasor only) - GH#659
|
||||
const UINT kUNIT_VERSION = 5;
|
||||
// 6: Changed SS_YAML_KEY_PHASOR_MODE from (0,1) to (0,5,7)
|
||||
// Added SS_YAML_KEY_VOTRAX_PHONEME
|
||||
// Removed: redundant SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR
|
||||
const UINT kUNIT_VERSION = 6;
|
||||
|
||||
const UINT NUM_MB_UNITS = 2;
|
||||
const UINT NUM_PHASOR_UNITS = 2;
|
||||
|
@ -2011,9 +2146,11 @@ const UINT NUM_PHASOR_UNITS = 2;
|
|||
#define SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY "Timer2 IRQ Delay"
|
||||
|
||||
#define SS_YAML_KEY_PHASOR_UNIT "Unit"
|
||||
#define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor"
|
||||
#define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor" // Redundant from v6
|
||||
#define SS_YAML_KEY_PHASOR_MODE "Mode"
|
||||
|
||||
#define SS_YAML_KEY_VOTRAX_PHONEME "Votrax Phoneme"
|
||||
|
||||
std::string MB_GetSnapshotCardName(void)
|
||||
{
|
||||
static const std::string name("Mockingboard C");
|
||||
|
@ -2070,6 +2207,8 @@ void MB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot)
|
|||
|
||||
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
|
||||
|
||||
yamlSaveHelper.SaveBool(SS_YAML_KEY_VOTRAX_PHONEME, g_bVotraxPhoneme);
|
||||
|
||||
for(UINT i=0; i<NUM_MB_UNITS; i++)
|
||||
{
|
||||
YamlSaveHelper::Label unit(yamlSaveHelper, "%s%d:\n", SS_YAML_KEY_MB_UNIT, i);
|
||||
|
@ -2145,6 +2284,8 @@ bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
|
|||
if (version < 1 || version > kUNIT_VERSION)
|
||||
throw std::string("Card: wrong version");
|
||||
|
||||
g_bVotraxPhoneme = (version >= 6) ? yamlLoadHelper.LoadBool(SS_YAML_KEY_VOTRAX_PHONEME) : false;
|
||||
|
||||
AY8910UpdateSetCycles();
|
||||
|
||||
const UINT nMbCardNum = slot - SLOT4;
|
||||
|
@ -2196,19 +2337,15 @@ bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
|
|||
StartTimer1(pMB); // Attempt to start timer
|
||||
}
|
||||
|
||||
// Crude - currently only support a single speech chip
|
||||
// FIX THIS:
|
||||
// . Speech chip could be Votrax instead
|
||||
// . Is this IRQ compatible with Phasor?
|
||||
if(pMB->SpeechChip.DurationPhoneme)
|
||||
// FIXME: currently only support a single speech chip
|
||||
// NB. g_bVotraxPhoneme is never true, as the phoneme playback completes in SSI263Thread() before this point in the save-state.
|
||||
// NB. SpeechChip.DurationPhoneme will mostly be non-zero during speech playback, as this is the SSI263 register, not whether the phonene is active.
|
||||
// FIXME: So possible race-condition between saving-state & SSI263Thread()
|
||||
if (pMB->SpeechChip.DurationPhoneme || g_bVotraxPhoneme)
|
||||
{
|
||||
g_nSSI263Device = nDeviceNum;
|
||||
|
||||
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL))
|
||||
{
|
||||
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
|
||||
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
|
||||
}
|
||||
g_bPhasorEnable = false;
|
||||
SetSpeechIRQ(pMB);
|
||||
}
|
||||
|
||||
nDeviceNum++;
|
||||
|
@ -2234,8 +2371,8 @@ void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot)
|
|||
|
||||
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
|
||||
|
||||
yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR, g_PhasorClockScaleFactor);
|
||||
yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_MODE, g_nPhasorMode);
|
||||
yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_MODE, g_phasorMode);
|
||||
yamlSaveHelper.SaveBool(SS_YAML_KEY_VOTRAX_PHONEME, g_bVotraxPhoneme);
|
||||
|
||||
for(UINT i=0; i<NUM_PHASOR_UNITS; i++)
|
||||
{
|
||||
|
@ -2268,8 +2405,21 @@ bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version
|
|||
if (version < 1 || version > kUNIT_VERSION)
|
||||
throw std::string("Card: wrong version");
|
||||
|
||||
g_PhasorClockScaleFactor = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR);
|
||||
g_nPhasorMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_MODE);
|
||||
if (version < 6)
|
||||
yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR); // Consume redundant data
|
||||
|
||||
UINT phasorMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_MODE);
|
||||
if (version < 6)
|
||||
{
|
||||
if (phasorMode == 0)
|
||||
phasorMode = PH_Mockingboard;
|
||||
else
|
||||
phasorMode = PH_Phasor;
|
||||
}
|
||||
g_phasorMode = (PHASOR_MODE) phasorMode;
|
||||
g_PhasorClockScaleFactor = (g_phasorMode == PH_Phasor) ? 2 : 1;
|
||||
|
||||
g_bVotraxPhoneme = (version >= 6) ? yamlLoadHelper.LoadBool(SS_YAML_KEY_VOTRAX_PHONEME) : false;
|
||||
|
||||
AY8910UpdateSetCycles();
|
||||
|
||||
|
@ -2324,19 +2474,12 @@ bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version
|
|||
StartTimer1(pMB); // Attempt to start timer
|
||||
}
|
||||
|
||||
// Crude - currently only support a single speech chip
|
||||
// FIX THIS:
|
||||
// . Speech chip could be Votrax instead
|
||||
// . Is this IRQ compatible with Phasor?
|
||||
if(pMB->SpeechChip.DurationPhoneme)
|
||||
// FIXME: currently only support a single speech chip
|
||||
if (pMB->SpeechChip.DurationPhoneme || g_bVotraxPhoneme)
|
||||
{
|
||||
g_nSSI263Device = nDeviceNum;
|
||||
|
||||
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL))
|
||||
{
|
||||
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
|
||||
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
|
||||
}
|
||||
g_bPhasorEnable = true;
|
||||
SetSpeechIRQ(pMB);
|
||||
}
|
||||
|
||||
nDeviceNum += 2;
|
||||
|
|
|
@ -2091,6 +2091,11 @@ static void VideoUpdateCycles( int cyclesLeftToUpdate )
|
|||
//===========================================================================
|
||||
void NTSC_VideoUpdateCycles( UINT cycles6502 )
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
extern UINT64 g_timeVideo;
|
||||
PerfMarker perfMarker(g_timeVideo);
|
||||
#endif
|
||||
|
||||
_ASSERT(cycles6502 && cycles6502 < g_videoScanner6502Cycles); // Use NTSC_VideoRedrawWholeScreen() instead
|
||||
|
||||
if (g_bDelayVideoMode)
|
||||
|
|
|
@ -399,7 +399,9 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nExecutedCycles)
|
|||
if (g_bQuieterSpeaker) // quieten the speaker if 8 bit DAC in use
|
||||
speakerDriveLevel /= 4; // NB. Don't shift -ve number right: undefined behaviour (MSDN says: implementation-dependent)
|
||||
|
||||
ResetDCFilter();
|
||||
// When full-speed: Don't ResetDCFilter(), otherwise get occasional clicks when speaker toggled
|
||||
if (!g_bFullSpeed)
|
||||
ResetDCFilter();
|
||||
|
||||
if (g_nSpeakerData == speakerDriveLevel)
|
||||
g_nSpeakerData = ~speakerDriveLevel;
|
||||
|
@ -415,6 +417,11 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nExecutedCycles)
|
|||
// Called by ContinueExecution()
|
||||
void SpkrUpdate (DWORD totalcycles)
|
||||
{
|
||||
#ifdef LOG_PERF_TIMINGS
|
||||
extern UINT64 g_timeSpeaker;
|
||||
PerfMarker perfMarker(g_timeSpeaker);
|
||||
#endif
|
||||
|
||||
if(!g_bSpkrToggleFlag)
|
||||
{
|
||||
if(!g_nSpkrQuietCycleCount)
|
||||
|
|
Loading…
Add table
Reference in a new issue